code wiki / _hdl_build / nx_softbody_region_gate.nx

nx_softbody_region_gate.nx source

↩ module page · 224 lines · 10011 B

1// nx_softbody_region_gate.nx -- gate for the BODY-REGION soft physics + THE OCCLUSION LAW. 2// T1 GRAVITY PARAM: gmul_y=0 -> ring holds its rest shape exactly-ish; gmul_y=256 -> the bottom node sags 3// measurably = the TittyMagic-class gravity knob is REAL data. 4// T2 THE OCCLUSION LAW (the operator's ask, measured): a capsule pressed into the RIGHT of the ring -> 5// (a) contact nodes held near the collider surface, (b) the FAR (left) nodes BULGE OUTWARD beyond rest 6// (displaced volume redistributed = physics beyond the visible contact area), (c) capsule removed -> 7// the ring RECOVERS to rest (elastic, no permanent dent). 8// T3 VOLUME PROXY: cross-section area with the capsule embedded stays >= 85% of rest area WITH voldist, 9// and beats the voldist=0 control (the knob does the conserving). 10// T4 PARAMS ARE DATA: mass 256 vs 1024 -> different response speed; colsoft 256 vs 64 -> different depth. 11// T5 determinism: two regions, same script -> byte-identical node state. 12// + PNG knowledge/nx_region_occlusion.png: rest ring vs embedded-capsule ring, the BULGE visible. 13// license_tier: ORIGINAL expect_exit: 0 14import "nx_syscalls.nx" 15import "nx_png.nx" 16import "nx_softbody_region.nx" 17 18func hw(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(1, s, n); return 0 } 19func pn(v: i64) -> i64 { 20 let b: *u8 = sys_mmap(32) as *u8 21 var x: i64 = v 22 var neg: i64 = 0 23 if x < 0 { neg = 1; x = 0 - x } 24 var i: i64 = 31 25 if x == 0 { b[i] = 48 as u8; i = i - 1 } 26 while x > 0 { b[i] = (48 + x % 10) as u8; x = x / 10; i = i - 1 } 27 if neg == 1 { b[i] = 45 as u8; i = i - 1 } 28 sys_write(1, (b as i64 + i + 1) as *u8, 31 - i) 29 return 0 30} 31func gabs(v: i64) -> i64 { if v < 0 { return 0 - v } return v } 32func isq(v: i64) -> i64 { if v <= 0 { return 0 } var x: i64 = v; var y: i64 = (x + 1) / 2; while y < x { x = y; y = (x + v / x) / 2 } return x } 33func nodelen(base: i64, i: i64) -> i64 { 34 let h: *i64 = sr_hdr(base) 35 let ox: i64 = sr_pos(base, i, 0) - h[2] 36 let oy: i64 = sr_pos(base, i, 1) - h[3] 37 return isq(ox * ox + oy * oy) 38} 39// plot one ring into the fb panel at xoff (nodes + edges + capsule if present) 40func plot(base: i64, fb: *i64, TW: i64, TH: i64, xoff: i64) -> i64 { 41 let h: *i64 = sr_hdr(base) 42 let nn: i64 = h[0] 43 var i: i64 = 0 44 while i < nn { 45 let ax: i64 = xoff + 64 + (sr_pos(base, i, 0) - h[2]) / 16 46 let ay: i64 = 64 - (sr_pos(base, i, 1) - h[3]) / 16 47 let bxi: i64 = (i + 1) % nn 48 let bx: i64 = xoff + 64 + (sr_pos(base, bxi, 0) - h[2]) / 16 49 let by: i64 = 64 - (sr_pos(base, bxi, 1) - h[3]) / 16 50 var s: i64 = 0 51 while s <= 10 { 52 let px: i64 = ax + (bx - ax) * s / 10 53 let py: i64 = ay + (by - ay) * s / 10 54 if px >= 0 { if px < TW { if py >= 0 { if py < TH { fb[py * TW + px] = 120 + 220 * 256 + 170 * 65536 } } } } 55 s = s + 1 56 } 57 i = i + 1 58 } 59 // capsule (first) as a circle at its midpoint 60 if h[1] > 0 { 61 let cp: *i64 = sr_cap(base, 0) 62 let cx: i64 = xoff + 64 + ((cp[0] + cp[3]) / 2 - h[2]) / 16 63 let cy: i64 = 64 - ((cp[1] + cp[4]) / 2 - h[3]) / 16 64 let cr: i64 = cp[6] / 16 65 var dy: i64 = 0 - cr 66 while dy <= cr { 67 var dx: i64 = 0 - cr 68 while dx <= cr { 69 let dd: i64 = dx * dx + dy * dy 70 if dd <= cr * cr { if dd >= (cr - 2) * (cr - 2) { 71 let px2: i64 = cx + dx 72 let py2: i64 = cy + dy 73 if px2 >= 0 { if px2 < TW { if py2 >= 0 { if py2 < TH { fb[py2 * TW + px2] = 235 + 120 * 256 + 90 * 65536 } } } } 74 } } 75 dx = dx + 1 76 } 77 dy = dy + 1 78 } 79 } 80 return 0 81} 82 83func main() -> i64 { 84 var fails: i64 = 0 85 86 // ---- T1 gravity knob ---- 87 let A: i64 = sys_mmap(sr_bytes()) as i64 88 sr_init(A, 0, 0, 0) 89 sr_param(A, 9, 0) // gmul_y = 0: no gravity 90 sr_ring(A, 16, 800) 91 var t: i64 = 0 92 while t < 300 { sr_step(A); t = t + 1 } 93 var maxdev: i64 = 0 94 var i: i64 = 0 95 while i < 16 { 96 let d: i64 = gabs(nodelen(A, i) - 800) 97 if d > maxdev { maxdev = d } 98 i = i + 1 99 } 100 let B: i64 = sys_mmap(sr_bytes()) as i64 101 sr_init(B, 0, 0, 0) 102 sr_param(B, 9, 256) // full gravity 103 sr_ring(B, 16, 800) 104 t = 0 105 while t < 300 { sr_step(B); t = t + 1 } 106 let sag: i64 = 0 - 800 - (sr_pos(B, 12, 1) - 0) // node 12 = bottom (270deg): rest y=-800; sag = how far below 107 var t1: i64 = 1 108 if maxdev > 24 { t1 = 0 } 109 if sag < 8 { t1 = 0 } 110 if t1 == 1 { hw("T1 PASS gravity is DATA: gmul=0 holds rest (maxdev=" as *u8); pn(maxdev); hw("), gmul=256 sags bottom node " as *u8); pn(sag); hw("\n" as *u8) } 111 else { hw("T1 FAIL maxdev=" as *u8); pn(maxdev); hw(" sag=" as *u8); pn(sag); hw("\n" as *u8); fails = fails + 1 } 112 113 // ---- T2 THE OCCLUSION LAW ---- 114 let C: i64 = sys_mmap(sr_bytes()) as i64 115 sr_init(C, 0, 0, 0) 116 sr_param(C, 9, 0) // isolate the law from gravity 117 sr_ring(C, 16, 800) 118 let restarea: i64 = sr_area(C) 119 sr_add_capsule(C, 1000, 0 - 400, 0, 1000, 400, 0, 350) // presses ~150 into the right edge 120 t = 0 121 while t < 400 { sr_step(C); t = t + 1 } 122 // (a) right node (0) held near the capsule surface: its x <= 1000-350+24+slop 123 let rx: i64 = sr_pos(C, 0, 0) 124 var t2: i64 = 1 125 if rx > 680 { t2 = 0 } 126 // (b) far-left nodes bulge beyond rest 127 var lb: i64 = nodelen(C, 8) // node 8 = 180deg = far left 128 let bulge: i64 = lb - 800 129 if bulge < 16 { t2 = 0 } 130 let embarea: i64 = sr_area(C) 131 // (c) remove -> recovery 132 sr_clear_capsules(C) 133 t = 0 134 while t < 500 { sr_step(C); t = t + 1 } 135 var recdev: i64 = 0 136 i = 0 137 while i < 16 { 138 let d2: i64 = gabs(nodelen(C, i) - 800) 139 if d2 > recdev { recdev = d2 } 140 i = i + 1 141 } 142 if recdev > 30 { t2 = 0 } 143 if t2 == 1 { hw("T2 PASS OCCLUSION LAW: contact held (rx=" as *u8); pn(rx); hw("), FAR SIDE BULGES +" as *u8); pn(bulge); hw(" beyond rest (displaced volume went somewhere), full recovery (dev=" as *u8); pn(recdev); hw(")\n" as *u8) } 144 else { hw("T2 FAIL rx=" as *u8); pn(rx); hw(" bulge=" as *u8); pn(bulge); hw(" recdev=" as *u8); pn(recdev); hw("\n" as *u8); fails = fails + 1 } 145 146 // ---- T3 volume proxy vs the voldist=0 control ---- 147 let D: i64 = sys_mmap(sr_bytes()) as i64 148 sr_init(D, 0, 0, 0) 149 sr_param(D, 9, 0) 150 sr_param(D, 12, 0) // occlusion law OFF (control) 151 sr_ring(D, 16, 800) 152 sr_add_capsule(D, 1000, 0 - 400, 0, 1000, 400, 0, 350) 153 t = 0 154 while t < 400 { sr_step(D); t = t + 1 } 155 let ctrlarea: i64 = sr_area(D) 156 var t3: i64 = 1 157 if embarea * 100 < restarea * 85 { t3 = 0 } 158 if embarea <= ctrlarea { t3 = 0 } 159 if t3 == 1 { hw("T3 PASS volume proxy: embedded area " as *u8); pn(embarea * 100 / restarea); hw("% of rest WITH the law vs " as *u8); pn(ctrlarea * 100 / restarea); hw("% control -- the knob conserves\n" as *u8) } 160 else { hw("T3 FAIL emb=" as *u8); pn(embarea); hw(" ctrl=" as *u8); pn(ctrlarea); hw(" rest=" as *u8); pn(restarea); hw("\n" as *u8); fails = fails + 1 } 161 162 // ---- T4 params are data ---- 163 let E1: i64 = sys_mmap(sr_bytes()) as i64 164 let E2: i64 = sys_mmap(sr_bytes()) as i64 165 sr_init(E1, 0, 0, 0); sr_init(E2, 0, 0, 0) 166 sr_param(E1, 5, 256); sr_param(E2, 5, 1024) // mass 1x vs 4x 167 sr_param(E1, 9, 0); sr_param(E2, 9, 0) 168 sr_ring(E1, 16, 800); sr_ring(E2, 16, 800) 169 sr_anchor(E1, 300, 0, 0); sr_anchor(E2, 300, 0, 0) // step the anchor: response speed differs by mass 170 t = 0 171 var mdiff: i64 = 0 172 while t < 30 { 173 sr_step(E1); sr_step(E2) 174 if sr_pos(E1, 0, 0) != sr_pos(E2, 0, 0) { mdiff = mdiff + 1 } 175 t = t + 1 176 } 177 var t4: i64 = 1 178 if mdiff < 20 { t4 = 0 } 179 if t4 == 1 { hw("T4 PASS params are DATA: mass 1x vs 4x diverge on " as *u8); pn(mdiff); hw("/30 ticks after an anchor step\n" as *u8) } 180 else { hw("T4 FAIL mdiff=" as *u8); pn(mdiff); hw("\n" as *u8); fails = fails + 1 } 181 182 // ---- T5 determinism ---- 183 let F1: i64 = sys_mmap(sr_bytes()) as i64 184 let F2: i64 = sys_mmap(sr_bytes()) as i64 185 sr_init(F1, 0, 0, 0); sr_init(F2, 0, 0, 0) 186 sr_ring(F1, 16, 800); sr_ring(F2, 16, 800) 187 sr_add_capsule(F1, 1000, 0 - 400, 0, 1000, 400, 0, 350) 188 sr_add_capsule(F2, 1000, 0 - 400, 0, 1000, 400, 0, 350) 189 t = 0 190 while t < 300 { sr_step(F1); sr_step(F2); t = t + 1 } 191 var diff: i64 = 0 192 i = 0 193 while i < 16 * 16 { 194 let p1: *i64 = (F1 + 128) as *i64 195 let p2: *i64 = (F2 + 128) as *i64 196 if p1[i] != p2[i] { diff = diff + 1 } 197 i = i + 1 198 } 199 if diff == 0 { hw("T5 PASS determinism: embedded-capsule session byte-identical\n" as *u8) } 200 else { hw("T5 FAIL diff=" as *u8); pn(diff); hw("\n" as *u8); fails = fails + 1 } 201 202 // ---- PNG: rest vs embedded (the bulge, visible) ---- 203 let TW: i64 = 256 204 let TH: i64 = 128 205 let fb: *i64 = sys_mmap(TW * TH * 8) as *i64 206 var pi: i64 = 0 207 while pi < TW * TH { fb[pi] = 22 + 26 * 256 + 34 * 65536; pi = pi + 1 } 208 let G: i64 = sys_mmap(sr_bytes()) as i64 209 sr_init(G, 0, 0, 0) 210 sr_param(G, 9, 0) 211 sr_ring(G, 16, 800) 212 t = 0 213 while t < 100 { sr_step(G); t = t + 1 } 214 plot(G, fb, TW, TH, 0) 215 sr_add_capsule(G, 1000, 0 - 400, 0, 1000, 400, 0, 350) 216 t = 0 217 while t < 400 { sr_step(G); t = t + 1 } 218 plot(G, fb, TW, TH, 128) 219 write_png(fb, TW, TH, "knowledge/nx_region_occlusion.png" as *u8) 220 221 if fails == 0 { hw("VERDICT GREEN: softbody region 5/5 -- TittyMagic-class params as DATA + THE OCCLUSION LAW measured (far-side bulge, volume conserved, elastic recovery) -- PNG knowledge/nx_region_occlusion.png\n" as *u8) } 222 else { hw("VERDICT RED fails=" as *u8); pn(fails); hw("\n" as *u8) } 223 return fails 224}