code wiki / _hdl_build / nx_explodelab_material_gate.nx

nx_explodelab_material_gate.nx source

↩ module page · 224 lines · 7506 B

1// nx_explodelab_material_gate.nx -- teeth on R-V6 PER-PART MATERIALS + the DEPTH CUE. 2// A material system fails quietly in two ways: the table is filled in but every entry is effectively the 3// same (nothing differentiates, yet "materials" ships), or the per-vertex material id never reaches the 4// rasteriser so the table is dead data. Both look GREEN to any "does it render" check. So: prove the table 5// is differentiated, prove the id survives into the vertex data, prove metal and dielectric highlights 6// behave DIFFERENTLY, prove depth actually attenuates, and prove the frame changes when materials are 7// flattened to one. expect_exit: 0 license_tier: ORIGINAL 8import "nx_wasm_explodelab.nx" 9 10func ag_w(s: *u8) -> i64 { 11 var n: i64 = 0 12 while s[n] != (0 as u8) { n = n + 1 } 13 sys_write(1, s, n) 14 return 0 15} 16func ag_n(v: i64) -> i64 { 17 let buf: *u8 = sys_mmap(64) 18 var a: i64 = v 19 var neg: i64 = 0 20 if a < 0 { 21 neg = 1 22 a = 0 - a 23 } 24 var i: i64 = 31 25 if a == 0 { 26 buf[i] = 48 as u8 27 i = i - 1 28 } 29 while a > 0 { 30 buf[i] = (48 + (a % 10)) as u8 31 a = a / 10 32 i = i - 1 33 } 34 if neg == 1 { 35 buf[i] = 45 as u8 36 i = i - 1 37 } 38 sys_write(1, ((buf as i64) + i + 1) as *u8, 31 - i) 39 return 0 40} 41func ag_tooth(name: *u8, pass: i64, fails: *i64) -> i64 { 42 ag_w(" " as *u8) 43 ag_w(name) 44 ag_w(" -> " as *u8) 45 if pass == 1 { 46 ag_w("PASS\n" as *u8) 47 return 0 48 } 49 ag_w("FAIL\n" as *u8) 50 fails[0] = fails[0] + 1 51 return 0 52} 53func ag_chk(base: i64) -> i64 { 54 let fb: *i64 = (base + 0) as *i64 55 var x: i64 = 0 56 var i: i64 = 0 57 let n: i64 = ww() * hh() 58 while i < n { 59 x = x + fb[i] * (1 + (i % 7)) 60 i = i + 1 61 } 62 return x 63} 64// how many of the 5 material fields differ between two kinds 65func ag_diff(k1: i64, k2: i64) -> i64 { 66 var d: i64 = 0 67 var f: i64 = 0 68 while f < 5 { 69 if exl_mat(k1, f) != exl_mat(k2, f) { d = d + 1 } 70 f = f + 1 71 } 72 return d 73} 74 75func main() -> i64 { 76 ag_w("=== nx_explodelab_material_gate -- per-part materials + depth cue ===\n" as *u8) 77 let fails: *i64 = sys_mmap(8) as *i64 78 fails[0] = 0 79 let base: i64 = sys_mmap(mem_bytes()) as i64 80 start_at(base) 81 let st: *i64 = st_ptr(base) 82 st[6] = 1 83 st[10] = 1 84 st[2] = 0 85 let e: *i64 = e_ptr(base) 86 let nrm: *i64 = (base + O_NRM) as *i64 87 let vst: *i64 = (base + O_VST) as *i64 88 let vct: *i64 = (base + O_VCT) as *i64 89 let nv: i64 = e[1] 90 91 // ---- T1 the table is genuinely DIFFERENTIATED (steel vs cast vs aluminium) 92 let d_sc: i64 = ag_diff(1, 4) 93 let d_sa: i64 = ag_diff(1, 5) 94 let d_ca: i64 = ag_diff(4, 5) 95 ag_w(" field diffs: steel/cast=" as *u8) 96 ag_n(d_sc) 97 ag_w(" steel/alu=" as *u8) 98 ag_n(d_sa) 99 ag_w(" cast/alu=" as *u8) 100 ag_n(d_ca) 101 ag_w(" of 5\n" as *u8) 102 var t1: i64 = 0 103 if d_sc >= 3 { if d_sa >= 3 { if d_ca >= 3 { t1 = 1 } } } 104 ag_tooth("T1 materials are genuinely distinct (>=3 of 5 fields differ between each pair)" as *u8, t1, fails) 105 106 // ---- T2 the per-vertex material id reaches the vertex data, and the smooth bit SURVIVED the packing 107 var wrongkind: i64 = 0 108 var anysmooth: i64 = 0 109 var p: i64 = 0 110 let np: i64 = exl_n() 111 while p < np { 112 let k: i64 = exl_kind(p) 113 var v: i64 = vst[p] 114 let vend: i64 = vst[p] + vct[p] 115 while v < vend { 116 if nrm[v * 4 + 3] / 2 != k { wrongkind = wrongkind + 1 } 117 if (nrm[v * 4 + 3] % 2) == 1 { anysmooth = anysmooth + 1 } 118 v = v + 1 119 } 120 p = p + 1 121 } 122 var t2: i64 = 0 123 if wrongkind == 0 { if anysmooth > 0 { t2 = 1 } } 124 ag_w(" (verts with wrong material id=" as *u8) 125 ag_n(wrongkind) 126 ag_w(" still-smooth=" as *u8) 127 ag_n(anysmooth) 128 ag_w(" of " as *u8) 129 ag_n(nv) 130 ag_w(")\n" as *u8) 131 ag_tooth("T2 material id packs into the vertex WITHOUT destroying the smooth-shading bit" as *u8, t2, fails) 132 133 // ---- T3 METAL vs DIELECTRIC: a metal tints its highlight by its own albedo, a dielectric adds white. 134 // With a saturated RED albedo the metal highlight must lift red far more than blue; the dielectric 135 // must lift them equally. 136 let red: i64 = 4278190080 + 200 137 let met: i64 = exl_shade2(red, 128, 200, 1, 256) 138 let die: i64 = exl_shade2(red, 128, 200, 0, 256) 139 let mr: i64 = met % 256 140 let mb: i64 = (met / 65536) % 256 141 let dr: i64 = die % 256 142 let db: i64 = (die / 65536) % 256 143 ag_w(" (metal r=" as *u8) 144 ag_n(mr) 145 ag_w(" b=" as *u8) 146 ag_n(mb) 147 ag_w(" dielectric r=" as *u8) 148 ag_n(dr) 149 ag_w(" b=" as *u8) 150 ag_n(db) 151 ag_w(")\n" as *u8) 152 var t3: i64 = 0 153 if mr - mb > 40 { if db - dr == 0 - (dr - db) { if db >= 100 { t3 = 1 } } } 154 ag_tooth("T3 metal tints its specular by albedo; dielectric stays white" as *u8, t3, fails) 155 156 // ---- T4 specular tightness really tightens: for a partial cosine, broad > medium > tight 157 let s0: i64 = exl_specp(200, 0) 158 let s1: i64 = exl_specp(200, 1) 159 let s2v: i64 = exl_specp(200, 2) 160 var t4: i64 = 0 161 if s0 > s1 { if s1 > s2v { t4 = 1 } } 162 ag_w(" (cos=200 -> broad " as *u8) 163 ag_n(s0) 164 ag_w(" med " as *u8) 165 ag_n(s1) 166 ag_w(" tight " as *u8) 167 ag_n(s2v) 168 ag_w(")\n" as *u8) 169 ag_tooth("T4 specular tightness is monotonic (broad > medium > tight)" as *u8, t4, fails) 170 171 // ---- T5 DEPTH CUE attenuates: same vertex, same material, deeper z -> darker 172 let scr: *i64 = (base + O_SCR) as *i64 173 let ig: i64 = render_at(base) 174 // ⚠set BOTH depths explicitly. Using the vertex's real (large) projected depth as the "near" case made 175 // both ends clamp to the same fog floor -- the tooth then compared two identical values and called the 176 // feature dead. Same one-variable discipline as everywhere else in this arc. 177 let zsave: i64 = scr[2] 178 scr[2] = 0 179 let near: i64 = exl_corner_col((base + O_WV) as *i64, nrm, scr, 0, 0, 0, NRM_Q, 0, 1000) 180 scr[2] = 1000 181 let far: i64 = exl_corner_col((base + O_WV) as *i64, nrm, scr, 0, 0, 0, NRM_Q, 0, 1000) 182 scr[2] = zsave 183 var t5: i64 = 0 184 if (far % 256) < (near % 256) { t5 = 1 } 185 ag_w(" (near r=" as *u8) 186 ag_n(near % 256) 187 ag_w(" far r=" as *u8) 188 ag_n(far % 256) 189 ag_w(")\n" as *u8) 190 ag_tooth("T5 DEPTH CUE: the same surface renders darker further away" as *u8, t5, fails) 191 192 // ---- T6 NON-VACUITY: flatten every vertex to ONE material and the frame must change 193 let real: i64 = ag_chk(base) 194 var i2: i64 = 0 195 while i2 < nv { 196 nrm[i2 * 4 + 3] = (nrm[i2 * 4 + 3] % 2) + 2 197 i2 = i2 + 1 198 } 199 let ig2: i64 = render_at(base) 200 let flat: i64 = ag_chk(base) 201 var t6: i64 = 0 202 if flat != real { t6 = 1 } 203 ag_tooth("T6 NON-VACUITY: flattening all parts to one material CHANGES the frame" as *u8, t6, fails) 204 205 // ---- T7 determinism after a clean rebuild 206 start_at(base) 207 st[6] = 1 208 st[10] = 1 209 st[2] = 0 210 let ig3: i64 = render_at(base) 211 var t7: i64 = 0 212 if ag_chk(base) == real { t7 = 1 } 213 ag_tooth("T7 deterministic: rebuild reproduces the material frame exactly" as *u8, t7, fails) 214 215 ag_w("\nfails=" as *u8) 216 ag_n(fails[0]) 217 ag_w("\n" as *u8) 218 if fails[0] == 0 { 219 ag_w("GREEN -- materials 7/7 (steel/cast/aluminium distinct, metal tint, depth cue live)\n" as *u8) 220 return 0 221 } 222 ag_w("RED\n" as *u8) 223 return 1 224}