1. Let's have some fun with EuRaylib

Andys EuRaylib 6 ( even though it says 5). These are each separate programs, make sure you have raylib setup, Eu32 bit, everything else is standard Eu.

-- random_pixels.ex 
-- Draws random pixels in random colours on an 800x600 window 
-- Requires: 32-bit Euphoria 4.x and Euraylib 5 (Andy P / Icy Viking) 
 
include std/rand.e 
include raylib.e 
 
constant SCREEN_W = 800 
constant SCREEN_H = 600 
constant PIXELS_PER_FRAME = 10000 
 
set_rand(time())   -- seed the random number generator 
 
InitWindow(SCREEN_W, SCREEN_H, "Euraylib 5 - Random Pixels") 
SetTargetFPS(60) 
 
while not WindowShouldClose() do 
 
    BeginDrawing() 
    ClearBackground(BLACK) 
 
    for i = 1 to PIXELS_PER_FRAME do 
        -- random position (raylib screen coords start at 0) 
        integer x = rand(SCREEN_W) - 1 
        integer y = rand(SCREEN_H) - 1 
 
        -- random colour {r, g, b, a} 
        sequence colour = {rand(256) - 1, rand(256) - 1, rand(256) - 1, 255} 
 
        DrawPixel(x, y, colour) 
    end for 
 
    EndDrawing() 
 
end while 
 
CloseWindow() 
 
-- lines.ex 
-- Lines screensaver: 1024x800 window, bouncing line with fading trail 
-- Requires: 32-bit Euphoria 4.x and Euraylib 5 (Andy P / Icy Viking) 
 
include std/rand.e 
include std/math.e 
include raylib.e 
 
constant SCREEN_W = 1024 
constant SCREEN_H = 800 
constant TRAIL_LENGTH = 80      -- how many old lines stay on screen 
constant MAX_SPEED = 7 
 
set_rand(time()) 
 
-- p = {x1, y1, x2, y2}  : the two endpoints of the current line 
sequence p = { 
    rand(SCREEN_W) - 1, rand(SCREEN_H) - 1, 
    rand(SCREEN_W) - 1, rand(SCREEN_H) - 1 
} 
 
-- v = velocity of each coordinate, random speed and direction 
sequence v = repeat(0, 4) 
for i = 1 to 4 do 
    v[i] = rand_range(2, MAX_SPEED) * (rand(2) * 2 - 3)   -- (rand(2)*2-3) is -1 or +1 
end for 
 
sequence history = {}     -- each entry: {x1, y1, x2, y2, r, g, b} 
atom hue = 0              -- drives the colour cycling 
 
InitWindow(SCREEN_W, SCREEN_H, "Euraylib 5 - Lines") 
SetTargetFPS(60) 
 
while not WindowShouldClose() do 
 
    -- move the endpoints, bouncing off the edges 
    for i = 1 to 4 do 
        integer limit 
        if remainder(i, 2) = 1 then 
            limit = SCREEN_W - 1   -- x coordinates 
        else 
            limit = SCREEN_H - 1   -- y coordinates 
        end if 
 
        p[i] += v[i] 
 
        if p[i] < 0 then 
            p[i] = 0 
            v[i] = -v[i] 
        elsif p[i] > limit then 
            p[i] = limit 
            v[i] = -v[i] 
        end if 
    end for 
 
    -- smoothly cycle the colour 
    hue += 0.02 
    integer r = floor(127.5 + 127.5 * sin(hue)) 
    integer g = floor(127.5 + 127.5 * sin(hue + 2.094)) 
    integer b = floor(127.5 + 127.5 * sin(hue + 4.188)) 
 
    -- add this frame's line to the trail, drop the oldest if it's full 
    history = append(history, {p[1], p[2], p[3], p[4], r, g, b}) 
    if length(history) > TRAIL_LENGTH then 
        history = history[2..$] 
    end if 
 
    BeginDrawing() 
    ClearBackground(BLACK) 
 
    -- draw oldest to newest, with newer lines more opaque 
    for i = 1 to length(history) do 
        sequence ln = history[i] 
        integer alpha = floor(255 * i / length(history)) 
        DrawLine(ln[1], ln[2], ln[3], ln[4], {ln[5], ln[6], ln[7], alpha}) 
    end for 
 
    EndDrawing() 
 
end while 
 
CloseWindow() 
-- cube.ex 
-- Rotating wireframe cube, 1024x800 window, colour-cycling edges 
-- Requires: 32-bit Euphoria 4.x and Euraylib 5 (Andy P / Icy Viking) 
 
include std/math.e 
include raylib.e 
 
constant SCREEN_W = 1024 
constant SCREEN_H = 800 
constant CENTRE_X = SCREEN_W / 2 
constant CENTRE_Y = SCREEN_H / 2 
 
constant CUBE_SIZE = 180      -- half the length of a cube edge, in pixels 
constant CAMERA_DIST = 700    -- distance from the "camera" to the cube centre 
constant FOCAL = 700          -- perspective strength 
 
-- the 8 corners of a cube centred on the origin 
constant verts = { 
    {-1, -1, -1}, { 1, -1, -1}, { 1,  1, -1}, {-1,  1, -1}, 
    {-1, -1,  1}, { 1, -1,  1}, { 1,  1,  1}, {-1,  1,  1} 
} 
 
-- the 12 edges, as pairs of indexes into verts 
constant edges = { 
    {1, 2}, {2, 3}, {3, 4}, {4, 1},     -- back face 
    {5, 6}, {6, 7}, {7, 8}, {8, 5},     -- front face 
    {1, 5}, {2, 6}, {3, 7}, {4, 8}      -- connecting edges 
} 
 
-- rotate a point around the X, then Y, then Z axis 
function rotate_point(sequence v, atom ax, atom ay, atom az) 
    atom x = v[1] 
    atom y = v[2] 
    atom z = v[3] 
    atom t 
 
    -- around X 
    t = y * cos(ax) - z * sin(ax) 
    z = y * sin(ax) + z * cos(ax) 
    y = t 
 
    -- around Y 
    t = x * cos(ay) + z * sin(ay) 
    z = -x * sin(ay) + z * cos(ay) 
    x = t 
 
    -- around Z 
    t = x * cos(az) - y * sin(az) 
    y = x * sin(az) + y * cos(az) 
    x = t 
 
    return {x, y, z} 
end function 
 
-- project a 3D point onto the 2D screen, returns {screen_x, screen_y} 
function project_point(sequence v) 
    atom scale = FOCAL / (CAMERA_DIST + v[3] * CUBE_SIZE) 
    integer sx = floor(CENTRE_X + v[1] * CUBE_SIZE * scale) 
    integer sy = floor(CENTRE_Y + v[2] * CUBE_SIZE * scale) 
    return {sx, sy} 
end function 
 
-- turn a hue angle (radians) into an {r, g, b, a} colour 
function hue_colour(atom h) 
    integer r = floor(127.5 + 127.5 * sin(h)) 
    integer g = floor(127.5 + 127.5 * sin(h + 2.094)) 
    integer b = floor(127.5 + 127.5 * sin(h + 4.188)) 
    return {r, g, b, 255} 
end function 
 
atom ax = 0 
atom ay = 0 
atom az = 0 
atom hue = 0 
 
InitWindow(SCREEN_W, SCREEN_H, "Euraylib 5 - Rotating Cube") 
SetTargetFPS(60) 
 
while not WindowShouldClose() do 
 
    -- advance the rotation angles (different speeds look more natural) 
    ax += 0.011 
    ay += 0.017 
    az += 0.007 
    hue += 0.03 
 
    -- rotate and project all 8 corners 
    sequence pts = repeat({0, 0}, length(verts)) 
    for i = 1 to length(verts) do 
        pts[i] = project_point(rotate_point(verts[i], ax, ay, az)) 
    end for 
 
    BeginDrawing() 
    ClearBackground(BLACK) 
 
    -- draw each edge, each with its own offset in the colour cycle 
    for i = 1 to length(edges) do 
        sequence a = pts[edges[i][1]] 
        sequence b = pts[edges[i][2]] 
        sequence col = hue_colour(hue + i * 0.5) 
 
        -- draw each line three times with 1-pixel offsets to make it thicker 
        DrawLine(a[1],     a[2],     b[1],     b[2],     col) 
        DrawLine(a[1] + 1, a[2],     b[1] + 1, b[2],     col) 
        DrawLine(a[1],     a[2] + 1, b[1],     b[2] + 1, col) 
    end for 
 
    EndDrawing() 
 
