nx_fbx_rig.nx source
↩ module page · 182 lines · 7158 B
1// nx_fbx_rig.nx -- RIG SURVEY: verified-facts instrument for the SKEL/SKIN/ANIM fill.
2// Walks a binary FBX and inventories the rig: Model/LimbNode counts (joints), Deformer
3// Skin/Cluster counts, Indexes/Weights array totals, Connections, AnimationCurve counts,
4// KeyTime totals -- and prints the first joint names. NOTHING is emitted yet: this is the
5// query-before-design step (agent prompts and format emitters get MEASURED facts, not guesses).
6// usage: nx_fbx_rig <file.fbx>
7// license_tier: ORIGINAL
8import "nx_syscalls.nx"
9const K_MAGIC_7500: i64 = 7500
10const K_MAGIC_500000: i64 = 500000
11
12func frw(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 }
13func frn(v: i64) -> i64 {
14 let t: *u8 = sys_mmap(32) as *u8
15 var m: i64 = v; var w: i64 = 0
16 if m<0 { t[w]=45 as u8; w=w+1; m=0-m }
17 if m==0 { t[w]=48 as u8; sys_write(1,t,w+1); return 0 }
18 let d: *u8 = sys_mmap(32) as *u8
19 var k: i64=0
20 while m>0 { d[k]=(48+(m%10)) as u8; m=m/10; k=k+1 }
21 var j: i64=0
22 while j<k { t[w]=d[k-1-j]; w=w+1; j=j+1 }
23 sys_write(1,t,w); return 0
24}
25func fr_u32(b: *u8, o: i64) -> i64 {
26 return ((b[o] & 0xff) as i64) | (((b[o+1] & 0xff) as i64) << 8)
27 | (((b[o+2] & 0xff) as i64) << 16) | (((b[o+3] & 0xff) as i64) << 24)
28}
29func fr_u64(b: *u8, o: i64) -> i64 { return fr_u32(b, o) | (fr_u32(b, o + 4) << 32) }
30
31// stats: 0=Model 1=LimbNode 2=Skin 3=Cluster 4=IndexesElems 5=WeightsElems 6=Conns
32// 7=AnimCurveNode 8=AnimCurve 9=KeyTimeElems 10=TransformArrays 11=jointNamesPrinted
33func fr_walk(b: *u8, flen: i64, off0: i64, big: i64, st: *i64) -> i64 {
34 var off: i64 = off0
35 var endo: i64 = 0
36 var nprops: i64 = 0
37 var plen: i64 = 0
38 var nlen: i64 = 0
39 var p: i64 = 0
40 if big == 1 {
41 endo = fr_u64(b, off)
42 nprops = fr_u64(b, off + 8)
43 plen = fr_u64(b, off + 16)
44 nlen = (b[off + 24] & 0xff) as i64
45 p = off + 25
46 }
47 if big == 0 {
48 endo = fr_u32(b, off)
49 nprops = fr_u32(b, off + 4)
50 plen = fr_u32(b, off + 8)
51 nlen = (b[off + 12] & 0xff) as i64
52 p = off + 13
53 }
54 if endo == 0 { return off }
55 if endo > flen { return flen }
56 // classify the node by name
57 var kind: i64 = 0
58 if nlen == 5 { if (b[p]&0xff)==77 { if (b[p+4]&0xff)==108 { kind = 1 } } } // Model
59 if nlen == 8 { if (b[p]&0xff)==68 { if (b[p+7]&0xff)==114 { kind = 2 } } } // Deformer
60 if nlen == 7 {
61 if (b[p]&0xff)==73 { if (b[p+6]&0xff)==115 { kind = 3 } } // Indexes
62 if (b[p]&0xff)==87 { if (b[p+6]&0xff)==115 { kind = 4 } } // Weights
63 if (b[p]&0xff)==75 { if (b[p+6]&0xff)==101 { kind = 5 } } // KeyTime
64 }
65 if nlen == 1 { if (b[p]&0xff)==67 { kind = 6 } } // C
66 if nlen == 18 { if (b[p]&0xff)==65 { if (b[p+17]&0xff)==101 { kind = 7 } } } // AnimationCurveNode
67 if nlen == 14 { if (b[p]&0xff)==65 { if (b[p+13]&0xff)==101 { kind = 8 } } } // AnimationCurve
68 if nlen == 9 { if (b[p]&0xff)==84 { if (b[p+8]&0xff)==109 { kind = 9 } } } // Transform
69 p = p + nlen
70 let pstart: i64 = p
71 // walk props; capture 2nd/3rd S-prop offsets+lens for Model/Deformer subtype checks
72 var s2o: i64 = 0
73 var s2l: i64 = 0
74 var s3o: i64 = 0
75 var s3l: i64 = 0
76 var sseen: i64 = 0
77 var pi: i64 = 0
78 var stop: i64 = 0
79 while pi < nprops {
80 if stop == 0 {
81 let t: i64 = (b[p] & 0xff) as i64
82 p = p + 1
83 var adv: i64 = 0 - 1
84 if t == 83 {
85 let l: i64 = fr_u32(b, p)
86 sseen = sseen + 1
87 if sseen == 1 { s2o = p + 4; s2l = l }
88 if sseen == 2 { s3o = p + 4; s3l = l }
89 adv = 4 + l
90 }
91 if t == 82 { adv = 4 + fr_u32(b, p) }
92 if t == 89 { adv = 2 }
93 if t == 67 { adv = 1 }
94 if t == 73 { adv = 4 }
95 if t == 70 { adv = 4 }
96 if t == 68 { adv = 8 }
97 if t == 76 { adv = 8 }
98 var isarr: i64 = 0
99 if t == 100 { isarr = 1 }
100 if t == 102 { isarr = 1 }
101 if t == 108 { isarr = 1 }
102 if t == 105 { isarr = 1 }
103 if t == 98 { isarr = 1 }
104 if isarr == 1 {
105 let alen: i64 = fr_u32(b, p)
106 let clen: i64 = fr_u32(b, p + 8)
107 if kind == 3 { st[4] = st[4] + alen }
108 if kind == 4 { st[5] = st[5] + alen }
109 if kind == 5 { st[9] = st[9] + alen }
110 if kind == 9 { st[10] = st[10] + alen }
111 adv = 12 + clen
112 }
113 if adv < 0 { stop = 1 }
114 if adv >= 0 { p = p + adv }
115 }
116 pi = pi + 1
117 }
118 if kind == 1 {
119 st[0] = st[0] + 1
120 // Model props: [L id][S name][S class] -- class is the 2nd S (s3), "LimbNode" = a joint
121 if s3l == 8 { if (b[s3o]&0xff)==76 { if (b[s3o+7]&0xff)==101 {
122 st[1] = st[1] + 1
123 if st[11] < 8 { if s2l > 0 { if s2l < 64 {
124 frw(" joint: " as *u8)
125 var q: i64 = 0
126 while q < s2l { if (b[s2o+q]&0xff) != 0 { if (b[s2o+q]&0xff) != 1 { sys_write(1, ((b as i64)+s2o+q) as *u8, 1) } } q = q + 1 }
127 frw("\n" as *u8)
128 st[11] = st[11] + 1
129 } } }
130 } } }
131 }
132 if kind == 2 {
133 if s3l == 4 { st[2] = st[2] + 1 }
134 if s3l == 7 { st[3] = st[3] + 1 }
135 }
136 if kind == 6 { st[6] = st[6] + 1 }
137 if kind == 7 { st[7] = st[7] + 1 }
138 if kind == 8 { st[8] = st[8] + 1 }
139 p = pstart + plen
140 var sent: i64 = 13
141 if big == 1 { sent = 25 }
142 while p < endo - sent {
143 p = fr_walk(b, flen, p, big, st)
144 if p >= flen { return flen }
145 }
146 return endo
147}
148
149func main(argc: i64, argv: *i64) -> i64 {
150 if argc < 2 { frw("usage: nx_fbx_rig <file.fbx>\n" as *u8); return 2 }
151 let lp: *i64 = sys_mmap(16) as *i64
152 let b: *u8 = sys_map_file(argv[1] as *u8, lp)
153 let flen: i64 = lp[0]
154 if flen < 64 { frw("unreadable\n" as *u8); return 3 }
155 let ver: i64 = fr_u32(b, 23)
156 var big: i64 = 0
157 if ver >= K_MAGIC_7500 { big = 1 }
158 frw("FBX ver=" as *u8); frn(ver); frw("\n" as *u8)
159 let st: *i64 = sys_mmap(128) as *i64
160 var pos: i64 = 27
161 var guard: i64 = 0
162 while pos < flen - 200 {
163 if guard > K_MAGIC_500000 { break }
164 let e: i64 = fr_walk(b, flen, pos, big, st)
165 if e <= pos { break }
166 pos = e
167 guard = guard + 1
168 }
169 frw("models=" as *u8); frn(st[0])
170 frw(" limbnodes=" as *u8); frn(st[1])
171 frw(" skins=" as *u8); frn(st[2])
172 frw(" clusters=" as *u8); frn(st[3])
173 frw("\nindexes_elems=" as *u8); frn(st[4])
174 frw(" weights_elems=" as *u8); frn(st[5])
175 frw(" transform_elems=" as *u8); frn(st[10])
176 frw("\nconnections=" as *u8); frn(st[6])
177 frw(" anim_curve_nodes=" as *u8); frn(st[7])
178 frw(" anim_curves=" as *u8); frn(st[8])
179 frw(" keytime_elems=" as *u8); frn(st[9])
180 frw("\nRIG-SURVEY DONE\n" as *u8)
181 return 0
182}