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}