end while 
 
CloseWindow() 
-- solid_cube.ex 
-- Rotating solid cube, 1024x800 window, six differently coloured opaque faces 
-- Requires: 32-bit Euphoria 4.x and Euraylib 5 (Andy P / Icy Viking) 
 
include std/math.e 
include raylib.e 
 
constant SCREEN_W = 1024 
constant SCREEN_H = 800 
constant CENTRE_X = SCREEN_W / 2 
constant CENTRE_Y = SCREEN_H / 2 
 
constant CUBE_SIZE = 180      -- half the length of a cube edge, in pixels 
constant CAMERA_DIST = 700    -- distance from the "camera" to the cube centre 
constant FOCAL = 700          -- perspective strength 
 
-- the 8 corners of a cube centred on the origin 
constant verts = { 
    {-1, -1, -1}, { 1, -1, -1}, { 1,  1, -1}, {-1,  1, -1}, 
    {-1, -1,  1}, { 1, -1,  1}, { 1,  1,  1}, {-1,  1,  1} 
} 
 
-- the 6 faces, each as 4 indexes into verts (in order around the face) 
constant faces = { 
    {1, 2, 3, 4},   -- back 
    {5, 6, 7, 8},   -- front 
    {1, 4, 8, 5},   -- left 
    {2, 3, 7, 6},   -- right 
    {1, 2, 6, 5},   -- top 
    {4, 3, 7, 8}    -- bottom 
} 
 
-- one colour per face {r, g, b, a} 
constant face_colours = { 
    {230,  40,  40, 255},   -- red 
    { 40, 200,  60, 255},   -- green 
    { 50,  90, 240, 255},   -- blue 
    {245, 220,  40, 255},   -- yellow 
    {220,  60, 220, 255},   -- magenta 
    { 40, 220, 220, 255}    -- cyan 
} 
 
-- rotate a point around the X, then Y, then Z axis 
function rotate_point(sequence v, atom ax, atom ay, atom az) 
    atom x = v[1] 
    atom y = v[2] 
    atom z = v[3] 
    atom t 
 
    -- around X 
    t = y * cos(ax) - z * sin(ax) 
    z = y * sin(ax) + z * cos(ax) 
    y = t 
 
    -- around Y 
    t = x * cos(ay) + z * sin(ay) 
    z = -x * sin(ay) + z * cos(ay) 
    x = t 
 
    -- around Z 
    t = x * cos(az) - y * sin(az) 
    y = x * sin(az) + y * cos(az) 
    x = t 
 
    return {x, y, z} 
end function 
 
-- project a 3D point onto the 2D screen, returns {screen_x, screen_y} 
function project_point(sequence v) 
    atom scale = FOCAL / (CAMERA_DIST + v[3] * CUBE_SIZE) 
    integer sx = floor(CENTRE_X + v[1] * CUBE_SIZE * scale) 
    integer sy = floor(CENTRE_Y + v[2] * CUBE_SIZE * scale) 
    return {sx, sy} 
end function 
 
-- draw a filled triangle, fixing the vertex order so raylib always accepts it 
-- (raylib only draws triangles whose points run counter-clockwise on screen) 
procedure draw_tri(sequence a, sequence b, sequence c, sequence col) 
    atom cross = (b[1] - a[1]) * (c[2] - a[2]) - (b[2] - a[2]) * (c[1] - a[1]) 
    if cross > 0 then 
        DrawTriangle(a, c, b, col) 
    else 
        DrawTriangle(a, b, c, col) 
    end if 
end procedure 
 
atom ax = 0 
atom ay = 0 
atom az = 0 
 
-- the camera sits on the negative Z side, in the same units as the cube corners 
constant cam_z = -CAMERA_DIST / CUBE_SIZE 
 
InitWindow(SCREEN_W, SCREEN_H, "Euraylib 5 - Solid Cube") 
SetTargetFPS(60) 
 
while not WindowShouldClose() do 
 
    ax += 0.011 
    ay += 0.017 
    az += 0.007 
 
    -- rotate all 8 corners, then project them 
    sequence rotated = repeat({0, 0, 0}, length(verts)) 
    sequence pts = repeat({0, 0}, length(verts)) 
    for i = 1 to length(verts) do 
        rotated[i] = rotate_point(verts[i], ax, ay, az) 
        pts[i] = project_point(rotated[i]) 
    end for 
 
    BeginDrawing() 
    ClearBackground(BLACK) 
 
    for f = 1 to length(faces) do 
        sequence idx = faces[f] 
 
        -- face centre = average of its 4 rotated corners. 
        -- For a cube centred on the origin this is also the outward normal. 
        atom cx = 0 
        atom cy = 0 
        atom cz = 0 
        for k = 1 to 4 do 
            cx += rotated[idx[k]][1] 
            cy += rotated[idx[k]][2] 
            cz += rotated[idx[k]][3] 
        end for 
        cx /= 4 
        cy /= 4 
        cz /= 4 
 
        -- the face is visible if its normal points towards the camera: 
        -- dot(normal, camera_position - face_centre) > 0 
        atom facing = cx * (0 - cx) + cy * (0 - cy) + cz * (cam_z - cz) 
 
        if facing > 0 then 
            sequence p1 = pts[idx[1]] 
            sequence p2 = pts[idx[2]] 
            sequence p3 = pts[idx[3]] 
            sequence p4 = pts[idx[4]] 
 
            -- a quad is two triangles 
            draw_tri(p1, p2, p3, face_colours[f]) 
            draw_tri(p1, p3, p4, face_colours[f]) 
 
            -- thin black outline so the edges stand out 
            DrawLine(p1[1], p1[2], p2[1], p2[2], BLACK) 
            DrawLine(p2[1], p2[2], p3[1], p3[2], BLACK) 
            DrawLine(p3[1], p3[2], p4[1], p4[2], BLACK) 
            DrawLine(p4[1], p4[2], p1[1], p1[2], BLACK) 
        end if 
    end for 
 
    EndDrawing() 
 
end while 
 
CloseWindow() 
 

And finally, this blew my mind

-- enterprise.ex 
-- Rotating wireframe starship, 1024x800 window 
-- Requires: 32-bit Euphoria 4.x and Euraylib 5 (Andy P / Icy Viking) 
 
include raylib.e 
 
constant SCREEN_W = 1024 
constant SCREEN_H = 800 
constant CENTRE_X = SCREEN_W / 2 
constant CENTRE_Y = SCREEN_H / 2 
 
constant MODEL_SCALE = 150    -- pixels per model unit 
constant CAMERA_DIST = 1100   -- distance from the "camera" to the model centre 
constant FOCAL = 1100         -- perspective strength 
constant TWO_PI = 6.283185307179586   -- own constant, avoids clashing with PI in raylib.e 
 
------------------------------------------------------------------ 
-- Model building helpers 
------------------------------------------------------------------ 
sequence verts = {}                  -- each: {x, y, z} 
sequence edges = {}                  -- each: {vertex_a, vertex_b, {r, g, b}} 
sequence cur_col = {190, 205, 235}   -- colour given to new edges 
 
function add_v(atom x, atom y, atom z) 
    verts = append(verts, {x, y, z}) 
    return length(verts) 
end function 
 
procedure add_e(integer a, integer b) 
    edges = append(edges, {a, b, cur_col}) 
end procedure 
 
