code wiki / _hdl_build / nx_fascia.nx

nx_fascia.nx source

↩ module page · 359 lines · 18082 B

1// nx_fascia.nx -- PIPELINE STAGE 3: FASCIA + FAT AS SOFT BODY, bridging muscle to skin. 2// 3// The industry pipeline is skeleton -> muscle -> fascia/fat -> skin, and an audit of our own stack found we 4// had that pipeline's SHAPE and almost none of its PHYSICS: "fat" was a scalar knob attenuating how much 5// muscle relief reached the skin. Nothing lagged, nothing settled, nothing was driven by the layer beneath. 6// 7// It also found that the solver had been built and gated months earlier and NEVER WIRED IN: runtime/ 8// nx_softdyn.nx is a spring-damper soft body whose stability envelope is enforced BY CONSTRUCTION (past a 9// damping threshold semi-implicit Euler inverts and amplifies velocity, so SD_CAPC/SD_CAPK make an unstable 10// configuration impossible to REQUEST rather than merely discouraged). It shipped with no soft-tissue 11// geometry to bind to. The layer emitter now emits muscle and fat layers, so this organ is the wiring. 12// 13// THE BINDING, and it is what makes this stage 3 rather than just re-running a solver: a LAYER-AWARE 14// LATTICE. Solver points are seated on a coarse band lattice over the figure; every vertex is displaced by 15// its band's point SCALED BY THE SOFTNESS OF ITS OWN LAYER. Bone scales to ZERO and does not move at all; 16// muscle moves partly; skin and fat move fully. That is fascia doing its actual job -- transmitting motion 17// from the rigid thing inside to the soft thing outside, with each layer lagging by its own amount. 18// 19// nx_fascia <in.nxmesh> <out.nxmesh> [accel] [K] [C] [steps] 20// nx_fascia selftest 21// license_tier: ORIGINAL expect_exit: 0 No hw writes (Rule 26). 22import "nx_gate_verdict.nx" 23import "nx_itoa_lib.nx" // shared MSB-first emitter (zero-alloc) 24import "nx_softdyn.nx" 25 26const FS2_M8388607: i64 = 8388607 27const FS2_M8388608: i64 = 8388608 28const FS2_HDR: i64 = 16 29const FS2_LAYENT: i64 = 24 30const FS2_TRI: i64 = 84 31const FS2_LID: i64 = 4 32const FS2_BANDS: i64 = 24 33const FS2_MM: i64 = 1000 34const FS2_MODE: i64 = 420 35const FS2_MAXD: i64 = 40 36const FS2_DEFK: i64 = 900 37const FS2_DEFC: i64 = 260 38const FS2_DEFA: i64 = 900 39const FS2_STEPS: i64 = 40 40const FS2_SOFTK: i64 = 120 41// full solver excursion maps to this per-mille of the figure's own height (~2pct = real tissue travel) 42const FS2_EXC: i64 = 20 43const FS2_SCR: i64 = 4096 44 45func fs2_puts(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 } 46// MIGRATED to the shared emitter (debt 1785563586). The old body mmapped a scratch buffer 47// per call and never freed it. At PAGE granularity that is 4096B leaked PER CALL -- the 48// defect that took 28.5GB of a 36GB host in nx_ts_lumadiff (2MB input, ~3.66M calls). 49// nxi_* is MSB-first, allocates NOTHING, and emits identical bytes including the sign. 50func fs2_pn(v: i64) -> i64 { nxi_out(v); return 0 } 51func fs2_rd32(b: *u8, o: i64) -> i64 { 52 return (b[o] as i64) | ((b[o+1] as i64)<<8) | ((b[o+2] as i64)<<16) | ((b[o+3] as i64)<<24) 53} 54func fs2_wr32(b: *u8, o: i64, v: i64) -> i64 { 55 b[o]=(v & 255) as u8; b[o+1]=((v>>8) & 255) as u8; b[o+2]=((v>>16) & 255) as u8; b[o+3]=((v>>24) & 255) as u8 56 return 0 57} 58func fs2_f32mul(b: *u8, o: i64, mul: i64) -> i64 { 59 let bits: i64 = fs2_rd32(b, o) 60 let sign: i64 = (bits>>31) & 1 61 let exp: i64 = (bits>>23) & 255 62 let mant: i64 = bits & FS2_M8388607 63 if exp == 0 { return 0 } 64 let m: i64 = (mant | FS2_M8388608) * mul 65 var e: i64 = exp - 127 - 23 66 var v: i64 = 0 67 if e >= 0 { v = m << e } else { let sh: i64 = 0 - e; v = (m + (1 << (sh-1))) >> sh } 68 if sign == 1 { v = 0 - v } 69 return v 70} 71// encode a small signed integer back to f32 (mesh positions are whole model units here) 72func fs2_f32of(v: i64) -> i64 { 73 if v == 0 { return 0 } 74 var s: i64 = 0 75 var m: i64 = v 76 if m < 0 { s = 1; m = 0 - m } 77 var ex: i64 = 0 78 var tv: i64 = m 79 while tv >= 2 { tv = tv/2; ex = ex + 1 } 80 var frac: i64 = 0 81 if ex > 0 { frac = (m - (1 << ex)) * (1 << 23) / (1 << ex) } 82 return (s << 31) | ((127 + ex) << 23) | frac 83} 84func fs2_streq(a: *u8, b: *u8) -> i64 { 85 var i: i64=0; var go: i64=1; var eq: i64=1 86 while go==1 { if a[i]!=b[i] { eq=0; go=0 } else { if a[i]==(0 as u8) { go=0 } else { i=i+1 } } } 87 return eq 88} 89func fs2_atoi(s: *u8) -> i64 { 90 var i: i64=0; var n: i64=0; var sg: i64=1 91 if s[0]==(45 as u8) { sg=0-1; i=1 } 92 while s[i]!=(0 as u8) { let c: i64=s[i] as i64; if c>=48 { if c<=57 { n=n*10+(c-48) } } i=i+1 } 93 return n*sg 94} 95// ★LAYER SOFTNESS, per-mille. This is the whole point of a layer-aware binding: the SAME lattice motion 96// reaches each layer scaled by what that layer physically is. Our emitter writes 0=skin, 1=muscle, 2=bone. 97// Bone is RIGID -- it returns zero and therefore cannot move, which is the property that makes this fascia 98// rather than a global wobble. 99func fs2_soft(layer: i64) -> i64 { 100 if layer == 2 { return 0 } // bone: rigid by construction 101 if layer == 1 { return 520 } // muscle: bound to bone, moves partly 102 return 1000 // skin / fat: the outermost soft envelope, moves fully 103} 104// out[0]=tris out[1]=layers out[2]=peak_lag out[3]=rest_energy out[4]=max_disp out[5]=moved_soft 105// out[6]=moved_bone (MUST be 0) out[7]=ymin out[8]=yspan 106func fs2_run(inp: *u8, outp: *u8, accel: i64, K: i64, C: i64, steps: i64, out: *i64) -> i64 { 107 var z: i64 = 0 108 while z < 12 { out[z] = 0; z = z + 1 } 109 let szp: *i64 = sys_mmap(16) as *i64 110 let mb: *u8 = sys_read_file(inp, szp) 111 if (mb as i64) == 0 { return 0-1 } 112 let sz: i64 = szp[0] 113 if sz < FS2_HDR { return 0-2 } 114 if mb[0]!=(78 as u8) { return 0-3 } 115 if mb[1]!=(88 as u8) { return 0-3 } 116 let nlay: i64 = fs2_rd32(mb, 8) 117 let nt: i64 = fs2_rd32(mb, 12) 118 if nlay <= 0 { return 0-4 } 119 if nt <= 0 { return 0-5 } 120 let hdr: i64 = FS2_HDR + nlay*FS2_LAYENT 121 if hdr + nt*FS2_TRI + nt*FS2_LID > sz { return 0-6 } 122 out[0] = nt 123 out[1] = nlay 124 // pass 1: y extent, so the lattice bands span the figure 125 var ymn: i64 = 0 126 var ymx: i64 = 0 127 var first: i64 = 1 128 var t: i64 = 0 129 while t < nt { 130 let o: i64 = hdr + t*FS2_TRI 131 var k: i64 = 0 132 while k < 3 { 133 let y: i64 = fs2_f32mul(mb, o + k*12 + 4, 1) 134 if first == 1 { ymn=y; ymx=y; first=0 } else { 135 if y<ymn { ymn=y } 136 if y>ymx { ymx=y } 137 } 138 k = k + 1 139 } 140 t = t + 1 141 } 142 let yspan: i64 = ymx - ymn 143 if yspan <= 0 { return 0-7 } 144 out[7] = ymn 145 out[8] = yspan 146 // ---- THE LATTICE: one soft-body point per band, seated at rest, then driven. 147 let st: *i64 = sd_alloc(FS2_BANDS) 148 var b: i64 = 0 149 while b < FS2_BANDS { sd_seat(st, b, 0, 0, 0); b = b + 1 } 150 // ★DRIVE: the anchor accelerates upward then stops -- a footfall. Real tissue LAGS behind the skeleton 151 // on the way up and OVERSHOOTS when it stops; that lag and overshoot IS the effect being simulated. 152 // ★★THE SNAPSHOT, and the bug it fixes is sharper than the units one: the first cut stepped the whole 153 // simulation and THEN read each band's displacement to deform the mesh -- by which point the tissue had 154 // SETTLED BACK ONTO ITS ANCHOR and the lag was gone. Peak lag read 40 during the motion and the applied 155 // displacement read 4, because I was measuring the physics at the moment it had finished happening. 156 // ★A transient is only observable while it is transient: capture the state AT PEAK LAG and deform from 157 // that, which is also what a renderer wants -- the frame where the tissue is furthest behind the bone. 158 let snap: *i64 = sys_mmap(FS2_BANDS*8 + 64) as *i64 159 var zs: i64 = 0 160 while zs < FS2_BANDS { snap[zs] = 0; zs = zs + 1 } 161 var peak: i64 = 0 162 var s: i64 = 0 163 while s < steps { 164 var ay: i64 = 0 165 if s < steps/2 { ay = accel * s / (steps/2) } // driven phase: the bone rises 166 if s >= steps/2 { ay = accel } // then holds: the tissue must catch up and settle 167 var bb: i64 = 0 168 while bb < FS2_BANDS { 169 sd_step(st, bb, 0, ay, 0, K, C, FS2_MAXD) 170 let dd: i64 = sd_disp_y(st, bb, ay) 171 let d: i64 = sd_abs(dd) 172 if d > peak { peak = d } 173 // hold each band's own most-lagged state -- the frame worth rendering 174 if d > sd_abs(snap[bb]) { snap[bb] = dd } 175 bb = bb + 1 176 } 177 s = s + 1 178 } 179 out[2] = peak 180 var esum: i64 = 0 181 var eb: i64 = 0 182 while eb < FS2_BANDS { esum = esum + sd_energy(st, eb); eb = eb + 1 } 183 out[3] = esum 184 // ---- APPLY: displace every vertex by its band's point, SCALED BY ITS LAYER'S SOFTNESS. 185 let obytes: i64 = hdr + nt*FS2_TRI + nt*FS2_LID 186 let ob: *u8 = sys_mmap(obytes + 64) 187 var c: i64 = 0 188 while c < obytes { ob[c] = mb[c]; c = c + 1 } 189 var maxd: i64 = 0 190 var movsoft: i64 = 0 191 var movbone: i64 = 0 192 var t2: i64 = 0 193 while t2 < nt { 194 let o2: i64 = hdr + t2*FS2_TRI 195 let lay: i64 = fs2_rd32(mb, hdr + nt*FS2_TRI + t2*FS2_LID) 196 let soft: i64 = fs2_soft(lay) 197 var k2: i64 = 0 198 while k2 < 3 { 199 let y2: i64 = fs2_f32mul(mb, o2 + k2*12 + 4, 1) 200 var bnd: i64 = (y2 - ymn) * FS2_BANDS / yspan 201 if bnd < 0 { bnd = 0 } 202 if bnd >= FS2_BANDS { bnd = FS2_BANDS - 1 } 203 // ⚠⚠UNITS BUG CAUGHT BY RENDERING IT, NOT BY MEASURING IT. The first cut applied the solver's raw 204 // displacement straight to mesh coordinates. The solver works in its own space where a full 205 // excursion is FS2_MAXD (tens of units); the mesh is in model units where the figure is tens of 206 // THOUSANDS tall. So tissue moved ~5 units on a body ~200,000 units high -- real, measurable, 207 // bounded, deterministic, and utterly invisible: the render changed by 26 pixels out of 84,000. 208 // ★THIS IS THE BANKED UNITS-TRAP CLASS: an integer scale mismatch does not error, it produces a 209 // physically negligible result that passes every numeric test. The gate could not catch it 210 // because the gate tests the SOLVER, and the solver was right -- the BINDING was dimensionless. 211 // ★THE FIX: a displacement is a FRACTION OF THE FIGURE, not a raw count. Map the solver's full 212 // excursion onto FS2_EXC per-mille of the mesh's own height, so tissue moves ~2pct of body 213 // height at full lag on ANY figure at ANY scale -- which is roughly what real tissue does. 214 let draw: i64 = snap[bnd] 215 let dy: i64 = ((draw * yspan / FS2_MAXD) * FS2_EXC / FS2_MM) * soft / FS2_MM 216 if dy != 0 { 217 if soft > 0 { movsoft = movsoft + 1 } else { movbone = movbone + 1 } 218 let ad: i64 = sd_abs(dy) 219 if ad > maxd { maxd = ad } 220 fs2_wr32(ob, o2 + k2*12 + 4, fs2_f32of(y2 + dy)) 221 } 222 k2 = k2 + 1 223 } 224 t2 = t2 + 1 225 } 226 out[4] = maxd 227 out[5] = movsoft 228 out[6] = movbone 229 let fd: i64 = sys_openat_wr(outp, FS2_MODE) 230 if fd < 0 { return 0-8 } 231 sys_write(fd, ob, obytes) 232 sys_close(fd) 233 return 0 234} 235func fs2_gate() -> i64 { 236 let ctr: *i64 = gv_ctr() 237 gv_head("nx_fascia selftest -- fascia as a LAYER-AWARE soft body, not a global wobble" as *u8) 238 // the lattice behaviour is testable without a mesh: seat points, drive them, watch them lag and settle. 239 let st: *i64 = sd_alloc(4) 240 var i: i64 = 0 241 while i < 4 { sd_seat(st, i, 0, 0, 0); i = i + 1 } 242 var peak: i64 = 0 243 var s: i64 = 0 244 while s < 20 { 245 let ay: i64 = FS2_DEFA * s / 20 246 sd_step(st, 0, 0, ay, 0, FS2_DEFK, FS2_DEFC, FS2_MAXD) 247 let d: i64 = sd_abs(sd_disp_y(st, 0, ay)) 248 if d > peak { peak = d } 249 s = s + 1 250 } 251 var t1: i64 = 0 252 if peak > 0 { t1 = 1 } 253 gv_check("T1 tissue LAGS behind the skeleton it hangs from" as *u8, t1, ctr) 254 var s2: i64 = 0 255 while s2 < 400 { sd_step(st, 0, 0, FS2_DEFA, 0, FS2_DEFK, FS2_DEFC, FS2_MAXD); s2 = s2 + 1 } 256 let rest: i64 = sd_energy(st, 0) 257 var t2: i64 = 0 258 if rest == 0 { t2 = 1 } 259 gv_check("T2 and SETTLES to rest once the motion stops" as *u8, t2, ctr) 260 var t3: i64 = 0 261 if sd_abs(sd_disp_y(st, 0, FS2_DEFA)) <= FS2_MAXD { t3 = 1 } 262 gv_check("T3 displacement BOUNDED -- tissue can never leave the body" as *u8, t3, ctr) 263 // ★THE LAYER TOOTH, and it is what makes this fascia rather than a wobble: bone is RIGID by 264 // construction. If fs2_soft ever returned non-zero for bone, the skeleton would jiggle. 265 var t4: i64 = 0 266 if fs2_soft(2) == 0 { if fs2_soft(1) > 0 { if fs2_soft(0) > fs2_soft(1) { t4 = 1 } } } 267 gv_check("T4 LAYER-AWARE: bone rigid, muscle partial, skin fullest" as *u8, t4, ctr) 268 // ★ANTI-VACUITY: stiffness must CONTROL the response. A solver that always wobbles the same amount 269 // would pass every test above and be simulating nothing. 270 // ⚠THE FIRST CUT OF THIS TOOTH COMPARED PEAK DISPLACEMENT AND WENT RED, AND THE PHYSICS SAYS IT SHOULD 271 // HAVE. A stiff, lightly-damped spring RINGS: its instantaneous peak can EXCEED a soft one's even though 272 // it tracks the anchor far better on average. That is the same trap banked when this solver was built -- 273 // a stiff config read as MORE jiggle, not less. The physically correct statement is about STEADY-STATE 274 // lag: under a constant drive the settled offset is proportional to load over stiffness, so a stiffer 275 // tissue MUST settle closer to its anchor. Measure after settling, not during ringing. 276 // ⚠⚠SECOND RED ON THE SAME TOOTH, AND THE SOLVER'S ACTUAL CONTRACT IS WHY: it is a pure spring-damper to 277 // its ANCHOR with no external load, so under a CONSTANT anchor every configuration converges to the 278 // anchor exactly and STEADY-STATE LAG IS ZERO FOR BOTH. My assertion could never have been true. The 279 // property that genuinely distinguishes stiffness is TRACKING WHILE THE ANCHOR IS STILL MOVING: through 280 // a ramp, a stiffer tissue stays closer to the bone it hangs from. Sample the lag at the END of the 281 // driven ramp, while there is still something to lag behind. 282 // ★LAW: read the solver's contract before asserting a property of it -- twice now the test was wrong 283 // rather than the code, and both times the physics was in the source all along. 284 let st2: *i64 = sd_alloc(2) 285 sd_seat(st2, 0, 0, 0, 0) 286 var stifflag: i64 = 0 287 var sA: i64 = 0 288 while sA < 20 { 289 let ay: i64 = FS2_DEFA * sA / 20 290 sd_step(st2, 0, 0, ay, 0, SD_CAPK, FS2_DEFC, FS2_MAXD) 291 stifflag = sd_abs(sd_disp_y_q8(st2, 0, ay)) 292 sA = sA + 1 293 } 294 let st4: *i64 = sd_alloc(2) 295 sd_seat(st4, 0, 0, 0, 0) 296 var softlag: i64 = 0 297 var sB: i64 = 0 298 while sB < 20 { 299 let ay: i64 = FS2_DEFA * sB / 20 300 sd_step(st4, 0, 0, ay, 0, FS2_SOFTK, FS2_DEFC, FS2_MAXD) 301 softlag = sd_abs(sd_disp_y_q8(st4, 0, ay)) 302 sB = sB + 1 303 } 304 var t5: i64 = 0 305 if stifflag < softlag { t5 = 1 } 306 gv_check("T5 anti-vacuity: STIFF tissue TRACKS the bone closer than soft tissue mid-motion" as *u8, t5, ctr) 307 // ★DETERMINISM: the same drive must produce the same tissue state, or nothing here is reproducible. 308 let st3: *i64 = sd_alloc(2) 309 sd_seat(st3, 0, 0, 0, 0) 310 var peak3: i64 = 0 311 var s4: i64 = 0 312 while s4 < 20 { 313 let ay: i64 = FS2_DEFA * s4 / 20 314 sd_step(st3, 0, 0, ay, 0, FS2_DEFK, FS2_DEFC, FS2_MAXD) 315 let d: i64 = sd_abs(sd_disp_y(st3, 0, ay)) 316 if d > peak3 { peak3 = d } 317 s4 = s4 + 1 318 } 319 var t6: i64 = 0 320 if peak3 == peak { t6 = 1 } 321 gv_check("T6 deterministic: identical drive, identical tissue" as *u8, t6, ctr) 322 let o: *i64 = sys_mmap(FS2_SCR) as *i64 323 var t7: i64 = 0 324 if fs2_run("/tmp/nx_fs2_absent_zz.nxmesh" as *u8, "/tmp/nx_fs2_o.nxmesh" as *u8, FS2_DEFA, FS2_DEFK, FS2_DEFC, FS2_STEPS, o) < 0 { t7 = 1 } 325 gv_check("T7 missing input refused, not silently empty" as *u8, t7, ctr) 326 return gv_verdict("TISSUE-GATE" as *u8, ctr, "layer-aware fascia; bone rigid by construction" as *u8) 327} 328func main(argc: i64, argv: *i64) -> i64 { 329 if argc >= 2 { 330 if fs2_streq(argv[1] as *u8, "selftest" as *u8) == 1 { return fs2_gate() } 331 } 332 if argc < 3 { 333 fs2_puts("usage: nx_fascia <in.nxmesh> <out.nxmesh> [accel] [K] [C] [steps] | selftest\n" as *u8) 334 return 2 335 } 336 var accel: i64 = FS2_DEFA 337 var K: i64 = FS2_DEFK 338 var C: i64 = FS2_DEFC 339 var steps: i64 = FS2_STEPS 340 if argc > 3 { accel = fs2_atoi(argv[3] as *u8) } 341 if argc > 4 { K = fs2_atoi(argv[4] as *u8) } 342 if argc > 5 { C = fs2_atoi(argv[5] as *u8) } 343 if argc > 6 { steps = fs2_atoi(argv[6] as *u8) } 344 let o: *i64 = sys_mmap(FS2_SCR) as *i64 345 let rc: i64 = fs2_run(argv[1] as *u8, argv[2] as *u8, accel, K, C, steps, o) 346 fs2_puts("{\x22organ\x22:\x22nx_fascia\x22,\x22v\x22:1,\x22stage\x22:\x22pipeline stage 3 -- fascia and fat as soft body, bridging muscle to skin\x22" as *u8) 347 fs2_puts(",\x22rc\x22:" as *u8); fs2_pn(rc) 348 fs2_puts(",\x22tris\x22:" as *u8); fs2_pn(o[0]) 349 fs2_puts(",\x22layers\x22:" as *u8); fs2_pn(o[1]) 350 fs2_puts(",\x22peak_lag\x22:" as *u8); fs2_pn(o[2]) 351 fs2_puts(",\x22rest_energy\x22:" as *u8); fs2_pn(o[3]) 352 fs2_puts(",\x22max_disp\x22:" as *u8); fs2_pn(o[4]) 353 fs2_puts(",\x22verts_moved_soft\x22:" as *u8); fs2_pn(o[5]) 354 fs2_puts(",\x22verts_moved_bone\x22:" as *u8); fs2_pn(o[6]) 355 fs2_puts(",\x22binding\x22:\x22layer-aware lattice: solver points on a band lattice, each vertex displaced by its band SCALED BY ITS LAYER SOFTNESS -- bone 0 (rigid by construction), muscle 520, skin/fat 1000. verts_moved_bone MUST read 0.\x22" as *u8) 356 fs2_puts(",\x22solver\x22:\x22nx_softdyn spring-damper, stability envelope enforced by construction (an unstable config cannot be requested), displacement hard-clamped so tissue can never leave the body\x22}\n" as *u8) 357 if rc < 0 { return 1 } 358 return 0 359}