code wiki / _hdl_build / nx_gltf_anim_gate.nx
nx_gltf_anim_gate.nx source
↩ module page · 80 lines · 4558 B
1// nx_gltf_anim_gate.nx -- ★export the being as a SKINNED, WALKING .glb. Mesh the skin, bind each vertex to its nearest
2// part's deepest FK bone, export with a walk-cycle animation, self-verify the container + names. Writes nishi_being_walk.glb.
3// license_tier: ORIGINAL expect_exit: 0
4import "nx_syscalls.nx"
5import "nx_trimesh.nx"
6import "nx_isosurf.nx"
7import "nx_bodyatlas.nx"
8import "nx_gltf_anim.nx"
9
10func hw(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 }
11func pn(v: i64) -> i64 { let b: *u8=sys_mmap(32) as *u8; var x: i64=v; var ng: i64=0; if x<0{ng=1;x=0-x} var i: i64=31; if x==0{b[i]=48 as u8;i=i-1} while x>0{b[i]=(48+x%10) as u8;x=x/10;i=i-1} if ng==1{b[i]=45 as u8;i=i-1} sys_write(1,(b as i64+i+1) as *u8,31-i); return 0 }
12func ru32(buf: *u8, at: i64) -> i64 { return (buf[at] as i64) + ((buf[at+1] as i64)<<8) + ((buf[at+2] as i64)<<16) + ((buf[at+3] as i64)<<24) }
13func hasstr(buf: *u8, n: i64, needle: *u8) -> i64 { var m: i64=0; while needle[m]!=(0 as u8){m=m+1} var i: i64=0; while i+m<=n { var k: i64=0; while k<m { if buf[i+k]!=needle[k] {k=m+9} else {k=k+1} } if k==m {return 1} i=i+1 } return 0 }
14
15const GX: i64 = 32
16const GY: i64 = 110
17const GZ: i64 = 20
18const GC: i64 = 18
19const OX: i64 = 0-288
20const OY: i64 = 0-990
21const OZ: i64 = 0-180
22
23func main() -> i64 {
24 hw("=== nx_gltf_anim_gate -- skinned WALKING being -> .glb ===\n" as *u8)
25 var fails: i64 = 0
26 atlas_build(0)
27 let grid: *i64 = sys_mmap((GX+1)*(GY+1)*(GZ+1)*8) as *i64
28 var i: i64 = 0
29 while i <= GX { var jj: i64=0; while jj<=GY { var k: i64=0; while k<=GZ { grid[(i*(GY+1)+jj)*(GZ+1)+k] = ba_sdf(OX+i*GC, OY+jj*GC, OZ+k*GC, 1); k=k+1 } jj=jj+1 } i=i+1 }
30 tm_reset()
31 surface_nets(grid, GX, GY, GZ, OX, OY, OZ, GC, 0, 216+172*256+152*65536)
32 let NV: i64 = tm_nv()
33 // per-vertex joint + colour, from nearest part
34 let jarr: *i64 = sys_mmap(NV*8) as *i64
35 let vp: *i64 = sys_mmap(24) as *i64
36 let jc: *i64 = sys_mmap(9*8) as *i64
37 var b: i64 = 0
38 while b < 9 { jc[b]=0; b=b+1 }
39 i = 0
40 while i < NV {
41 tm_vpos(i, vp)
42 let kk: i64 = ba_nearest(vp[0], vp[1], vp[2], 1)
43 var jt: i64 = 0
44 if kk >= 0 { jt = ba_part_bone(kk); tm_vcol(i, ba_part_color(kk)) } else { tm_vcol(i, 216+172*256+152*65536) }
45 jarr[i] = jt
46 jc[jt] = jc[jt] + 1
47 i = i + 1
48 }
49 hw(" verts="); pn(NV); hw(" joint spread root="); pn(jc[0]); hw(" Lsh="); pn(jc[1]); hw(" Lel="); pn(jc[2]); hw(" Rsh="); pn(jc[3]); hw(" Lhip="); pn(jc[5]); hw(" Lkn="); pn(jc[6]); hw("\n" as *u8)
50 var t0: i64 = 0
51 if jc[1] > 20 { if jc[5] > 20 { if jc[6] > 20 { t0 = 1 } } } // limbs actually got bound to bones
52 if t0 == 1 { hw("T0 PASS vertices bound across the FK bones (arms + legs rigged)\n" as *u8) } else { fails=fails+1; hw("T0 FAIL binding\n" as *u8) }
53
54 let out: *u8 = sys_mmap(8388608)
55 let total: i64 = gltf_anim_export(out, jarr)
56 hw(" glb bytes="); pn(total); hw("\n" as *u8)
57 // self-verify container + rigging/animation presence
58 var t1: i64 = 0
59 if (out[0] as i64)==103 { if ru32(out,8)==total { t1=1 } }
60 if t1 == 1 { hw("T1 PASS glTF header + length\n" as *u8) } else { fails=fails+1; hw("T1 FAIL\n" as *u8) }
61 let jsonLen: i64 = ru32(out,12)
62 let binLenPos: i64 = 20+jsonLen
63 let binLen: i64 = ru32(out,binLenPos)
64 var t2: i64 = 0
65 if (12+8+jsonLen+8+binLen)==total { if (out[binLenPos+4] as i64)==66 { t2=1 } }
66 if t2 == 1 { hw("T2 PASS chunk arithmetic + BIN type\n" as *u8) } else { fails=fails+1; hw("T2 FAIL\n" as *u8) }
67 var t3: i64 = 0
68 if hasstr(out,20+jsonLen,"animations"as *u8)==1 { if hasstr(out,20+jsonLen,"skins"as *u8)==1 { if hasstr(out,20+jsonLen,"JOINTS_0"as *u8)==1 { if hasstr(out,20+jsonLen,"\"walk\""as *u8)==1 { t3=1 } } } }
69 if t3 == 1 { hw("T3 PASS JSON declares skin + JOINTS_0 + a 'walk' animation\n" as *u8) } else { fails=fails+1; hw("T3 FAIL\n" as *u8) }
70
71 let fd: i64 = sys_openat_wr("knowledge/nishi_being_walk.glb\x00" as *u8, 0x1a4)
72 sys_write(fd, out, total)
73 sys_close(fd)
74 hw("wrote knowledge/nishi_being_walk.glb ("); pn(total); hw(" bytes)\n" as *u8)
75
76 if fails == 0 { hw("GLTF-ANIM-GATE GREEN -- the being exports as a SKINNED, WALKING .glb (11-joint rig: 9 FK bones + 2 ankle calf-landmarks, walk-cycle quaternion keyframes). Plays in any glTF viewer. Residual: skinning in our own web viewer (next).\n" as *u8); sys_exit(0); return 0 }
77 hw("GLTF-ANIM-GATE RED fails="); pn(fails); hw("\n" as *u8)
78 sys_exit(1)
79 return 1
80}