-- Spin a profile around an axis to make a ring-and-spoke surface. 
-- axis  : 2 = spin around Y (vertical), 3 = spin around Z (lengthwise) 
-- shape : list of {radius, position_along_axis}, in order along the axis 
-- A radius of 0 makes a single point (a nose or tail tip). 
-- spoke_step: draw a lengthwise/radial line every N segments 
procedure add_lathe(integer axis, atom cx, atom cy, atom cz, 
                    sequence shape, integer segs, integer spoke_step) 
    sequence prev = {} 
 
    for p = 1 to length(shape) do 
        atom r = shape[p][1] 
        atom along = shape[p][2] 
        sequence ring = repeat(0, segs) 
 
        if r = 0 then 
            if axis = 2 then 
                ring = repeat(add_v(cx, cy + along, cz), segs) 
            else 
                ring = repeat(add_v(cx, cy, cz + along), segs) 
            end if 
        else 
            for s = 1 to segs do 
                atom a = TWO_PI * (s - 1) / segs 
                atom u = r * cos(a) 
                atom w = r * sin(a) 
                if axis = 2 then 
                    ring[s] = add_v(cx + u, cy + along, cz + w) 
                else 
                    ring[s] = add_v(cx + u, cy + w, cz + along) 
                end if 
            end for 
 
            -- the ring itself 
            for s = 1 to segs do 
                add_e(ring[s], ring[remainder(s, segs) + 1]) 
            end for 
        end if 
 
        -- spokes joining this ring to the previous one 
        if p > 1 then 
            for s = 1 to segs by spoke_step do 
                if prev[s] != ring[s] then 
                    add_e(prev[s], ring[s]) 
                end if 
            end for 
        end if 
 
        prev = ring 
    end for 
end procedure 
 
------------------------------------------------------------------ 
-- Build the ship (nose points towards +Z) 
------------------------------------------------------------------ 
 
-- Saucer section: {radius, height}, top to bottom 
cur_col = {190, 205, 235} 
add_lathe(2, 0, 0, 0.9, 
    {{0.0, 0.17}, {0.25, 0.17}, {0.5, 0.13}, {0.8, 0.07}, {1.0, 0.0}, 
     {0.8, -0.06}, {0.5, -0.09}, {0.25, -0.1}, {0.0, -0.1}}, 
    32, 2) 
 
-- Bridge dome on top of the saucer 
cur_col = {255, 230, 140} 
add_lathe(2, 0, 0.17, 0.9, 
    {{0.0, 0.1}, {0.08, 0.07}, {0.12, 0.0}}, 
    12, 3) 
 
-- Secondary (engineering) hull: {radius, z} 
cur_col = {170, 185, 215} 
add_lathe(3, 0, -0.5, -0.4, 
    {{0.0, -0.9}, {0.1, -0.85}, {0.17, -0.7}, {0.17, 0.3}, 
     {0.12, 0.5}, {0.0, 0.6}}, 
    16, 4) 
 
-- Neck joining the secondary hull to the underside of the saucer 
integer n1 = add_v(-0.07, -0.345, -0.35) 
integer n2 = add_v( 0.07, -0.345, -0.35) 
integer n3 = add_v( 0.07, -0.345, -0.10) 
integer n4 = add_v(-0.07, -0.345, -0.10) 
integer t1 = add_v(-0.10, -0.07,  0.10) 
integer t2 = add_v( 0.10, -0.07,  0.10) 
integer t3 = add_v( 0.10, -0.095, 0.50) 
integer t4 = add_v(-0.10, -0.095, 0.50) 
add_e(n1, n2) 
add_e(n2, n3) 
add_e(n3, n4) 
add_e(n4, n1) 
add_e(t1, t2) 
add_e(t2, t3) 
add_e(t3, t4) 
add_e(t4, t1) 
add_e(n1, t1) 
add_e(n2, t2) 
add_e(n3, t3) 
add_e(n4, t4) 
 
-- Two nacelles with pylons (sx = -1 is one side, +1 is the other) 
for sx = -1 to 1 by 2 do 
    -- nacelle body 
    cur_col = {90, 170, 255} 
    add_lathe(3, sx * 0.7, 0.12, -0.75, 
        {{0.0, -0.78}, {0.08, -0.72}, {0.1, -0.6}, {0.1, 0.4}}, 
        12, 3) 
 
    -- glowing red front dome 
    cur_col = {255, 90, 70} 
    add_lathe(3, sx * 0.7, 0.12, -0.35, 
        {{0.1, 0.0}, {0.085, 0.12}, {0.05, 0.22}, {0.0, 0.3}}, 
        12, 3) 
 
    -- pylon from the secondary hull up to the nacelle 
    cur_col = {170, 185, 215} 
    integer pa = add_v(sx * 0.1, -0.36, -1.05) 
    integer pb = add_v(sx * 0.1, -0.36, -0.70) 
    integer pc = add_v(sx * 0.7,  0.03, -1.05) 
    integer pd = add_v(sx * 0.7,  0.03, -0.70) 
    add_e(pa, pb) 
    add_e(pc, pd) 
    add_e(pa, pc) 
    add_e(pb, pd) 
end for 
 
-- Centre the whole model on the origin so it spins about its middle 
sequence lo = {1e30, 1e30, 1e30} 
sequence hi = {-1e30, -1e30, -1e30} 
for i = 1 to length(verts) do 
    for k = 1 to 3 do 
        if verts[i][k] < lo[k] then lo[k] = verts[i][k] end if 
        if verts[i][k] > hi[k] then hi[k] = verts[i][k] end if 
    end for 
end for 
sequence mid = (lo + hi) / 2 
for i = 1 to length(verts) do 
    verts[i] -= mid 
end for 
 
------------------------------------------------------------------ 
-- 3D maths 
------------------------------------------------------------------ 
 
-- rotate a point around the X, then Y, then Z axis 
function rotate_point(sequence v, atom ax, atom ay, atom az) 
    atom x = v[1] 
    atom y = v[2] 
    atom z = v[3] 
    atom t 
 
    -- around X 
    t = y * cos(ax) - z * sin(ax) 
    z = y * sin(ax) + z * cos(ax) 
    y = t 
 
    -- around Y 
    t = x * cos(ay) + z * sin(ay) 
    z = -x * sin(ay) + z * cos(ay) 
    x = t 
 
    -- around Z 
    t = x * cos(az) - y * sin(az) 
    y = x * sin(az) + y * cos(az) 
    x = t 
 
    return {x, y, z} 
end function 
 
-- project a 3D point onto the screen (model +Y is up, screen Y is down) 
function project_point(sequence v) 
    atom scale = FOCAL / (CAMERA_DIST + v[3] * MODEL_SCALE) 
    integer sx = floor(CENTRE_X + v[1] * MODEL_SCALE * scale) 
    integer sy = floor(CENTRE_Y - v[2] * MODEL_SCALE * scale) 
    return {sx, sy} 
end function 
 
------------------------------------------------------------------ 
-- Main program 
------------------------------------------------------------------ 
atom ax = 0.4 
atom ay = 0 
atom az = 0 
 
InitWindow(SCREEN_W, SCREEN_H, "Euraylib 5 - Wireframe Starship") 
SetTargetFPS(60) 
 
while not WindowShouldClose() do 
 
    -- spin on all three axes at different speeds 
    ax += 0.011 
    ay += 0.017 
    az += 0.007 
 
    sequence rotated = repeat({0, 0, 0}, length(verts)) 
    sequence pts = repeat({0, 0}, length(verts)) 
    for i = 1 to length(verts) do 
        rotated[i] = rotate_point(verts[i], ax, ay, az) 
        pts[i] = project_point(rotated[i]) 
    end for 
 
    BeginDrawing() 
    ClearBackground(BLACK) 
 
    for i = 1 to length(edges) do 
        integer ia = edges[i][1] 
        integer ib = edges[i][2] 
        sequence c = edges[i][3] 
 
        -- dim edges that are further from the camera (+Z is away from us) 
        atom zavg = (rotated[ia][3] + rotated[ib][3]) / 2 
        atom f = 0.65 - 0.35 * zavg / 1.9 
        if f < 0.25 then f = 0.25 end if 
        if f > 1 then f = 1 end if 
 
        DrawLine(pts[ia][1], pts[ia][2], pts[ib][1], pts[ib][2], 
                 {floor(c[1] * f), floor(c[2] * f), floor(c[3] * f), 255}) 
    end for 
 
    EndDrawing() 
 
end while 
 
CloseWindow() 
 
 

All written with the help of claude in 1/2 an hours - it even corrected a mistake with duplicate PI in raylib.e and math.e.

Enjoy

Cheers

Chris

Edit - and then it made a suggestion which I couldn't resist

