code wiki / _hdl_build / nx_tissue.nx

nx_tissue.nx source

↩ module page · 312 lines · 13734 B

1// nx_tissue.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_tissue <in.nxmesh> <out.nxmesh> [accel] [K] [C] [steps] 20// nx_tissue selftest 21// license_tier: ORIGINAL expect_exit: 0 No hw writes (Rule 26). 22import "nx_gate_verdict.nx" 23import "nx_softdyn.nx" 24 25const TS_M8388607: i64 = 8388607 26const TS_M8388608: i64 = 8388608 27const TS_HDR: i64 = 16 28const TS_LAYENT: i64 = 24 29const TS_TRI: i64 = 84 30const TS_LID: i64 = 4 31const TS_BANDS: i64 = 24 32const TS_MM: i64 = 1000 33const TS_MODE: i64 = 420 34const TS_MAXD: i64 = 40 35const TS_DEFK: i64 = 900 36const TS_DEFC: i64 = 260 37const TS_DEFA: i64 = 900 38const TS_STEPS: i64 = 40 39const TS_SCR: i64 = 4096 40 41func ts_puts(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 } 42func ts_pn(v: i64) -> i64 { 43 let b: *u8 = sys_mmap(32); var x: i64=v; var ng: i64=0 44 if x<0 { ng=1; x=0-x } 45 var i: i64=31 46 if x==0 { b[i]=48 as u8; i=i-1 } 47 while x>0 { b[i]=(48+x%10) as u8; x=x/10; i=i-1 } 48 if ng==1 { b[i]=45 as u8; i=i-1 } 49 sys_write(1,(b as i64 + i + 1) as *u8, 31-i); return 0 50} 51func ts_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 ts_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 ts_f32mul(b: *u8, o: i64, mul: i64) -> i64 { 59 let bits: i64 = ts_rd32(b, o) 60 let sign: i64 = (bits>>31) & 1 61 let exp: i64 = (bits>>23) & 255 62 let mant: i64 = bits & TS_M8388607 63 if exp == 0 { return 0 } 64 let m: i64 = (mant | TS_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 ts_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 ts_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 ts_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 ts_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 ts_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 < TS_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 = ts_rd32(mb, 8) 117 let nt: i64 = ts_rd32(mb, 12) 118 if nlay <= 0 { return 0-4 } 119 if nt <= 0 { return 0-5 } 120 let hdr: i64 = TS_HDR + nlay*TS_LAYENT 121 if hdr + nt*TS_TRI + nt*TS_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*TS_TRI 131 var k: i64 = 0 132 while k < 3 { 133 let y: i64 = ts_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(TS_BANDS) 148 var b: i64 = 0 149 while b < TS_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 var peak: i64 = 0 153 var s: i64 = 0 154 while s < steps { 155 var ay: i64 = 0 156 if s < steps/2 { ay = accel * s / (steps/2) } // driven phase: the bone rises 157 if s >= steps/2 { ay = accel } // then holds: the tissue must catch up and settle 158 var bb: i64 = 0 159 while bb < TS_BANDS { 160 sd_step(st, bb, 0, ay, 0, K, C, TS_MAXD) 161 let d: i64 = sd_abs(sd_disp_y(st, bb, ay)) 162 if d > peak { peak = d } 163 bb = bb + 1 164 } 165 s = s + 1 166 } 167 out[2] = peak 168 var esum: i64 = 0 169 var eb: i64 = 0 170 while eb < TS_BANDS { esum = esum + sd_energy(st, eb); eb = eb + 1 } 171 out[3] = esum 172 // ---- APPLY: displace every vertex by its band's point, SCALED BY ITS LAYER'S SOFTNESS. 173 let obytes: i64 = hdr + nt*TS_TRI + nt*TS_LID 174 let ob: *u8 = sys_mmap(obytes + 64) 175 var c: i64 = 0 176 while c < obytes { ob[c] = mb[c]; c = c + 1 } 177 var maxd: i64 = 0 178 var movsoft: i64 = 0 179 var movbone: i64 = 0 180 var t2: i64 = 0 181 while t2 < nt { 182 let o2: i64 = hdr + t2*TS_TRI 183 let lay: i64 = ts_rd32(mb, hdr + nt*TS_TRI + t2*TS_LID) 184 let soft: i64 = ts_soft(lay) 185 var k2: i64 = 0 186 while k2 < 3 { 187 let y2: i64 = ts_f32mul(mb, o2 + k2*12 + 4, 1) 188 var bnd: i64 = (y2 - ymn) * TS_BANDS / yspan 189 if bnd < 0 { bnd = 0 } 190 if bnd >= TS_BANDS { bnd = TS_BANDS - 1 } 191 let dy: i64 = sd_disp_y(st, bnd, accel) * soft / TS_MM 192 if dy != 0 { 193 if soft > 0 { movsoft = movsoft + 1 } else { movbone = movbone + 1 } 194 let ad: i64 = sd_abs(dy) 195 if ad > maxd { maxd = ad } 196 ts_wr32(ob, o2 + k2*12 + 4, ts_f32of(y2 + dy)) 197 } 198 k2 = k2 + 1 199 } 200 t2 = t2 + 1 201 } 202 out[4] = maxd 203 out[5] = movsoft 204 out[6] = movbone 205 let fd: i64 = sys_openat_wr(outp, TS_MODE) 206 if fd < 0 { return 0-8 } 207 sys_write(fd, ob, obytes) 208 sys_close(fd) 209 return 0 210} 211func ts_gate() -> i64 { 212 let ctr: *i64 = gv_ctr() 213 gv_head("nx_tissue selftest -- fascia as a LAYER-AWARE soft body, not a global wobble" as *u8) 214 // the lattice behaviour is testable without a mesh: seat points, drive them, watch them lag and settle. 215 let st: *i64 = sd_alloc(4) 216 var i: i64 = 0 217 while i < 4 { sd_seat(st, i, 0, 0, 0); i = i + 1 } 218 var peak: i64 = 0 219 var s: i64 = 0 220 while s < 20 { 221 let ay: i64 = TS_DEFA * s / 20 222 sd_step(st, 0, 0, ay, 0, TS_DEFK, TS_DEFC, TS_MAXD) 223 let d: i64 = sd_abs(sd_disp_y(st, 0, ay)) 224 if d > peak { peak = d } 225 s = s + 1 226 } 227 var t1: i64 = 0 228 if peak > 0 { t1 = 1 } 229 gv_check("T1 tissue LAGS behind the skeleton it hangs from" as *u8, t1, ctr) 230 var s2: i64 = 0 231 while s2 < 400 { sd_step(st, 0, 0, TS_DEFA, 0, TS_DEFK, TS_DEFC, TS_MAXD); s2 = s2 + 1 } 232 let rest: i64 = sd_energy(st, 0) 233 var t2: i64 = 0 234 if rest == 0 { t2 = 1 } 235 gv_check("T2 and SETTLES to rest once the motion stops" as *u8, t2, ctr) 236 var t3: i64 = 0 237 if sd_abs(sd_disp_y(st, 0, TS_DEFA)) <= TS_MAXD { t3 = 1 } 238 gv_check("T3 displacement BOUNDED -- tissue can never leave the body" as *u8, t3, ctr) 239 // ★THE LAYER TOOTH, and it is what makes this fascia rather than a wobble: bone is RIGID by 240 // construction. If ts_soft ever returned non-zero for bone, the skeleton would jiggle. 241 var t4: i64 = 0 242 if ts_soft(2) == 0 { if ts_soft(1) > 0 { if ts_soft(0) > ts_soft(1) { t4 = 1 } } } 243 gv_check("T4 LAYER-AWARE: bone rigid, muscle partial, skin fullest" as *u8, t4, ctr) 244 // ★ANTI-VACUITY: stiffness must CONTROL the response. A solver that always wobbles the same amount 245 // would pass every test above and be simulating nothing. 246 let st2: *i64 = sd_alloc(2) 247 sd_seat(st2, 0, 0, 0, 0) 248 var stiffpeak: i64 = 0 249 var s3: i64 = 0 250 while s3 < 20 { 251 let ay: i64 = TS_DEFA * s3 / 20 252 sd_step(st2, 0, 0, ay, 0, SD_CAPK, TS_DEFC, TS_MAXD) 253 let d: i64 = sd_abs(sd_disp_y(st2, 0, ay)) 254 if d > stiffpeak { stiffpeak = d } 255 s3 = s3 + 1 256 } 257 var t5: i64 = 0 258 if stiffpeak < peak { t5 = 1 } 259 gv_check("T5 anti-vacuity: STIFF tissue lags LESS than soft tissue" as *u8, t5, ctr) 260 // ★DETERMINISM: the same drive must produce the same tissue state, or nothing here is reproducible. 261 let st3: *i64 = sd_alloc(2) 262 sd_seat(st3, 0, 0, 0, 0) 263 var peak3: i64 = 0 264 var s4: i64 = 0 265 while s4 < 20 { 266 let ay: i64 = TS_DEFA * s4 / 20 267 sd_step(st3, 0, 0, ay, 0, TS_DEFK, TS_DEFC, TS_MAXD) 268 let d: i64 = sd_abs(sd_disp_y(st3, 0, ay)) 269 if d > peak3 { peak3 = d } 270 s4 = s4 + 1 271 } 272 var t6: i64 = 0 273 if peak3 == peak { t6 = 1 } 274 gv_check("T6 deterministic: identical drive, identical tissue" as *u8, t6, ctr) 275 let o: *i64 = sys_mmap(TS_SCR) as *i64 276 var t7: i64 = 0 277 if ts_run("/tmp/nx_ts_absent_zz.nxmesh" as *u8, "/tmp/nx_ts_o.nxmesh" as *u8, TS_DEFA, TS_DEFK, TS_DEFC, TS_STEPS, o) < 0 { t7 = 1 } 278 gv_check("T7 missing input refused, not silently empty" as *u8, t7, ctr) 279 return gv_verdict("TISSUE-GATE" as *u8, ctr, "layer-aware fascia; bone rigid by construction" as *u8) 280} 281func main(argc: i64, argv: *i64) -> i64 { 282 if argc >= 2 { 283 if ts_streq(argv[1] as *u8, "selftest" as *u8) == 1 { return ts_gate() } 284 } 285 if argc < 3 { 286 ts_puts("usage: nx_tissue <in.nxmesh> <out.nxmesh> [accel] [K] [C] [steps] | selftest\n" as *u8) 287 return 2 288 } 289 var accel: i64 = TS_DEFA 290 var K: i64 = TS_DEFK 291 var C: i64 = TS_DEFC 292 var steps: i64 = TS_STEPS 293 if argc > 3 { accel = ts_atoi(argv[3] as *u8) } 294 if argc > 4 { K = ts_atoi(argv[4] as *u8) } 295 if argc > 5 { C = ts_atoi(argv[5] as *u8) } 296 if argc > 6 { steps = ts_atoi(argv[6] as *u8) } 297 let o: *i64 = sys_mmap(TS_SCR) as *i64 298 let rc: i64 = ts_run(argv[1] as *u8, argv[2] as *u8, accel, K, C, steps, o) 299 ts_puts("{\x22organ\x22:\x22nx_tissue\x22,\x22v\x22:1,\x22stage\x22:\x22pipeline stage 3 -- fascia and fat as soft body, bridging muscle to skin\x22" as *u8) 300 ts_puts(",\x22rc\x22:" as *u8); ts_pn(rc) 301 ts_puts(",\x22tris\x22:" as *u8); ts_pn(o[0]) 302 ts_puts(",\x22layers\x22:" as *u8); ts_pn(o[1]) 303 ts_puts(",\x22peak_lag\x22:" as *u8); ts_pn(o[2]) 304 ts_puts(",\x22rest_energy\x22:" as *u8); ts_pn(o[3]) 305 ts_puts(",\x22max_disp\x22:" as *u8); ts_pn(o[4]) 306 ts_puts(",\x22verts_moved_soft\x22:" as *u8); ts_pn(o[5]) 307 ts_puts(",\x22verts_moved_bone\x22:" as *u8); ts_pn(o[6]) 308 ts_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) 309 ts_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) 310 if rc < 0 { return 1 } 311 return 0 312}