nx_scene_demo.nx source
↩ module page · 106 lines · 5297 B
1// nx_scene_demo.nx -- SOVEREIGN VISUAL ENGINE: sprites + Image->browser-canvas.
2//
3// Reuses nx_image (RGB container) for the framebuffer; adds color drawing
4// (px/fill_rect), pixel-art SPRITE blit (palette index grid, 0=transparent), a
5// small game scene, and the missing bridge: emit a rendered Image as a scaled,
6// pixel-perfect HTML canvas (base64 RGB -> ImageData). No external images, no
7// library -- pixels authored in .nx. license_tier: ORIGINAL.
8
9import "nx_syscalls.nx"
10import "nx_image.nx"
11import "nx_base64.nx"
12const K_MAGIC_262144: i64 = 262144
13
14func sc_px(img: *Image, x: i64, y: i64, r: i64, g: i64, b: i64) -> i64 {
15 nx_image_set(img, x, y, 0, r)
16 nx_image_set(img, x, y, 1, g)
17 nx_image_set(img, x, y, 2, b)
18 return 0
19}
20func sc_fill(img: *Image, x0: i64, y0: i64, w: i64, h: i64, r: i64, g: i64, b: i64) -> i64 {
21 var y: i64 = y0
22 while y < y0 + h { var x: i64 = x0; while x < x0 + w { sc_px(img, x, y, r, g, b); x = x + 1 } y = y + 1 }
23 return 0
24}
25// blit an 8x8 sprite from a 64-char index string ('0'=transparent) with one color
26func sc_blit8(img: *Image, dx: i64, dy: i64, grid: *u8, r: i64, g: i64, b: i64) -> i64 {
27 var i: i64 = 0
28 while i < 64 {
29 if grid[i] != (48 as u8) { // not '0'
30 sc_px(img, dx + (i % 8), dy + (i / 8), r, g, b)
31 }
32 i = i + 1
33 }
34 return 0
35}
36
37func sc_app(out: *u8, off: *i64, s: *u8) -> i64 { var i: i64 = 0; while s[i] != (0 as u8) { out[off[0]] = s[i]; off[0] = off[0] + 1; i = i + 1 } return 0 }
38func sc_app_n(out: *u8, off: *i64, v: i64) -> i64 {
39 let t: *u8 = sys_mmap(28); var m: i64 = v; var k: i64 = 0
40 if m == 0 { t[0] = 48 as u8; k = 1 }
41 while m > 0 { t[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 }
42 var q: i64 = k - 1; while q >= 0 { out[off[0]] = t[q]; off[0] = off[0] + 1; q = q - 1 }
43 return 0
44}
45
46// build a small game scene into a fresh RGB image; returns the image
47func nx_scene_build() -> *Image {
48 let W: i64 = 64
49 let H: i64 = 48
50 let img: *Image = nx_image_alloc(W, H, 3)
51 sc_fill(img, 0, 0, W, 28, 135, 206, 235) // sky
52 sc_fill(img, 0, 28, W, 20, 92, 160, 74) // grass
53 // factory: body, roof, chimney, door, windows
54 sc_fill(img, 8, 18, 22, 14, 120, 124, 132) // body
55 sc_fill(img, 8, 14, 22, 4, 80, 84, 92) // roof
56 sc_fill(img, 24, 8, 4, 7, 70, 74, 82) // chimney
57 sc_fill(img, 16, 25, 5, 7, 60, 44, 30) // door
58 sc_fill(img, 11, 21, 4, 4, 200, 230, 255) // window
59 sc_fill(img, 22, 21, 4, 4, 200, 230, 255) // window
60 // store (right)
61 sc_fill(img, 40, 20, 18, 12, 150, 90, 70) // body
62 sc_fill(img, 39, 16, 20, 4, 200, 70, 60) // awning
63 sc_fill(img, 46, 25, 6, 7, 230, 220, 180) // door
64 // coins (gold pixel-art discs)
65 let coin: *u8 = "0011110001111110111111111111111111111111111111110111111000111100" as *u8
66 sc_blit8(img, 33, 34, coin, 255, 200, 40)
67 sc_blit8(img, 45, 36, coin, 255, 200, 40)
68 sc_blit8(img, 21, 37, coin, 255, 200, 40)
69 return img
70}
71
72// emit `img` (RGB) as a scaled pixel-perfect HTML canvas page; returns length
73func nx_img_canvas_page(img: *Image, scale: i64, out: *u8, cap: i64) -> i64 {
74 let W: i64 = img.width
75 let H: i64 = img.height
76 let nbytes: i64 = W * H * 3
77 let b64: *u8 = sys_mmap(nbytes * 2 + 64)
78 let bn: i64 = b64_encode(img.pixels, nbytes, b64)
79 let off: *i64 = (sys_mmap(8)) as *i64
80 off[0] = 0
81 sc_app(out, off, "<!doctype html><html><head><meta charset=\"utf-8\"><title>Nishi Scene</title></head><body style=\"background:#111;text-align:center\">" as *u8)
82 sc_app(out, off, "<h2 style=\"color:#dde;font-family:sans-serif\">Sovereign render — pixels authored in NishiLang, no images, no library</h2>" as *u8)
83 sc_app(out, off, "<canvas id=c width=" as *u8); sc_app_n(out, off, W * scale)
84 sc_app(out, off, " height=" as *u8); sc_app_n(out, off, H * scale)
85 sc_app(out, off, " style=\"image-rendering:pixelated;border:2px solid #444\"></canvas><script>var W=" as *u8); sc_app_n(out, off, W)
86 sc_app(out, off, ",H=" as *u8); sc_app_n(out, off, H)
87 sc_app(out, off, ",S=" as *u8); sc_app_n(out, off, scale)
88 sc_app(out, off, ",b=\"" as *u8)
89 var i: i64 = 0
90 while i < bn { out[off[0]] = b64[i]; off[0] = off[0] + 1; i = i + 1 }
91 sc_app(out, off, "\";var r=atob(b),o=document.createElement('canvas');o.width=W;o.height=H;var x=o.getContext('2d'),d=x.createImageData(W,H),p=0,i2=0;for(i2=0;i2<W*H;i2++){d.data[i2*4]=r.charCodeAt(p++);d.data[i2*4+1]=r.charCodeAt(p++);d.data[i2*4+2]=r.charCodeAt(p++);d.data[i2*4+3]=255;}x.putImageData(d,0,0);var c=document.getElementById('c'),t=c.getContext('2d');t.imageSmoothingEnabled=false;t.drawImage(o,0,0,W*S,H*S);</script></body></html>\n" as *u8)
92 out[off[0]] = 0 as u8
93 return off[0]
94}
95
96func nx_scene_save(path: *u8, scale: i64) -> i64 {
97 let img: *Image = nx_scene_build()
98 let out: *u8 = sys_mmap(K_MAGIC_262144)
99 let len: i64 = nx_img_canvas_page(img, scale, out, K_MAGIC_262144)
100 let fd: i64 = sys_openat_wr(path, 420)
101 if fd < 0 { return 0 - 1 }
102 var wr: i64 = 0
103 while wr < len { let c: i64 = sys_write(fd, out + wr, len - wr); if c <= 0 { break } wr = wr + c }
104 sys_close(fd)
105 return wr
106}