-- enterprise2.ex 
-- Wireframe starship (Constitution-class refit style) with starfield and keyboard control 
-- 1024x800 window 
-- Requires: 32-bit Euphoria 4.x and Euraylib 5 (Andy P / Icy Viking) 
-- 
-- Controls: 
--   Arrow keys : pitch (up/down) and yaw (left/right) 
--   Z / X      : roll 
--   SPACE      : turn the automatic spin on/off 
--   R          : reset the orientation 
 
include std/rand.e 
include raylib.e 
 
constant SCREEN_W = 1024 
constant SCREEN_H = 800 
constant CENTRE_X = SCREEN_W / 2 
constant CENTRE_Y = SCREEN_H / 2 
 
constant MODEL_SCALE = 150    -- pixels per model unit 
constant CAMERA_DIST = 1100   -- distance from the "camera" to the model centre 
constant FOCAL = 1100         -- perspective strength 
constant TWO_PI = 6.283185307179586   -- own constant, avoids clashing with PI in raylib.e 
 
constant TURN_RATE = 0.03     -- radians per frame while a key is held 
 
-- starfield settings 
constant NUM_STARS = 300 
constant STAR_FAR = 1000      -- how far away new stars appear 
constant STAR_NEAR = 20       -- stars closer than this are recycled 
constant STAR_SPEED = 3       -- how fast the stars fly past 
constant STAR_FOCAL = 500 
 
set_rand(time()) 
 
------------------------------------------------------------------ 
-- Model building helpers 
------------------------------------------------------------------ 
sequence verts = {}                  -- each: {x, y, z} 
sequence edges = {}                  -- each: {vertex_a, vertex_b, {r, g, b}} 
sequence cur_col = {190, 205, 235}   -- colour given to new edges 
 
function add_v(atom x, atom y, atom z) 
    verts = append(verts, {x, y, z}) 
    return length(verts) 
end function 
 
procedure add_e(integer a, integer b) 
    edges = append(edges, {a, b, cur_col}) 
end procedure 
 
-- Spin a profile around an axis to make a ring-and-spoke surface. 
-- axis  : 2 = spin around Y (vertical), 3 = spin around Z (lengthwise) 
-- shape : list of {radius, position_along_axis}, in order along the axis 
-- A radius of 0 makes a single point (a nose or tail tip). 
-- A shape with just one entry makes a single ring (used for accent lines). 
-- spoke_step: draw a lengthwise/radial line every N segments 
procedure add_lathe(integer axis, atom cx, atom cy, atom cz, 
                    sequence shape, integer segs, integer spoke_step) 
    sequence prev = {} 
 
    for p = 1 to length(shape) do 
        atom r = shape[p][1] 
        atom along = shape[p][2] 
        sequence ring = repeat(0, segs) 
 
        if r = 0 then 
            if axis = 2 then 
                ring = repeat(add_v(cx, cy + along, cz), segs) 
            else 
                ring = repeat(add_v(cx, cy, cz + along), segs) 
            end if 
        else 
            for s = 1 to segs do 
                atom a = TWO_PI * (s - 1) / segs 
                atom u = r * cos(a) 
                atom w = r * sin(a) 
                if axis = 2 then 
                    ring[s] = add_v(cx + u, cy + along, cz + w) 
                else 
                    ring[s] = add_v(cx + u, cy + w, cz + along) 
                end if 
            end for 
 
            -- the ring itself 
            for s = 1 to segs do 
                add_e(ring[s], ring[remainder(s, segs) + 1]) 
            end for 
        end if 
 
        -- spokes joining this ring to the previous one 
        if p > 1 then 
            for s = 1 to segs by spoke_step do 
                if prev[s] != ring[s] then 
                    add_e(prev[s], ring[s]) 
                end if 
            end for 
        end if 
 
        prev = ring 
    end for 
end procedure 
 
------------------------------------------------------------------ 
-- Build the ship (nose points towards +Z) 
------------------------------------------------------------------ 
 
-- Primary hull (saucer): {radius, height}, top to bottom 
cur_col = {190, 205, 235} 
add_lathe(2, 0, 0, 0.9, 
    {{0.0, 0.20}, {0.15, 0.20}, {0.30, 0.17}, {0.45, 0.155}, {0.60, 0.12}, 
     {0.80, 0.08}, {0.95, 0.03}, {1.0, 0.0}, {0.95, -0.03}, {0.80, -0.07}, 
     {0.60, -0.09}, {0.40, -0.10}, {0.20, -0.11}, {0.0, -0.11}}, 
    40, 2) 
 
-- Window-light rings around the saucer edge 
cur_col = {255, 235, 150} 
add_lathe(2, 0, 0, 0.9, {{0.97, 0.025}}, 40, 1) 
add_lathe(2, 0, 0, 0.9, {{0.97, -0.025}}, 40, 1) 
 
-- Bridge dome on top of the saucer 
cur_col = {255, 230, 140} 
add_lathe(2, 0, 0.20, 0.9, 
    {{0.0, 0.09}, {0.06, 0.085}, {0.10, 0.05}, {0.13, 0.0}}, 
    12, 3) 
 
-- Sensor dome underneath the saucer 
cur_col = {120, 220, 255} 
add_lathe(2, 0, -0.11, 0.9, 
    {{0.12, 0.0}, {0.07, -0.05}, {0.0, -0.07}}, 
    12, 3) 
 
-- Secondary (engineering) hull: {radius, z} 
cur_col = {170, 185, 215} 
add_lathe(3, 0, -0.5, -0.4, 
    {{0.0, -0.9}, {0.08, -0.88}, {0.14, -0.80}, {0.17, -0.70}, {0.18, -0.40}, 
     {0.18, 0.0}, {0.17, 0.2}, {0.14, 0.35}, {0.10, 0.45}}, 
    16, 4) 
 
-- Hull accent rings 
cur_col = {255, 235, 150} 
add_lathe(3, 0, -0.5, -0.4, {{0.185, -0.55}}, 16, 1) 
add_lathe(3, 0, -0.5, -0.4, {{0.185, 0.15}}, 16, 1) 
 
-- Deflector dish at the front of the secondary hull 
cur_col = {120, 220, 255} 
add_lathe(3, 0, -0.5, -0.4, 
    {{0.10, 0.45}, {0.07, 0.42}, {0.03, 0.40}, {0.0, 0.395}}, 
    12, 3) 
 
-- Neck joining the secondary hull to the underside of the saucer 
cur_col = {170, 185, 215} 
integer n1 = add_v(-0.07, -0.33, -0.35) 
integer n2 = add_v( 0.07, -0.33, -0.35) 
integer n3 = add_v( 0.07, -0.33, -0.10) 
integer n4 = add_v(-0.07, -0.33, -0.10) 
integer t1 = add_v(-0.10, -0.07,  0.10) 
integer t2 = add_v( 0.10, -0.07,  0.10) 
integer t3 = add_v( 0.10, -0.10,  0.50) 
integer t4 = add_v(-0.10, -0.10,  0.50) 
add_e(n1, n2) 
add_e(n2, n3) 
add_e(n3, n4) 
add_e(n4, n1) 
add_e(t1, t2) 
add_e(t2, t3) 
add_e(t3, t4) 
add_e(t4, t1) 
add_e(n1, t1) 
add_e(n2, t2) 
add_e(n3, t3) 
add_e(n4, t4) 
 
-- Two nacelles with pylons (sx = -1 is one side, +1 is the other) 
for sx = -1 to 1 by 2 do 
    -- nacelle body 
    cur_col = {90, 170, 255} 
    add_lathe(3, sx * 0.7, 0.12, -0.75, 
        {{0.0, -0.78}, {0.05, -0.76}, {0.085, -0.70}, {0.10, -0.60}, 
         {0.10, 0.0}, {0.10, 0.40}}, 
        16, 4) 
 
    -- blue accent rings along the nacelle 
    cur_col = {120, 220, 255} 
    add_lathe(3, sx * 0.7, 0.12, -0.75, {{0.104, -0.35}}, 16, 1) 
    add_lathe(3, sx * 0.7, 0.12, -0.75, {{0.104, 0.05}}, 16, 1) 
 
    -- glowing red front dome (Bussard collector) 
    cur_col = {255, 90, 70} 
    add_lathe(3, sx * 0.7, 0.12, -0.35, 
        {{0.10, 0.0}, {0.09, 0.08}, {0.065, 0.17}, {0.035, 0.25}, {0.0, 0.30}}, 
        16, 4) 
 
    -- pylon from the secondary hull up to the nacelle 
    cur_col = {170, 185, 215} 
    integer pa = add_v(sx * 0.1, -0.36, -1.05) 
    integer pb = add_v(sx * 0.1, -0.36, -0.70) 
    integer pc = add_v(sx * 0.7,  0.03, -1.05) 
    integer pd = add_v(sx * 0.7,  0.03, -0.70) 
    add_e(pa, pb) 
    add_e(pc, pd) 
    add_e(pa, pc) 
    add_e(pb, pd) 
    add_e(pa, pd) 
