code wiki / _hdl_build / nx_arcade_render.nx
nx_arcade_render.nx source
↩ module page · 113 lines · 5577 B
1// nx_arcade_render.nx -- CORRECTED sovereign game: logic AND rendering are PURE NISHI, NO FLOAT (all i64),
2// NO JavaScript logic, NO 3rd-party canvas drawing. Integer game state + integer rasterizer write pixels
3// into a packed-RGB framebuffer (R|G<<8|B<<16). This same module is what the sovereign WASM chain
4// (nx_compile_wat -> nx_wat_compiler -> blit shim) ships to the browser, where the ONLY browser touch is
5// blitting this framebuffer + forwarding keys. Here it is verified NATIVELY by rendering a frame to PNG
6// (the sovereign eyeball loop). license_tier: ORIGINAL expect_exit: 0
7import "nx_syscalls.nx"
8import "nx_shade.nx"
9import "nx_png.nx"
10
11func aw(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 }
12func an(v: i64) -> i64 { let bb: *u8=sys_mmap(28); var m: i64=v; if m<0{m=0-m;sys_write(1,"-" as *u8,1)} let t: *u8=sys_mmap(28); var k: i64=0; if m==0{t[0]=48 as u8;k=1} while m>0{t[k]=(48+(m%10)) as u8;m=m/10;k=k+1} var i: i64=0; while i<k{bb[i]=t[k-1-i];i=i+1} sys_write(1,bb,k); return 0 }
13
14// integer rectangle fill into the packed-RGB framebuffer (no float).
15func fill_rect(fb: *i64, w: i64, h: i64, x0: i64, y0: i64, x1: i64, y1: i64, c: i64) -> i64 {
16 var yy: i64 = y0; if yy < 0 { yy = 0 }
17 var ye: i64 = y1; if ye > h { ye = h }
18 while yy < ye {
19 var xx: i64 = x0; if xx < 0 { xx = 0 }
20 var xe: i64 = x1; if xe > w { xe = w }
21 while xx < xe { fb[yy*w + xx] = c; xx = xx + 1 }
22 yy = yy + 1
23 }
24 return 0
25}
26
27// ---- pure-Nishi integer game state (no float) ----
28// st layout: [0]=px [1]=py [2]=score [3]=ng [4]=nh ; goals at gx[],gy[] ; hazards hx[],hy[]
29func g_at(xs: *i64, ys: *i64, n: i64, x: i64, y: i64) -> i64 {
30 var i: i64 = 0
31 while i < n { if xs[i]==x { if ys[i]==y { return i } } i = i + 1 }
32 return 0 - 1
33}
34
35// the LOGIC (in Nishi, not JS): move player; collect a goal on contact.
36func tick(st: *i64, gx: *i64, gy: *i64, dir: i64, gw: i64, gh: i64) -> i64 {
37 var nx: i64 = st[0]
38 var ny: i64 = st[1]
39 if dir == 0 { ny = ny - 1 }
40 if dir == 1 { ny = ny + 1 }
41 if dir == 2 { nx = nx - 1 }
42 if dir == 3 { nx = nx + 1 }
43 if nx < 0 { return 0 }
44 if ny < 0 { return 0 }
45 if nx >= gw { return 0 }
46 if ny >= gh { return 0 }
47 st[0] = nx; st[1] = ny
48 let gi: i64 = g_at(gx, gy, st[3], nx, ny)
49 if gi >= 0 { gx[gi] = 0 - 9; gy[gi] = 0 - 9; st[2] = st[2] + 1 } // collect (move off-grid)
50 return 0
51}
52
53// render the integer game state to the framebuffer (integer raster, no float, no canvas).
54func render(st: *i64, gx: *i64, gy: *i64, hx: *i64, hy: *i64, fb: *i64, w: i64, h: i64, cell: i64, gw: i64, gh: i64) -> i64 {
55 sh_clear(fb, w, h, sh_rgb(16, 20, 30))
56 // grid lines
57 var c: i64 = 0
58 while c <= gw { fill_rect(fb, w, h, c*cell, 0, c*cell+1, gh*cell, sh_rgb(40, 46, 60)); c = c + 1 }
59 var r: i64 = 0
60 while r <= gh { fill_rect(fb, w, h, 0, r*cell, gw*cell, r*cell+1, sh_rgb(40, 46, 60)); r = r + 1 }
61 // goals (gold)
62 var i: i64 = 0
63 while i < st[3] { if gx[i] >= 0 { fill_rect(fb, w, h, gx[i]*cell+6, gy[i]*cell+6, gx[i]*cell+cell-6, gy[i]*cell+cell-6, sh_rgb(255, 210, 70)) } i = i + 1 }
64 // hazards (red)
65 var j: i64 = 0
66 while j < st[4] { fill_rect(fb, w, h, hx[j]*cell+4, hy[j]*cell+4, hx[j]*cell+cell-4, hy[j]*cell+cell-4, sh_rgb(224, 80, 58)) j = j + 1 }
67 // player (green)
68 fill_rect(fb, w, h, st[0]*cell+4, st[1]*cell+4, st[0]*cell+cell-4, st[1]*cell+cell-4, sh_rgb(90, 210, 122))
69 return 0
70}
71
72func main() -> i64 {
73 let GW: i64 = 10
74 let GH: i64 = 8
75 let CELL: i64 = 24
76 let W: i64 = 240
77 let H: i64 = 192
78 let st: *i64 = sys_mmap(8 * 8) as *i64
79 st[0]=0; st[1]=0; st[2]=0; st[3]=4; st[4]=3
80 let gx: *i64 = sys_mmap(8*8) as *i64
81 let gy: *i64 = sys_mmap(8*8) as *i64
82 let hx: *i64 = sys_mmap(8*8) as *i64
83 let hy: *i64 = sys_mmap(8*8) as *i64
84 gx[0]=3; gy[0]=0; gx[1]=6; gy[1]=2; gx[2]=8; gy[2]=5; gx[3]=2; gy[3]=6
85 hx[0]=5; hy[0]=4; hx[1]=1; hy[1]=3; hx[2]=7; hy[2]=1
86
87 // scripted LOGIC playthrough: walk right to collect the first goal at (3,0)
88 tick(st, gx, gy, 3, GW, GH)
89 tick(st, gx, gy, 3, GW, GH)
90 tick(st, gx, gy, 3, GW, GH)
91
92 var pass: i64 = 0
93 var total: i64 = 0
94 total=total+1; if st[2] >= 1 { pass=pass+1 } else { aw("A1 FAIL logic did not collect\n") } // pure-Nishi LOGIC works
95 total=total+1; if st[0] == 3 { if st[1] == 0 { pass=pass+1 } else { aw("A2 FAIL pos\n") } } else { aw("A2 FAIL pos\n") }
96
97 let fb: *i64 = sys_mmap(8 * 240 * 192) as *i64
98 render(st, gx, gy, hx, hy, fb, W, H, CELL, GW, GH)
99 write_png(fb, W, H, "knowledge/nx_arcade_native.png" as *u8)
100
101 // verify rendered pixels (player center green, a hazard center red) -- integer raster, no float
102 let pc: i64 = fb[(0*CELL+12)*W + (3*CELL+12)] // player now at (3,0)
103 total=total+1; if sh_g(pc) > sh_r(pc) { pass=pass+1 } else { aw("A3 FAIL player not green\n") }
104 let hc: i64 = fb[(4*CELL+12)*W + (5*CELL+12)] // hazard at (5,4)
105 total=total+1; if sh_r(hc) > sh_g(hc) { pass=pass+1 } else { aw("A4 FAIL hazard not red\n") }
106
107 aw("=== PURE-NISHI NO-FLOAT arcade (logic+render, no JS, no canvas-draw) ===\n")
108 aw(" player=("); an(st[0]); aw(","); an(st[1]); aw(") score="); an(st[2]); aw(" frame -> knowledge/nx_arcade_native.png\n")
109 aw("ARCADE-RENDER "); an(pass); aw("/"); an(total); aw("\n")
110 if pass == total { aw("ARCADE-RENDER ALL-PASS (sovereign integer game logic + integer raster framebuffer; PNG-verified)\n"); sys_exit(0) }
111 sys_exit(1)
112 return 1
113}