code wiki / _hdl_build / nx_anat_rig.nx
nx_anat_rig.nx source
↩ module page · 431 lines · 20507 B
1// nx_anat_rig.nx -- ★SOVEREIGN ARTICULATED RIG + PHYSICS on the REAL 662k-tri BodyParts3D skeleton.
2// The being stops being a rendered corpse and becomes a DYNAMIC BODY: a joint tree (sagittal hinges) over the
3// 15 bone layers, forward kinematics per vertex, and a DETERMINISTIC integer damped-pendulum integrator that
4// drives the joints. Because every BodyParts3D part shares one cadaver frame, the bones are already positioned
5// -- the rig only has to add joints. 100% integer, no float, no GPU: same pose sequence replays bit-identically.
6// nx_anat_rig <mesh> <nframes> <W> <H> <outprefix>
7// license_tier: ORIGINAL expect_exit: 0
8import "nx_syscalls.nx"
9import "nx_png.nx"
10const RG_MAGIC_14000: i64 = 14000
11const RG_MAGIC_18000: i64 = 18000
12const RG_MAGIC_70000: i64 = 70000
13const RG_MAGIC_12000: i64 = 12000
14const RG_MAGIC_8388607: i64 = 8388607
15const RG_MAGIC_8388608: i64 = 8388608
16const RG_MAGIC_65536: i64 = 65536
17const RG_MAGIC_2000000000: i64 = 2000000000
18const RG_MAGIC_40500: i64 = 40500
19const RG_MAGIC_16384: i64 = 16384
20const RG_MAGIC_1024: i64 = 1024
21const RG_MAGIC_1280: i64 = 1280
22const RG_MAGIC_5423: i64 = 5423
23const RG_MAGIC_9487: i64 = 9487
24const RG_MAGIC_12206: i64 = 12206
25const RG_MAGIC_10160: i64 = 10160
26const RG_MAGIC_4064: i64 = 4064
27const RG_MAGIC_12190: i64 = 12190
28const RG_NL: i64 = 14
29// physics tuning (declared, not hidden): restoring gain, damping, substeps per frame
30const RG_GRAV: i64 = 460
31const RG_DAMP: i64 = 105
32const RG_STEPS: i64 = 7
33// GX-20 root rigid-body + ground contact (Q8 = model-units*256)
34const RG_Q8: i64 = 256
35const RG_GY: i64 = 150 // gravity, Q8 units per substep^2
36const RG_REST: i64 = 280 // restitution per-1024 (bone on floor: mostly inelastic)
37const RG_DROP0: i64 = 260 // release height, model units
38const RG_STOPV: i64 = 900 // |v| below this on contact -> come to rest (no infinite micro-bounce)
39
40func rg_hw(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 }
41func rg_pn(v: i64) -> i64 {
42 let b: *u8=sys_mmap(32); var x: i64=v; var ng: i64=0
43 if x<0 { ng=1; x=0-x }
44 var i: i64=31
45 if x==0 { b[i]=48 as u8; i=i-1 }
46 while x>0 { b[i]=(48+x%10) as u8; x=x/10; i=i-1 }
47 if ng==1 { b[i]=45 as u8; i=i-1 }
48 sys_write(1,(b as i64+i+1) as *u8,31-i); return 0
49}
50func rg_satoi(s: *u8) -> i64 {
51 var i: i64=0; var n: i64=0
52 while s[i]!=(0 as u8) { let c: i64=s[i] as i64; if c>=48 { if c<=57 { n=n*10+(c-48) } } i=i+1 }
53 return n
54}
55func rg_rdbits(b: *u8, o: i64) -> i64 {
56 return (b[o] as i64) | ((b[o+1] as i64)<<8) | ((b[o+2] as i64)<<16) | ((b[o+3] as i64)<<24)
57}
58func rg_f32mul(b: *u8, o: i64, mul: i64) -> i64 {
59 let bits: i64 = rg_rdbits(b,o)
60 let sign: i64 = (bits>>31)&1
61 let exp: i64 = (bits>>23)&255
62 let mant: i64 = bits & RG_MAGIC_8388607
63 if exp==0 { return 0 }
64 let m: i64 = (mant | RG_MAGIC_8388608)*mul
65 var e: i64 = exp-127-23
66 var v: i64 = 0
67 if e>=0 { v = m<<e } else { let sh: i64 = 0-e; v = (m + (1<<(sh-1)))>>sh }
68 if sign==1 { v = 0-v }
69 return v
70}
71func rg_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 }
72func rg_min(a: i64, b: i64) -> i64 { if a<b {return a} return b }
73func rg_max(a: i64, b: i64) -> i64 { if a>b {return a} return b }
74// Bhaskara I degree-form sine, EXACT at 0/30/90/150/180: sin(d) = 4P/(40500-P), P=d(180-d). Q14 out.
75func rg_sin_fill(tab: *i64) -> i64 {
76 var d: i64 = 0
77 while d < 180 {
78 let P: i64 = d*(180-d)
79 tab[d] = RG_MAGIC_16384*4*P/(RG_MAGIC_40500-P)
80 tab[d+180] = 0 - tab[d]
81 d = d + 1
82 }
83 return 0
84}
85func rg_wrap(d: i64) -> i64 { var x: i64 = d % 360; if x < 0 { x = x + 360 } return x }
86// FK a point up the joint chain and return only its WORLD Y -- used by the contact probes.
87func rg_fk_y(px: i64, py: i64, pz: i64, L: i64, par: *i64, thD: *i64, pvY: *i64, pvZ: *i64, sinT: *i64) -> i64 {
88 var y: i64 = py; var z: i64 = pz
89 var cur: i64 = L
90 var guard: i64 = 0
91 while guard < 8 {
92 if cur < 0 { guard = 8 } else {
93 let d: i64 = thD[cur]
94 if d != 0 {
95 let sc: i64 = sinT[d]
96 let cc: i64 = sinT[rg_wrap(d+90)]
97 let dy: i64 = y - pvY[cur]; let dz: i64 = z - pvZ[cur]
98 y = (dy*cc - dz*sc)/RG_MAGIC_16384 + pvY[cur]
99 z = (dy*sc + dz*cc)/RG_MAGIC_16384 + pvZ[cur]
100 }
101 cur = par[cur]
102 guard = guard + 1
103 }
104 }
105 return y
106}
107
108func main(argc: i64, argv: *i64) -> i64 {
109 let meshp: *u8 = argv[1] as *u8
110 let nframes: i64 = rg_satoi(argv[2] as *u8)
111 let W: i64 = rg_satoi(argv[3] as *u8)
112 let H: i64 = rg_satoi(argv[4] as *u8)
113 let pref: *u8 = argv[5] as *u8
114 // mode: argv[6][0]=='d' -> DROP (root rigid-body + ground contact); 'n' -> NO-CONTACT neg-control
115 var mode: i64 = 0
116 if argc > 6 {
117 let mp: *u8 = argv[6] as *u8
118 if mp[0] == (100 as u8) { mode = 1 }
119 if mp[0] == (110 as u8) { mode = 2 }
120 }
121
122 let sinT: *i64 = sys_mmap(400*8) as *i64
123 rg_sin_fill(sinT)
124
125 let lenp: *i64 = sys_mmap(16) as *i64
126 let mb: *u8 = sys_read_file(meshp, lenp)
127 if (mb as i64)==0 { rg_hw("{\x22error\x22:\x22mesh\x22}\n" as *u8); return 2 }
128 let nlayers: i64 = rg_rdbits(mb,8)
129 let ntris: i64 = rg_rdbits(mb,12)
130 let triBase: i64 = 16 + nlayers*24
131 let lidBase: i64 = triBase + ntris*84
132
133 // ---- global AABB (centering) + PER-LAYER AABB (joint pivots) ----
134 var mnx: i64=RG_MAGIC_2000000000; var mny: i64=RG_MAGIC_2000000000; var mnz: i64=RG_MAGIC_2000000000
135 var mxx: i64=0-RG_MAGIC_2000000000; var mxy: i64=0-RG_MAGIC_2000000000; var mxz: i64=0-RG_MAGIC_2000000000
136 let lminY: *i64 = sys_mmap(RG_NL*8) as *i64
137 let lmaxY: *i64 = sys_mmap(RG_NL*8) as *i64
138 let lsumZ: *i64 = sys_mmap(RG_NL*8) as *i64
139 let lcnt: *i64 = sys_mmap(RG_NL*8) as *i64
140 // GX-20 contact probes: the LOWEST vertex of each bone (its would-be ground contact point)
141 let prX: *i64 = sys_mmap(RG_NL*8) as *i64
142 let prY: *i64 = sys_mmap(RG_NL*8) as *i64
143 let prZ: *i64 = sys_mmap(RG_NL*8) as *i64
144 var i0: i64 = 0
145 while i0 < RG_NL { lminY[i0]=RG_MAGIC_2000000000; lmaxY[i0]=0-RG_MAGIC_2000000000; lsumZ[i0]=0; lcnt[i0]=0
146 prX[i0]=0; prY[i0]=0; prZ[i0]=0; i0=i0+1 }
147 var t: i64 = 0
148 while t < ntris {
149 let L: i64 = rg_rdbits(mb, lidBase+t*4) & 255
150 var v: i64 = 0
151 while v < 3 {
152 let o: i64 = triBase + t*84 + v*12
153 let x: i64 = rg_f32mul(mb,o,1); let y: i64 = rg_f32mul(mb,o+4,1); let z: i64 = rg_f32mul(mb,o+8,1)
154 if x<mnx {mnx=x} if x>mxx {mxx=x}
155 if y<mny {mny=y} if y>mxy {mxy=y}
156 if z<mnz {mnz=z} if z>mxz {mxz=z}
157 if L < RG_NL {
158 if y<lminY[L] { lminY[L]=y; prX[L]=x; prY[L]=y; prZ[L]=z }
159 if y>lmaxY[L] {lmaxY[L]=y}
160 lsumZ[L]=lsumZ[L]+z; lcnt[L]=lcnt[L]+1
161 }
162 v=v+1
163 }
164 t=t+1
165 }
166 let cx0: i64=(mnx+mxx)/2; let cy0: i64=(mny+mxy)/2; let cz0: i64=(mnz+mxz)/2
167
168 // ---- RIG: joint tree over the 15 bone layers (sagittal hinges about X) ----
169 // 0 skull 1 vertebrae 2 ribs 3 clavicle 4 scapula 5 humerus 6 pelvis(ROOT)
170 // 7 femur 8 tibia 9 fibula 10 patella 11 hand_L 12 hand_R 13 feet
171 // (sternum + costal cartilage dropped: PROVEN duplicates already inside the rib-cage aggregate)
172 let par: *i64 = sys_mmap(RG_NL*8) as *i64
173 par[0]=1; par[1]=6; par[2]=1; par[3]=1; par[4]=1; par[5]=4; par[6]=0-1
174 par[7]=6; par[8]=7; par[9]=7; par[10]=7; par[11]=5; par[12]=5; par[13]=8
175 let pvY: *i64 = sys_mmap(RG_NL*8) as *i64
176 let pvZ: *i64 = sys_mmap(RG_NL*8) as *i64
177 var L2: i64 = 0
178 while L2 < RG_NL {
179 var cz: i64 = 0
180 if lcnt[L2] > 0 { cz = lsumZ[L2]/lcnt[L2] - cz0 }
181 pvZ[L2] = cz
182 pvY[L2] = (lminY[L2]+lmaxY[L2])/2 - cy0
183 L2 = L2 + 1
184 }
185 // anatomically-placed hinge pivots: attach point to the PARENT bone
186 pvY[0] = lminY[0]-cy0 // skull -> neck (base of skull)
187 pvY[1] = lminY[1]-cy0 // spine -> waist (base of vertebral column)
188 pvY[5] = lmaxY[5]-cy0 // humerus-> shoulder (head of humerus)
189 pvY[7] = lmaxY[7]-cy0 // femur -> hip (head of femur)
190 pvY[8] = lmaxY[8]-cy0 // tibia -> knee (tibial plateau)
191
192 // ---- physics state: damped pendulums restoring to the neutral standing pose ----
193 let th: *i64 = sys_mmap(RG_NL*8) as *i64 // milli-degrees
194 let om: *i64 = sys_mmap(RG_NL*8) as *i64 // md per substep
195 var q: i64 = 0
196 while q < RG_NL { th[q]=0; om[q]=0; q=q+1 }
197 th[1]=RG_MAGIC_14000; th[0]=RG_MAGIC_18000; th[5]=RG_MAGIC_70000; th[7]=RG_MAGIC_12000; th[8]=0-RG_MAGIC_12000 // released-from pose
198 let drv: *i64 = sys_mmap(8*8) as *i64
199 drv[0]=1; drv[1]=0; drv[2]=5; drv[3]=7; drv[4]=8
200 let ndrv: i64 = 5
201
202 // ---- render buffers ----
203 let npx: i64 = W*H
204 let fb: *i64 = sys_mmap(npx*8) as *i64
205 let zb: *i64 = sys_mmap(npx*8) as *i64
206 let thD: *i64 = sys_mmap(RG_NL*8) as *i64
207 let l1x: i64=0-RG_MAGIC_5423; let l1y: i64=RG_MAGIC_9487; let l1z: i64=RG_MAGIC_12206
208 let l2x: i64=RG_MAGIC_10160; let l2y: i64=0-RG_MAGIC_4064; let l2z: i64=RG_MAGIC_12190
209 let cxh: i64=W/2; let cyh: i64=H/2
210 // framing from the REST silhouette (fixed across frames so motion is visible, not re-framed away)
211 var halfH: i64=(mxy-mny)/2; let halfW: i64=(mxx-mnx)/2
212 if mode > 0 { halfH = halfH + RG_DROP0*3/4 } // headroom so the released body stays in frame
213 let FOCAL: i64 = H
214 var dist: i64 = 2*halfH
215 let dw: i64 = 2*halfW*H/W
216 if dw > dist { dist = dw }
217 dist = dist*128/100 + (mxz-mnz)/2
218 if dist < 1 { dist = 1 }
219 let floorY: i64 = mny - cy0
220
221 rg_hw("{\x22organ\x22:\x22nx_anat_rig\x22,\x22ntris\x22:" as *u8); rg_pn(ntris)
222 rg_hw(",\x22layers\x22:" as *u8); rg_pn(nlayers)
223 rg_hw(",\x22joints_driven\x22:" as *u8); rg_pn(ndrv)
224 rg_hw(",\x22grav\x22:" as *u8); rg_pn(RG_GRAV); rg_hw(",\x22damp\x22:" as *u8); rg_pn(RG_DAMP)
225 rg_hw(",\x22substeps_per_frame\x22:" as *u8); rg_pn(RG_STEPS); rg_hw(",\x22frames\x22:[" as *u8)
226
227 // ---- GX-20 root rigid-body state (drop modes) ----
228 var rootY: i64 = 0
229 var rootV: i64 = 0
230 var contacts: i64 = 0
231 var worstPen: i64 = 0
232 if mode > 0 { rootY = RG_DROP0*RG_Q8 }
233 if mode > 0 { var z9: i64 = 0; while z9 < RG_NL { th[z9]=0; om[z9]=0; z9=z9+1 } }
234
235 var f: i64 = 0
236 while f < nframes {
237 // ---- integrate physics for this frame (frame 0 = the released state) ----
238 if f > 0 {
239 var s: i64 = 0
240 while s < RG_STEPS {
241 var k: i64 = 0
242 while k < ndrv {
243 let j: i64 = drv[k]
244 let dg: i64 = rg_wrap(th[j]/1000)
245 let sv: i64 = sinT[dg]
246 let acc: i64 = 0 - (RG_GRAV*sv)/RG_MAGIC_16384 - (RG_DAMP*om[j])/1000
247 om[j] = om[j] + acc
248 th[j] = th[j] + om[j]
249 k = k + 1
250 }
251 // ---- root: gravity + GROUND CONTACT ----
252 if mode > 0 {
253 rootV = rootV - RG_GY
254 rootY = rootY + rootV
255 var L4: i64 = 0
256 while L4 < RG_NL { thD[L4] = rg_wrap(th[L4]/1000); L4 = L4 + 1 }
257 // deepest probe below the floor
258 var lowest: i64 = RG_MAGIC_2000000000
259 var pr: i64 = 0
260 while pr < RG_NL {
261 if lcnt[pr] > 0 {
262 let wy: i64 = rg_fk_y(prX[pr]-cx0, prY[pr]-cy0, prZ[pr]-cz0, pr, par, thD, pvY, pvZ, sinT)
263 let ay2: i64 = wy*RG_Q8 + rootY
264 if ay2 < lowest { lowest = ay2 }
265 }
266 pr = pr + 1
267 }
268 let pen: i64 = (mny-cy0)*RG_Q8 - lowest // >0 means penetrating the floor
269 if pen > 0 {
270 if mode == 1 {
271 if pen > worstPen { worstPen = pen }
272 rootY = rootY + pen // positional resolve: never sink
273 contacts = contacts + 1
274 if rootV < 0 {
275 rootV = (0-rootV)*RG_REST/RG_MAGIC_1024 // bounce
276 if rootV < RG_STOPV { rootV = 0 } // rest instead of micro-bouncing
277 }
278 } else { if pen > worstPen { worstPen = pen } } // mode 2 = NO-CONTACT neg control
279 }
280 }
281 s = s + 1
282 }
283 }
284 var L3: i64 = 0
285 while L3 < RG_NL { thD[L3] = rg_wrap(th[L3]/1000); L3 = L3 + 1 }
286
287 // ---- clear: sky + ground ----
288 var p: i64 = 0
289 while p < npx {
290 let py: i64 = p/W
291 var br: i64 = 34 + (56*(H-py))/H
292 var bg: i64 = 41 + (69*(H-py))/H
293 var bb: i64 = 56 + (94*(H-py))/H
294 let rdy: i64 = cyh - py
295 if rdy < 0 {
296 let t16: i64 = floorY*RG_MAGIC_65536/rdy
297 let dxtra: i64 = t16/RG_MAGIC_65536
298 let ff: i64 = 900*RG_MAGIC_1024/(900 + dxtra)
299 br = (112*ff + br*(RG_MAGIC_1024-ff))/RG_MAGIC_1024
300 bg = (105*ff + bg*(RG_MAGIC_1024-ff))/RG_MAGIC_1024
301 bb = ( 96*ff + bb*(RG_MAGIC_1024-ff))/RG_MAGIC_1024
302 }
303 fb[p] = br + bg*256 + bb*RG_MAGIC_65536
304 zb[p] = RG_MAGIC_2000000000
305 p = p + 1
306 }
307
308 // ---- raster with per-vertex FORWARD KINEMATICS up the joint chain ----
309 let vx: *i64 = sys_mmap(64) as *i64
310 let vy: *i64 = sys_mmap(64) as *i64
311 let vz: *i64 = sys_mmap(64) as *i64
312 let nxa: *i64 = sys_mmap(64) as *i64
313 let nya: *i64 = sys_mmap(64) as *i64
314 let nza: *i64 = sys_mmap(64) as *i64
315 t = 0
316 while t < ntris {
317 let L: i64 = rg_rdbits(mb, lidBase+t*4) & 255
318 let ob: i64 = triBase + t*84
319 var v: i64 = 0
320 while v < 3 {
321 var px1: i64 = rg_f32mul(mb,ob+v*12,1)-cx0
322 var py1: i64 = rg_f32mul(mb,ob+v*12+4,1)-cy0
323 var pz1: i64 = rg_f32mul(mb,ob+v*12+8,1)-cz0
324 var qx: i64 = rg_f32mul(mb,ob+36+v*12,RG_MAGIC_16384)
325 var qy: i64 = rg_f32mul(mb,ob+40+v*12,RG_MAGIC_16384)
326 var qz: i64 = rg_f32mul(mb,ob+44+v*12,RG_MAGIC_16384)
327 // walk self -> root, applying each hinge about its pivot (sagittal, about X)
328 var cur: i64 = L
329 var guard: i64 = 0
330 while guard < 8 {
331 if cur < 0 { guard = 8 } else {
332 let d: i64 = thD[cur]
333 if d != 0 {
334 let sc: i64 = sinT[d]
335 let cc: i64 = sinT[rg_wrap(d+90)]
336 let dy: i64 = py1 - pvY[cur]; let dz: i64 = pz1 - pvZ[cur]
337 py1 = (dy*cc - dz*sc)/RG_MAGIC_16384 + pvY[cur]
338 pz1 = (dy*sc + dz*cc)/RG_MAGIC_16384 + pvZ[cur]
339 let ny2: i64 = (qy*cc - qz*sc)/RG_MAGIC_16384
340 let nz2: i64 = (qy*sc + qz*cc)/RG_MAGIC_16384
341 qy = ny2; qz = nz2
342 }
343 cur = par[cur]
344 guard = guard + 1
345 }
346 }
347 vx[v]=px1; vy[v]=py1+rootY/RG_Q8; vz[v]=pz1; nxa[v]=qx; nya[v]=qy; nza[v]=qz
348 v = v + 1
349 }
350 let d0: i64 = dist - vz[0]; let d1: i64 = dist - vz[1]; let d2: i64 = dist - vz[2]
351 if d0>0 { if d1>0 { if d2>0 {
352 let sx0: i64=cxh+(vx[0]*FOCAL)/d0; let sy0: i64=cyh-(vy[0]*FOCAL)/d0
353 let sx1: i64=cxh+(vx[1]*FOCAL)/d1; let sy1: i64=cyh-(vy[1]*FOCAL)/d1
354 let sx2: i64=cxh+(vx[2]*FOCAL)/d2; let sy2: i64=cyh-(vy[2]*FOCAL)/d2
355 var area: i64 = (sx1-sx0)*(sy2-sy0)-(sx2-sx0)*(sy1-sy0)
356 if area != 0 {
357 var sgn: i64 = 1
358 if area < 0 { sgn = 0-1 }
359 let aabs: i64 = area*sgn
360 let cr: i64=rg_f32mul(mb,ob+72,255); let cg: i64=rg_f32mul(mb,ob+76,255); let cbb: i64=rg_f32mul(mb,ob+80,255)
361 var bxmn: i64=rg_max(0, rg_min(sx0, rg_min(sx1,sx2)))
362 var bxmx: i64=rg_min(W-1, rg_max(sx0, rg_max(sx1,sx2)))
363 var bymn: i64=rg_max(0, rg_min(sy0, rg_min(sy1,sy2)))
364 var bymx: i64=rg_min(H-1, rg_max(sy0, rg_max(sy1,sy2)))
365 var yy: i64 = bymn
366 while yy <= bymx {
367 var xx: i64 = bxmn
368 while xx <= bxmx {
369 let e0: i64=((sx2-sx1)*(yy-sy1)-(sy2-sy1)*(xx-sx1))*sgn
370 let e1: i64=((sx0-sx2)*(yy-sy2)-(sy0-sy2)*(xx-sx2))*sgn
371 let e2: i64=((sx1-sx0)*(yy-sy0)-(sy1-sy0)*(xx-sx0))*sgn
372 if e0>=0 { if e1>=0 { if e2>=0 {
373 let dep: i64=(e0*d0+e1*d1+e2*d2)/aabs
374 let idx: i64=yy*W+xx
375 if dep < zb[idx] {
376 var nx1: i64=(e0*nxa[0]+e1*nxa[1]+e2*nxa[2])/aabs
377 var ny1: i64=(e0*nya[0]+e1*nya[1]+e2*nya[2])/aabs
378 var nz1: i64=(e0*nza[0]+e1*nza[1]+e2*nza[2])/aabs
379 var nl: i64=rg_isqrt(nx1*nx1+ny1*ny1+nz1*nz1)
380 if nl<1 {nl=1}
381 nx1=nx1*RG_MAGIC_16384/nl; ny1=ny1*RG_MAGIC_16384/nl; nz1=nz1*RG_MAGIC_16384/nl
382 if nz1<0 { nx1=0-nx1; ny1=0-ny1; nz1=0-nz1 }
383 let da: i64=rg_max(0,(nx1*l1x+ny1*l1y+nz1*l1z)/RG_MAGIC_16384)
384 let db: i64=rg_max(0,(nx1*l2x+ny1*l2y+nz1*l2z)/RG_MAGIC_16384)
385 var lit: i64=225 + 676*da/RG_MAGIC_16384 + 256*db/RG_MAGIC_16384
386 if lit>RG_MAGIC_1280 { lit=RG_MAGIC_1280 }
387 var rr: i64=cr*lit/RG_MAGIC_1024
388 var gg: i64=cg*lit/RG_MAGIC_1024
389 var bb2: i64=cbb*lit/RG_MAGIC_1024
390 if rr>255 {rr=255} if gg>255 {gg=255} if bb2>255 {bb2=255}
391 zb[idx]=dep; fb[idx]=rr+gg*256+bb2*RG_MAGIC_65536
392 }
393 }}}
394 xx = xx + 1
395 }
396 yy = yy + 1
397 }
398 }
399 }}}
400 t = t + 1
401 }
402
403 // frame checksum (order-sensitive) = the determinism witness
404 var ck: i64 = 0
405 var c2: i64 = 0
406 while c2 < npx { ck = (ck*31 + fb[c2]) & RG_MAGIC_2000000000; c2 = c2 + 3 }
407
408 let path: *u8 = sys_mmap(256)
409 var pi: i64 = 0
410 while pref[pi]!=(0 as u8) { path[pi]=pref[pi]; pi=pi+1 }
411 path[pi]=(48+f) as u8; pi=pi+1
412 path[pi]=46 as u8; path[pi+1]=112 as u8; path[pi+2]=110 as u8; path[pi+3]=103 as u8; path[pi+4]=0 as u8
413 write_png(fb, W, H, path)
414
415 if f>0 { rg_hw("," as *u8) }
416 rg_hw("{\x22f\x22:" as *u8); rg_pn(f)
417 rg_hw(",\x22shoulder\x22:" as *u8); rg_pn(th[5]/1000)
418 rg_hw(",\x22spine\x22:" as *u8); rg_pn(th[1]/1000)
419 rg_hw(",\x22neck\x22:" as *u8); rg_pn(th[0]/1000)
420 rg_hw(",\x22hip\x22:" as *u8); rg_pn(th[7]/1000)
421 rg_hw(",\x22knee\x22:" as *u8); rg_pn(th[8]/1000)
422 rg_hw(",\x22rootY\x22:" as *u8); rg_pn(rootY/RG_Q8)
423 rg_hw(",\x22rootV\x22:" as *u8); rg_pn(rootV/RG_Q8)
424 rg_hw(",\x22contacts\x22:" as *u8); rg_pn(contacts)
425 rg_hw(",\x22worst_penetration\x22:" as *u8); rg_pn(worstPen/RG_Q8)
426 rg_hw(",\x22ck\x22:" as *u8); rg_pn(ck); rg_hw("}" as *u8)
427 f = f + 1
428 }
429 rg_hw("]}\n" as *u8)
430 return 0
431}