end for 
 
-- Centre the whole model on the origin so it spins about its middle 
sequence lo = {1e30, 1e30, 1e30} 
sequence hi = {-1e30, -1e30, -1e30} 
for i = 1 to length(verts) do 
    for k = 1 to 3 do 
        if verts[i][k] < lo[k] then lo[k] = verts[i][k] end if 
        if verts[i][k] > hi[k] then hi[k] = verts[i][k] end if 
    end for 
end for 
sequence mid = (lo + hi) / 2 
for i = 1 to length(verts) do 
    verts[i] -= mid 
end for 
 
------------------------------------------------------------------ 
-- 3D maths (3x3 rotation matrices, so steering always feels the same 
-- no matter which way the ship is currently facing) 
------------------------------------------------------------------ 
 
function m3_mul(sequence a, sequence b) 
    sequence r = repeat(repeat(0, 3), 3) 
    for i = 1 to 3 do 
        for j = 1 to 3 do 
            r[i][j] = a[i][1] * b[1][j] + a[i][2] * b[2][j] + a[i][3] * b[3][j] 
        end for 
    end for 
    return r 
end function 
 
function m3_rotx(atom t) 
    return {{1, 0, 0}, {0, cos(t), -sin(t)}, {0, sin(t), cos(t)}} 
end function 
 
function m3_roty(atom t) 
    return {{cos(t), 0, sin(t)}, {0, 1, 0}, {-sin(t), 0, cos(t)}} 
end function 
 
function m3_rotz(atom t) 
    return {{cos(t), -sin(t), 0}, {sin(t), cos(t), 0}, {0, 0, 1}} 
end function 
 
function m3_apply(sequence m, sequence v) 
    return { 
        m[1][1] * v[1] + m[1][2] * v[2] + m[1][3] * v[3], 
        m[2][1] * v[1] + m[2][2] * v[2] + m[2][3] * v[3], 
        m[3][1] * v[1] + m[3][2] * v[2] + m[3][3] * v[3] 
    } 
end function 
 
-- project a 3D point onto the screen (model +Y is up, screen Y is down) 
function project_point(sequence v) 
    atom scale = FOCAL / (CAMERA_DIST + v[3] * MODEL_SCALE) 
    integer sx = floor(CENTRE_X + v[1] * MODEL_SCALE * scale) 
    integer sy = floor(CENTRE_Y - v[2] * MODEL_SCALE * scale) 
    return {sx, sy} 
end function 
 
------------------------------------------------------------------ 
-- Starfield 
------------------------------------------------------------------ 
function new_star(integer at_far_end) 
    integer z 
    if at_far_end then 
        z = STAR_FAR 
    else 
        z = rand_range(STAR_NEAR, STAR_FAR) 
    end if 
    return {rand_range(-1200, 1200), rand_range(-1000, 1000), z} 
end function 
 
sequence stars = repeat({0, 0, 0}, NUM_STARS) 
for i = 1 to NUM_STARS do 
    stars[i] = new_star(0) 
end for 
 
procedure draw_stars() 
    for i = 1 to NUM_STARS do 
        stars[i][3] -= STAR_SPEED 
 
        if stars[i][3] < STAR_NEAR then 
            stars[i] = new_star(1) 
        end if 
 
        integer sx = floor(CENTRE_X + stars[i][1] * STAR_FOCAL / stars[i][3]) 
        integer sy = floor(CENTRE_Y + stars[i][2] * STAR_FOCAL / stars[i][3]) 
 
        if sx < 0 or sx >= SCREEN_W - 1 or sy < 0 or sy >= SCREEN_H - 1 then 
            -- flew off the edge of the screen, send it back to the distance 
            stars[i] = new_star(1) 
        else 
            -- nearer stars are brighter 
            integer b = floor(255 * (1 - stars[i][3] / STAR_FAR)) 
            if b < 40 then b = 40 end if 
            sequence col = {b, b, b, 255} 
 
            DrawPixel(sx, sy, col) 
            if b > 170 then 
                -- the nearest stars are drawn as little 2x2 squares 
                DrawPixel(sx + 1, sy, col) 
                DrawPixel(sx, sy + 1, col) 
                DrawPixel(sx + 1, sy + 1, col) 
            end if 
        end if 
    end for 
end procedure 
 
------------------------------------------------------------------ 
-- Main program 
------------------------------------------------------------------ 
sequence orient = m3_rotx(0.4)    -- current orientation of the ship 
integer auto_spin = 1 
 
InitWindow(SCREEN_W, SCREEN_H, "Euraylib 5 - Wireframe Starship") 
SetTargetFPS(60) 
 
while not WindowShouldClose() do 
 
    -- ---- keyboard ---- 
    if IsKeyPressed(KEY_SPACE) then 
        auto_spin = not auto_spin 
    end if 
 
    if IsKeyPressed(KEY_R) then 
        orient = m3_rotx(0.4) 
    end if 
 
    atom dx = 0 
    atom dy = 0 
    atom dz = 0 
 
    if auto_spin then 
        dx = 0.011 
        dy = 0.017 
        dz = 0.007 
    end if 
 
    if IsKeyDown(KEY_UP)    then dx -= TURN_RATE end if 
    if IsKeyDown(KEY_DOWN)  then dx += TURN_RATE end if 
    if IsKeyDown(KEY_LEFT)  then dy -= TURN_RATE end if 
    if IsKeyDown(KEY_RIGHT) then dy += TURN_RATE end if 
    if IsKeyDown(KEY_Z)     then dz += TURN_RATE end if 
    if IsKeyDown(KEY_X)     then dz -= TURN_RATE end if 
 
    -- turn the ship a small step about the screen's X, Y and Z axes 
    orient = m3_mul(m3_rotz(dz), m3_mul(m3_roty(dy), m3_mul(m3_rotx(dx), orient))) 
 
    -- ---- transform the model ---- 
    sequence rotated = repeat({0, 0, 0}, length(verts)) 
    sequence pts = repeat({0, 0}, length(verts)) 
    for i = 1 to length(verts) do 
        rotated[i] = m3_apply(orient, verts[i]) 
        pts[i] = project_point(rotated[i]) 
    end for 
 
    -- ---- draw ---- 
    BeginDrawing() 
    ClearBackground(BLACK) 
 
    draw_stars() 
 
    for i = 1 to length(edges) do 
        integer ia = edges[i][1] 
        integer ib = edges[i][2] 
        sequence c = edges[i][3] 
 
        -- dim edges that are further from the camera (+Z is away from us) 
        atom zavg = (rotated[ia][3] + rotated[ib][3]) / 2 
        atom f = 0.65 - 0.35 * zavg / 1.9 
        if f < 0.25 then f = 0.25 end if 
        if f > 1 then f = 1 end if 
 
        DrawLine(pts[ia][1], pts[ia][2], pts[ib][1], pts[ib][2], 
                 {floor(c[1] * f), floor(c[2] * f), floor(c[3] * f), 255}) 
    end for 
 
    DrawText("Arrows: steer   Z/X: roll   SPACE: auto-spin   R: reset", 
             10, 10, 18, {150, 160, 185, 255}) 
 
    EndDrawing() 
 
end while 
 
CloseWindow() 
 

Try stabilising the tumbling ship with the arrow keys

new topic     » topic index » view message » categorize

2. Re: Let's have some fun with EuRaylib

Thanks Chris for using my mostly hand written code to train AI (slight sarcarsm). Regardless these are some cool programs.

new topic     » goto parent     » topic index » view message » categorize

3. Re: Let's have some fun with EuRaylib

