code wiki / _hdl_build / nx_boxtex_gate.nx
nx_boxtex_gate.nx source
↩ module page · 140 lines · 7387 B
1// nx_boxtex_gate.nx -- ★IMAGE TEXTURES + UV (field-evidence rung 4): Khronos BoxTextured.glb -- "start with this to
2// test textures". The embedded 256x256 PALETTE PNG is decoded by the ECOSYSTEM's own nx_png_decoder (upgraded this
3// session with PLTE support), UVs come from the asset's TEXCOORD_0, and the box renders with the texture sampled
4// per-pixel. T1 PNG decodes (256x256, multi-colour). T2 textured render differs hugely from untextured + is multi-
5// coloured. T3 determinism. T4 regression (Duck/Box/bunny still load). T5 evidence -> knowledge/nx_boxtex.png.
6// license_tier: ORIGINAL expect_exit: 0
7import "nx_syscalls.nx"
8import "nx_png.nx"
9import "nx_trimesh.nx"
10import "nx_gltf_load.nx"
11import "nx_img_bytes_to_rgb.nx"
12
13func hw(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 }
14func pn(v: i64) -> i64 { let b: *u8=sys_mmap(32) as *u8; var x: i64=v; var ng: i64=0; if x<0{ng=1;x=0-x} var i: i64=31; if x==0{b[i]=48 as u8;i=i-1} while x>0{b[i]=(48+x%10) as u8;x=x/10;i=i-1} if ng==1{b[i]=45 as u8;i=i-1} sys_write(1,(b as i64+i+1) as *u8,31-i); return 0 }
15func clearfb(fb: *i64, n: i64, c: i64) -> i64 { var i: i64=0; while i<n { fb[i]=c; i=i+1 } return 0 }
16func filled(fb: *i64, n: i64, bg: i64) -> i64 { var c: i64=0; var i: i64=0; while i<n { if fb[i]!=bg { c=c+1 } i=i+1 } return c }
17func imdiff(a: *i64, b: *i64, n: i64) -> i64 { var s: i64=0; var i: i64=0; while i<n { if a[i]!=b[i] { s=s+1 } i=i+1 } return s }
18// count distinct colours among non-bg pixels (capped scan)
19func distinct(fb: *i64, n: i64, bg: i64) -> i64 {
20 let CAP: i64 = 600
21 let cols: *i64 = sys_mmap(CAP*8) as *i64
22 var nd: i64 = 0
23 var i: i64 = 0
24 while i < n {
25 let p: i64 = fb[i]
26 if p != bg {
27 var k: i64 = 0
28 var f: i64 = 0
29 while k < nd { if cols[k]==p { f=1; k=nd } else { k=k+1 } }
30 if f == 0 { if nd < CAP { cols[nd]=p; nd=nd+1 } }
31 }
32 i = i + 1
33 }
34 return nd
35}
36
37const BG: i64 = 24 + 26*256 + 34*65536
38const W: i64 = 320
39const H: i64 = 320
40
41func main() -> i64 {
42 hw("=== nx_boxtex_gate -- Khronos BoxTextured: image texture + UV through the ecosystem PNG decoder ===\n" as *u8)
43 var fails: i64 = 0
44 let npx: i64 = W*H
45 let fb: *i64 = sys_mmap(npx*8) as *i64
46 let fb2: *i64 = sys_mmap(npx*8) as *i64
47 let zb: *i64 = sys_mmap(npx*8) as *i64
48 tm_set_spec(0)
49 tm_set_tex(0)
50 tm_set_image(0 as *u8, 0, 0)
51
52 // ---- T1 extract + decode the embedded PALETTE PNG via the ecosystem decoder ----
53 let szp: *i64 = sys_mmap(16) as *i64
54 let glb: *u8 = sys_read_file("knowledge/stdassets/BoxTextured.glb" as *u8, szp)
55 var t1: i64 = 0
56 let sl: *i64 = sys_mmap(16) as *i64
57 var rgb: *u8 = 0 as *u8
58 let wh: *i64 = sys_mmap(16) as *i64
59 if (glb as i64) != 0 {
60 if gls_image_slice(glb, szp[0], sl) == 1 {
61 hw(" image slice: off="); pn(sl[0]); hw(" len="); pn(sl[1]); hw("\n" as *u8)
62 rgb = nx_img_bytes_to_rgb((glb as i64 + sl[0]) as *u8, sl[1], wh)
63 }
64 }
65 var texcols: i64 = 0
66 if (rgb as i64) != 0 {
67 // count distinct colours in the decoded texture (sample every 97th texel)
68 let tn: i64 = wh[0]*wh[1]
69 let tmp: *i64 = sys_mmap(700*8) as *i64
70 var nd: i64 = 0
71 var i: i64 = 0
72 while i < tn {
73 let o: i64 = i*3
74 let c: i64 = (rgb[o] as i64) + (rgb[o+1] as i64)*256 + (rgb[o+2] as i64)*65536
75 var k: i64 = 0
76 var f: i64 = 0
77 while k < nd { if tmp[k]==c { f=1; k=nd } else { k=k+1 } }
78 if f == 0 { if nd < 700 { tmp[nd]=c; nd=nd+1 } }
79 i = i + 97
80 }
81 texcols = nd
82 hw(" decoded: "); pn(wh[0]); hw("x"); pn(wh[1]); hw(" distinct-colours(sampled)="); pn(texcols); hw("\n" as *u8)
83 if wh[0] == 256 { if wh[1] == 256 { if texcols >= 3 { t1 = 1 } } }
84 }
85 if t1 == 1 { hw("T1 PASS PALETTE PNG decoded by the ecosystem decoder (256x256, multi-colour) -- PLTE upgrade works\n" as *u8) }
86 else { fails=fails+1; hw("T1 FAIL\n" as *u8) }
87
88 // ---- T2 textured vs untextured render ----
89 let ok: i64 = gltf_load_std("knowledge/stdassets/BoxTextured.glb" as *u8, 520)
90 hw(" BoxTextured mesh: ok="); pn(ok); hw(" verts="); pn(tm_nv()); hw(" tris="); pn(tm_nt()); hw("\n" as *u8)
91 clearfb(fb2, npx, BG); trimesh_zclear(zb, npx); trimesh_render(fb2, zb, W, H, 2600, 0-600, 1500, 520, 2) // untextured
92 tm_set_image(rgb, wh[0], wh[1])
93 clearfb(fb, npx, BG); trimesh_zclear(zb, npx); trimesh_render(fb, zb, W, H, 2600, 0-600, 1500, 520, 2) // textured
94 let dd: i64 = imdiff(fb, fb2, npx)
95 let dcT: i64 = distinct(fb, npx, BG)
96 let dcU: i64 = distinct(fb2, npx, BG)
97 hw(" textured-vs-plain diff px="); pn(dd); hw(" distinct colours textured="); pn(dcT); hw(" plain="); pn(dcU); hw("\n" as *u8)
98 var t2: i64 = 0
99 if ok == 1 { if dd > 3000 { if dcT > dcU*3 { t2 = 1 } } }
100 if t2 == 1 { hw("T2 PASS IMAGE TEXTURE: the asset's own PNG, sampled via its own UVs, renders on the box (rich multi-colour vs flat)\n" as *u8) }
101 else { fails=fails+1; hw("T2 FAIL\n" as *u8) }
102
103 // ---- T3 determinism ----
104 clearfb(fb2, npx, BG); trimesh_zclear(zb, npx); trimesh_render(fb2, zb, W, H, 2600, 0-600, 1500, 520, 2)
105 var diff: i64 = 0; var i: i64 = 0
106 while i < npx { if fb2[i]!=fb[i] { diff=diff+1 } i=i+1 }
107 var t3: i64 = 0
108 if diff == 0 { t3 = 1 }
109 if t3 == 1 { hw("T3 PASS deterministic\n" as *u8) } else { fails=fails+1; hw("T3 FAIL diff="); pn(diff); hw("\n" as *u8) }
110
111 // ---- T4 regression: untextured assets unaffected ----
112 tm_set_image(0 as *u8, 0, 0)
113 let okD: i64 = gltf_load_std("knowledge/stdassets/Duck.glb" as *u8, 1000)
114 var t4: i64 = 0
115 if okD == 1 { if tm_nv() == 2399 { t4 = 1 } }
116 if t4 == 1 { hw("T4 PASS regression: Duck still loads exactly (2399 verts)\n" as *u8) }
117 else { fails=fails+1; hw("T4 FAIL\n" as *u8) }
118
119 // ---- T5 evidence: textured box, two views ----
120 let GW: i64 = W*2
121 let gal: *i64 = sys_mmap(GW*H*8) as *i64
122 clearfb(gal, GW*H, BG)
123 let cell: *i64 = sys_mmap(npx*8) as *i64
124 gltf_load_std("knowledge/stdassets/BoxTextured.glb" as *u8, 520)
125 tm_set_image(rgb, wh[0], wh[1])
126 clearfb(cell,npx,BG); trimesh_zclear(zb,npx); trimesh_render(cell,zb,W,H,2600,0-600,1500,520,2)
127 var y: i64 = 0
128 while y < H { var x: i64=0; while x<W { gal[y*GW+x]=cell[y*W+x]; x=x+1 } y=y+1 }
129 clearfb(cell,npx,BG); trimesh_zclear(zb,npx); trimesh_render(cell,zb,W,H,900,0-350,1500,520,2)
130 y = 0
131 while y < H { var x: i64=0; while x<W { gal[y*GW+W+x]=cell[y*W+x]; x=x+1 } y=y+1 }
132 write_png(gal, GW, H, "knowledge/nx_boxtex.png" as *u8)
133 tm_set_image(0 as *u8, 0, 0)
134 hw("T5 evidence -> knowledge/nx_boxtex.png (Khronos BoxTextured, two views)\n" as *u8)
135
136 if fails == 0 { hw("BOXTEX-GATE GREEN -- image texture mapping via UV: the Khronos conformance texture (PALETTE PNG, decoded by the upgraded ecosystem nx_png_decoder) samples onto the box through the asset's own TEXCOORD_0. Census texture-mapping PARTIAL->HAVE. Residual: DamagedHelmet (normal/occlusion/emissive maps), bilinear filtering, perspective-correct UV, UV UNWRAP authoring (stays GAP).\n" as *u8); sys_exit(0); return 0 }
137 hw("BOXTEX-GATE RED fails="); pn(fails); hw("\n" as *u8)
138 sys_exit(1)
139 return 1
140}