code wiki / (root) / nx_bodyatlas.nx

nx_bodyatlas.nx source

↩ module page · 729 lines · 39081 B

1// nx_bodyatlas.nx -- ★HOLISTIC ANATOMICAL BEING (operator 2026-07-10, ref zygotebody.com + sloyd.ai/3d-human-model-generator): 2// "we are doing humans... generate holistic beings with parts". A whole-body human generated procedurally with ALL of its 3// anatomical SYSTEMS present as independently peelable layers -- exactly ZygoteBody's peel-a-layer atlas, and Sloyd's 4// parametric body generator, but 100% integer + sovereign (own SDF + integer ortho ray-march, no ML/Blender/externals). 5// 8 SYSTEMS (bit in the visibility mask): 0 SKIN 1 MUSCLE 2 SKELETON 3 DIGESTIVE 4 CIRCULATORY 5 RESPIRATORY 6// 6 URINARY 7 NERVOUS 7// ~77 parts / ~60 NAMED structures head-to-toe (skull..foot; heart,lungs,liver,kidneys,brain,spinal cord,...). 8// PARAMETRIC (Sloyd-style): height / girth / frame-width / sex presets reshape the whole being from one seed. 9// PEEL (ZygoteBody-style): render with any subset of systems visible -> strip skin to see muscle, strip muscle to 10// see skeleton + viscera, isolate one system. Each part carries a system id + a name id -> the atlas can name parts. 11// This extends the layered idea in nx_anatstack (bone->muscle->fat->skin peel) from the FACE to the WHOLE BEING and 12// from tissue layers to full anatomical SYSTEMS. license_tier: ORIGINAL 13import "nx_syscalls.nx" 14import "nx_itrig.nx" 15import "nx_vecmath.nx" 16const BS_MAGIC_1024: i64 = 1024 17const BS_MAGIC_4096: i64 = 4096 18const BS_MAGIC_1000000000: i64 = 1000000000 19const BS_MAGIC_999999999: i64 = 999999999 20const BS_MAGIC_1500: i64 = 1500 21const BS_MAGIC_5800: i64 = 5800 22const BS_MAGIC_6000: i64 = 6000 23const BS_MAGIC_8600: i64 = 8600 24const BS_MAGIC_1600: i64 = 1600 25const BS_MAGIC_1360: i64 = 1360 26const BS_MAGIC_1090: i64 = 1090 27const BS_MAGIC_1078: i64 = 1078 28const BS_MAGIC_65536: i64 = 65536 29const BS_MAGIC_3072: i64 = 3072 30const BS_MAGIC_1000000: i64 = 1000000 31const BS_MAGIC_1400: i64 = 1400 32const BS_MAGIC_2600: i64 = 2600 33const BS_MAGIC_3200: i64 = 3200 34const BS_MAGIC_2120: i64 = 2120 35const BS_MAGIC_1780: i64 = 1780 36 37// ---- system ids (also the bit index in the visibility mask) ---- 38const BS_SKIN: i64 = 0 39const BS_MUS: i64 = 1 40const BS_SKEL: i64 = 2 41const BS_DIG: i64 = 3 42const BS_CIRC: i64 = 4 43const BS_RESP: i64 = 5 44const BS_URI: i64 = 6 45const BS_NERV: i64 = 7 46const BS_NSYS: i64 = 8 47 48const BA_STRIDE: i64 = 13 // per-part: sys, cx,cy,cz, rx,ry,rz, col, nid, rmax, b1, b2 (FK bone ids, 0=none) 49const BA_CAP: i64 = 160 50static BA_BOX: i64 // part list ptr 51static BA_N: i64 // part count 52// parametric shape factors (fx1024; default 1024 = neutral adult male) 53static BA_TALL: i64 // vertical (height) scale 54static BA_GIRTH: i64 // soft-tissue lateral girth scale (skin/muscle/organ) 55static BA_WIDE: i64 // frame width scale (frame/shoulder/hip x) 56static BA_SEX: i64 // 0 male, 1 female 57static BA_CURL: i64 // ★R4 per-hand finger curl (0 open .. 1024 fist), read at build time 58// ---- R6 FK RIG: sagittal (Y-Z plane) joint rotation about a pivot. Bones 1..8 (0=none/root) ---- 59// 1 L-shoulder 2 L-elbow 3 R-shoulder 4 R-elbow 5 L-hip 6 L-knee 7 R-hip 8 R-knee. A part on (b1,b2) is FK'd: 60// world = R_b1 . R_b2 (rest); the SDF inverse-transforms the query point back to rest space before the ellipsoid test. 61const BA_NB: i64 = 11 62static BA_PIV: i64 // ptr NB*3: pivot x,y,z per bone (parametric-transformed) 63static BA_ANG: i64 // ptr NB: joint angle (rad*4096) per bone -- the POSE 64static BA_SIN: i64 // ptr NB: precomputed sin(angle) fx4096 65static BA_COS: i64 // ptr NB: precomputed cos(angle) fx4096 66 67func ba_isqrt(v: i64) -> i64 { return vm_isqrt(v) } 68func ba_iabs(v: i64) -> i64 { if v < 0 { return 0-v } return v } 69func ba_min(a: i64, b: i64) -> i64 { if a < b { return a } return b } 70func ba_max(a: i64, b: i64) -> i64 { if a > b { return a } return b } 71func ba_clamp(v: i64, lo: i64, hi: i64) -> i64 { if v<lo {return lo} if v>hi {return hi} return v } 72 73// add an axis-aligned ellipsoid part, transformed by the current parametric factors. Soft tissue (skin/muscle/ 74// digestive) gets the girth factor on its lateral radii; every part gets height on cy and frame-width on cx. 75// ★PER-AXIS FRAME PARAMS (debt 1785900993, spec'd FROM the measured Seed-san retarget vector: a single 76// BA_WIDE cannot serve shoulders-narrower + hips-wider at once, and arm length had no knob at all). 77// fx1024, ALL DEFAULT 1024 => v*1024/1024 is an exact integer identity => today's body is reproduced 78// BYTE-IDENTICAL (that equality IS the regression gate). Anchors are the rig's own pivot heights, so a 79// scaled limb still hangs off its joint. Donor proportions (VRM, kk cards, VaM) all ride THIS surface. 80static BA_SHW: i64 // shoulder width (arm chain x + thorax rx + shoulder/elbow pivots) 81static BA_HIPW: i64 // hip width (leg chain x + pelvis rx + hip/knee pivots) 82static BA_ARM: i64 // arm length below the shoulder anchor (upper arm + forearm + hand) 83static BA_THIGH: i64 // thigh length hip->knee (moves the knee, legs below ride it) 84static BA_CALF: i64 // calf length knee->foot 85const BA_ANCH_SH: i64 = 520 // shoulder pivot y 86const BA_ANCH_HIP: i64 = 40 // hip pivot y is -40 87const BA_ANCH_KNEE: i64 = 430 // knee pivot y is -430 88const BA_ANCH_ANKLE: i64 = 830 // ankle pivot y is -830 (tibia bottom -828 / foot top -824): the calf landmark 89func ba_ax_defaults() -> i64 { 90 if BA_SHW == 0 { BA_SHW = BS_MAGIC_1024 } 91 if BA_HIPW == 0 { BA_HIPW = BS_MAGIC_1024 } 92 if BA_ARM == 0 { BA_ARM = BS_MAGIC_1024 } 93 if BA_THIGH == 0 { BA_THIGH = BS_MAGIC_1024 } 94 if BA_CALF == 0 { BA_CALF = BS_MAGIC_1024 } 95 return 0 96} 97func ba_set_axes(shw: i64, hipw: i64, arm: i64, thigh: i64, calf: i64) -> i64 { 98 BA_SHW = shw; BA_HIPW = hipw; BA_ARM = arm; BA_THIGH = thigh; BA_CALF = calf 99 return 0 100} 101func ba_is_arm(nid: i64) -> i64 { 102 if nid == 58 { return 1 } 103 if nid == 59 { return 1 } 104 if nid == 60 { return 1 } 105 if nid == 64 { return 1 } 106 if nid == 65 { return 1 } 107 return 0 108} 109func ba_is_leg(nid: i64) -> i64 { 110 if nid == 61 { return 1 } 111 if nid == 62 { return 1 } 112 if nid == 63 { return 1 } 113 return 0 114} 115// knee y after the thigh param (the anchor everything below the knee rides) 116func ba_knee_y() -> i64 { 117 ba_ax_defaults() 118 return (0 - BA_ANCH_HIP) + ((0 - BA_ANCH_KNEE) + BA_ANCH_HIP) * BA_THIGH / BS_MAGIC_1024 119} 120func ba_axis_x(nid: i64, cx: i64) -> i64 { 121 ba_ax_defaults() 122 if ba_is_arm(nid) == 1 { return cx * BA_SHW / BS_MAGIC_1024 } 123 if ba_is_leg(nid) == 1 { return cx * BA_HIPW / BS_MAGIC_1024 } 124 return cx 125} 126func ba_axis_y(nid: i64, cy: i64) -> i64 { 127 ba_ax_defaults() 128 if ba_is_arm(nid) == 1 { return BA_ANCH_SH + (cy - BA_ANCH_SH) * BA_ARM / BS_MAGIC_1024 } 129 if nid == 61 { return (0 - BA_ANCH_HIP) + (cy + BA_ANCH_HIP) * BA_THIGH / BS_MAGIC_1024 } 130 if nid == 62 { return ba_knee_y() + (cy + BA_ANCH_KNEE) * BA_CALF / BS_MAGIC_1024 } 131 if nid == 63 { return ba_knee_y() + (cy + BA_ANCH_KNEE) * BA_CALF / BS_MAGIC_1024 } 132 return cy 133} 134 135func ba_add(sys: i64, cx: i64, cy: i64, cz: i64, rx: i64, ry: i64, rz: i64, col: i64, nid: i64) -> i64 { 136 if BA_BOX == 0 { BA_BOX = sys_mmap(BA_CAP*BA_STRIDE*8) as i64 } 137 let B: *i64 = BA_BOX as *i64 138 var gx: i64 = rx 139 var gz: i64 = rz 140 if sys == BS_SKIN { gx = rx*BA_GIRTH/BS_MAGIC_1024; gz = rz*BA_GIRTH/BS_MAGIC_1024 } 141 if sys == BS_MUS { gx = rx*BA_GIRTH/BS_MAGIC_1024; gz = rz*BA_GIRTH/BS_MAGIC_1024 } 142 if sys == BS_DIG { gx = rx*BA_GIRTH/BS_MAGIC_1024; gz = rz*BA_GIRTH/BS_MAGIC_1024 } 143 if nid == 55 { gx = gx*BA_SHW/BS_MAGIC_1024 } // thorax width follows the shoulder axis 144 if nid == 57 { gx = gx*BA_HIPW/BS_MAGIC_1024 } // pelvis width follows the hip axis 145 let tcx: i64 = ba_axis_x(nid, cx)*BA_WIDE/BS_MAGIC_1024 146 let tcy: i64 = ba_axis_y(nid, cy)*BA_TALL/BS_MAGIC_1024 147 let i: i64 = BA_N*BA_STRIDE 148 B[i]=sys; B[i+1]=tcx; B[i+2]=tcy; B[i+3]=cz; B[i+4]=gx; B[i+5]=ry; B[i+6]=gz; B[i+7]=col; B[i+8]=nid; B[i+9]=ba_max(ba_max(gx,ry),gz); B[i+10]=0; B[i+11]=0; B[i+12]=0 149 BA_N = BA_N + 1 150 return 0 151} 152 153// is nid one of a small set (helper for rig assignment) 154func ba_nin(nid: i64, a: i64, b: i64, c: i64, d: i64) -> i64 { if nid==a {return 1} if nid==b {return 1} if nid==c {return 1} if nid==d {return 1} return 0 } 155 156// ★R6 rig: place the 8 joint pivots (parametric-transformed) and assign each limb part to its bone chain by 157// (nid, side). Torso/head/organs stay on bone 0 (rigid). Pose starts at STAND (all angles 0). 158func ba_rig_setup() -> i64 { 159 if BA_PIV == 0 { BA_PIV = sys_mmap(BA_NB*3*8) as i64; BA_ANG = sys_mmap(BA_NB*8) as i64; BA_SIN = sys_mmap(BA_NB*8) as i64; BA_COS = sys_mmap(BA_NB*8) as i64 } 160 let PV: *i64 = BA_PIV as *i64 161 // base pivots (pre-transform): [bone*3 + {x,y,z}] 162 let bx: *i64 = sys_mmap(BA_NB*8) as *i64 163 let by: *i64 = sys_mmap(BA_NB*8) as *i64 164 let bz: *i64 = sys_mmap(BA_NB*8) as *i64 165 bx[1]=0-185; by[1]=520; bz[1]=15 // L shoulder 166 bx[2]=0-205; by[2]=300; bz[2]=20 // L elbow 167 bx[3]=185; by[3]=520; bz[3]=15 // R shoulder 168 bx[4]=205; by[4]=300; bz[4]=20 // R elbow 169 bx[5]=0-88; by[5]=0-40; bz[5]=10 // L hip 170 bx[6]=0-84; by[6]=0-430; bz[6]=20 // L knee 171 bx[7]=88; by[7]=0-40; bz[7]=10 // R hip 172 bx[8]=84; by[8]=0-430; bz[8]=20 // R knee 173 bx[9]=0-84; by[9]=0-BA_ANCH_ANKLE; bz[9]=20 // L ankle (calf landmark bone: no FK chain, angle stays 0) 174 bx[10]=84; by[10]=0-BA_ANCH_ANKLE; bz[10]=20 // R ankle 175 // per-axis frame params on the PIVOTS too, else a scaled limb and its bone disagree (the rig IS 176 // what the glb export carries, so this is the half the retarget measurement reads). 177 ba_ax_defaults() 178 bx[1] = bx[1]*BA_SHW/BS_MAGIC_1024 179 bx[3] = bx[3]*BA_SHW/BS_MAGIC_1024 180 bx[2] = bx[2]*BA_SHW/BS_MAGIC_1024 181 bx[4] = bx[4]*BA_SHW/BS_MAGIC_1024 182 by[2] = BA_ANCH_SH + (by[2] - BA_ANCH_SH)*BA_ARM/BS_MAGIC_1024 183 by[4] = BA_ANCH_SH + (by[4] - BA_ANCH_SH)*BA_ARM/BS_MAGIC_1024 184 bx[5] = bx[5]*BA_HIPW/BS_MAGIC_1024 185 bx[7] = bx[7]*BA_HIPW/BS_MAGIC_1024 186 bx[6] = bx[6]*BA_HIPW/BS_MAGIC_1024 187 bx[8] = bx[8]*BA_HIPW/BS_MAGIC_1024 188 by[6] = (0 - BA_ANCH_HIP) + (by[6] + BA_ANCH_HIP)*BA_THIGH/BS_MAGIC_1024 189 by[8] = (0 - BA_ANCH_HIP) + (by[8] + BA_ANCH_HIP)*BA_THIGH/BS_MAGIC_1024 190 // ankles ride the (already thigh-scaled) knees; the knee->ankle segment is the calf axis (debt 1785900993) 191 bx[9] = bx[9]*BA_HIPW/BS_MAGIC_1024 192 bx[10] = bx[10]*BA_HIPW/BS_MAGIC_1024 193 by[9] = by[6] + (by[9] + BA_ANCH_KNEE)*BA_CALF/BS_MAGIC_1024 194 by[10] = by[8] + (by[10] + BA_ANCH_KNEE)*BA_CALF/BS_MAGIC_1024 195 var b: i64 = 1 196 while b < BA_NB { 197 PV[b*3] = bx[b]*BA_WIDE/BS_MAGIC_1024 198 PV[b*3+1] = by[b]*BA_TALL/BS_MAGIC_1024 199 PV[b*3+2] = bz[b] 200 b = b + 1 201 } 202 let AN: *i64 = BA_ANG as *i64 203 let SI: *i64 = BA_SIN as *i64 204 let CO: *i64 = BA_COS as *i64 205 var a: i64 = 0 206 while a < BA_NB { AN[a] = 0; SI[a] = 0; CO[a] = BS_MAGIC_4096; a = a + 1 } // stand pose baked -> ba_sdf safe immediately after build 207 // assign parts to bones by nid + side 208 let B: *i64 = BA_BOX as *i64 209 var k: i64 = 0 210 while k < BA_N { 211 let i: i64 = k*BA_STRIDE 212 let nid: i64 = B[i+8] 213 let left: i64 = B[i+1] // cx (transformed) -- sign gives side 214 var b1: i64 = 0 215 var b2: i64 = 0 216 // arm upper (shoulder only) 217 if ba_nin(nid, 45, 47, 10, 58) == 1 { if left < 0 { b1=1 } else { b1=3 } } 218 // arm lower (shoulder + elbow) 219 if ba_nin(nid, 50, 11, 59, 60) == 1 { if left < 0 { b1=1; b2=2 } else { b1=3; b2=4 } } 220 // fingers + thumb follow the forearm chain (R4) 221 if ba_nin(nid, 64, 65, 0-1, 0-1) == 1 { if left < 0 { b1=1; b2=2 } else { b1=3; b2=4 } } 222 // leg upper (hip only) 223 if ba_nin(nid, 51, 13, 61, 0-1) == 1 { if left < 0 { b1=5 } else { b1=7 } } 224 // leg lower (hip + knee) 225 if ba_nin(nid, 52, 14, 15, 62) == 1 { if left < 0 { b1=5; b2=6 } else { b1=7; b2=8 } } 226 if ba_nin(nid, 63, 20, 0-1, 0-1) == 1 { if left < 0 { b1=5; b2=6 } else { b1=7; b2=8 } } 227 B[i+11] = b1 228 B[i+12] = b2 229 k = k + 1 230 } 231 return 0 232} 233 234// bake the current pose's joint sin/cos so ba_sdf can be called standalone (isosurface sampling, not just atlas_render). 235// ★Q5 FOOT PLANTING (2026-07-12, the motion-realism audit: "feet float mid-stride, no ground contact"): after a 236// pose, forward-FK each foot's SOLE point through its (hip, knee) chain and DROP the whole being so the stance 237// foot touches the rest ground level. BA_GY is applied to every SDF query (the being rides on its planted foot). 238static BA_GY: i64 239static BA_PLANT: i64 240// forward-FK a point through (b1, b2): the inverse of ba_part_sdf's inverse-FK (transpose rotations, b2 first) 241func ba_fwd_fk(py: i64, pz: i64, b1: i64, b2: i64, out: *i64) -> i64 { 242 let PV: *i64 = BA_PIV as *i64 243 let SI: *i64 = BA_SIN as *i64 244 let CO: *i64 = BA_COS as *i64 245 var qy: i64 = py 246 var qz: i64 = pz 247 if b2 != 0 { 248 let c: i64 = CO[b2] 249 let s: i64 = SI[b2] 250 let dy: i64 = qy - PV[b2*3+1] 251 let dz: i64 = qz - PV[b2*3+2] 252 qy = PV[b2*3+1] + (c*dy - s*dz)/BS_MAGIC_4096 253 qz = PV[b2*3+2] + (s*dy + c*dz)/BS_MAGIC_4096 254 } 255 if b1 != 0 { 256 let c: i64 = CO[b1] 257 let s: i64 = SI[b1] 258 let dy: i64 = qy - PV[b1*3+1] 259 let dz: i64 = qz - PV[b1*3+2] 260 qy = PV[b1*3+1] + (c*dy - s*dz)/BS_MAGIC_4096 261 qz = PV[b1*3+2] + (s*dy + c*dz)/BS_MAGIC_4096 262 } 263 out[0] = qy 264 out[1] = qz 265 return 0 266} 267func atlas_sync_pose() -> i64 { 268 if BA_ANG == 0 { return 0 } 269 let AN: *i64 = BA_ANG as *i64 270 let SI: *i64 = BA_SIN as *i64 271 let CO: *i64 = BA_COS as *i64 272 var bn: i64 = 0 273 while bn < BA_NB { SI[bn] = it_sin4096(AN[bn]); CO[bn] = it_cos4096(AN[bn]); bn = bn + 1 } 274 // ★Q5 ground solve: plant the lowest foot sole at its rest level 275 BA_GY = 0 276 if BA_PLANT == 1 { 277 let B: *i64 = BA_BOX as *i64 278 let fk: *i64 = sys_mmap(16) as *i64 279 var minPosed: i64 = BS_MAGIC_1000000000 280 var minRest: i64 = BS_MAGIC_1000000000 281 var k: i64 = 0 282 while k < BA_N { 283 let i: i64 = k*BA_STRIDE 284 if B[i+8] == 63 { // a foot part 285 let soleY: i64 = B[i+2] - B[i+5] // cy - ry 286 let soleZ: i64 = B[i+3] 287 if soleY < minRest { minRest = soleY } 288 ba_fwd_fk(soleY, soleZ, B[i+11], B[i+12], fk) 289 if fk[0] < minPosed { minPosed = fk[0] } 290 } 291 k = k + 1 292 } 293 if minPosed < BS_MAGIC_999999999 { BA_GY = minPosed - minRest } 294 } 295 return 0 296} 297// ★genome substrate hooks (nx_genome builds NON-HUMAN creatures on the same part list + SDF) 298func atlas_custom_reset() -> i64 { BA_N = 0; BA_TALL = BS_MAGIC_1024; BA_GIRTH = BS_MAGIC_1024; BA_WIDE = BS_MAGIC_1024; BA_SEX = 0; ba_set_axes(BS_MAGIC_1024, BS_MAGIC_1024, BS_MAGIC_1024, BS_MAGIC_1024, BS_MAGIC_1024); return 0 } 299func atlas_custom_finish() -> i64 { 300 if BA_ANG != 0 { 301 let AN: *i64 = BA_ANG as *i64 302 var a: i64 = 0 303 while a < BA_NB { AN[a] = 0; a = a + 1 } 304 } 305 BA_PLANT = 0 306 BA_GY = 0 307 atlas_sync_pose() 308 return 0 309} 310func atlas_part_count() -> i64 { return BA_N } 311func atlas_part_sys(k: i64) -> i64 { let B: *i64 = BA_BOX as *i64; return B[k*BA_STRIDE] } 312func atlas_set_plant(v: i64) -> i64 { BA_PLANT = v; atlas_sync_pose(); return 0 } 313func atlas_ground_off() -> i64 { return BA_GY } 314// ★set the POSE (joint angles). 0 stand, 1 walk (mid-stride), 2 sit, 3 wave. 315func atlas_pose(preset: i64) -> i64 { 316 if BA_ANG == 0 { return 0 } 317 let AN: *i64 = BA_ANG as *i64 318 var a: i64 = 0 319 while a < BA_NB { AN[a] = 0; a = a + 1 } 320 if preset == 1 { // WALK: opposite arm/leg swing 321 AN[1] = 0-BS_MAGIC_1500; AN[2] = 0-600 // L arm forward 322 AN[3] = BS_MAGIC_1500; AN[4] = 0-300 // R arm back 323 AN[5] = BS_MAGIC_1500; AN[6] = 300 // L leg forward 324 AN[7] = 0-BS_MAGIC_1500; AN[8] = BS_MAGIC_1500 // R leg back, knee bent 325 } 326 if preset == 2 { // SIT: thighs up, shins down 327 AN[5] = BS_MAGIC_5800; AN[6] = 0-BS_MAGIC_6000 328 AN[7] = BS_MAGIC_5800; AN[8] = 0-BS_MAGIC_6000 329 AN[1] = 0-700; AN[3] = 700 330 } 331 if preset == 3 { // WAVE: right arm up 332 AN[3] = BS_MAGIC_8600; AN[4] = BS_MAGIC_1600 333 AN[1] = 0-500 334 } 335 atlas_sync_pose() // keep BA_SIN/COS in sync so ba_sdf is safe standalone (no footgun) 336 return 0 337} 338 339// ★build the whole being for a parametric preset. 0 default-male, 1 heavy-male, 2 female, 3 tall-lean. 340func atlas_build(preset: i64) -> i64 { 341 BA_N = 0 342 BA_TALL = BS_MAGIC_1024; BA_GIRTH = BS_MAGIC_1024; BA_WIDE = BS_MAGIC_1024; BA_SEX = 0 343 // ⚠PER-AXIS PARAMS ARE NOT RESET HERE, DELIBERATELY (caught by the closing measurement 2026-08-04: 344 // resetting them here silently clobbered a caller that had set the retarget vector BEFORE the build, 345 // so the export measured identical and the convergence test failed -- correctly). Semantics: the 346 // presets own the 3 GLOBAL scales; per-axis frame params are an explicit caller opt-in that PERSISTS 347 // until atlas_custom_reset() or an explicit ba_set_axes(1024...) -- set them, then build. 348 if preset == 1 { BA_GIRTH = BS_MAGIC_1360; BA_WIDE = BS_MAGIC_1090 } 349 if preset == 2 { BA_TALL = 968; BA_GIRTH = 1012; BA_WIDE = 952; BA_SEX = 1 } 350 if preset == 3 { BA_TALL = BS_MAGIC_1078; BA_GIRTH = 872; BA_WIDE = 980 } 351 352 // organ / bone / vessel / nerve colours (r + g*256 + b*65536) 353 let C_SKIN: i64 = 216 + 172*256 + 152*BS_MAGIC_65536 354 let C_BONE: i64 = 234 + 228*256 + 206*BS_MAGIC_65536 355 let C_MUS: i64 = 196 + 74*256 + 68*BS_MAGIC_65536 356 let C_HEART: i64= 178 + 44*256 + 44*BS_MAGIC_65536 357 let C_ART: i64 = 206 + 60*256 + 56*BS_MAGIC_65536 358 let C_VEIN: i64 = 96 + 104*256 + 168*BS_MAGIC_65536 359 let C_LUNG: i64 = 214 + 158*256 + 162*BS_MAGIC_65536 360 let C_LIVER: i64= 132 + 62*256 + 48*BS_MAGIC_65536 361 let C_STOM: i64 = 196 + 150*256 + 120*BS_MAGIC_65536 362 let C_INT: i64 = 210 + 156*256 + 138*BS_MAGIC_65536 363 let C_SPLN: i64 = 122 + 60*256 + 74*BS_MAGIC_65536 364 let C_PANC: i64 = 198 + 176*256 + 122*BS_MAGIC_65536 365 let C_GALL: i64 = 120 + 156*256 + 92*BS_MAGIC_65536 366 let C_KID: i64 = 138 + 74*256 + 86*BS_MAGIC_65536 367 let C_BLAD: i64 = 206 + 196*256 + 128*BS_MAGIC_65536 368 let C_BRAIN: i64= 212 + 182*256 + 182*BS_MAGIC_65536 369 let C_NERVE: i64= 232 + 222*256 + 156*BS_MAGIC_65536 370 371 // ================= SKELETON (sys 2) -- ivory bone ================= 372 ba_add(BS_SKEL, 0, 762, 0, 96, 118, 100, C_BONE, 1) // 1 skull (cranium) 373 ba_add(BS_SKEL, 0, 662, 40, 78, 62, 66, C_BONE, 2) // 2 mandible (jaw) 374 ba_add(BS_SKEL, 0, 610, 0-30, 34, 60, 34, C_BONE, 3) // 3 cervical spine (neck) 375 ba_add(BS_SKEL, 0, 430, 0-40, 34, 150, 34, C_BONE, 4) // 4 thoracic spine 376 ba_add(BS_SKEL, 0, 210, 0-45, 36, 110, 36, C_BONE, 5) // 5 lumbar spine 377 ba_add(BS_SKEL, 0, 470, 92, 30, 150, 26, C_BONE, 6) // 6 sternum (breastbone) 378 // ribcage -- 4 rib hoops per side (front-curving ellipsoids), all named "rib"(7) 379 ba_add(BS_SKEL, 0-92, 500, 40, 96, 26, 96, C_BONE, 7) 380 ba_add(BS_SKEL, 92, 500, 40, 96, 26, 96, C_BONE, 7) 381 ba_add(BS_SKEL, 0-112, 450, 46, 116, 26, 108, C_BONE, 7) 382 ba_add(BS_SKEL, 112, 450, 46, 116, 26, 108, C_BONE, 7) 383 ba_add(BS_SKEL, 0-118, 398, 48, 122, 26, 112, C_BONE, 7) 384 ba_add(BS_SKEL, 118, 398, 48, 122, 26, 112, C_BONE, 7) 385 ba_add(BS_SKEL, 0-108, 348, 44, 112, 26, 104, C_BONE, 7) 386 ba_add(BS_SKEL, 108, 348, 44, 112, 26, 104, C_BONE, 7) 387 ba_add(BS_SKEL, 0-130, 556, 20, 92, 22, 30, C_BONE, 8) // 8 clavicle L 388 ba_add(BS_SKEL, 130, 556, 20, 92, 22, 30, C_BONE, 8) // clavicle R 389 ba_add(BS_SKEL, 0-176, 500, 0-30, 40, 62, 40, C_BONE, 9) // 9 scapula L 390 ba_add(BS_SKEL, 176, 500, 0-30, 40, 62, 40, C_BONE, 9) // scapula R 391 ba_add(BS_SKEL, 0-198, 405, 20, 26, 132, 26, C_BONE, 10) // 10 humerus L 392 ba_add(BS_SKEL, 198, 405, 20, 26, 132, 26, C_BONE, 10) // humerus R 393 ba_add(BS_SKEL, 0-222, 190, 20, 22, 128, 22, C_BONE, 11) // 11 forearm bones L (radius+ulna) 394 ba_add(BS_SKEL, 222, 190, 20, 22, 128, 22, C_BONE, 11) // forearm bones R 395 ba_add(BS_SKEL, 0, 0-20, 0, 150, 96, 96, C_BONE, 12) // 12 pelvis 396 ba_add(BS_SKEL, 0-88, 0-230, 10, 30, 210, 30, C_BONE, 13) // 13 femur L (thigh bone) 397 ba_add(BS_SKEL, 88, 0-230, 10, 30, 210, 30, C_BONE, 13) // femur R 398 ba_add(BS_SKEL, 0-84, 0-436, 24, 26, 34, 26, C_BONE, 14) // 14 patella L (kneecap) 399 ba_add(BS_SKEL, 84, 0-436, 24, 26, 34, 26, C_BONE, 14) // patella R 400 ba_add(BS_SKEL, 0-82, 0-628, 10, 26, 200, 26, C_BONE, 15) // 15 tibia+fibula L (shin bones) 401 ba_add(BS_SKEL, 82, 0-628, 10, 26, 200, 26, C_BONE, 15) // tibia+fibula R 402 403 // ================= NERVOUS (sys 7) ================= 404 ba_add(BS_NERV, 0-46, 792, 6, 74, 78, 84, C_BRAIN, 16) // 16 cerebrum L hemisphere 405 ba_add(BS_NERV, 46, 792, 6, 74, 78, 84, C_BRAIN, 16) // cerebrum R hemisphere 406 ba_add(BS_NERV, 0, 720, 0-42, 66, 44, 52, C_BRAIN, 17) // 17 cerebellum 407 ba_add(BS_NERV, 0, 676, 0-24, 26, 46, 30, C_BRAIN, 18) // 18 brainstem 408 ba_add(BS_NERV, 0, 300, 0-56, 18, 350, 18, C_NERVE, 19) // 19 spinal cord 409 ba_add(BS_NERV, 0-60, 0-260, 0-40, 20, 200, 20, C_NERVE, 20) // 20 sciatic nerve L 410 ba_add(BS_NERV, 60, 0-260, 0-40, 20, 200, 20, C_NERVE, 20) // sciatic nerve R 411 412 // ================= RESPIRATORY (sys 5) ================= 413 ba_add(BS_RESP, 0-96, 452, 8, 82, 150, 84, C_LUNG, 21) // 21 left lung 414 ba_add(BS_RESP, 96, 466, 8, 88, 162, 86, C_LUNG, 22) // 22 right lung 415 ba_add(BS_RESP, 0, 560, 24, 22, 74, 22, C_LUNG, 23) // 23 trachea (windpipe) 416 ba_add(BS_RESP, 0-44, 480, 16, 40, 24, 30, C_LUNG, 24) // 24 bronchus L 417 ba_add(BS_RESP, 44, 480, 16, 40, 24, 30, C_LUNG, 24) // bronchus R 418 ba_add(BS_RESP, 0, 300, 10, 158, 26, 108, C_MUS, 25) // 25 diaphragm 419 420 // ================= CIRCULATORY (sys 4) ================= 421 ba_add(BS_CIRC, 0-26, 396, 44, 72, 88, 62, C_HEART, 26) // 26 heart 422 ba_add(BS_CIRC, 0-6, 500, 8, 30, 60, 26, C_ART, 27) // 27 aortic arch 423 ba_add(BS_CIRC, 0-6, 260, 0-30, 22, 260, 22, C_ART, 28) // 28 descending aorta 424 ba_add(BS_CIRC, 38, 320, 0-24, 22, 260, 22, C_VEIN, 29) // 29 inferior vena cava 425 ba_add(BS_CIRC, 0-30, 452, 30, 24, 40, 24, C_ART, 30) // 30 pulmonary trunk 426 ba_add(BS_CIRC, 0-40, 600, 26, 16, 90, 16, C_ART, 31) // 31 carotid artery L 427 ba_add(BS_CIRC, 40, 600, 26, 16, 90, 16, C_ART, 31) // carotid artery R 428 429 // ================= DIGESTIVE (sys 3) ================= 430 ba_add(BS_DIG, 0, 500, 12, 22, 130, 22, C_STOM, 32) // 32 esophagus 431 ba_add(BS_DIG, 74, 268, 46, 140, 84, 96, C_LIVER, 33) // 33 liver 432 ba_add(BS_DIG, 0-76, 250, 42, 88, 74, 62, C_STOM, 34) // 34 stomach 433 ba_add(BS_DIG, 0-134, 282, 4, 46, 58, 42, C_SPLN, 35) // 35 spleen 434 ba_add(BS_DIG, 0-8, 232, 0-6, 92, 26, 36, C_PANC, 36) // 36 pancreas 435 ba_add(BS_DIG, 96, 228, 66, 30, 40, 28, C_GALL, 37) // 37 gallbladder 436 ba_add(BS_DIG, 0, 96, 66, 122, 92, 72, C_INT, 38) // 38 small intestine 437 ba_add(BS_DIG, 0-120, 150, 54, 40, 120, 46, C_INT, 39) // 39 large intestine (ascending) 438 ba_add(BS_DIG, 0, 208, 54, 130, 30, 46, C_INT, 39) // large intestine (transverse) 439 ba_add(BS_DIG, 120, 150, 54, 40, 120, 46, C_INT, 39) // large intestine (descending) 440 441 // ================= URINARY (sys 6) ================= 442 ba_add(BS_URI, 0-96, 208, 0-42, 36, 62, 40, C_KID, 40) // 40 kidney L 443 ba_add(BS_URI, 96, 194, 0-42, 36, 62, 40, C_KID, 40) // kidney R 444 ba_add(BS_URI, 0-30, 60, 0-20, 12, 150, 12, C_KID, 41) // 41 ureter L 445 ba_add(BS_URI, 30, 46, 0-20, 12, 150, 12, C_KID, 41) // ureter R 446 ba_add(BS_URI, 0, 0-30, 60, 54, 46, 46, C_BLAD, 42) // 42 urinary bladder 447 448 // ================= MUSCLE (sys 1) ================= 449 ba_add(BS_MUS, 0-46, 596, 42, 26, 74, 30, C_MUS, 43) // 43 sternocleidomastoid L 450 ba_add(BS_MUS, 46, 596, 42, 26, 74, 30, C_MUS, 43) // sternocleidomastoid R 451 ba_add(BS_MUS, 0, 540, 0-30, 178, 60, 74, C_MUS, 44) // 44 trapezius 452 ba_add(BS_MUS, 0-186, 512, 12, 66, 74, 66, C_MUS, 45) // 45 deltoid L 453 ba_add(BS_MUS, 186, 512, 12, 66, 74, 66, C_MUS, 45) // deltoid R 454 ba_add(BS_MUS, 0-78, 440, 82, 92, 68, 46, C_MUS, 46) // 46 pectoralis L 455 ba_add(BS_MUS, 78, 440, 82, 92, 68, 46, C_MUS, 46) // pectoralis R 456 ba_add(BS_MUS, 0-200, 400, 30, 48, 92, 48, C_MUS, 47) // 47 biceps L 457 ba_add(BS_MUS, 200, 400, 30, 48, 92, 48, C_MUS, 47) // biceps R 458 ba_add(BS_MUS, 0, 176, 92, 72, 140, 40, C_MUS, 48) // 48 rectus abdominis (abs) 459 ba_add(BS_MUS, 0-104, 178, 62, 46, 122, 56, C_MUS, 49) // 49 external oblique L 460 ba_add(BS_MUS, 104, 178, 62, 46, 122, 56, C_MUS, 49) // external oblique R 461 ba_add(BS_MUS, 0-224, 188, 26, 46, 104, 46, C_MUS, 50) // 50 forearm flexors L 462 ba_add(BS_MUS, 224, 188, 26, 46, 104, 46, C_MUS, 50) // forearm flexors R 463 ba_add(BS_MUS, 0-72, 0-230, 58, 74, 156, 62, C_MUS, 51) // 51 quadriceps L 464 ba_add(BS_MUS, 72, 0-230, 58, 74, 156, 62, C_MUS, 51) // quadriceps R 465 ba_add(BS_MUS, 0-76, 0-620, 0-28, 56, 116, 58, C_MUS, 52) // 52 gastrocnemius (calf) L 466 ba_add(BS_MUS, 76, 0-620, 0-28, 56, 116, 58, C_MUS, 52) // gastrocnemius R 467 468 // ================= SKIN (sys 0) -- outer envelope ================= 469 ba_add(BS_SKIN, 0, 762, 0, 104, 134, 108, C_SKIN, 53) // 53 head (Q4: canon head-height 1/7.5 stature) 470 ba_add(BS_SKIN, 0, 606, 0, 60, 76, 60, C_SKIN, 54) // 54 neck 471 ba_add(BS_SKIN, 0, 432, 12, 184, 152, 118, C_SKIN, 55) // 55 thorax 472 ba_add(BS_SKIN, 0, 172, 16, 162, 150, 122, C_SKIN, 56) // 56 abdomen 473 ba_add(BS_SKIN, 0, 45, 6, 200, 95, 122, C_SKIN, 57) // 57 pelvis / hips (Q4: crotch raised to canon legs, hip width to male shoulder:hip band) 474 ba_add(BS_SKIN, 0-198, 408, 22, 58, 150, 58, C_SKIN, 58) // 58 upper arm L 475 ba_add(BS_SKIN, 198, 408, 22, 58, 150, 58, C_SKIN, 58) // upper arm R 476 ba_add(BS_SKIN, 0-226, 130, 24, 48, 186, 48, C_SKIN, 59) // 59 forearm L (Q4: lengthened -- fingertips reach mid-thigh) 477 ba_add(BS_SKIN, 226, 130, 24, 48, 186, 48, C_SKIN, 59) // forearm R 478 ba_add(BS_SKIN, 0-240, 0-125, 20, 52, 74, 34, C_SKIN, 60) // 60 hand L (Q4: wrist at canon height) 479 ba_add(BS_SKIN, 240, 0-125, 20, 52, 74, 34, C_SKIN, 60) // hand R 480 ba_add(BS_SKIN, 0-88, 0-232, 16, 88, 216, 82, C_SKIN, 61) // 61 thigh L 481 ba_add(BS_SKIN, 88, 0-232, 16, 88, 216, 82, C_SKIN, 61) // thigh R 482 ba_add(BS_SKIN, 0-82, 0-624, 6, 62, 208, 62, C_SKIN, 62) // 62 shin L 483 ba_add(BS_SKIN, 82, 0-624, 6, 62, 208, 62, C_SKIN, 62) // shin R 484 ba_add(BS_SKIN, 0-86, 0-864, 62, 52, 40, 118, C_SKIN, 63) // 63 foot L 485 ba_add(BS_SKIN, 86, 0-864, 62, 52, 40, 118, C_SKIN, 63) // foot R 486 // ★R4 HANDS: 4 fingers (2 segments) + thumb (2 segments) per hand, nid 64/65. Positions computed from the 487 // per-hand CURL parameter (0 = open, 1024 = fist) at build time -- pose the hands via atlas_hand_curl(). 488 let a1: i64 = BA_CURL*3 // per-segment curl angle, it4096 (0..BS_MAGIC_3072 ~ 43 deg) 489 let s1: i64 = it_sin4096(a1) 490 let c1: i64 = it_cos4096(a1) 491 let a2: i64 = a1*2 492 let s2: i64 = it_sin4096(a2) 493 let c2: i64 = it_cos4096(a2) 494 var side: i64 = 0 495 while side < 2 { 496 var sgn: i64 = 0-1 497 if side == 1 { sgn = 1 } 498 let hx: i64 = sgn*240 499 var fj: i64 = 0 500 while fj < 4 { 501 let fx: i64 = hx + sgn*(0-27 + fj*18) // spread across the hand 502 let e1y: i64 = 0-199 - 14*c1/BS_MAGIC_4096 503 let e1z: i64 = 20 + 14*s1/BS_MAGIC_4096 504 ba_add(BS_SKIN, fx, e1y, e1z, 7, 15, 8, C_SKIN, 64) 505 let jy: i64 = 0-199 - 28*c1/BS_MAGIC_4096 506 let jz: i64 = 20 + 28*s1/BS_MAGIC_4096 507 let e2y: i64 = jy - 12*c2/BS_MAGIC_4096 508 let e2z: i64 = jz + 12*s2/BS_MAGIC_4096 509 ba_add(BS_SKIN, fx, e2y, e2z, 6, 13, 7, C_SKIN, 64) 510 fj = fj + 1 511 } 512 let tx: i64 = hx - sgn*46 // thumb: inner side, angles forward with curl 513 ba_add(BS_SKIN, tx - sgn*8, 0-149, 34, 8, 16, 9, C_SKIN, 65) 514 ba_add(BS_SKIN, tx - sgn*14, 0-167, 44 + BA_CURL*18/BS_MAGIC_1024, 7, 12, 8, C_SKIN, 65) 515 side = side + 1 516 } 517 if BA_SEX == 1 { 518 ba_add(BS_SKIN, 0-78, 402, 108, 68, 62, 58, C_SKIN, 55) // breast L (female frame) 519 ba_add(BS_SKIN, 78, 402, 108, 68, 62, 58, C_SKIN, 55) // breast R 520 } 521 ba_rig_setup() // place joints + assign limb parts to bones (STAND) 522 BA_PLANT = 1 // ★Q5 ground-contact solve ON by default 523 atlas_sync_pose() 524 return BA_N 525} 526// ★R4: per-hand finger CURL (0 open .. 1024 fist). Set BEFORE atlas_build (build-time articulation). 527func atlas_hand_curl(v: i64) -> i64 { BA_CURL = v; return 0 } 528 529// rig accessors so consumers (the glb exporter) read the atlas's OWN pivots instead of baking a copy 530// (the R3 closing-measurement finding 2026-08-04: a baked copy exports the wrong skeleton for a 531// reshaped body). ba_piv_ready()==0 means no build has run yet -> the caller keeps its fallback. 532func ba_piv_ready() -> i64 { if BA_PIV == 0 { return 0 } return 1 } 533func ba_piv(j: i64, axis: i64) -> i64 { 534 if BA_PIV == 0 { return 0 } 535 let PV: *i64 = BA_PIV as *i64 536 return PV[j*3 + axis] 537} 538 539func ba_n() -> i64 { return BA_N } 540// how many DISTINCT named structures (nid) are present -> the "parts" count 541func ba_named_count() -> i64 { 542 let B: *i64 = BA_BOX as *i64 543 var seen: i64 = 0 544 var c: i64 = 0 545 var target: i64 = 1 546 while target <= 65 { 547 var k: i64 = 0 548 var found: i64 = 0 549 while k < BA_N { if B[k*BA_STRIDE+8] == target { found = 1 } k = k + 1 } 550 if found == 1 { c = c + 1 } 551 target = target + 1 552 } 553 return c 554} 555// how many of the 8 systems have at least one part 556func ba_systems_present() -> i64 { 557 let B: *i64 = BA_BOX as *i64 558 var s: i64 = 0 559 var present: i64 = 0 560 while s < BS_NSYS { 561 var k: i64 = 0 562 var f: i64 = 0 563 while k < BA_N { if B[k*BA_STRIDE] == s { f = 1 } k = k + 1 } 564 if f == 1 { present = present + 1 } 565 s = s + 1 566 } 567 return present 568} 569func ba_sys_part_count(sys: i64) -> i64 { 570 let B: *i64 = BA_BOX as *i64 571 var k: i64 = 0 572 var c: i64 = 0 573 while k < BA_N { if B[k*BA_STRIDE] == sys { c = c + 1 } k = k + 1 } 574 return c 575} 576func ba_part_color(k: i64) -> i64 { let B: *i64 = BA_BOX as *i64; return B[k*BA_STRIDE+7] } 577// the DEEPEST FK bone driving part k (b2 if set, else b1, else 0=root) -> used as the skin joint for glTF rigging 578func ba_part_bone(k: i64) -> i64 { let B: *i64 = BA_BOX as *i64; let b2: i64 = B[k*BA_STRIDE+12]; if b2 != 0 { return b2 } return B[k*BA_STRIDE+11] } 579 580// ---- ellipsoid SDF (same integer formulation as nx_anatstack) + inverse FK for posed limb parts ---- 581func ba_part_sdf(k: i64, x: i64, y: i64, z: i64) -> i64 { 582 let B: *i64 = BA_BOX as *i64 583 let i: i64 = k*BA_STRIDE 584 var qx: i64 = x; var qy: i64 = y; var qz: i64 = z 585 let b1: i64 = B[i+11] 586 if b1 != 0 { // inverse FK (undo b1 then b2), sagittal Y-Z plane 587 let PV: *i64 = BA_PIV as *i64 588 let CO: *i64 = BA_COS as *i64 589 let SI: *i64 = BA_SIN as *i64 590 var c: i64 = CO[b1]; var s: i64 = SI[b1] 591 var ddy: i64 = qy - PV[b1*3+1]; var ddz: i64 = qz - PV[b1*3+2] 592 qy = PV[b1*3+1] + (c*ddy + s*ddz)/BS_MAGIC_4096 593 qz = PV[b1*3+2] + (0-s*ddy + c*ddz)/BS_MAGIC_4096 594 let b2: i64 = B[i+12] 595 if b2 != 0 { 596 c = CO[b2]; s = SI[b2] 597 ddy = qy - PV[b2*3+1]; ddz = qz - PV[b2*3+2] 598 qy = PV[b2*3+1] + (c*ddy + s*ddz)/BS_MAGIC_4096 599 qz = PV[b2*3+2] + (0-s*ddy + c*ddz)/BS_MAGIC_4096 600 } 601 } 602 let dx: i64 = qx - B[i+1]; let dy: i64 = qy - B[i+2]; let dz: i64 = qz - B[i+3] 603 let rx: i64 = B[i+4]; let ry: i64 = B[i+5]; let rz: i64 = B[i+6] 604 let sd: i64 = ba_isqrt((dx*BS_MAGIC_1024/rx)*(dx*BS_MAGIC_1024/rx) + (dy*BS_MAGIC_1024/ry)*(dy*BS_MAGIC_1024/ry) + (dz*BS_MAGIC_1024/rz)*(dz*BS_MAGIC_1024/rz)) 605 let rmin: i64 = ba_min(ba_min(rx, ry), rz) 606 return (sd - BS_MAGIC_1024) * rmin / BS_MAGIC_1024 607} 608// min SDF over VISIBLE systems (mask bit sys), with a bounding-sphere reject so open space is cheap. 609const BA_SMK: i64 = 34 // ★de-clay (operator: 'clay monsters'): smooth-union radius for SKIN parts 610func ba_smin(a: i64, b: i64) -> i64 { 611 var m: i64 = a 612 if b < m { m = b } 613 var d: i64 = a - b 614 if d < 0 { d = 0-d } 615 let hh: i64 = BA_SMK - d 616 if hh > 0 { m = m - hh*hh/(4*BA_SMK) } 617 return m 618} 619func ba_sdf(x: i64, y: i64, z: i64, mask: i64) -> i64 { 620 let y2: i64 = y + BA_GY // ★Q5 ground solve: the being rides its planted foot 621 let B: *i64 = BA_BOX as *i64 622 var best: i64 = BS_MAGIC_1000000 623 var k: i64 = 0 624 while k < BA_N { 625 let sys: i64 = B[k*BA_STRIDE] 626 if ((mask >> sys) & 1) == 1 { 627 let dx: i64 = x - B[k*BA_STRIDE+1]; let dy: i64 = y2 - B[k*BA_STRIDE+2]; let dz: i64 = z - B[k*BA_STRIDE+3] 628 let thr: i64 = best + B[k*BA_STRIDE+9] + BA_SMK 629 let dd: i64 = dx*dx + dy*dy + dz*dz 630 var skip: i64 = 0 631 if thr > 0 { if dd >= thr*thr { skip = 1 } } 632 if B[k*BA_STRIDE+11] != 0 { skip = 0 } // posed part: rest-center reject invalid -> always test 633 if skip == 0 { 634 let pd: i64 = ba_part_sdf(k, x, y2, z) 635 if sys == BS_SKIN { best = ba_smin(best, pd) } // ★skin FLOWS (smooth union) -- joints blend, not balloon 636 else { if pd < best { best = pd } } 637 } 638 } 639 k = k + 1 640 } 641 return best 642} 643// nearest VISIBLE part index at a point (for colour) -- called once per hit, so no reject needed. 644func ba_nearest(x: i64, y: i64, z: i64, mask: i64) -> i64 { 645 let y2: i64 = y + BA_GY // ★Q5 ground solve (match ba_sdf) 646 let B: *i64 = BA_BOX as *i64 647 var best: i64 = BS_MAGIC_1000000000 648 var out: i64 = 0-1 649 var k: i64 = 0 650 while k < BA_N { 651 if ((mask >> B[k*BA_STRIDE]) & 1) == 1 { 652 let pd: i64 = ba_part_sdf(k, x, y2, z) 653 if pd < best { best = pd; out = k } 654 } 655 k = k + 1 656 } 657 return out 658} 659 660// ★orthographic integer sphere-trace. yaw rotates the being about its vertical axis; mask = visible systems; 661// hi_sys = a system to spotlight (others ghosted) or -1 for none. Writes fb (W*H, 0xRRGGBB). 662const BA_ZMAX: i64 = 560 663func atlas_render(fb: *i64, W: i64, H: i64, yaw: i64, mask: i64, hi_sys: i64) -> i64 { 664 // precompute the pose's joint sin/cos once per frame (read in ba_part_sdf's inverse FK) 665 if BA_ANG != 0 { 666 let AN: *i64 = BA_ANG as *i64 667 let SI: *i64 = BA_SIN as *i64 668 let CO: *i64 = BA_COS as *i64 669 var bn: i64 = 0 670 while bn < BA_NB { SI[bn] = it_sin4096(AN[bn]); CO[bn] = it_cos4096(AN[bn]); bn = bn + 1 } 671 } 672 let cy4: i64 = it_cos4096(yaw) 673 let sy4: i64 = it_sin4096(yaw) 674 // light dir in view space (upper-left-front), rotated into body space 675 let lx0: i64 = 0-BS_MAGIC_1400; let ly0: i64 = BS_MAGIC_2600; let lz0: i64 = BS_MAGIC_3200 676 let lbx: i64 = (lx0*cy4 - lz0*sy4)/BS_MAGIC_4096 677 let lbz: i64 = (lx0*sy4 + lz0*cy4)/BS_MAGIC_4096 678 let lby: i64 = ly0 679 let llen: i64 = ba_isqrt(lbx*lbx + lby*lby + lbz*lbz) + 1 680 let scale: i64 = BS_MAGIC_2120 / H // world units per pixel (fits ~BS_MAGIC_1780-tall body + margin) 681 let ycen: i64 = 0-10 682 var py: i64 = 0 683 while py < H { 684 var px: i64 = 0 685 while px < W { 686 let wx: i64 = (px - W/2)*scale 687 let wy: i64 = (H/2 - py)*scale + ycen 688 var zc: i64 = BA_ZMAX 689 var hit: i64 = 0 690 var steps: i64 = 0 691 var bx: i64 = 0; var by: i64 = 0; var bz: i64 = 0 692 while steps < 90 { 693 bx = (wx*cy4 - zc*sy4)/BS_MAGIC_4096 694 by = wy 695 bz = (wx*sy4 + zc*cy4)/BS_MAGIC_4096 696 let d: i64 = ba_sdf(bx, by, bz, mask) 697 if d < 3 { hit = 1; steps = 999 } 698 else { zc = zc - ba_max(d, 2); if zc < 0-BA_ZMAX { steps = 999 } else { steps = steps + 1 } } 699 } 700 var rr: i64 = 24; var gg: i64 = 26; var bb: i64 = 34 // background slate 701 if hit == 1 { 702 let e: i64 = 4 703 let gx: i64 = ba_sdf(bx+e,by,bz,mask) - ba_sdf(bx-e,by,bz,mask) 704 let gy: i64 = ba_sdf(bx,by+e,bz,mask) - ba_sdf(bx,by-e,bz,mask) 705 let gz: i64 = ba_sdf(bx,by,bz+e,mask) - ba_sdf(bx,by,bz-e,mask) 706 let gl: i64 = ba_isqrt(gx*gx + gy*gy + gz*gz) + 1 707 var lam: i64 = (gx*lbx + gy*lby + gz*lbz)/(gl*llen/BS_MAGIC_1024) // fx1024 Lambert 708 if lam < 0 { lam = 0 } 709 let ki: i64 = ba_nearest(bx, by, bz, mask) 710 let B: *i64 = BA_BOX as *i64 711 var col: i64 = 200 + 200*256 + 200*BS_MAGIC_65536 712 var psys: i64 = 0 713 if ki >= 0 { col = B[ki*BA_STRIDE+7]; psys = B[ki*BA_STRIDE] } 714 var cr: i64 = col & 255; var cg: i64 = (col>>8)&255; var cb: i64 = (col>>16)&255 715 // shade: ambient + diffuse + a soft front rim; depth cue by hit z 716 let sh: i64 = 46 + 82*lam/BS_MAGIC_1024 717 cr = cr*sh/128; cg = cg*sh/128; cb = cb*sh/128 718 // spotlight: ghost the non-highlighted systems 719 if hi_sys >= 0 { if psys != hi_sys { cr = cr*32/100 + 14; cg = cg*32/100 + 15; cb = cb*32/100 + 20 } } 720 if cr>255 {cr=255} if cg>255 {cg=255} if cb>255 {cb=255} 721 rr = cr; gg = cg; bb = cb 722 } 723 fb[py*W+px] = rr + gg*256 + bb*BS_MAGIC_65536 724 px = px + 1 725 } 726 py = py + 1 727 } 728 return 0 729}