ChrisB said...

Andys EuRaylib 6 ( even though it says 5). These are each separate programs, make sure you have raylib setup, Eu32 bit, everything else is standard Eu.

Hi, that's cool.

I quickly adapted it for my wrapper. It's just for Windows and 64-bit (but it supports Phix and Euphoria).

If you don't mind, I'll add it to my raylib example collection on github https://github.com/andizk4kx/raylib-playground/tree/main/examples. Let me know.

Yeah, I think it's a good idea to feed artificial intelligence with Euphoria code. Someone's got to remember Euphoria in the future.

Andreas

new topic     » goto parent     » topic index » view message » categorize

4. Re: Let's have some fun with EuRaylib

Icy_Viking said...

Thanks Chris for using my mostly hand written code to train AI (slight sarcarsm). Regardless these are some cool programs.

Haha

No, thankyou Andy for providing such a bloody good lib. You probably write code as fast as I prompt anyway!

I do think these highlight what raylib is capable of, and I for one vote for it's adoption into a general programming release.

Cheers Chris

new topic     » goto parent     » topic index » view message » categorize

5. Re: Let's have some fun with EuRaylib

andreasWagner said...
ChrisB said...

Andys EuRaylib 6 ( even though it says 5). These are each separate programs, make sure you have raylib setup, Eu32 bit, everything else is standard Eu.

Hi, that's cool.

I quickly adapted it for my wrapper. It's just for Windows and 64-bit (but it supports Phix and Euphoria).

If you don't mind, I'll add it to my raylib example collection on github https://github.com/andizk4kx/raylib-playground/tree/main/examples. Let me know.

Yeah, I think it's a good idea to feed artificial intelligence with Euphoria code. Someone's got to remember Euphoria in the future.

Andreas

Absolutely - I can hardly claim they are my work anyway! Standing on the shoulders of giants as ever.

Perhaps you and Andy could agree on a common API to make translation between 32 and 64 bit trivial.

Cheers Chris

new topic     » goto parent     » topic index » view message » categorize

6. Re: Let's have some fun with EuRaylib

ChrisB said...
andreasWagner said...
ChrisB said...

Andys EuRaylib 6 ( even though it says 5). These are each separate programs, make sure you have raylib setup, Eu32 bit, everything else is standard Eu.

Hi, that's cool.

I quickly adapted it for my wrapper. It's just for Windows and 64-bit (but it supports Phix and Euphoria).

If you don't mind, I'll add it to my raylib example collection on github https://github.com/andizk4kx/raylib-playground/tree/main/examples. Let me know.

Yeah, I think it's a good idea to feed artificial intelligence with Euphoria code. Someone's got to remember Euphoria in the future.

Andreas

Absolutely - I can hardly claim they are my work anyway! Standing on the shoulders of giants as ever.

Perhaps you and Andy could agree on a common API to make translation between 32 and 64 bit trivial.

Cheers Chris

There's probably a way for the end-user to select if they wanna use 32-bit or 64-bit or way programming wise to make it so it can tell if the loaded DLL is 32 or 64-bit. I've kept it mostly 32-bit for compatibility reasons

new topic     » goto parent     » topic index » view message » categorize

7. Re: Let's have some fun with EuRaylib

I don't understand this thread. I ckecked EuRaylib6 with Linux Mint Debian x64. It works on Linux x64 and euc (4.2.0) already builds a 64-bit executable.

duro@hp-zbook15g2:~/Data/Euphoria/v4/EuRaylib6$ euc basic_win.ex  
Build directory: build-975579/ 
Translating code, pass: 1 2 3 4 5 6 7  generating 
Compiling with GCC 
Compiling   5% init-.c 
Compiling  21% basic_win.c 
Compiling  32% main-.c 
Compiling  42% raylib.c 
Compiling  53% ffi.c 
Compiling  63% machine.c 
Compiling  74% memory.c 
Compiling  84% dll.c 
Compiling  95% types.c 
Linking 100% ../basic_win 
duro@hp-zbook15g2:~/Data/Euphoria/v4/EuRaylib6$ file ./basic_win 
./basic_win: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=9a172f96fcaac31a68f8467ba134dda9e8c7686a, for GNU/Linux 3.2.0, not stripped 
duro@hp-zbook15g2:~/Data/Euphoria/v4/EuRaylib6$ ./basic_win  
INFO: Initializing raylib 6.2 
INFO: Platform backend: DESKTOP (GLFW) 
INFO: Supported raylib modules: 
INFO:     > rcore:..... loaded (mandatory) 
INFO:     > rlgl:...... loaded (mandatory) 
INFO:     > rshapes:... loaded (optional) 
INFO:     > rtextures:. loaded (optional) 
INFO:     > rtext:..... loaded (optional) 
INFO:     > rmodels:... loaded (optional) 
INFO:     > raudio:.... loaded (optional) 
INFO: DISPLAY: Device initialized successfully  
INFO:     > Display size: 1600 x 900 
INFO:     > Screen size:  800 x 600 
INFO:     > Render size:  800 x 600 
INFO:     > Viewport offsets: 0, 0 
INFO: GLAD: OpenGL extensions loaded successfully 
INFO: GL: Supported extensions count: 216 
INFO: GL: OpenGL device information: 
INFO:     > Vendor:   Mesa 
INFO:     > Renderer: NVE6 
INFO:     > Version:  4.3 (Core Profile) Mesa 25.0.7-2+deb13u1 
INFO:     > GLSL:     4.30 
INFO: GL: VAO extension detected, VAO functions loaded successfully 
INFO: GL: NPOT textures extension detected, full NPOT textures supported 
INFO: GL: DXT compressed textures supported 
INFO: GL: ETC2/EAC compressed textures supported 
INFO: PLATFORM: DESKTOP (GLFW - X11): Initialized successfully 
INFO: TEXTURE: [ID 1] Texture loaded successfully (1x1 | R8G8B8A8 | 1 mipmaps) 
INFO: TEXTURE: [ID 1] Default texture loaded successfully 
INFO: SHADER: [ID 1] Vertex shader compiled successfully 
INFO: SHADER: [ID 2] Fragment shader compiled successfully 
INFO: SHADER: [ID 3] Program shader loaded successfully 
INFO: SHADER: [ID 3] Default shader loaded successfully 
INFO: RLGL: Render batch vertex buffers loaded successfully in RAM (CPU) 
INFO: RLGL: Render batch vertex buffers loaded successfully in VRAM (GPU) 
INFO: RLGL: Default OpenGL state initialized successfully 
INFO: TEXTURE: [ID 2] Texture loaded successfully (128x128 | GRAY_ALPHA | 1 mipmaps) 
INFO: FONT: Default font loaded successfully (224 glyphs) 
INFO: SYSTEM: Working Directory: /home/duro/Data/Euphoria/v4/EuRaylib6 
INFO: TIMER: Target time per frame: 16.667 milliseconds 
INFO: TEXTURE: [ID 2] Unloaded texture data from VRAM (GPU) 
INFO: SHADER: [ID 3] Default shader unloaded successfully 
INFO: TEXTURE: [ID 1] Default texture unloaded successfully 
INFO: Window closed successfully 

So where is the need to get a multiarch version as the existing one, based on FFI, already is? Did I miss something ?

Jean-Marc

new topic     » goto parent     » topic index » view message » categorize

8. Re: Let's have some fun with EuRaylib

I tried other AI engines (just for the hell of it), and claude trounced it. This is tonights promp

Using the euphoria programming, euraylib 5or 6 by Icy Viking (Andy P) on 1024 * 800 window, create a randomly generated maze that a player can walk through first person in a doom like fashion. Use a colour schem for the walls to enable easy visualisation. Use the keys wasd to control movement, and use the mouse to look around 

and this is the result

-------------------------------------------------------------------------------- 
-- maze3d.ex : Doom-style first-person random maze (raycaster) 
-- Euphoria 4.1 (32-bit) + EuRayLib5 (Raylib wrapper by Andy P. / Icy Viking) 
-- 
-- Controls:  W/A/S/D = move/strafe     Mouse = look (left/right turns, up/down tilts) 
--            M = cycle map (local / full / off)     R = new maze     ESC = quit 
-- 
-- Wall colours (by the direction the wall FACES, so you always know which way 
-- you are heading, and darker with distance): 
--      North-facing = RED    South-facing = BLUE 
--      East-facing  = GREEN  West-facing  = YELLOW 
-------------------------------------------------------------------------------- 
include raylib.e 
include std/rand.e 
 
