nx_wasm_sandbox.nx source
↩ module page · 127 lines · 5704 B
1// nx_wasm_sandbox.nx -- BROWSER-PLAYABLE sovereign Sandbox (falling-sand): BASE-RELATIVE integer core, runs
2// native (-> PNG) AND in the browser (base = 0). NO float, NO JS logic, NO canvas drawing. CLICK a palette
3// swatch (sand / water / wall / eraser), CLICK the grid to paint a brush; a cellular-automata tick makes sand
4// pile, water flow, walls hold. Uses the click(x,y) export. init()/tick(input)/render()/score()/ww()/hh()/
5// fb_off()/click(x,y) = the wasm interface. license_tier: ORIGINAL
6const W: i64 = 180
7const H: i64 = 160
8const TOOLH: i64 = 20
9const CELL: i64 = 4
10const GW: i64 = 45 // W/CELL
11const GH: i64 = 35 // (H-TOOLH)/CELL
12const O_FB: i64 = 0 // framebuffer W*H i64
13const O_MAP: i64 = 230400 // map[GW*GH]: 0 empty,1 sand,2 water,3 wall (W*H*8)
14const O_ST: i64 = 243000 // scalars[16]: 0=sel 1=placed
15
16func rgb(r: i64, g: i64, b: i64) -> i64 { return (r & 255) | ((g & 255) << 8) | ((b & 255) << 16) }
17func matcolor(m: i64) -> i64 {
18 if m == 1 { return rgb(222, 200, 128) } // sand
19 if m == 2 { return rgb(64, 120, 224) } // water
20 if m == 3 { return rgb(112, 112, 124) } // wall
21 return rgb(20, 22, 30) // empty
22}
23
24func fillr(base: i64, x0: i64, y0: i64, x1: i64, y1: i64, c: i64) -> i64 {
25 let fb: *i64 = (base + O_FB) as *i64
26 var yy: i64 = y0; if yy < 0 { yy = 0 }
27 var ye: i64 = y1; if ye > H { ye = H }
28 while yy < ye {
29 var xx: i64 = x0; if xx < 0 { xx = 0 }
30 var xe: i64 = x1; if xe > W { xe = W }
31 while xx < xe { fb[yy*W + xx] = c; xx = xx + 1 }
32 yy = yy + 1
33 }
34 return 0
35}
36
37func init_impl(base: i64) -> i64 {
38 let mp: *i64 = (base + O_MAP) as *i64
39 let st: *i64 = (base + O_ST) as *i64
40 var i: i64 = 0; while i < GW*GH { mp[i] = 0; i = i + 1 }
41 st[0] = 1; st[1] = 0
42 return 0
43}
44
45func click_impl(base: i64, x: i64, y: i64) -> i64 {
46 let mp: *i64 = (base + O_MAP) as *i64
47 let st: *i64 = (base + O_ST) as *i64
48 if y < TOOLH {
49 let s: i64 = x / 20
50 if s == 0 { st[0] = 1 } else { if s == 1 { st[0] = 2 } else { if s == 2 { st[0] = 3 } else { st[0] = 0 } } }
51 return 0
52 }
53 let cx: i64 = x / CELL; let cy: i64 = (y - TOOLH) / CELL
54 var by: i64 = cy - 1
55 while by <= cy + 1 {
56 var bx: i64 = cx - 1
57 while bx <= cx + 1 {
58 if bx >= 0 { if by >= 0 { if bx < GW { if by < GH { mp[by*GW + bx] = st[0]; st[1] = st[1] + 1 } } } }
59 bx = bx + 1
60 }
61 by = by + 1
62 }
63 return 0
64}
65
66func tick_impl(base: i64, input: i64) -> i64 {
67 let mp: *i64 = (base + O_MAP) as *i64
68 var y: i64 = GH - 1
69 while y >= 0 {
70 var x: i64 = 0
71 while x < GW {
72 let c: i64 = mp[y*GW + x]
73 if c == 1 { // sand: down, down-left, down-right
74 if y+1 < GH {
75 if mp[(y+1)*GW + x] == 0 { mp[(y+1)*GW + x] = 1; mp[y*GW + x] = 0 }
76 else { if x-1 >= 0 { if mp[(y+1)*GW + x-1] == 0 { mp[(y+1)*GW + x-1] = 1; mp[y*GW + x] = 0 }
77 else { if x+1 < GW { if mp[(y+1)*GW + x+1] == 0 { mp[(y+1)*GW + x+1] = 1; mp[y*GW + x] = 0 } } } }
78 else { if x+1 < GW { if mp[(y+1)*GW + x+1] == 0 { mp[(y+1)*GW + x+1] = 1; mp[y*GW + x] = 0 } } } }
79 }
80 } else { if c == 2 { // water: fall, else flow sideways
81 var moved: i64 = 0
82 if y+1 < GH { if mp[(y+1)*GW + x] == 0 { mp[(y+1)*GW + x] = 2; mp[y*GW + x] = 0; moved = 1 } }
83 if moved == 0 { if y+1 < GH { if x-1 >= 0 { if mp[(y+1)*GW + x-1] == 0 { mp[(y+1)*GW + x-1] = 2; mp[y*GW + x] = 0; moved = 1 } } } }
84 if moved == 0 { if y+1 < GH { if x+1 < GW { if mp[(y+1)*GW + x+1] == 0 { mp[(y+1)*GW + x+1] = 2; mp[y*GW + x] = 0; moved = 1 } } } }
85 if moved == 0 { if x-1 >= 0 { if mp[y*GW + x-1] == 0 { mp[y*GW + x-1] = 2; mp[y*GW + x] = 0; moved = 1 } } }
86 if moved == 0 { if x+1 < GW { if mp[y*GW + x+1] == 0 { mp[y*GW + x+1] = 2; mp[y*GW + x] = 0; moved = 1 } } }
87 } }
88 x = x + 1
89 }
90 y = y - 1
91 }
92 return 0
93}
94
95func render_impl(base: i64) -> i64 {
96 let mp: *i64 = (base + O_MAP) as *i64
97 let st: *i64 = (base + O_ST) as *i64
98 fillr(base, 0, 0, W, TOOLH, rgb(16, 18, 24)) // palette bar
99 var s: i64 = 0
100 while s < 4 {
101 var m: i64 = s + 1; if s == 3 { m = 0 } // 0=sand,1=water,2=wall,3=eraser(empty)
102 fillr(base, s*20 + 2, 3, s*20 + 18, 17, matcolor(m))
103 var selm: i64 = st[0]; var seli: i64 = selm - 1; if selm == 0 { seli = 3 }
104 if seli == s { fillr(base, s*20+1, 1, s*20+19, 2, rgb(240,240,255)); fillr(base, s*20+1, 18, s*20+19, 19, rgb(240,240,255)); fillr(base, s*20+1, 1, s*20+2, 19, rgb(240,240,255)); fillr(base, s*20+18, 1, s*20+19, 19, rgb(240,240,255)) }
105 s = s + 1
106 }
107 var y: i64 = 0
108 while y < GH {
109 var x: i64 = 0
110 while x < GW {
111 let c: i64 = mp[y*GW + x]
112 if c != 0 { fillr(base, x*CELL, TOOLH + y*CELL, x*CELL + CELL, TOOLH + y*CELL + CELL, matcolor(c)) }
113 x = x + 1
114 }
115 y = y + 1
116 }
117 return 0
118}
119
120func init() -> i64 { return init_impl(0) }
121func tick(input: i64) -> i64 { return tick_impl(0, input) }
122func render() -> i64 { return render_impl(0) }
123func click(x: i64, y: i64) -> i64 { return click_impl(0, x, y) }
124func score() -> i64 { let st: *i64 = (0 + O_ST) as *i64; return st[1] }
125func fb_off() -> i64 { return O_FB }
126func ww() -> i64 { return W }
127func hh() -> i64 { return H }