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}