constant SW = 1024, SH = 800          -- window size 
constant COLW = 2                     -- pixel width of each ray column (1 = sharper, slower) 
constant NUMCOLS = floor(SW / COLW) 
constant MZ_PI = 3.14159265358979 
constant FOV = 0.66                   -- camera plane length (~66 degree view) 
constant MOVE_SPEED = 3.2             -- cells per second 
constant MOUSE_SENS = 0.0025          -- radians per pixel 
constant PITCH_SENS = 1.0             -- pixels of horizon shift per pixel 
constant MAX_PITCH  = 280 
constant PLAYER_R   = 0.22            -- collision radius 
 
constant mzDX = {1,-1,0,0}, mzDY = {0,0,1,-1} 
 
-- base colours: N, S, E, W 
constant mzFace = { {230,70,55}, {60,115,240}, {65,205,95}, {245,205,55} } 
 
-- ---------------------------------------------------------------- state ------ 
sequence mzGrid = {} 
integer  mzG = 0, mzN = 8, mzLevel = 1 
atom     posX = 1.5, posY = 1.5, ang = 0, pitch = 0 
atom     goalX = 0, goalY = 0 
atom     msgTimer = 0 
integer  mapMode = 1 
 
-- ------------------------------------------------------------- helpers ------- 
-- Colour helper: works whether the wrapper stores colours as {r,g,b,a} 
-- or as a packed 32-bit integer. If your colours break, edit only this. 
constant COLOR_IS_SEQ = sequence(RAYWHITE) 
 
function mzRGB(integer r, integer g, integer b, integer a = 255) 
    if COLOR_IS_SEQ then 
        return {r, g, b, a} 
    end if 
    return r + g * 256 + b * 65536 + a * 16777216 
end function 
 
function mzAbs(atom x) 
    if x < 0 then return -x end if 
    return x 
end function 
 
function mzMax(integer a, integer b) 
    if a > b then return a end if 
    return b 
end function 
 
function mzMin(integer a, integer b) 
    if a < b then return a end if 
    return b 
end function 
 
-- ------------------------------------------------------ maze generation ------ 
-- Recursive backtracker on an (2n+1)x(2n+1) grid. 1 = wall, 0 = passage. 
-- Cells live on even 1-based indices (2,4,..,2n). 
procedure mzGenerate(integer n) 
    sequence stack, cand, cur 
    integer nx, ny, k 
 
    mzG = 2 * n + 1 
    mzGrid = repeat(repeat(1, mzG), mzG) 
    mzGrid[2][2] = 0 
    stack = {{2, 2}} 
 
    while length(stack) > 0 do 
        cur = stack[$] 
        cand = {} 
        for d = 1 to 4 do 
            nx = cur[1] + mzDX[d] * 2 
            ny = cur[2] + mzDY[d] * 2 
            if nx >= 2 and nx <= mzG - 1 and ny >= 2 and ny <= mzG - 1 then 
                if mzGrid[ny][nx] = 1 then 
                    cand = append(cand, d) 
                end if 
            end if 
        end for 
 
        if length(cand) = 0 then 
            stack = stack[1..$-1] 
        else 
            k  = cand[rand(length(cand))] 
            nx = cur[1] + mzDX[k] * 2 
            ny = cur[2] + mzDY[k] * 2 
            mzGrid[cur[2] + mzDY[k]][cur[1] + mzDX[k]] = 0   -- knock out wall between 
            mzGrid[ny][nx] = 0 
            stack = append(stack, {nx, ny}) 
        end if 
    end while 
end procedure 
 
procedure mzNewLevel() 
    mzGenerate(mzN) 
    posX = 1.5 
    posY = 1.5 
    if mzGrid[2][3] = 0 then 
        ang = 0                 -- face east if open 
    else 
        ang = MZ_PI / 2         -- otherwise face south 
    end if 
    pitch = 0 
    goalX = mzG - 1.5           -- centre of far corner cell 
    goalY = mzG - 1.5 
end procedure 
 
-- ------------------------------------------------------------ collision ------ 
function mzBlocked(atom x, atom y) 
    integer gx, gy 
    gx = floor(x) + 1 
    gy = floor(y) + 1 
    if gx < 1 or gy < 1 or gx > mzG or gy > mzG then 
        return 1 
    end if 
    return mzGrid[gy][gx] 
end function 
 
function mzCanStand(atom x, atom y) 
    if mzBlocked(x - PLAYER_R, y - PLAYER_R) then return 0 end if 
    if mzBlocked(x + PLAYER_R, y - PLAYER_R) then return 0 end if 
    if mzBlocked(x - PLAYER_R, y + PLAYER_R) then return 0 end if 
    if mzBlocked(x + PLAYER_R, y + PLAYER_R) then return 0 end if 
    return 1 
end function 
 
procedure mzMove(atom dx, atom dy)       -- axis-separated => slide along walls 
    if mzCanStand(posX + dx, posY) then posX += dx end if 
    if mzCanStand(posX, posY + dy) then posY += dy end if 
end procedure 
 
-- ------------------------------------------------------------ 3D render ------- 
procedure mzRender() 
    atom dirX, dirY, plX, plY, camX, rdx, rdy 
    atom ddX, ddY, sdX, sdY, perp, wallX, shade 
    integer mx, my, stepX, stepY, side, hit, face, top, h, horizon, lineH 
    integer r, g, b, y0, y1 
    sequence base 
 
    dirX = cos(ang) 
    dirY = sin(ang) 
    plX  = -dirY * FOV 
    plY  =  dirX * FOV 
    horizon = floor(SH / 2 + pitch) 
 
    -- ceiling (dark blue, brighter toward the horizon) 
    for i = 0 to 9 do 
        y0 = floor(horizon * i / 10) 
        y1 = floor(horizon * (i + 1) / 10) 
        DrawRectangle(0, y0, SW, y1 - y0 + 1, mzRGB(16 + i * 3, 18 + i * 3, 40 + i * 5)) 
    end for 
    -- floor (brown, brighter toward the player) 
    for i = 0 to 9 do 
        y0 = horizon + floor((SH - horizon) * i / 10) 
        y1 = horizon + floor((SH - horizon) * (i + 1) / 10) 
        DrawRectangle(0, y0, SW, y1 - y0 + 1, mzRGB(22 + i * 5, 20 + i * 4, 18 + i * 3)) 
    end for 
 
    -- walls: one DDA ray per column 
    for col = 0 to NUMCOLS - 1 do 
        camX = 2 * col / NUMCOLS - 1 
        rdx = dirX + plX * camX 
        rdy = dirY + plY * camX 
 
        mx = floor(posX) 
        my = floor(posY) 
 
        if rdx = 0 then ddX = 1e30 else ddX = mzAbs(1 / rdx) end if 
        if rdy = 0 then ddY = 1e30 else ddY = mzAbs(1 / rdy) end if 
 
        if rdx < 0 then 
            stepX = -1 
            sdX = (posX - mx) * ddX 
        else 
            stepX = 1 
            sdX = (mx + 1 - posX) * ddX 
        end if 
        if rdy < 0 then 
            stepY = -1 
            sdY = (posY - my) * ddY 
        else 
            stepY = 1 
            sdY = (my + 1 - posY) * ddY 
        end if 
 
        hit = 0 
        side = 0 
        while hit = 0 do 
            if sdX < sdY then 
                sdX += ddX 
                mx += stepX 
                side = 0 
            else 
                sdY += ddY 
                my += stepY 
                side = 1 
            end if 
            if mx < 0 or my < 0 or mx >= mzG or my >= mzG then 
                hit = 1 
            elsif mzGrid[my + 1][mx + 1] = 1 then 
                hit = 1 
            end if 
        end while 
 
        if side = 0 then 
            perp = sdX - ddX 
            wallX = posY + perp * rdy 
            if stepX > 0 then face = 4 else face = 3 end if   -- W / E face 
        else 
            perp = sdY - ddY 
            wallX = posX + perp * rdx 
            if stepY > 0 then face = 1 else face = 2 end if   -- N / S face 
        end if 
        if perp < 0.05 then perp = 0.05 end if 
        wallX -= floor(wallX) 
 
        -- distance fog + dark edges between wall blocks 
        shade = 1.2 / (1 + perp * 0.30) 
        if shade > 1 then shade = 1 end if 
        if shade < 0.10 then shade = 0.10 end if 
        if wallX < 0.03 or wallX > 0.97 then shade *= 0.55 end if 
 
        base = mzFace[face] 
        r = floor(base[1] * shade) 
        g = floor(base[2] * shade) 
        b = floor(base[3] * shade) 
 
        lineH = floor(SH / perp) 
        top = horizon - floor(lineH / 2) 
        h = lineH 
        if top < 0 then 
            h += top 
            top = 0 
        end if 
        if top + h > SH then 
            h = SH - top 
        end if 
        if h > 0 then 
            DrawRectangle(col * COLW, top, COLW, h, mzRGB(r, g, b)) 
        end if 
    end for 
