code wiki / _hdl_build / nx_critic2_gate.nx
nx_critic2_gate.nx source
↩ module page · 156 lines · 6990 B
1// nx_critic2_gate.nx -- prove gc_quality2 UNSATURATES the top of the render-quality scale.
2// The old headline gc_quality clamps every dimension at its target: craft 983 vs Veloren 1000
3// was unmeasurable and every further graphics rung would have been built blind.
4// T1 ORDERING flat toy < structured rich (sanity: the extended scale preserves order)
5// T2 UNSATURATION two frames that BOTH pin the OLD ruler at its cap are SEPARATED by quality2
6// T3 HISTORY SAFE gc_quality (the old number) is untouched: toy scores TOY, rich pins the cap
7// T4 CEILING the asymptote holds: no frame reaches 2000
8// T5 MONOTONIC palette-crushing a rich frame DROPS quality2 (the ruler can move DOWN)
9// T6 BITE incoherent noise gets NO headroom bonus (fires on noise, silent on art)
10// license_tier: ORIGINAL expect_exit: 0
11import "nx_syscalls.nx"
12import "nx_game_critic.nx"
13import "nx_gate_verdict.nx"
14
15const CG_W: i64 = 200
16const CG_H: i64 = 120
17
18// deterministic LCG for the noise fixture
19func cg_rnd(s: *i64) -> i64 { s[0] = (s[0]*1103515245 + 12345) % 2147483648; if s[0] < 0 { s[0] = 0 - s[0] } return s[0] }
20
21func cg_alloc() -> *i64 { return sys_mmap(CG_W*CG_H*8) as *i64 }
22
23// FLAT TOY: one background, one disc-ish block of a second colour
24func cg_mk_flat(fb: *i64) -> i64 {
25 var i: i64 = 0
26 while i < CG_W*CG_H { fb[i] = 0x202030; i = i + 1 }
27 var y: i64 = 40
28 while y < 80 { var x: i64 = 80; while x < 120 { fb[y*CG_W+x] = 0xC04040; x = x + 1 } y = y + 1 }
29 return 0
30}
31
32// RICH: smooth vertical shade ramp + coarse 16px colour regions + sparse 1px texture ticks.
33// huestep controls how much per-region hue variety exists -- MORE variety = bigger palette at the
34// SAME structure, which is exactly the axis the old ruler cannot see past its cap.
35func cg_mk_rich(fb: *i64, huestep: i64) -> i64 {
36 var y: i64 = 0
37 while y < CG_H {
38 var x: i64 = 0
39 while x < CG_W {
40 let ramp: i64 = 40 + y*140/CG_H
41 // FOUR interleaved row types make every OLD dimension exceed its target BY CONSTRUCTION
42 // (margins: cohere ~69% need 45, grad ~50% need 26, det1 ~31% need 12, det4 ~25% need 9):
43 // y%4==0 flat row (coherence), ==1 d=5 sawtooth (gradient+coherence),
44 // ==2 d=17 sawtooth (fine detail+gradient), ==3 4px square wave d=22 (coarse structure)
45 let rt: i64 = y % 4
46 var L: i64 = 0
47 if rt == 1 { L = (x % 2)*5 }
48 if rt == 2 { L = (x % 2)*17 }
49 if rt == 3 { L = ((x/4) % 2)*22 }
50 let rgx: i64 = x/16
51 let rgy: i64 = y/16
52 let hue: i64 = ((rgx*3 + rgy*5) % 24) * huestep
53 var r: i64 = ramp + L + hue % 60
54 var g: i64 = ramp + L + (hue/2) % 50
55 var b: i64 = ramp + L + (hue/3) % 40
56 if r > 255 { r = 255 }
57 if g > 255 { g = 255 }
58 if b > 255 { b = 255 }
59 fb[y*CG_W+x] = r + g*256 + b*65536
60 x = x + 1
61 }
62 y = y + 1
63 }
64 return 0
65}
66
67// NOISE: every pixel random -- huge palette, zero coherence (the red-team attack frame)
68func cg_mk_noise(fb: *i64) -> i64 {
69 let s: *i64 = sys_mmap(8) as *i64
70 s[0] = 987654321
71 var i: i64 = 0
72 while i < CG_W*CG_H { fb[i] = cg_rnd(s) % 16777216; i = i + 1 }
73 return 0
74}
75
76// crush palette: mask low 6 bits of every channel (strictly degrades variety, keeps structure)
77func cg_crush(src: *i64, dst: *i64) -> i64 {
78 var i: i64 = 0
79 while i < CG_W*CG_H { dst[i] = src[i] & 0xC0C0C0; i = i + 1 }
80 return 0
81}
82
83func main() -> i64 {
84 let ctr: *i64 = gv_ctr()
85 gv_head("nx_critic2 gate -- the extended headline unsaturates the top of the quality scale" as *u8)
86
87 let m: *i64 = sys_mmap(GC_N*8) as *i64
88 let flat: *i64 = cg_alloc()
89 let richA: *i64 = cg_alloc()
90 let richB: *i64 = cg_alloc()
91 let crushed: *i64 = cg_alloc()
92 let noise: *i64 = cg_alloc()
93 cg_mk_flat(flat)
94 cg_mk_rich(richA, 2)
95 cg_mk_rich(richB, 11)
96 cg_crush(richB, crushed)
97 cg_mk_noise(noise)
98
99 gc_score(flat, CG_W, CG_H, m)
100 let q_flat_old: i64 = gc_quality(m)
101 let q_flat: i64 = gc_quality2(m)
102 gc_score(richA, CG_W, CG_H, m)
103 let q_ra_old: i64 = gc_quality(m)
104 let q_ra: i64 = gc_quality2(m)
105 gv_puts(" richA: pal=" as *u8); gv_num(m[GC_M_PAL]); gv_puts(" cohere=" as *u8); gv_num(m[GC_M_COHERE]); gv_puts("\n" as *u8)
106 gc_score(richB, CG_W, CG_H, m)
107 let q_rb_old: i64 = gc_quality(m)
108 let q_rb: i64 = gc_quality2(m)
109 gv_puts(" richB: pal=" as *u8); gv_num(m[GC_M_PAL]); gv_puts(" cohere=" as *u8); gv_num(m[GC_M_COHERE]); gv_puts("\n" as *u8)
110 gc_score(crushed, CG_W, CG_H, m)
111 let q_cr: i64 = gc_quality2(m)
112 gc_score(noise, CG_W, CG_H, m)
113 let q_nz_old: i64 = gc_quality(m)
114 let q_nz: i64 = gc_quality2(m)
115 let nz_cohere: i64 = m[GC_M_COHERE]
116 let nz_pal: i64 = m[GC_M_PAL]
117
118 gv_puts(" scores old->new: flat " as *u8); gv_num(q_flat_old); gv_puts("->" as *u8); gv_num(q_flat)
119 gv_puts(" richA " as *u8); gv_num(q_ra_old); gv_puts("->" as *u8); gv_num(q_ra)
120 gv_puts(" richB " as *u8); gv_num(q_rb_old); gv_puts("->" as *u8); gv_num(q_rb)
121 gv_puts(" crushed ->" as *u8); gv_num(q_cr)
122 gv_puts(" noise " as *u8); gv_num(q_nz_old); gv_puts("->" as *u8); gv_num(q_nz)
123 gv_puts(" (pal=" as *u8); gv_num(nz_pal); gv_puts(" cohere=" as *u8); gv_num(nz_cohere); gv_puts(")\n" as *u8)
124
125 var t1: i64 = 0
126 if q_flat < q_ra { if q_ra <= q_rb { t1 = 1 } }
127 gv_check("T1 ordering: flat < richA <= richB on quality2" as *u8, t1, ctr)
128
129 // THE tooth this gate exists for: both rich frames pin the OLD ruler, quality2 separates them
130 var t2: i64 = 0
131 if q_ra_old == q_rb_old { if q_rb > q_ra { t2 = 1 } }
132 gv_check("T2 UNSATURATION: old reads richA==richB at its cap, quality2 separates them" as *u8, t2, ctr)
133
134 var t3: i64 = 0
135 if q_flat_old < GC_TOY { if q_ra_old >= 900 { t3 = 1 } }
136 gv_check("T3 history safe: old number unchanged in kind (toy TOY, rich near cap)" as *u8, t3, ctr)
137
138 var t4: i64 = 0
139 if q_rb < 2000 { if q_ra < 2000 { t4 = 1 } }
140 gv_check("T4 ceiling asymptote holds (< 2000 always)" as *u8, t4, ctr)
141
142 var t5: i64 = 0
143 if q_cr < q_rb { t5 = 1 }
144 gv_check("T5 monotonic: palette-crushed rich frame DROPS on quality2" as *u8, t5, ctr)
145
146 // BITE: the no-bonus-for-incoherence guard. bad = noise WOULD outscore richA if it got its
147 // palette bonus (pal is huge); detector fires when noise stays floored despite that palette.
148 var bad_fires: i64 = 0
149 if q_nz < GC_TOY { if nz_pal > 500 { bad_fires = 1 } }
150 var good_fires: i64 = 0
151 if q_ra < GC_TOY { good_fires = 1 }
152 gv_bite("T6 BITE incoherent noise gets NO headroom (floored despite huge palette), art does" as *u8, bad_fires, good_fires, ctr)
153
154 let rc: i64 = gv_verdict("CRITIC2-GATE" as *u8, ctr, "the ruler can move again: top unsaturated, history preserved, noise still floored" as *u8)
155 return rc
156}