142 lines
3.3 KiB
Plaintext
142 lines
3.3 KiB
Plaintext
import rl "vendor:raylib"
|
|
|
|
import agent "vendor:agent"
|
|
|
|
import edn "vendor:edn"
|
|
|
|
const screen-width = 900
|
|
const screen-height = 600
|
|
const cell-size = 5
|
|
const rows = screen-height / cell-size
|
|
const cols = screen-width / cell-size
|
|
const brush-size = 10
|
|
|
|
fn dyn->f64(v: f64) -> f64 = v
|
|
|
|
fn dyn->u32(v: i64) -> u32 = u32(v)
|
|
|
|
let gravity = 0.05
|
|
|
|
let colors =
|
|
let v = vec-new(dyn)
|
|
push(v, 0xFFF00FFF)
|
|
push(v, 0x3B6E8CFF)
|
|
push(v, 0xA83232FF)
|
|
push(v, 0xCC6B1FFF)
|
|
v
|
|
|
|
once grid: [rows [cols u32]]
|
|
once velocity: [rows [cols f32]]
|
|
once current-color = 0
|
|
|
|
fn clear-grid() -> ()
|
|
grid = zeroed()
|
|
velocity = zeroed()
|
|
|
|
fn next-color() -> ()
|
|
current-color = (current-color + 1) % length(colors)
|
|
|
|
fn paint-at(row: i32, col: i32) -> ()
|
|
let half = brush-size / 2
|
|
for x in range(brush-size)
|
|
for y in range(brush-size)
|
|
let r = y + (row - half)
|
|
c = x + (col - half)
|
|
if r >= 0 and r < rows - 1 and c >= 0 and c < cols - 1 and 0 == grid[r, c] and f32(rand()) < 0.5
|
|
grid[r, c] = dyn->u32(colors[current-color])
|
|
velocity[r, c] = 1.0
|
|
|
|
fn settle(row: i32, col: i32) -> ()
|
|
let vel = f32(dyn->f64(gravity)) + velocity[row, col]
|
|
let y = min(rows - 1, row + i32(vel))
|
|
while y > row
|
|
if 0 == grid[y, col]
|
|
grid[y, col] = grid[row, col]
|
|
grid[row, col] = 0
|
|
velocity[y, col] = vel
|
|
velocity[row, col] = 0.0
|
|
return
|
|
let is-left = col > 0 and 0 == grid[y, col - 1]
|
|
is-right = col < cols - 1 and 0 == grid[y, col + 1]
|
|
if is-left or is-right
|
|
let side =
|
|
if not is-left
|
|
1
|
|
elif not is-right
|
|
-1
|
|
elif f32(rand()) < 0.5
|
|
1
|
|
else
|
|
-1
|
|
grid[y, col + side] = grid[row, col]
|
|
grid[row, col] = 0
|
|
velocity[y, col + side] = vel
|
|
velocity[row, col] = 0.0
|
|
return
|
|
y -= 1
|
|
velocity[row, col] = 0.0
|
|
|
|
fn step() -> ()
|
|
let row = rows - 2
|
|
while row >= 0
|
|
for col in range(cols)
|
|
unless(0 == grid[row, col]):
|
|
settle(row, col)
|
|
row -= 1
|
|
|
|
const fnv-offset: u64 = 0xcbf29ce484222325
|
|
const fnv-prime: u64 = 1099511628211
|
|
|
|
fn hash-grid() -> u64
|
|
let h = fnv-offset
|
|
for row in range(rows)
|
|
for col in range(cols)
|
|
let c = grid[row, col]
|
|
for b in range(4)
|
|
h = h ^^ u64(c >> u32(b * 8) && 255)
|
|
h *= fnv-prime
|
|
h
|
|
|
|
fn game-update() -> ()
|
|
if rl/is-key-pressed(:key-r)
|
|
clear-grid()
|
|
if rl/is-mouse-button-down(:mouse-left)
|
|
let m = rl/get-mouse-position()
|
|
paint-at(i32(m.y) / cell-size, i32(m.x) / cell-size)
|
|
if rl/is-mouse-button-released(:mouse-left)
|
|
next-color()
|
|
step()
|
|
|
|
fn game-draw() -> ()
|
|
rl/clear-background(rl/black)
|
|
for row in range(rows)
|
|
for col in range(cols)
|
|
let c = grid[row, col]
|
|
unless(0 == c):
|
|
rl/draw-rectangle(i32(col * cell-size), i32(row * cell-size), cell-size,
|
|
cell-size, rl/get-color(c))
|
|
rl/draw-fps(20, 20)
|
|
|
|
once frame: Allocator = arena-new(262144)
|
|
|
|
let game-data =
|
|
handler-case
|
|
edn/read-file("game-data.edn")
|
|
on FileError(c)
|
|
nil
|
|
|
|
fn main() -> ()
|
|
rl/set-trace-log-level(:log-warning)
|
|
rl/init-window(screen-width, screen-height, "SAND")
|
|
defer rl/close-window()
|
|
rl/set-target-fps(120)
|
|
agent/start("/tmp/flan-sand.sock")
|
|
until rl/window-should-close()
|
|
restart-case
|
|
agent/poll()
|
|
game-update()
|
|
restart continue()
|
|
()
|
|
rl/with-drawing:
|
|
game-draw()
|