code wiki / (root) / nx_nxa_dyna.nx

nx_nxa_dyna.nx source

↩ module page · 473 lines · 24228 B

1// nx_nxa_dyna.nx -- WRITE THE DYNA SECTION: per-bone soft-tissue physics DECLARED IN THE ASSET, 2// with the lateral breast-bone pair DERIVED FROM THE MESH'S OWN GEOMETRY. 3// 4// WHY THIS EXISTS. nx_asset_floor_gate measured our shipped character and found 5 midline chest 5// joints and ZERO lateral pair. Real breast bones come in L/R pairs OFF the midline; midline joints 6// at chest height ARE THE SPINE CHAIN, so driving them swings the whole torso -- the wobble the 7// operator kept reporting. With no bone to drive, chest motion had to be faked at the shader vertex 8// band, and the engine's own joint picker (|bind.x| < 9000, i.e. near-midline) was selecting spine 9// joints as stand-ins using a superseded height normalisation (z/171530, which ignores the mesh 10// origin -- the same error that once put the nipples below the legs). 11// 12// THE FIX IS A FORMAT CAPABILITY, NOT ANOTHER SHADER PATCH. FBX and its class carry no physics at 13// all: a rig travels as geometry plus a joint tree, and every consumer re-invents the dynamics in 14// engine code. DYNA makes the ASSET carry its own soft-tissue contract -- anchor, axis, stiffness, 15// damping, travel clamp, influence radius, falloff -- so the engine DRIVES DECLARED DATA instead of 16// hardcoding bands. That is the difference between a mannequin and a body. 17// 18// ANCHORS ARE MEASURED, NEVER GUESSED. For each side we take the CENTROID of the front-hemisphere 19// vertices inside the bust band. Anatomy therefore comes from the mesh in front of us, so a 20// different body type yields different anchors -- and the firm/bouncy RANGE the operator asked for 21// falls out of geometry rather than a table of magic numbers. 22// 23// Physics constants are NOT invented here: they are the banked, in-band values already proven by 24// the chest-motion oracle (2.5 Hz, 3.2 cm travel, 0.0 cm torso, 0.89 coherence) and by nx_softbind 25// (chest K base 60 step 25, C base 100 step 16). Moving them out of code and into the asset is the 26// point -- rule 11, and the recombinator wants them as data. 27// 28// nx_nxa_dyna <in.nxa> <out.nxa> 29// 30// ADDITIVE AND IDEMPOTENT: the input is never modified; an existing DYNA is REPLACED, not doubled, 31// so running twice is identical to running once. 32// 33// DYNA payload (i64 words): [0]=n_bones [1]=stride(12), then per bone: 34// 0 side(-1 L,+1 R,0 mid) 1 anchor_x 2 anchor_y 3 anchor_z 35// 4 k_q8 5 c_q8 6 max_disp 7 influence_radius 8 falloff_q8 36// 9 axis_mask(1=x,2=y,4=z) 10 k_step_q8 11 c_step_q8 37// license_tier: ORIGINAL No hw writes (Rule 26). expect_exit: 0 38import "nx_syscalls.nx" 39import "nx_nxa.nx" 40const ND_MAGIC_1710: i64 = 1710 41const ND_MAGIC_4096: i64 = 4096 42 43const ND_HDR: i64 = 32 44const ND_TOCE: i64 = 32 45const ND_STRIDE: i64 = 12 46const ND_MAXSEC: i64 = 64 47const ND_MODE: i64 = 0x1a4 48const ND_ERRFD: i64 = 2 49const ND_EXIT_USAGE: i64 = 2 50const ND_EXIT_BAD: i64 = 3 51const ND_EXIT_IO: i64 = 1 52const ND_EXIT_NOPAIR: i64 = 4 53// bust band: NIP at 744 permil of stature, derived 2026-08-02 from anthropometric ratios mapped 54// through the asset's own pelvis(580)/head(917) anchors. Half-width 40 permil brackets the band 55// the shader already used (0.085 smoothstep width). 56// Admissible left/right vertex-count imbalance for a bust band, in permil. See the balance check 57// in main() for the derivation and the observed separation it is set from. 58const ND_BAL_MAX_PERMIL: i64 = 250 59const ND_NIP_PERMIL: i64 = 744 60const ND_BAND_PERMIL: i64 = 40 61// R7 REGIONS (2026-08-26): belly/glute/thigh bands from the same permil arithmetic as the 62// bust band -- pelvis anchor 580, so the belly soft mass sits just above it, the glutes just 63// below it on the POSTERIOR side, the thigh pair below that. Constants K/C are the SAME 64// pinned tissue bands (gamefeel_oracle tissue_fn 4000-5200 mHz, zeta 350-600 permil are 65// tissue-class rows, not breast-specific per Haake-Scurr's forced-damped model); regions 66// differ by MEASURED GEOMETRY (anchor, influence), never by tasted constants. 67const ND_BELLY_PERMIL: i64 = 520 68const ND_GLUTE_PERMIL: i64 = 555 69const ND_THIGH_PERMIL: i64 = 420 70const ND_RBAND_PERMIL: i64 = 45 71// banked oracle values -- see nx_softbind + gamefeel_oracle.conf. NOT tuned here. 72const ND_K_BASE: i64 = 60 73const ND_K_STEP: i64 = 25 74const ND_C_BASE: i64 = 100 75const ND_C_STEP: i64 = 16 76const ND_FALLOFF_Q8: i64 = 256 77const ND_AXIS_ALL: i64 = 7 78 79func nd_slen(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n } 80func nd_werr(s: *u8) -> i64 { sys_write(ND_ERRFD, s, nd_slen(s)); return 0 } 81func nd_out(s: *u8) -> i64 { sys_write(1, s, nd_slen(s)); return 0 } 82func nd_num(v: i64) -> i64 { 83 if v == 0 { sys_write(1, "0" as *u8, 1); return 0 } 84 var m: i64 = v 85 if m < 0 { sys_write(1, "-" as *u8, 1); m = 0 - m } 86 let t: *u8 = sys_mmap(32) 87 var k: i64 = 0 88 while m > 0 { t[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 } 89 let o: *u8 = sys_mmap(32) 90 var i: i64 = 0 91 while i < k { o[i] = t[k - 1 - i]; i = i + 1 } 92 sys_write(1, o, k) 93 return 0 94} 95func nd_rd64(b: *u8, off: i64) -> i64 { 96 var v: i64 = 0 97 var i: i64 = 7 98 while i >= 0 { v = v*256 + ((b[off + i] & 0xff) as i64); i = i - 1 } 99 return v 100} 101func nd_wr64(b: *u8, off: i64, v: i64) -> i64 { 102 var m: i64 = v 103 var i: i64 = 0 104 while i < 8 { b[off + i] = (m & 0xff) as u8; m = m >> 8; i = i + 1 } 105 return 0 106} 107func nd_tageq(b: *u8, off: i64, t: *u8) -> i64 { 108 var i: i64 = 0 109 while i < 4 { if b[off + i] != t[i] { return 0 } i = i + 1 } 110 return 1 111} 112 113// R7 helpers: centroid of band vertices, split L/R (pair) or single (midline, one hemisphere). 114// out layout pair: [lx,ly,lz,ln, rx,ry,rz,rn, llat,rlat]; mid: [x,y,z,n]. Report-only on empty. 115func nd_band_pair(b: *u8, vo: i64, nv: i64, la: i64, aa: i64, sa: i64, zmin: i64, span: i64, plo: i64, phi: i64, asign: i64, out: *i64) -> i64 { 116 var k: i64 = 0 117 while k < 10 { out[k] = 0; k = k + 1 } 118 var j: i64 = 0 119 while j < nv { 120 let ox: i64 = nd_rd64(b, vo + 8 + (j*3)*8) 121 let oy: i64 = nd_rd64(b, vo + 8 + (j*3 + 1)*8) 122 let oz: i64 = nd_rd64(b, vo + 8 + (j*3 + 2)*8) 123 let plat: i64 = nd_rd64(b, vo + 8 + (j*3 + la)*8) 124 let pant: i64 = nd_rd64(b, vo + 8 + (j*3 + aa)*8) 125 let pst: i64 = nd_rd64(b, vo + 8 + (j*3 + sa)*8) 126 let pm: i64 = (pst - zmin)*1000/span 127 if pm >= plo { if pm <= phi { if pant*asign < 0 { 128 if plat < 0 { out[0] = out[0] + ox; out[1] = out[1] + oy; out[2] = out[2] + oz; out[8] = out[8] + plat; out[3] = out[3] + 1 } 129 if plat > 0 { out[4] = out[4] + ox; out[5] = out[5] + oy; out[6] = out[6] + oz; out[9] = out[9] + plat; out[7] = out[7] + 1 } 130 } } } 131 j = j + 1 132 } 133 if out[3] > 0 { if out[7] > 0 { return 1 } } 134 return 0 135} 136func nd_band_mid(b: *u8, vo: i64, nv: i64, aa: i64, sa: i64, zmin: i64, span: i64, plo: i64, phi: i64, asign: i64, out: *i64) -> i64 { 137 out[0] = 0; out[1] = 0; out[2] = 0; out[3] = 0 138 var j: i64 = 0 139 while j < nv { 140 let ox: i64 = nd_rd64(b, vo + 8 + (j*3)*8) 141 let oy: i64 = nd_rd64(b, vo + 8 + (j*3 + 1)*8) 142 let oz: i64 = nd_rd64(b, vo + 8 + (j*3 + 2)*8) 143 let pant: i64 = nd_rd64(b, vo + 8 + (j*3 + aa)*8) 144 let pst: i64 = nd_rd64(b, vo + 8 + (j*3 + sa)*8) 145 let pm: i64 = (pst - zmin)*1000/span 146 if pm >= plo { if pm <= phi { if pant*asign < 0 { 147 out[0] = out[0] + ox; out[1] = out[1] + oy; out[2] = out[2] + oz; out[3] = out[3] + 1 148 } } } 149 j = j + 1 150 } 151 if out[3] > 0 { return 1 } 152 return 0 153} 154// emit one DYNA row at wo; returns the new wo. side/anchor/k/c/max/infl/falloff/axis/ksts/csts. 155func nd_row(nb: *u8, wo0: i64, side: i64, ax: i64, ay: i64, az: i64, k: i64, c: i64, maxd: i64, infl: i64) -> i64 { 156 var wo: i64 = wo0 157 nd_wr64(nb, wo, side); wo = wo + 8 158 nd_wr64(nb, wo, ax); wo = wo + 8 159 nd_wr64(nb, wo, ay); wo = wo + 8 160 nd_wr64(nb, wo, az); wo = wo + 8 161 nd_wr64(nb, wo, k); wo = wo + 8 162 nd_wr64(nb, wo, c); wo = wo + 8 163 nd_wr64(nb, wo, maxd); wo = wo + 8 164 nd_wr64(nb, wo, infl); wo = wo + 8 165 nd_wr64(nb, wo, ND_FALLOFF_Q8); wo = wo + 8 166 nd_wr64(nb, wo, ND_AXIS_ALL); wo = wo + 8 167 nd_wr64(nb, wo, ND_K_STEP); wo = wo + 8 168 nd_wr64(nb, wo, ND_C_STEP); wo = wo + 8 169 return wo 170} 171 172func main(argc: i64, argv: *i64) -> i64 { 173 if argc < 3 { 174 nd_werr("usage: nx_nxa_dyna <in.nxa> <out.nxa>\n" as *u8) 175 nd_werr(" derives the lateral soft-tissue bone pair from the mesh and writes a DYNA section.\n" as *u8) 176 nd_werr(" <in.nxa> is never modified; an existing DYNA is replaced, so re-runs are identical.\n" as *u8) 177 sys_exit(ND_EXIT_USAGE) 178 return ND_EXIT_USAGE 179 } 180 let inp: *u8 = argv[1] as *u8 181 let outp: *u8 = argv[2] as *u8 182 let lp: *i64 = sys_mmap(16) as *i64 183 let b: *u8 = sys_read_file(inp, lp) 184 if (b as i64) == 0 { nd_werr("DYNA-RED cannot read input NXA\n" as *u8); sys_exit(ND_EXIT_IO); return ND_EXIT_IO } 185 let flen: i64 = lp[0] 186 if flen < ND_HDR { nd_werr("DYNA-RED file too short to be an NXA\n" as *u8); sys_exit(ND_EXIT_BAD); return ND_EXIT_BAD } 187 if nd_rd64(b, 0) != nxa_magic() { nd_werr("DYNA-RED not an NXA (bad magic)\n" as *u8); sys_exit(ND_EXIT_BAD); return ND_EXIT_BAD } 188 if nd_rd64(b, 8) > NXA_VER { nd_werr("DYNA-RED future version -- refusing\n" as *u8); sys_exit(ND_EXIT_BAD); return ND_EXIT_BAD } 189 let ns: i64 = nd_rd64(b, 16) 190 if ns < 1 { nd_werr("DYNA-RED section count invalid\n" as *u8); sys_exit(ND_EXIT_BAD); return ND_EXIT_BAD } 191 if ns >= ND_MAXSEC { nd_werr("DYNA-RED section table full\n" as *u8); sys_exit(ND_EXIT_BAD); return ND_EXIT_BAD } 192 193 // ---- locate VERT and any existing DYNA ---- 194 var vo: i64 = 0 - 1 195 var dyi: i64 = 0 - 1 196 var s: i64 = 0 197 while s < ns { 198 let e: i64 = ND_HDR + s*ND_TOCE 199 if nd_tageq(b, e, "VERT" as *u8) == 1 { vo = nd_rd64(b, e + 8) } 200 if nd_tageq(b, e, "DYNA" as *u8) == 1 { dyi = s } 201 s = s + 1 202 } 203 if vo < 0 { nd_werr("DYNA-RED no VERT section -- cannot derive anatomy\n" as *u8); sys_exit(ND_EXIT_BAD); return ND_EXIT_BAD } 204 let nv: i64 = nd_rd64(b, vo) 205 206 // ---- pass 1: the BODY AXES ARE DERIVED FROM THE MESH'S OWN EXTENTS, never assumed ---- 207 // Stature is the largest extent. Of the remaining two the LATERAL axis is the larger (a 208 // humanoid is wider across the shoulders than it is deep front-to-back) and the ANTERIOR axis 209 // is the smaller. Both assumptions are DECLARED here rather than buried. 210 // WHY THIS REPLACED A HARDCODED CONVENTION: this reader assumed z-is-stature and y-is-front. 211 // Our own NXA assets are Z-up, but FBX and VRM donors are authored Y-UP -- so the band test 212 // selected nothing on every donor and the organ refused all four with "no left-side front 213 // vertices in the bust band". The refusal was correct; the axis assumption was not. Measured 214 // 2026-08-23; the sibling renderer lane derived the same axis from vertex extents the same day. 215 // Stature from the VERTEX span (the same basis the browser probe uses; a first version of the 216 // floor gate normalised on the JOINT span and the two instruments then CONTRADICTED each other 217 // on the same asset, because the joint ladder is shorter than the mesh -- feet and crown carry 218 // no bones). 219 var mnc0: i64 = 0 220 var mxc0: i64 = 0 221 var mnc1: i64 = 0 222 var mxc1: i64 = 0 223 var mnc2: i64 = 0 224 var mxc2: i64 = 0 225 var first: i64 = 1 226 var i: i64 = 0 227 while i < nv { 228 let c0: i64 = nd_rd64(b, vo + 8 + (i*3)*8) 229 let c1: i64 = nd_rd64(b, vo + 8 + (i*3 + 1)*8) 230 let c2: i64 = nd_rd64(b, vo + 8 + (i*3 + 2)*8) 231 if first == 1 { mnc0 = c0; mxc0 = c0; mnc1 = c1; mxc1 = c1; mnc2 = c2; mxc2 = c2; first = 0 } 232 if c0 < mnc0 { mnc0 = c0 } 233 if c0 > mxc0 { mxc0 = c0 } 234 if c1 < mnc1 { mnc1 = c1 } 235 if c1 > mxc1 { mxc1 = c1 } 236 if c2 < mnc2 { mnc2 = c2 } 237 if c2 > mxc2 { mxc2 = c2 } 238 i = i + 1 239 } 240 let ex0: i64 = mxc0 - mnc0 241 let ex1: i64 = mxc1 - mnc1 242 let ex2: i64 = mxc2 - mnc2 243 var sa: i64 = 2 244 if ex0 >= ex1 { if ex0 >= ex2 { sa = 0 } } 245 if ex1 > ex0 { if ex1 >= ex2 { sa = 1 } } 246 var la: i64 = 0 247 var aa: i64 = 1 248 if sa == 0 { la = 1; aa = 2; if ex2 > ex1 { la = 2; aa = 1 } } 249 if sa == 1 { la = 0; aa = 2; if ex2 > ex0 { la = 2; aa = 0 } } 250 if sa == 2 { la = 0; aa = 1; if ex1 > ex0 { la = 1; aa = 0 } } 251 var zmin: i64 = mnc2 252 if sa == 0 { zmin = mnc0 } 253 if sa == 1 { zmin = mnc1 } 254 var span: i64 = ex2 255 if sa == 0 { span = ex0 } 256 if sa == 1 { span = ex1 } 257 nd_out(" axes DERIVED: stature=" as *u8); nd_num(sa) 258 nd_out(" lateral=" as *u8); nd_num(la) 259 nd_out(" anterior=" as *u8); nd_num(aa) 260 nd_out(" (0=x 1=y 2=z) 261" as *u8) 262 if span <= 0 { nd_werr("DYNA-RED degenerate vertex span\n" as *u8); sys_exit(ND_EXIT_BAD); return ND_EXIT_BAD } 263 264 // ---- pass 2: per-side centroid of FRONT-HEMISPHERE vertices inside the bust band ---- 265 // front hemisphere is y<0 in this asset's frame (the floor gate and the shader agree on this). 266 var lx: i64 = 0 267 var ly: i64 = 0 268 var lz: i64 = 0 269 var ln: i64 = 0 270 var rx: i64 = 0 271 var ry: i64 = 0 272 var rz: i64 = 0 273 var rn: i64 = 0 274 let plo: i64 = ND_NIP_PERMIL - ND_BAND_PERMIL 275 let phi: i64 = ND_NIP_PERMIL + ND_BAND_PERMIL 276 // The ANTERIOR SIGN is derived by TRIAL, not assumed: we accumulate with front = negative 277 // anterior first (the convention this organ shipped with, so a Z-up asset is unchanged and the 278 // neutrality of this rewrite is provable), and only if that yields no pair do we try the 279 // opposite sign. Refusal is preserved for the case where neither sign produces both lobes -- 280 // a fabricated anchor is still worse than none. 281 var llat: i64 = 0 282 var rlat: i64 = 0 283 var asign: i64 = 1 284 var trial: i64 = 0 285 while trial < 2 { 286 if ln == 0 { 287 if rn == 0 { 288 if trial == 1 { asign = 0 - 1 } 289 lx = 0; ly = 0; lz = 0; llat = 0 290 rx = 0; ry = 0; rz = 0; rlat = 0 291 var j: i64 = 0 292 while j < nv { 293 let ox: i64 = nd_rd64(b, vo + 8 + (j*3)*8) 294 let oy: i64 = nd_rd64(b, vo + 8 + (j*3 + 1)*8) 295 let oz: i64 = nd_rd64(b, vo + 8 + (j*3 + 2)*8) 296 let plat: i64 = nd_rd64(b, vo + 8 + (j*3 + la)*8) 297 let pant: i64 = nd_rd64(b, vo + 8 + (j*3 + aa)*8) 298 let pst: i64 = nd_rd64(b, vo + 8 + (j*3 + sa)*8) 299 let pm: i64 = (pst - zmin)*1000/span 300 if pm >= plo { if pm <= phi { if pant*asign < 0 { 301 if plat < 0 { lx = lx + ox; ly = ly + oy; lz = lz + oz; llat = llat + plat; ln = ln + 1 } 302 if plat > 0 { rx = rx + ox; ry = ry + oy; rz = rz + oz; rlat = rlat + plat; rn = rn + 1 } 303 } } } 304 j = j + 1 305 } 306 } 307 } 308 trial = trial + 1 309 } 310 nd_out(" anterior sign chosen by trial: " as *u8); nd_num(asign) 311 nd_out(" (left=" as *u8); nd_num(ln); nd_out(" right=" as *u8); nd_num(rn); nd_out(") 312" as *u8) 313 // REFUSE rather than emit a fabricated pair. A DYNA section naming anchors we could not measure 314 // would be worse than none: the engine would drive declared-looking data that is actually a 315 // guess, and every downstream reader would treat it as measured. 316 if ln == 0 { nd_werr("DYNA-RED no left-side front vertices in the bust band -- refusing to fabricate an anchor\n" as *u8); sys_exit(ND_EXIT_NOPAIR); return ND_EXIT_NOPAIR } 317 if rn == 0 { nd_werr("DYNA-RED no right-side front vertices in the bust band -- refusing to fabricate an anchor\n" as *u8); sys_exit(ND_EXIT_NOPAIR); return ND_EXIT_NOPAIR } 318 // ---- L/R BALANCE: is what we found actually TISSUE? ------------------------------------- 319 // The anchor search proves a pair EXISTS; it never proved the pair is a BUST. On a costumed 320 // donor the bust band happily selects a hat brim, a collar or a dress panel, and the organ 321 // then emits a confident, measured-looking anchor for a GARMENT. Measured 2026-08-23 on the 322 // real corpus: paladin 499/497 bound verts (0.4 percent imbalance) against dark_witch 8/44 323 // (450 percent) and toon3d8 16197/8299 (95 percent), with derived influence radii swinging 324 // 744 to 34290 -- the imbalance is exactly the signal that separates tissue from costume. 325 // A human bust is bilaterally symmetric to a few percent. ND_BAL_MAX_PERMIL is set an ORDER 326 // OF MAGNITUDE looser than that physiological asymmetry, so this refuses only GROSS 327 // contamination and never a real body: at 250 permil it admits paladin (4 permil) and refuses 328 // both donors above. It is a separation bound, and the observed separation is published here 329 // rather than left implicit. 330 var bal_hi: i64 = ln 331 var bal_lo: i64 = rn 332 if rn > ln { bal_hi = rn; bal_lo = ln } 333 let imb_permil: i64 = (bal_hi - bal_lo)*1000/bal_hi 334 nd_out(" L/R balance: left=" as *u8); nd_num(ln); nd_out(" right=" as *u8); nd_num(rn) 335 nd_out(" imbalance_permil=" as *u8); nd_num(imb_permil) 336 nd_out(" bound=" as *u8); nd_num(ND_BAL_MAX_PERMIL); nd_out("\n" as *u8) 337 if imb_permil > ND_BAL_MAX_PERMIL { 338 nd_werr("DYNA-RED bust band is NOT bilaterally symmetric -- the anchor found costume, not tissue. Refusing to bind soft-tissue physics to a garment; strip or exclude non-body geometry, or declare the region by hand.\n" as *u8) 339 sys_exit(ND_EXIT_NOPAIR) 340 return ND_EXIT_NOPAIR 341 } 342 let lax: i64 = lx/ln 343 let lay: i64 = ly/ln 344 let laz: i64 = lz/ln 345 let rax: i64 = rx/rn 346 let ray: i64 = ry/rn 347 let raz: i64 = rz/rn 348 // influence radius = half the gap between the two anchors, so the L and R fields meet at the 349 // midline and neither reaches across it. Derived from the body, not chosen. 350 // gap measured along the DERIVED lateral axis, not along x -- on a Y-up donor those differ. 351 var gap: i64 = rlat/rn - llat/ln 352 if gap < 0 { gap = 0 - gap } 353 let infl: i64 = gap/2 354 // travel clamp from the oracle: 3.2 cm measured, and the asset's stature is `span` units for a 355 // ~1.71 m figure, so the clamp scales with the body instead of being a fixed constant. 356 let maxd: i64 = span*32/ND_MAGIC_1710 357 // ---- R7 regions: belly (anterior mid), glutes (posterior mid), thigh pair ---- 358 let rb: *i64 = sys_mmap(16*8) as *i64 359 let rlo1: i64 = ND_BELLY_PERMIL - ND_RBAND_PERMIL 360 let rhi1: i64 = ND_BELLY_PERMIL + ND_RBAND_PERMIL 361 let have_belly: i64 = nd_band_mid(b, vo, nv, aa, sa, zmin, span, rlo1, rhi1, asign, rb) 362 let rg: *i64 = sys_mmap(16*8) as *i64 363 let rlo2: i64 = ND_GLUTE_PERMIL - ND_RBAND_PERMIL 364 let rhi2: i64 = ND_GLUTE_PERMIL + ND_RBAND_PERMIL 365 let have_glute: i64 = nd_band_mid(b, vo, nv, aa, sa, zmin, span, rlo2, rhi2, 0 - asign, rg) 366 let rt: *i64 = sys_mmap(16*8) as *i64 367 let rlo3: i64 = ND_THIGH_PERMIL - ND_RBAND_PERMIL 368 let rhi3: i64 = ND_THIGH_PERMIL + ND_RBAND_PERMIL 369 let have_thigh: i64 = nd_band_pair(b, vo, nv, la, aa, sa, zmin, span, rlo3, rhi3, asign, rt) 370 var nbones: i64 = 2 371 if have_belly == 1 { nbones = nbones + 1 } 372 if have_glute == 1 { nbones = nbones + 1 } 373 if have_thigh == 1 { nbones = nbones + 2 } 374 nd_out(" R7 regions: belly=" as *u8); nd_num(have_belly) 375 nd_out(" glutes=" as *u8); nd_num(have_glute) 376 nd_out(" thighs=" as *u8); nd_num(have_thigh) 377 nd_out(" -> bones=" as *u8); nd_num(nbones); nd_out("\n" as *u8) 378 379 // ---- build the new file ---- 380 var nsec: i64 = ns 381 if dyi < 0 { nsec = ns + 1 } 382 let dwords: i64 = 2 + nbones*ND_STRIDE 383 let toclen: i64 = ND_HDR + nsec*ND_TOCE 384 var total: i64 = toclen 385 // measure: every kept payload, then ours 386 var s2: i64 = 0 387 while s2 < ns { 388 if s2 != dyi { 389 let e2: i64 = ND_HDR + s2*ND_TOCE 390 total = total + nd_rd64(b, e2 + 16)*8 391 } 392 s2 = s2 + 1 393 } 394 total = total + dwords*8 395 let nb: *u8 = sys_mmap(total + ND_MAGIC_4096) 396 if (nb as i64) == 0 { nd_werr("DYNA-RED cannot allocate output\n" as *u8); sys_exit(ND_EXIT_IO); return ND_EXIT_IO } 397 nd_wr64(nb, 0, nxa_magic()) 398 nd_wr64(nb, 8, NXA_VER) 399 nd_wr64(nb, 16, nsec) 400 // copy kept sections, laying payloads out contiguously after the (grown) TOC 401 var wo: i64 = toclen 402 var ti: i64 = 0 403 var s3: i64 = 0 404 while s3 < ns { 405 if s3 != dyi { 406 let e3: i64 = ND_HDR + s3*ND_TOCE 407 let oldoff: i64 = nd_rd64(b, e3 + 8) 408 let wl: i64 = nd_rd64(b, e3 + 16) 409 let te: i64 = ND_HDR + ti*ND_TOCE 410 nd_wr64(nb, te, nd_rd64(b, e3)) 411 nd_wr64(nb, te + 8, wo) 412 nd_wr64(nb, te + 16, wl) 413 var k2: i64 = 0 414 while k2 < wl*8 { nb[wo + k2] = b[oldoff + k2]; k2 = k2 + 1 } 415 // recompute rather than copy the old checksum: a copied checksum would still verify if 416 // the copy loop were wrong, so it would validate its own bug. 417 let pw: *i64 = ((nb as i64) + wo) as *i64 418 nd_wr64(nb, te + 24, nxa_check2(1, pw, wl)) 419 wo = wo + wl*8 420 ti = ti + 1 421 } 422 s3 = s3 + 1 423 } 424 // ---- the DYNA payload ---- 425 let dstart: i64 = wo 426 nd_wr64(nb, wo, nbones); wo = wo + 8 427 nd_wr64(nb, wo, ND_STRIDE); wo = wo + 8 428 wo = nd_row(nb, wo, 0 - 1, lax, lay, laz, ND_K_BASE, ND_C_BASE, maxd, infl) 429 wo = nd_row(nb, wo, 1, rax, ray, raz, ND_K_BASE, ND_C_BASE, maxd, infl) 430 // region rows: influence from each band's own vertical half-width (span*band/1000); 431 // travel clamp shared (the oracle's 3.2 cm body-scaled bound applies to the tissue class) 432 let rinfl: i64 = span*ND_RBAND_PERMIL/1000 433 if have_belly == 1 { wo = nd_row(nb, wo, 0, rb[0]/rb[3], rb[1]/rb[3], rb[2]/rb[3], ND_K_BASE, ND_C_BASE, maxd, rinfl) } 434 if have_glute == 1 { wo = nd_row(nb, wo, 0, rg[0]/rg[3], rg[1]/rg[3], rg[2]/rg[3], ND_K_BASE, ND_C_BASE, maxd, rinfl) } 435 if have_thigh == 1 { 436 wo = nd_row(nb, wo, 0 - 1, rt[0]/rt[3], rt[1]/rt[3], rt[2]/rt[3], ND_K_BASE, ND_C_BASE, maxd, rinfl) 437 wo = nd_row(nb, wo, 1, rt[4]/rt[7], rt[5]/rt[7], rt[6]/rt[7], ND_K_BASE, ND_C_BASE, maxd, rinfl) 438 } 439 let dte: i64 = ND_HDR + ti*ND_TOCE 440 nd_wr64(nb, dte, nxa_tag4("DYNA" as *u8)) 441 nd_wr64(nb, dte + 8, dstart) 442 nd_wr64(nb, dte + 16, dwords) 443 let dpw: *i64 = ((nb as i64) + dstart) as *i64 444 nd_wr64(nb, dte + 24, nxa_check2(1, dpw, dwords)) 445 // TOC checksum LAST -- it covers the table we just finished writing 446 let tbp: *i64 = ((nb as i64) + ND_HDR) as *i64 447 nd_wr64(nb, 24, nxa_check2(1, tbp, nsec*4)) 448 449 let fd: i64 = sys_openat_wr(outp, ND_MODE) 450 if fd < 0 { nd_werr("DYNA-RED cannot open output for write\n" as *u8); sys_exit(ND_EXIT_IO); return ND_EXIT_IO } 451 var w2: i64 = 0 452 while w2 < wo { 453 let kk: i64 = sys_write(fd, ((nb as i64) + w2) as *u8, wo - w2) 454 if kk <= 0 { sys_close(fd); nd_werr("DYNA-RED short write\n" as *u8); sys_exit(ND_EXIT_IO); return ND_EXIT_IO } 455 w2 = w2 + kk 456 } 457 sys_close(fd) 458 459 nd_out("DYNA-GREEN sections " as *u8); nd_num(ns); nd_out(" -> " as *u8); nd_num(nsec) 460 if dyi >= 0 { nd_out(" (replaced existing DYNA)" as *u8) } 461 nd_out("\n stature span=" as *u8); nd_num(span) 462 nd_out(" bust band permil " as *u8); nd_num(plo); nd_out(".." as *u8); nd_num(phi) 463 nd_out("\n LEFT anchor from " as *u8); nd_num(ln); nd_out(" verts: x=" as *u8); nd_num(lax) 464 nd_out(" y=" as *u8); nd_num(lay); nd_out(" z=" as *u8); nd_num(laz) 465 nd_out("\n RIGHT anchor from " as *u8); nd_num(rn); nd_out(" verts: x=" as *u8); nd_num(rax) 466 nd_out(" y=" as *u8); nd_num(ray); nd_out(" z=" as *u8); nd_num(raz) 467 nd_out("\n lateral gap=" as *u8); nd_num(gap); nd_out(" influence=" as *u8); nd_num(infl) 468 nd_out(" travel clamp=" as *u8); nd_num(maxd) 469 nd_out("\n bytes=" as *u8); nd_num(wo) 470 nd_out("\n <- the pair is LATERAL and MEASURED: soft tissue now has a bone that is not the spine.\n" as *u8) 471 sys_exit(0) 472 return 0 473}