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}