end procedure 
 
-- --------------------------------------------------------------- map --------- 
procedure mzDrawMap(integer ox, integer oy, integer tile, integer x0, integer y0, integer x1, integer y1) 
    integer lo, hi, rs, px, py, gcx, gcy 
    sequence wallCol 
 
    wallCol = mzRGB(120, 130, 170) 
    DrawRectangle(ox - 3, oy - 3, (x1 - x0 + 1) * tile + 6, (y1 - y0 + 1) * tile + 6, mzRGB(0, 0, 0, 200)) 
    DrawRectangle(ox, oy, (x1 - x0 + 1) * tile, (y1 - y0 + 1) * tile, mzRGB(18, 18, 28, 230)) 
 
    lo = mzMax(x0, 1) 
    hi = mzMin(x1, mzG) 
    for gy = mzMax(y0, 1) to mzMin(y1, mzG) do 
        rs = 0 
        for gx = lo to hi + 1 do 
            if gx <= hi and mzGrid[gy][gx] = 1 then 
                if rs = 0 then rs = gx end if 
            elsif rs != 0 then 
                DrawRectangle(ox + (rs - x0) * tile, oy + (gy - y0) * tile, (gx - rs) * tile, tile, wallCol) 
                rs = 0 
            end if 
        end for 
    end for 
 
    -- exit (green) 
    gcx = floor(goalX) + 1 
    gcy = floor(goalY) + 1 
    if gcx >= x0 and gcx <= x1 and gcy >= y0 and gcy <= y1 then 
        DrawRectangle(ox + (gcx - x0) * tile, oy + (gcy - y0) * tile, tile, tile, mzRGB(60, 255, 100)) 
    end if 
 
    -- player (red dot + heading line) 
    px = ox + floor((posX - (x0 - 1)) * tile) 
    py = oy + floor((posY - (y0 - 1)) * tile) 
    DrawLine(px, py, px + floor(cos(ang) * tile * 1.6), py + floor(sin(ang) * tile * 1.6), mzRGB(255, 255, 255)) 
    DrawCircle(px, py, tile * 0.35 + 1, mzRGB(255, 60, 60)) 
end procedure 
 
procedure mzDrawMapOverlay() 
    integer cgx, cgy, tile, ox, oy 
    if mapMode = 1 then 
        cgx = floor(posX) + 1 
        cgy = floor(posY) + 1 
        tile = 9 
        ox = SW - 10 - 17 * tile 
        oy = 10 
        mzDrawMap(ox, oy, tile, cgx - 8, cgy - 8, cgx + 8, cgy + 8) 
    elsif mapMode = 2 then 
        tile = floor(700 / mzG) 
        if tile < 2 then tile = 2 end if 
        ox = floor((SW - mzG * tile) / 2) 
        oy = floor((SH - mzG * tile) / 2) 
        mzDrawMap(ox, oy, tile, 1, 1, mzG, mzG) 
    end if 
end procedure 
 
-- --------------------------------------------------------------- main -------- 
InitWindow(SW, SH, "Euphoria Maze - EuRayLib5 raycaster") 
SetTargetFPS(60) 
set_rand(time()) 
mzNewLevel() 
 
integer cx = floor(SW / 2), cy = floor(SH / 2) 
integer warm = 0, mxp, myp 
integer mvF, mvS 
atom dt, spd, ln, dx, dy, dist 
 
HideCursor() 
SetMousePosition(cx, cy) 
 
while not WindowShouldClose() do 
    dt = GetFrameTime() 
    if dt > 0.1 then dt = 0.1 end if 
 
    -- ---- mouse look (re-centre the mouse every frame) ---- 
    if IsWindowFocused() then 
        mxp = GetMouseX() 
        myp = GetMouseY() 
        if warm > 5 then 
            ang   += (mxp - cx) * MOUSE_SENS 
            pitch -= (myp - cy) * PITCH_SENS 
            if pitch >  MAX_PITCH then pitch =  MAX_PITCH end if 
            if pitch < -MAX_PITCH then pitch = -MAX_PITCH end if 
        else 
            warm += 1 
        end if 
        SetMousePosition(cx, cy) 
    end if 
 
    -- ---- keyboard movement ---- 
    mvF = 0 
    mvS = 0 
    if IsKeyDown(KEY_W) then mvF += 1 end if 
    if IsKeyDown(KEY_S) then mvF -= 1 end if 
    if IsKeyDown(KEY_D) then mvS += 1 end if 
    if IsKeyDown(KEY_A) then mvS -= 1 end if 
 
    if mvF != 0 or mvS != 0 then 
        ln  = sqrt(mvF * mvF + mvS * mvS) 
        spd = MOVE_SPEED * dt 
        dx  = (cos(ang) * mvF - sin(ang) * mvS) / ln * spd 
        dy  = (sin(ang) * mvF + cos(ang) * mvS) / ln * spd 
        mzMove(dx, dy) 
    end if 
 
    if IsKeyPressed(KEY_M) then mapMode = remainder(mapMode + 1, 3) end if 
    if IsKeyPressed(KEY_R) then mzNewLevel() end if 
 
    -- ---- reached the exit? ---- 
    dist = sqrt((goalX - posX) * (goalX - posX) + (goalY - posY) * (goalY - posY)) 
    if dist < 0.7 then 
        mzLevel += 1 
        mzN = mzMin(8 + (mzLevel - 1) * 2, 24) 
        mzNewLevel() 
        msgTimer = 2.5 
    end if 
    if msgTimer > 0 then msgTimer -= dt end if 
 
    -- ---- draw ---- 
    BeginDrawing() 
        ClearBackground(mzRGB(0, 0, 0)) 
        mzRender() 
        mzDrawMapOverlay() 
 
        -- crosshair 
        DrawRectangle(cx - 8, cy - 1, 16, 2, mzRGB(255, 255, 255, 160)) 
        DrawRectangle(cx - 1, cy - 8, 2, 16, mzRGB(255, 255, 255, 160)) 
 
        DrawFPS(10, 10) 
        DrawText(sprintf("Level %d   Exit: %.1f m", {mzLevel, dist}), 10, 36, 20, mzRGB(255, 255, 255)) 
        DrawText("WASD move | Mouse look | M map | R new maze | ESC quit", 10, SH - 28, 18, mzRGB(220, 220, 220)) 
        if msgTimer > 0 then 
            DrawText("You escaped! Next maze...", cx - 170, 90, 32, mzRGB(255, 230, 80)) 
        end if 
    EndDrawing() 
end while 
 
ShowCursor() 
CloseWindow() 
 

I'm not bragging about my prompt writing skills, but just showing how good eu and raylib are together. I'm truly blown away.

Cheers Chris

new topic     » goto parent     » topic index » view message » categorize

9. Re: Let's have some fun with EuRaylib

I did recently upgrade my Raylib wrapper for Raylib 6.2 if I hadn't mentioned it before.

new topic     » goto parent     » topic index » view message » categorize

10. Re: Let's have some fun with EuRaylib

Hi Andy

For handy ref, is there an EuRaylib constant to query which version is being run?

Cheers Chris

new topic     » goto parent     » topic index » view message » categorize

Search



Quick Links

User menu

Not signed in.

Misc Menu