code wiki / (root) / nx_bodyatlas.nx

nx_bodyatlas.nx source

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