code wiki / _hdl_build / nx_gi_gate.nx
nx_gi_gate.nx source
↩ module page · 135 lines · 6168 B
1// nx_gi_gate.nx -- ★R3 of the Infinigen ladder: SINGLE-BOUNCE GI (irradiance cache). Verifies the PHYSICS
2// signatures, not just "pixels changed":
3// T1 SCOPE: sky pixels are BYTE-IDENTICAL with GI on (bounce light cannot reach the sky) + terrain changed
4// T2 ★SHADE-FILL: relative brightening in the darkest terrain quartile >> in the brightest (bounce dominates
5// where direct light is absent -- the defining GI behaviour)
6// T3 ★COLOURED bounce: in shade, green gains more than blue (sunlit GRASS bleeds green -- colour transport,
7// not a flat ambient boost) + panel knowledge/nx_gi_panel.png (off | on | amplified difference)
8// license_tier: ORIGINAL expect_exit: 0
9import "nx_syscalls.nx"
10import "nx_png.nx"
11import "nx_worldgen.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 lum(px: i64) -> i64 { return (px&255) + ((px>>8)&255) + ((px>>16)&255) }
16
17func main() -> i64 {
18 hw("=== nx_gi_gate -- R3: single-bounce irradiance cache (colour-bleeding GI) ===\n" as *u8)
19 var fails: i64 = 0
20 let W: i64 = wg_w(); let H: i64 = wg_h(); let npx: i64 = W*H
21 let seed: i64 = 314
22 let cam: *i64 = sys_mmap(4*8) as *i64
23 let fbA: *i64 = sys_mmap(npx*8) as *i64
24 let fbB: *i64 = sys_mmap(npx*8) as *i64
25 let dep: *i64 = sys_mmap(npx*8) as *i64
26 let seg: *i64 = sys_mmap(npx*8) as *i64
27 let nrm: *i64 = sys_mmap(npx*8) as *i64
28 wg_set_gi(0)
29 worldgen_render_full(seed, 0, 0, cam, fbA, dep, seg, nrm)
30 wg_set_gi(1)
31 worldgen_render_full(seed, 0, 0, cam, fbB, dep, seg, nrm)
32 wg_set_gi(0)
33
34 // ---- T1 scope: sky identical, terrain changed ----
35 var skydiff: i64 = 0
36 var terrdiff: i64 = 0
37 var i: i64 = 0
38 while i < npx {
39 if seg[i] == 0 { if fbA[i] != fbB[i] { skydiff = skydiff + 1 } }
40 if seg[i] == 1 { if fbA[i] != fbB[i] { terrdiff = terrdiff + 1 } }
41 i = i + 1
42 }
43 hw(" scope: sky-diff px="); pn(skydiff); hw(" terrain-diff px="); pn(terrdiff); hw("\n" as *u8)
44 var t1: i64 = 0
45 if skydiff == 0 { if terrdiff > 50000 { t1 = 1 } }
46 if t1 == 1 { hw("T1 PASS bounce reaches terrain, never the sky (scope is physical)\n" as *u8) }
47 else { fails=fails+1; hw("T1 FAIL scope\n" as *u8) }
48
49 // ---- T2 shade-fill: split terrain by A-luma quartiles; compare RELATIVE gains ----
50 // luma histogram over terrain
51 let hist: *i64 = sys_mmap(800*8) as *i64
52 var nterr: i64 = 0
53 i = 0
54 while i < npx {
55 if seg[i] == 1 { let l: i64 = lum(fbA[i]); hist[l] = hist[l] + 1; nterr = nterr + 1 }
56 i = i + 1
57 }
58 var q1: i64 = 0
59 var acc: i64 = 0
60 var li: i64 = 0
61 while li < 766 { acc = acc + hist[li]; if q1 == 0 { if acc*4 >= nterr { q1 = li } } li = li + 1 }
62 var q3: i64 = 0
63 acc = 0
64 li = 0
65 while li < 766 { acc = acc + hist[li]; if q3 == 0 { if acc*4 >= nterr*3 { q3 = li } } li = li + 1 }
66 var shade_pm: i64 = 0
67 var shade_n: i64 = 0
68 var sun_pm: i64 = 0
69 var sun_n: i64 = 0
70 var shade_dg: i64 = 0
71 var shade_db: i64 = 0
72 i = 0
73 while i < npx {
74 if seg[i] == 1 {
75 let lA: i64 = lum(fbA[i])
76 let dl: i64 = lum(fbB[i]) - lA
77 if lA <= q1 {
78 shade_pm = shade_pm + dl*1000/(lA+1)
79 shade_dg = shade_dg + ((fbB[i]>>8)&255) - ((fbA[i]>>8)&255)
80 shade_db = shade_db + ((fbB[i]>>16)&255) - ((fbA[i]>>16)&255)
81 shade_n = shade_n + 1
82 }
83 if lA >= q3 {
84 sun_pm = sun_pm + dl*1000/(lA+1)
85 sun_n = sun_n + 1
86 }
87 }
88 i = i + 1
89 }
90 let shade_rel: i64 = shade_pm/(shade_n+1)
91 let sun_rel: i64 = sun_pm/(sun_n+1)
92 hw(" shade-fill: q1="); pn(q1); hw(" q3="); pn(q3); hw(" relative gain shade="); pn(shade_rel); hw("pm sunlit="); pn(sun_rel); hw("pm\n" as *u8)
93 var t2: i64 = 0
94 if shade_rel > 60 { if shade_rel > sun_rel*2 { t2 = 1 } }
95 if t2 == 1 { hw("T2 PASS bounce FILLS SHADE (relative gain in shadow >> in sunlight -- the GI signature)\n" as *u8) }
96 else { fails=fails+1; hw("T2 FAIL shade-fill\n" as *u8) }
97
98 // ---- T3 coloured bounce + panel ----
99 let dgm: i64 = shade_dg/(shade_n+1)
100 let dbm: i64 = shade_db/(shade_n+1)
101 hw(" colour transport in shade: mean dG="); pn(dgm); hw(" mean dB="); pn(dbm); hw("\n" as *u8)
102 var t3: i64 = 0
103 if dgm > dbm + 1 { if dgm > 2 { t3 = 1 } }
104 if t3 == 1 { hw("T3 PASS the bounce is GREEN (grass colour transported into shade, not a flat boost)\n" as *u8) }
105 else { fails=fails+1; hw("T3 FAIL colour\n" as *u8) }
106
107 // panel: off | on | amplified difference (x6 around mid-grey)
108 let GW: i64 = W*3
109 let gal: *i64 = sys_mmap(GW*H*8) as *i64
110 var y: i64 = 0
111 while y < H {
112 var x: i64 = 0
113 while x < W {
114 let pi: i64 = y*W+x
115 gal[y*GW+x] = fbA[pi]
116 gal[y*GW+W+x] = fbB[pi]
117 var dr: i64 = 128 + ((fbB[pi]&255) - (fbA[pi]&255))*6
118 var dg: i64 = 128 + (((fbB[pi]>>8)&255) - ((fbA[pi]>>8)&255))*6
119 var db: i64 = 128 + (((fbB[pi]>>16)&255) - ((fbA[pi]>>16)&255))*6
120 if dr<0{dr=0} if dr>255{dr=255}
121 if dg<0{dg=0} if dg>255{dg=255}
122 if db<0{db=0} if db>255{db=255}
123 gal[y*GW+W*2+x] = dr + dg*256 + db*65536
124 x = x + 1
125 }
126 y = y + 1
127 }
128 write_png(gal, GW, H, "knowledge/nx_gi_panel.png" as *u8)
129 hw("T4 panel -> knowledge/nx_gi_panel.png (GI off | GI on | difference x6)\n" as *u8)
130
131 if fails == 0 { hw("GI-GATE GREEN -- R3: single-bounce irradiance cache verified by physics (sky-scope + shade-fill + green colour transport). Honest label: one bounce, no bounce-visibility, coarse cells -- not path tracing\n" as *u8); sys_exit(0); return 0 }
132 hw("GI-GATE RED fails="); pn(fails); hw("\n" as *u8)
133 sys_exit(1)
134 return 1
135}