code wiki / (root) / nx_nxa_skin.nx

nx_nxa_skin.nx source

↩ module page · 950 lines · 37119 B

1// nx_nxa_skin.nx -- RIG IMPORTER: fills the NXA's SKEL + SKIN sections from a binary FBX. 2// Walks the FBX id-graph (Model/LimbNode joints, Deformer Clusters with Indexes/Weights/ 3// TransformLink bind matrices, the Connections table) and emits a 5-section NXA: 4// VERT/TRIS/CLUS copied from the mesh import, SKEL = joints [parent][t mm][quat q12=identity] 5// (delta-LBS convention: animation is applied RELATIVE to bind, so identity bind quats are 6// exact), SKIN = per-vertex top-4 joints + q12 weights normalized to sum 4096. 7// usage: nx_nxa_skin <in.fbx> <in.nxa> <out.nxa> 8// license_tier: ORIGINAL 9import "nx_syscalls.nx" 10import "nx_zlib_wrap.nx" 11import "nx_nxa.nx" 12import "nx_nxa_fk.nx" 13const G_MAGIC_20000: i64 = 20000 14const G_MAGIC_2047: i64 = 2047 15const G_MAGIC_1048575: i64 = 1048575 16const G_MAGIC_4503599627370496: i64 = 4503599627370496 17const G_MAGIC_4090: i64 = 4090 18const G_MAGIC_99990: i64 = 99990 19const G_MAGIC_4096: i64 = 4096 20const G_MAGIC_7500: i64 = 7500 21const G_MAGIC_500000: i64 = 500000 22const G_MAGIC_4611686018427387903: i64 = 4611686018427387903 23 24// G layout (word offsets): 0=mcount 1=ccount 2=conncount 3=bestVertAlen 4=bestGeomId 5=skincount 25const G_MO: i64 = 16 // model ids x4096 26const G_LO: i64 = 4112 // limb flags x4096 27const G_CID: i64 = 8208 // cluster ids x512 28const G_CIX: i64 = 8720 // cluster Indexes meta (off,alen,enc,clen) x512x4 29const G_CW: i64 = 10768 // cluster Weights meta x512x4 30const G_CT: i64 = 12816 // cluster TransformLink meta x512x4 31const G_CONN: i64 = 14864 // connection pairs (src,dst) x100000x2 32const G_SID: i64 = 214864 // Skin deformer ids x64 33const G_PR: i64 = 216000 // per-model PreRotation millideg x3 34const G_LR: i64 = 228288 // per-model Lcl Rotation default millideg x3 35const G_LT: i64 = 240576 // per-model Lcl Translation default units x3 36const G_PF: i64 = 252864 // per-model flags: 1=pre 2=lclrot 4=lclt 37const G_WORDS: i64 = 258000 38 39func skw(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 } 40func skn(v: i64) -> i64 { 41 let t: *u8 = sys_mmap(32) as *u8 42 var m: i64 = v; var w: i64 = 0 43 if m<0 { t[w]=45 as u8; w=w+1; m=0-m } 44 if m==0 { t[w]=48 as u8; sys_write(1,t,w+1); return 0 } 45 let d: *u8 = sys_mmap(32) as *u8 46 var k: i64=0 47 while m>0 { d[k]=(48+(m%10)) as u8; m=m/10; k=k+1 } 48 var j: i64=0 49 while j<k { t[w]=d[k-1-j]; w=w+1; j=j+1 } 50 sys_write(1,t,w); return 0 51} 52func sk_u32(b: *u8, o: i64) -> i64 { 53 return ((b[o] & 0xff) as i64) | (((b[o+1] & 0xff) as i64) << 8) 54 | (((b[o+2] & 0xff) as i64) << 16) | (((b[o+3] & 0xff) as i64) << 24) 55} 56func sk_u64(b: *u8, o: i64) -> i64 { return sk_u32(b, o) | (sk_u32(b, o + 4) << 32) } 57// IEEE754 double -> value x scale (scale=1000 for mm, 4096 for q12 weights). DRY debt vs 58// nx_fbx_measure's copy -- extract to a shared nx_f64.nx when the third user appears. 59func sk_f64(b: *u8, o: i64, scale: i64) -> i64 { 60 let lo: i64 = sk_u32(b, o) 61 let hi: i64 = sk_u32(b, o + 4) 62 let sign: i64 = (hi >> 31) & 1 63 let expo: i64 = (hi >> 20) & G_MAGIC_2047 64 if expo == 0 { return 0 } 65 var mant: i64 = ((hi & G_MAGIC_1048575) << 32) | lo 66 mant = mant | G_MAGIC_4503599627370496 67 let sh: i64 = expo - 1023 68 var v: i64 = 0 69 if sh >= 52 { v = mant * scale * (1 << (sh - 52)) } 70 if sh < 52 { 71 let rs: i64 = 52 - sh 72 if rs > 62 { return 0 } 73 v = (mant * scale) >> rs 74 } 75 if sign == 1 { return 0 - v } 76 return v 77} 78 79// recursive walk; ctx = current Cluster index (child arrays attach to it) or -1; 80// gctx = current Geometry node id (Vertices children identify OUR mesh's geometry) or 0 81func sk_walk(b: *u8, flen: i64, off0: i64, big: i64, G: *i64, ctx: i64, gctx: i64, mctx: i64) -> i64 { 82 let off: i64 = off0 83 var endo: i64 = 0 84 var nprops: i64 = 0 85 var plen: i64 = 0 86 var nlen: i64 = 0 87 var p: i64 = 0 88 if big == 1 { 89 endo = sk_u64(b, off) 90 nprops = sk_u64(b, off + 8) 91 plen = sk_u64(b, off + 16) 92 nlen = (b[off + 24] & 0xff) as i64 93 p = off + 25 94 } 95 if big == 0 { 96 endo = sk_u32(b, off) 97 nprops = sk_u32(b, off + 4) 98 plen = sk_u32(b, off + 8) 99 nlen = (b[off + 12] & 0xff) as i64 100 p = off + 13 101 } 102 if endo == 0 { return off } 103 if endo > flen { return flen } 104 var kind: i64 = 0 105 if nlen == 5 { if (b[p]&0xff)==77 { if (b[p+4]&0xff)==108 { kind = 1 } } } // Model 106 if nlen == 8 { 107 if (b[p]&0xff)==68 { if (b[p+7]&0xff)==114 { kind = 2 } } // Deformer 108 if (b[p]&0xff)==71 { if (b[p+7]&0xff)==121 { kind = 7 } } // Geometry 109 if (b[p]&0xff)==86 { if (b[p+7]&0xff)==115 { kind = 8 } } // Vertices 110 } 111 if nlen == 7 { 112 if (b[p]&0xff)==73 { if (b[p+6]&0xff)==115 { kind = 3 } } // Indexes 113 if (b[p]&0xff)==87 { if (b[p+6]&0xff)==115 { kind = 4 } } // Weights 114 } 115 if nlen == 13 { if (b[p]&0xff)==84 { if (b[p+12]&0xff)==107 { kind = 5 } } } // TransformLink 116 if nlen == 1 { if (b[p]&0xff)==67 { kind = 6 } } // C 117 if nlen == 1 { if (b[p]&0xff)==80 { kind = 9 } } // P (Properties70) 118 p = p + nlen 119 let pstart: i64 = p 120 var id1: i64 = 0 121 var id2: i64 = 0 122 var lseen: i64 = 0 123 var s1l: i64 = 0 124 var s1o: i64 = 0 125 var s2l: i64 = 0 126 var s2o: i64 = 0 127 var sseen: i64 = 0 128 var dseen: i64 = 0 129 var dv1: i64 = 0 130 var dv2: i64 = 0 131 var dv3: i64 = 0 132 var arro: i64 = 0 133 var arrl: i64 = 0 134 var arre: i64 = 0 135 var arrc: i64 = 0 136 var pi: i64 = 0 137 var stop: i64 = 0 138 while pi < nprops { 139 if stop == 0 { 140 let t: i64 = (b[p] & 0xff) as i64 141 p = p + 1 142 var adv: i64 = 0 - 1 143 if t == 83 { 144 let l: i64 = sk_u32(b, p) 145 sseen = sseen + 1 146 if sseen == 1 { s1o = p + 4; s1l = l } 147 if sseen == 2 { s2o = p + 4; s2l = l } 148 adv = 4 + l 149 } 150 if t == 82 { adv = 4 + sk_u32(b, p) } 151 if t == 89 { adv = 2 } 152 if t == 67 { adv = 1 } 153 if t == 73 { adv = 4 } 154 if t == 70 { adv = 4 } 155 if t == 68 { 156 if dseen == 0 { dv1 = p } 157 if dseen == 1 { dv2 = p } 158 if dseen == 2 { dv3 = p } 159 dseen = dseen + 1 160 adv = 8 161 } 162 if t == 76 { 163 lseen = lseen + 1 164 if lseen == 1 { id1 = sk_u64(b, p) } 165 if lseen == 2 { id2 = sk_u64(b, p) } 166 adv = 8 167 } 168 var isarr: i64 = 0 169 if t == 100 { isarr = 1 } 170 if t == 102 { isarr = 1 } 171 if t == 108 { isarr = 1 } 172 if t == 105 { isarr = 1 } 173 if t == 98 { isarr = 1 } 174 if isarr == 1 { 175 arrl = sk_u32(b, p) 176 arre = sk_u32(b, p + 4) 177 arrc = sk_u32(b, p + 8) 178 arro = p + 12 179 adv = 12 + arrc 180 } 181 if adv < 0 { stop = 1 } 182 if adv >= 0 { p = p + adv } 183 } 184 pi = pi + 1 185 } 186 var childctx: i64 = ctx 187 var childg: i64 = gctx 188 var childm: i64 = mctx 189 if kind == 1 { if G[0] < G_MAGIC_4090 { 190 G[G_MO + G[0]] = id1 191 var lf: i64 = 0 192 if s2l == 8 { if (b[s2o]&0xff)==76 { if (b[s2o+7]&0xff)==101 { lf = 1 } } } 193 G[G_LO + G[0]] = lf 194 childm = G[0] 195 G[0] = G[0] + 1 196 } } 197 if kind == 2 { if s2l == 7 { if G[1] < 510 { 198 G[G_CID + G[1]] = id1 199 childctx = G[1] 200 G[1] = G[1] + 1 201 } } } 202 if kind == 2 { if s2l == 4 { if G[5] < 60 { 203 G[G_SID + G[5]] = id1 204 G[5] = G[5] + 1 205 } } } 206 if kind == 7 { childg = id1 } 207 if kind == 8 { if arrl > G[3] { G[3] = arrl; G[4] = gctx } } 208 if kind == 3 { if ctx >= 0 { 209 G[G_CIX + ctx*4] = arro 210 G[G_CIX + ctx*4 + 1] = arrl 211 G[G_CIX + ctx*4 + 2] = arre 212 G[G_CIX + ctx*4 + 3] = arrc 213 } } 214 if kind == 4 { if ctx >= 0 { 215 G[G_CW + ctx*4] = arro 216 G[G_CW + ctx*4 + 1] = arrl 217 G[G_CW + ctx*4 + 2] = arre 218 G[G_CW + ctx*4 + 3] = arrc 219 } } 220 if kind == 5 { if ctx >= 0 { 221 G[G_CT + ctx*4] = arro 222 G[G_CT + ctx*4 + 1] = arrl 223 G[G_CT + ctx*4 + 2] = arre 224 G[G_CT + ctx*4 + 3] = arrc 225 } } 226 if kind == 6 { if G[2] < G_MAGIC_99990 { 227 G[G_CONN + G[2]*2] = id1 228 G[G_CONN + G[2]*2 + 1] = id2 229 G[2] = G[2] + 1 230 } } 231 // Properties70 P entry under a Model: name = FIRST S prop; vector value = 3 D props. 232 // Matched by (len, first, last): PreRotation(11 P..n), Lcl Rotation(12 L..n), 233 // Lcl Translation(15 L..n). Angles degrees->millideg, translation units x1000. 234 if kind == 9 { if mctx >= 0 { if dseen >= 3 { 235 var pk: i64 = 0 236 if s1l == 11 { if (b[s1o]&0xff)==80 { if (b[s1o+10]&0xff)==110 { pk = 1 } } } 237 if s1l == 12 { if (b[s1o]&0xff)==76 { if (b[s1o+11]&0xff)==110 { pk = 2 } } } 238 if s1l == 15 { if (b[s1o]&0xff)==76 { if (b[s1o+14]&0xff)==110 { pk = 3 } } } 239 if pk == 1 { 240 G[G_PR + mctx*3] = sk_f64(b, dv1, 1000) 241 G[G_PR + mctx*3 + 1] = sk_f64(b, dv2, 1000) 242 G[G_PR + mctx*3 + 2] = sk_f64(b, dv3, 1000) 243 G[G_PF + mctx] = G[G_PF + mctx] | 1 244 } 245 if pk == 2 { 246 G[G_LR + mctx*3] = sk_f64(b, dv1, 1000) 247 G[G_LR + mctx*3 + 1] = sk_f64(b, dv2, 1000) 248 G[G_LR + mctx*3 + 2] = sk_f64(b, dv3, 1000) 249 G[G_PF + mctx] = G[G_PF + mctx] | 2 250 } 251 if pk == 3 { 252 G[G_LT + mctx*3] = sk_f64(b, dv1, 1000) 253 G[G_LT + mctx*3 + 1] = sk_f64(b, dv2, 1000) 254 G[G_LT + mctx*3 + 2] = sk_f64(b, dv3, 1000) 255 G[G_PF + mctx] = G[G_PF + mctx] | 4 256 } 257 } } } 258 p = pstart + plen 259 var sent: i64 = 13 260 if big == 1 { sent = 25 } 261 while p < endo - sent { 262 p = sk_walk(b, flen, p, big, G, childctx, childg, childm) 263 if p >= flen { return flen } 264 } 265 return endo 266} 267 268// inflate-or-raw helper for FBX arrays 269func sk_arr(b: *u8, off: i64, alen: i64, enc: i64, clen: i64, esz: i64) -> *u8 { 270 if enc == 0 { return ((b as i64) + off) as *u8 } 271 let zr: *NxZlibResult = nx_zlib_inflate(((b as i64) + off) as *u8, clen, alen*esz + G_MAGIC_4096) 272 if zr.error_code != 0 { return 0 as *u8 } 273 return zr.output_data 274} 275 276func main(argc: i64, argv: *i64) -> i64 { 277 if argc < 4 { skw("usage: nx_nxa_skin <in.fbx> <in.nxa> <out.nxa>\n" as *u8); return 2 } 278 let lpf: *i64 = sys_mmap(16) as *i64 279 let fb: *u8 = sys_map_file(argv[1] as *u8, lpf) 280 let flen: i64 = lpf[0] 281 if flen < 64 { skw("fbx unreadable\n" as *u8); return 3 } 282 let ver: i64 = sk_u32(fb, 23) 283 var big: i64 = 0 284 if ver >= G_MAGIC_7500 { big = 1 } 285 let G: *i64 = sys_mmap(G_WORDS*8) as *i64 286 var pos: i64 = 27 287 var guard: i64 = 0 288 while pos < flen - 200 { 289 if guard > G_MAGIC_500000 { break } 290 let e: i64 = sk_walk(fb, flen, pos, big, G, 0 - 1, 0, 0 - 1) 291 if e <= pos { break } 292 pos = e 293 guard = guard + 1 294 } 295 let mc: i64 = G[0] 296 let cc: i64 = G[1] 297 let nc: i64 = G[2] 298 let gid: i64 = G[4] 299 skw("models=" as *u8); skn(mc) 300 skw(" clusters=" as *u8); skn(cc) 301 skw(" conns=" as *u8); skn(nc) 302 skw(" skins=" as *u8); skn(G[5]); skw("\n" as *u8) 303 // OUR mesh only: valid Skins connect to the geometry that carries the LARGEST Vertices 304 // (the body we imported); clusters of other meshes index foreign control points and would 305 // stamp weights onto wrong vertices -- filter them out entirely. 306 let sval: *i64 = sys_mmap(64*8 + 64) as *i64 307 var sv0: i64 = 0 308 while sv0 < G[5] { 309 sval[sv0] = 0 310 var k9: i64 = 0 311 while k9 < nc { 312 if G[G_CONN + k9*2] == G[G_SID + sv0] { if G[G_CONN + k9*2 + 1] == gid { 313 sval[sv0] = 1 314 k9 = nc 315 } } 316 k9 = k9 + 1 317 } 318 sv0 = sv0 + 1 319 } 320 // cluster validity: cluster -> (valid Skin) 321 let cval: *i64 = sys_mmap(cc*8 + 64) as *i64 322 var cv0: i64 = 0 323 while cv0 < cc { 324 cval[cv0] = 0 325 var k8: i64 = 0 326 while k8 < nc { 327 if G[G_CONN + k8*2] == G[G_CID + cv0] { 328 let d8: i64 = G[G_CONN + k8*2 + 1] 329 var s8: i64 = 0 330 while s8 < G[5] { 331 if G[G_SID + s8] == d8 { if sval[s8] == 1 { 332 cval[cv0] = 1 333 s8 = 64 334 k8 = nc 335 } } 336 s8 = s8 + 1 337 } 338 } 339 k8 = k8 + 1 340 } 341 cv0 = cv0 + 1 342 } 343 // joints = limb models in encounter order 344 let jmap: *i64 = sys_mmap(mc*8 + 64) as *i64 345 var nj: i64 = 0 346 var m0: i64 = 0 347 while m0 < mc { 348 jmap[m0] = 0 - 1 349 if G[G_LO + m0] == 1 { jmap[m0] = nj; nj = nj + 1 } 350 m0 = m0 + 1 351 } 352 // parent per joint via Connections (child -> parent) 353 let jpar: *i64 = sys_mmap(nj*8 + 64) as *i64 354 var j0: i64 = 0 355 while j0 < nj { jpar[j0] = 0 - 1; j0 = j0 + 1 } 356 var m1: i64 = 0 357 while m1 < mc { 358 if jmap[m1] >= 0 { 359 let myid: i64 = G[G_MO + m1] 360 var k: i64 = 0 361 while k < nc { 362 if G[G_CONN + k*2] == myid { 363 let dst: i64 = G[G_CONN + k*2 + 1] 364 var m2: i64 = 0 365 while m2 < mc { 366 if G[G_MO + m2] == dst { if jmap[m2] >= 0 { 367 jpar[jmap[m1]] = jmap[m2] 368 m2 = mc 369 k = nc 370 } } 371 m2 = m2 + 1 372 } 373 } 374 k = k + 1 375 } 376 } 377 m1 = m1 + 1 378 } 379 // cluster -> joint (Model(limb) --conn--> Cluster) + bind translation from TransformLink 380 let cjoint: *i64 = sys_mmap(cc*8 + 64) as *i64 381 let jbind: *i64 = sys_mmap(nj*24 + 64) as *i64 382 let jreal: *i64 = sys_mmap(nj*8 + 64) as *i64 383 var c0: i64 = 0 384 while c0 < cc { cjoint[c0] = 0 - 1; c0 = c0 + 1 } 385 var c1: i64 = 0 386 while c1 < cc { 387 let cid: i64 = G[G_CID + c1] 388 var k2: i64 = 0 389 while k2 < nc { 390 if G[G_CONN + k2*2 + 1] == cid { 391 let src: i64 = G[G_CONN + k2*2] 392 var m3: i64 = 0 393 while m3 < mc { 394 if G[G_MO + m3] == src { if jmap[m3] >= 0 { 395 cjoint[c1] = jmap[m3] 396 m3 = mc 397 k2 = nc 398 } } 399 m3 = m3 + 1 400 } 401 } 402 k2 = k2 + 1 403 } 404 // bind translation: TransformLink col-major elems 12,13,14 (joint->world at bind) 405 if cjoint[c1] >= 0 { if G[G_CT + c1*4 + 1] == 16 { 406 let tl: *u8 = sk_arr(fb, G[G_CT + c1*4], 16, G[G_CT + c1*4 + 2], G[G_CT + c1*4 + 3], 8) 407 if (tl as i64) != 0 { 408 let jj: i64 = cjoint[c1] 409 jbind[jj*3] = sk_f64(tl, 12*8, 1000) 410 jbind[jj*3+1] = sk_f64(tl, 13*8, 1000) 411 jbind[jj*3+2] = sk_f64(tl, 14*8, 1000) 412 jreal[jj] = 1 413 } 414 } } 415 c1 = c1 + 1 416 } 417 // v2: STATIC FK -> TRUE bind positions for ALL joints, replacing the old placeholder 418 // propagation (which parked unclustered joints on an ancestor; auto-skin against those 419 // degenerate segments mis-bound flesh -- shoulder shards under real per-joint mocap). 420 // Local = PreRotation x LclRotation chained down parents; non-limb ancestor Models 421 // compose into a per-root prefix. VALIDATED against the real cluster binds before use. 422 let mpar: *i64 = sys_mmap(mc*8 + 64) as *i64 423 var mp0: i64 = 0 424 while mp0 < mc { mpar[mp0] = 0 - 1; mp0 = mp0 + 1 } 425 var mp1: i64 = 0 426 while mp1 < mc { 427 let myid2: i64 = G[G_MO + mp1] 428 var kp: i64 = 0 429 while kp < nc { 430 if G[G_CONN + kp*2] == myid2 { 431 let dstp: i64 = G[G_CONN + kp*2 + 1] 432 var mp2: i64 = 0 433 while mp2 < mc { 434 if G[G_MO + mp2] == dstp { mpar[mp1] = mp2; mp2 = mc; kp = nc } 435 mp2 = mp2 + 1 436 } 437 } 438 kp = kp + 1 439 } 440 mp1 = mp1 + 1 441 } 442 let jmi: *i64 = sys_mmap(G_MAGIC_4096*8 + 64) as *i64 443 var mj0: i64 = 0 444 while mj0 < mc { 445 if jmap[mj0] >= 0 { jmi[jmap[mj0]] = mj0 } 446 mj0 = mj0 + 1 447 } 448 let scr: *i64 = sys_mmap(256) as *i64 449 let pq: *i64 = sys_mmap(nj*32 + 64) as *i64 450 let sq: *i64 = sys_mmap(nj*32 + 64) as *i64 451 var jq0: i64 = 0 452 while jq0 < nj { 453 let mi: i64 = jmi[jq0] 454 nf_eul2q(G[G_PR + mi*3], G[G_PR + mi*3 + 1], G[G_PR + mi*3 + 2], ((pq as i64) + jq0*32) as *i64, scr) 455 nf_eul2q(G[G_LR + mi*3], G[G_LR + mi*3 + 1], G[G_LR + mi*3 + 2], ((sq as i64) + jq0*32) as *i64, scr) 456 jq0 = jq0 + 1 457 } 458 let topo: *i64 = sys_mmap(nj*8 + 64) as *i64 459 let done: *i64 = sys_mmap(nj*8 + 64) as *i64 460 var tn: i64 = 0 461 var pass2: i64 = 0 462 while pass2 < nj { 463 if tn < nj { 464 var jp0: i64 = 0 465 while jp0 < nj { 466 if done[jp0] == 0 { 467 var ok: i64 = 0 468 if jpar[jp0] < 0 { ok = 1 } 469 if jpar[jp0] >= 0 { if done[jpar[jp0]] == 1 { ok = 1 } } 470 if ok == 1 { topo[tn] = jp0; tn = tn + 1; done[jp0] = 1 } 471 } 472 jp0 = jp0 + 1 473 } 474 } 475 pass2 = pass2 + 1 476 } 477 if tn != nj { skw("PARENT-CYCLE -- refusing\n" as *u8); return 7 } 478 let gqs: *i64 = sys_mmap(nj*32 + 64) as *i64 479 let gts: *i64 = sys_mmap(nj*24 + 64) as *i64 480 let lq: *i64 = sys_mmap(64) as *i64 481 let rv: *i64 = sys_mmap(64) as *i64 482 let prefq: *i64 = sys_mmap(nj*32 + 64) as *i64 483 let preft: *i64 = sys_mmap(nj*24 + 64) as *i64 484 let anc: *i64 = sys_mmap(32*8 + 64) as *i64 485 let aqq: *i64 = sys_mmap(64) as *i64 486 let bqq: *i64 = sys_mmap(64) as *i64 487 let tq2: *i64 = sys_mmap(64) as *i64 488 var jr0: i64 = 0 489 while jr0 < nj { 490 prefq[jr0*4] = 0 491 prefq[jr0*4+1] = 0 492 prefq[jr0*4+2] = 0 493 prefq[jr0*4+3] = G_MAGIC_4096 494 if jpar[jr0] < 0 { 495 var nanc: i64 = 0 496 var cm: i64 = mpar[jmi[jr0]] 497 var hops: i64 = 0 498 while cm >= 0 { 499 if nanc < 30 { anc[nanc] = cm; nanc = nanc + 1 } 500 cm = mpar[cm] 501 hops = hops + 1 502 if hops > 30 { cm = 0 - 1 } 503 } 504 var pi2: i64 = nanc - 1 505 while pi2 >= 0 { 506 let am: i64 = anc[pi2] 507 nf_eul2q(G[G_PR + am*3], G[G_PR + am*3 + 1], G[G_PR + am*3 + 2], aqq, scr) 508 nf_eul2q(G[G_LR + am*3], G[G_LR + am*3 + 1], G[G_LR + am*3 + 2], bqq, scr) 509 nf_qmul(aqq, bqq, tq2) 510 nf_qnorm(tq2) 511 nf_qrotv(((prefq as i64) + jr0*32) as *i64, G[G_LT + am*3], G[G_LT + am*3 + 1], G[G_LT + am*3 + 2], rv, scr) 512 preft[jr0*3] = preft[jr0*3] + rv[0] 513 preft[jr0*3+1] = preft[jr0*3+1] + rv[1] 514 preft[jr0*3+2] = preft[jr0*3+2] + rv[2] 515 nf_qmul(((prefq as i64) + jr0*32) as *i64, tq2, aqq) 516 nf_qnorm(aqq) 517 prefq[jr0*4] = aqq[0] 518 prefq[jr0*4+1] = aqq[1] 519 prefq[jr0*4+2] = aqq[2] 520 prefq[jr0*4+3] = aqq[3] 521 pi2 = pi2 - 1 522 } 523 } 524 jr0 = jr0 + 1 525 } 526 var ti9: i64 = 0 527 while ti9 < nj { 528 let j9: i64 = topo[ti9] 529 let mi9: i64 = jmi[j9] 530 nf_qmul(((pq as i64) + j9*32) as *i64, ((sq as i64) + j9*32) as *i64, lq) 531 nf_qnorm(lq) 532 let pj9: i64 = jpar[j9] 533 if pj9 < 0 { 534 nf_qmul(((prefq as i64) + j9*32) as *i64, lq, ((gqs as i64) + j9*32) as *i64) 535 nf_qnorm(((gqs as i64) + j9*32) as *i64) 536 nf_qrotv(((prefq as i64) + j9*32) as *i64, G[G_LT + mi9*3], G[G_LT + mi9*3 + 1], G[G_LT + mi9*3 + 2], rv, scr) 537 gts[j9*3] = preft[j9*3] + rv[0] 538 gts[j9*3+1] = preft[j9*3+1] + rv[1] 539 gts[j9*3+2] = preft[j9*3+2] + rv[2] 540 } 541 if pj9 >= 0 { 542 nf_qmul(((gqs as i64) + pj9*32) as *i64, lq, ((gqs as i64) + j9*32) as *i64) 543 nf_qnorm(((gqs as i64) + j9*32) as *i64) 544 nf_qrotv(((gqs as i64) + pj9*32) as *i64, G[G_LT + mi9*3], G[G_LT + mi9*3 + 1], G[G_LT + mi9*3 + 2], rv, scr) 545 gts[j9*3] = gts[pj9*3] + rv[0] 546 gts[j9*3+1] = gts[pj9*3+1] + rv[1] 547 gts[j9*3+2] = gts[pj9*3+2] + rv[2] 548 } 549 ti9 = ti9 + 1 550 } 551 var fkmax: i64 = 0 552 var fkvb: i64 = 0 553 var jv0: i64 = 0 554 while jv0 < nj { 555 if jreal[jv0] == 1 { 556 fkvb = fkvb + 1 557 var a9: i64 = 0 558 while a9 < 3 { 559 var d9: i64 = gts[jv0*3+a9] - jbind[jv0*3+a9] 560 if d9 < 0 { d9 = 0 - d9 } 561 if d9 > fkmax { fkmax = d9 } 562 a9 = a9 + 1 563 } 564 } 565 jv0 = jv0 + 1 566 } 567 skw("fk_validated=" as *u8); skn(fkvb) 568 skw(" fk_maxerr_units=" as *u8); skn(fkmax); skw("\n" as *u8) 569 if fkvb < 8 { skw("TOO-FEW-REAL-BINDS -- refusing FK bind replacement\n" as *u8); return 7 } 570 if fkmax > G_MAGIC_20000 { skw("FK-DIVERGES from cluster binds -- refusing\n" as *u8); return 7 } 571 var jb9: i64 = 0 572 while jb9 < nj { 573 jbind[jb9*3] = gts[jb9*3] 574 jbind[jb9*3+1] = gts[jb9*3+1] 575 jbind[jb9*3+2] = gts[jb9*3+2] 576 jb9 = jb9 + 1 577 } 578 // SKIN accumulation: top-4 (joint, weight q12) per vertex of the main mesh 579 let lpn: *i64 = sys_mmap(16) as *i64 580 let nb: *u8 = sys_map_file(argv[2] as *u8, lpn) 581 let nlen2: i64 = lpn[0] 582 let vwo: i64 = nxa_find(nb, nlen2, nxa_tag4("VERT" as *u8)) 583 if vwo < 0 { skw("in.nxa bad\n" as *u8); return 5 } 584 let two: i64 = nxa_find(nb, nlen2, nxa_tag4("TRIS" as *u8)) 585 if two < 0 { skw("in.nxa bad\n" as *u8); return 5 } 586 let cwo: i64 = nxa_find(nb, nlen2, nxa_tag4("CLUS" as *u8)) 587 let nh: *i64 = nb as *i64 588 let nv: i64 = nh[vwo] 589 let nt: i64 = nh[two] 590 var nclw: i64 = 0 591 if cwo >= 0 { nclw = 1 + nh[cwo]*10 } 592 let j4: *i64 = sys_mmap(nv*32 + 64) as *i64 593 let w4: *i64 = sys_mmap(nv*32 + 64) as *i64 594 let japp: *i64 = sys_mmap(nj*8 + 64) as *i64 595 var cvn: i64 = 0 596 var cvi: i64 = 0 597 var dbg: i64 = 0 598 while dbg < cc { 599 if cval[dbg] == 1 { cvn = cvn + 1; cvi = cvi + G[G_CIX + dbg*4 + 1] } 600 dbg = dbg + 1 601 } 602 skw("valid_clusters=" as *u8); skn(cvn) 603 skw(" their_index_elems=" as *u8); skn(cvi) 604 skw(" gid_vert_alen=" as *u8); skn(G[3]); skw("\n" as *u8) 605 var c2: i64 = 0 606 var applied: i64 = 0 607 while c2 < cc { 608 if cval[c2] == 1 { if cjoint[c2] >= 0 { if G[G_CIX + c2*4 + 1] > 0 { if G[G_CIX + c2*4 + 1] == G[G_CW + c2*4 + 1] { 609 let ni: i64 = G[G_CIX + c2*4 + 1] 610 let ia: *u8 = sk_arr(fb, G[G_CIX + c2*4], ni, G[G_CIX + c2*4 + 2], G[G_CIX + c2*4 + 3], 4) 611 let wa: *u8 = sk_arr(fb, G[G_CW + c2*4], ni, G[G_CW + c2*4 + 2], G[G_CW + c2*4 + 3], 8) 612 if (ia as i64) != 0 { if (wa as i64) != 0 { 613 let jj2: i64 = cjoint[c2] 614 var k3: i64 = 0 615 while k3 < ni { 616 let vi: i64 = sk_u32(ia, k3*4) 617 if vi < nv { 618 let wq: i64 = sk_f64(wa, k3*8, G_MAGIC_4096) 619 if wq > 0 { 620 // replace the smallest of the vertex's 4 slots if we beat it 621 var mslot: i64 = 0 622 var s: i64 = 1 623 while s < 4 { if w4[vi*4+s] < w4[vi*4+mslot] { mslot = s } s = s + 1 } 624 if wq > w4[vi*4+mslot] { 625 w4[vi*4+mslot] = wq 626 j4[vi*4+mslot] = jj2 627 japp[jj2] = japp[jj2] + 1 628 applied = applied + 1 629 } 630 } 631 } 632 k3 = k3 + 1 633 } 634 } } 635 } } } } 636 c2 = c2 + 1 637 } 638 // normalize each vertex to exact sum 4096; unskinned verts -> AUTO-SKIN to the nearest 639 // two clustered joints by inverse distance (authored weights only cover skin sub-regions 640 // in CC exports, and unrigged sculpts have none at all -- auto-fill makes every mesh posable) 641 let vx5: *i64 = ((nb as i64) + vwo*8 + 8) as *i64 642 // auto-skin candidates = ONLY bones that received AUTHORED cluster weight on OUR mesh. 643 // v2 regression caught by the name instrument: FK-true binds gave EYE/TONGUE bones real 644 // positions and nearest-segment auto-skin bound ~1600 FACE verts to an eyeball rotating 645 // 260deg in the mocap -- the "scapula shards" were the face. Organ bones whose clusters 646 // live on foreign meshes (eyes/tongue/teeth) drop out of japp by construction. 647 let jok: *i64 = sys_mmap(nj*8 + 64) as *i64 648 var jo0: i64 = 0 649 while jo0 < nj { 650 jok[jo0] = 0 651 if japp[jo0] > 0 { jok[jo0] = 1 } 652 jo0 = jo0 + 1 653 } 654 var skinned: i64 = 0 655 var autos: i64 = 0 656 var v0: i64 = 0 657 while v0 < nv { 658 let s0: i64 = w4[v0*4] + w4[v0*4+1] + w4[v0*4+2] + w4[v0*4+3] 659 if s0 == 0 { 660 var b1: i64 = 0 - 1 661 var b2j: i64 = 0 - 1 662 var d1: i64 = G_MAGIC_4611686018427387903 663 var d2: i64 = d1 664 var jn: i64 = 0 665 while jn < nj { 666 if jok[jn] == 1 { 667 // distance to the BONE SEGMENT (parent->joint), not the joint point -- 668 // point-distance bound mid-limb verts to the wrong bone = walk clipping 669 var ax: i64 = jbind[jn*3] 670 var ay: i64 = jbind[jn*3+1] 671 var az: i64 = jbind[jn*3+2] 672 let pj: i64 = jpar[jn] 673 var bxs: i64 = ax 674 var bys: i64 = ay 675 var bzs: i64 = az 676 if pj >= 0 { if jok[pj] == 1 { 677 bxs = jbind[pj*3] 678 bys = jbind[pj*3+1] 679 bzs = jbind[pj*3+2] 680 } } 681 let abx: i64 = (bxs - ax)/16 682 let aby: i64 = (bys - ay)/16 683 let abz: i64 = (bzs - az)/16 684 let vax: i64 = (vx5[v0*3] - ax)/16 685 let vay: i64 = (vx5[v0*3+1] - ay)/16 686 let vaz: i64 = (vx5[v0*3+2] - az)/16 687 let denom: i64 = abx*abx + aby*aby + abz*abz 688 var tq: i64 = 0 689 if denom > 0 { tq = (vax*abx + vay*aby + vaz*abz)*G_MAGIC_4096/denom } 690 if tq < 0 { tq = 0 } 691 if tq > G_MAGIC_4096 { tq = G_MAGIC_4096 } 692 let dx: i64 = vax - abx*tq/G_MAGIC_4096 693 let dy: i64 = vay - aby*tq/G_MAGIC_4096 694 let dz: i64 = vaz - abz*tq/G_MAGIC_4096 695 let dd: i64 = dx*dx + dy*dy + dz*dz 696 if dd < d1 { d2 = d1; b2j = b1; d1 = dd; b1 = jn } 697 if dd >= d1 { if dd < d2 { d2 = dd; b2j = jn } } 698 } 699 jn = jn + 1 700 } 701 if b1 >= 0 { 702 if b2j >= 0 { 703 // inverse-distance split over the two nearest bones (d in squared space) 704 let wsum: i64 = d1 + d2 705 var wa: i64 = G_MAGIC_4096*d2/wsum 706 if wa > G_MAGIC_4096 { wa = G_MAGIC_4096 } 707 j4[v0*4] = b1 708 w4[v0*4] = wa 709 j4[v0*4+1] = b2j 710 w4[v0*4+1] = G_MAGIC_4096 - wa 711 } 712 if b2j < 0 { 713 j4[v0*4] = b1 714 w4[v0*4] = G_MAGIC_4096 715 } 716 autos = autos + 1 717 } 718 if b1 < 0 { 719 j4[v0*4] = 0 720 w4[v0*4] = G_MAGIC_4096 721 } 722 } 723 if s0 > 0 { 724 skinned = skinned + 1 725 var acc: i64 = 0 726 var s1: i64 = 0 727 while s1 < 3 { 728 let nw: i64 = w4[v0*4+s1]*G_MAGIC_4096/s0 729 w4[v0*4+s1] = nw 730 acc = acc + nw 731 s1 = s1 + 1 732 } 733 w4[v0*4+3] = G_MAGIC_4096 - acc 734 } 735 v0 = v0 + 1 736 } 737 // WEIGHT SMOOTHING (2 Laplacian passes over the mesh graph): the stretch instrument 738 // measured hard 100pct-to-100pct weight steps tearing under real per-joint motion -- 739 // armpit Spine02<>UpperarmTwist01 128 torn edges, hip crease Pelvis<>ThighTwist01 118, 740 // shoulder top <>Clavicle 112. 60/40 own/neighbor blend, top-4 retruncate, sum=4096. 741 let tr5: *i64 = ((nb as i64) + two*8 + 8) as *i64 742 let deg: *i64 = sys_mmap(nv*8 + 64) as *i64 743 var te0: i64 = 0 744 while te0 < nt { 745 deg[tr5[te0*3]] = deg[tr5[te0*3]] + 2 746 deg[tr5[te0*3+1]] = deg[tr5[te0*3+1]] + 2 747 deg[tr5[te0*3+2]] = deg[tr5[te0*3+2]] + 2 748 te0 = te0 + 1 749 } 750 let adjo: *i64 = sys_mmap(nv*8 + 72) as *i64 751 var ao0: i64 = 0 752 var acc0: i64 = 0 753 while ao0 < nv { adjo[ao0] = acc0; acc0 = acc0 + deg[ao0]; ao0 = ao0 + 1 } 754 adjo[nv] = acc0 755 let adjl: *i64 = sys_mmap(acc0*8 + 64) as *i64 756 let cur: *i64 = sys_mmap(nv*8 + 64) as *i64 757 var te1: i64 = 0 758 while te1 < nt { 759 var ec0: i64 = 0 760 while ec0 < 3 { 761 let a5: i64 = tr5[te1*3 + ec0] 762 var b5: i64 = tr5[te1*3] 763 var c5: i64 = tr5[te1*3 + 1] 764 if ec0 == 0 { b5 = tr5[te1*3+1]; c5 = tr5[te1*3+2] } 765 if ec0 == 1 { b5 = tr5[te1*3]; c5 = tr5[te1*3+2] } 766 if ec0 == 2 { b5 = tr5[te1*3]; c5 = tr5[te1*3+1] } 767 adjl[adjo[a5] + cur[a5]] = b5 768 cur[a5] = cur[a5] + 1 769 adjl[adjo[a5] + cur[a5]] = c5 770 cur[a5] = cur[a5] + 1 771 ec0 = ec0 + 1 772 } 773 te1 = te1 + 1 774 } 775 let j4b: *i64 = sys_mmap(nv*32 + 64) as *i64 776 let w4b: *i64 = sys_mmap(nv*32 + 64) as *i64 777 let mj: *i64 = sys_mmap(64*8 + 64) as *i64 778 let mw: *i64 = sys_mmap(64*8 + 64) as *i64 779 var it0: i64 = 0 780 while it0 < 3 { 781 var vs0: i64 = 0 782 while vs0 < nv { 783 let dv5: i64 = deg[vs0] 784 if dv5 == 0 { 785 var sc0: i64 = 0 786 while sc0 < 4 { j4b[vs0*4+sc0] = j4[vs0*4+sc0]; w4b[vs0*4+sc0] = w4[vs0*4+sc0]; sc0 = sc0 + 1 } 787 } 788 if dv5 > 0 { 789 var mn: i64 = 0 790 var so0: i64 = 0 791 while so0 < 4 { 792 if w4[vs0*4+so0] > 0 { 793 let jj5: i64 = j4[vs0*4+so0] 794 let ww5: i64 = w4[vs0*4+so0]*6*dv5 795 var f0: i64 = 0 - 1 796 var m0s: i64 = 0 797 while m0s < mn { if mj[m0s] == jj5 { f0 = m0s; m0s = mn } m0s = m0s + 1 } 798 if f0 >= 0 { mw[f0] = mw[f0] + ww5 } 799 if f0 < 0 { if mn < 60 { mj[mn] = jj5; mw[mn] = ww5; mn = mn + 1 } } 800 } 801 so0 = so0 + 1 802 } 803 var nb0: i64 = 0 804 while nb0 < dv5 { 805 let vn5: i64 = adjl[adjo[vs0] + nb0] 806 var sn0: i64 = 0 807 while sn0 < 4 { 808 if w4[vn5*4+sn0] > 0 { 809 let jj6: i64 = j4[vn5*4+sn0] 810 let ww6: i64 = w4[vn5*4+sn0]*4 811 var f1: i64 = 0 - 1 812 var m1s: i64 = 0 813 while m1s < mn { if mj[m1s] == jj6 { f1 = m1s; m1s = mn } m1s = m1s + 1 } 814 if f1 >= 0 { mw[f1] = mw[f1] + ww6 } 815 if f1 < 0 { if mn < 60 { mj[mn] = jj6; mw[mn] = ww6; mn = mn + 1 } } 816 } 817 sn0 = sn0 + 1 818 } 819 nb0 = nb0 + 1 820 } 821 // top-4 of the merged map -> renormalize to exact 4096 822 var sl0: i64 = 0 823 while sl0 < 4 { 824 var bi5: i64 = 0 - 1 825 var bw5: i64 = 0 826 var m2s: i64 = 0 827 while m2s < mn { 828 if mw[m2s] > bw5 { bw5 = mw[m2s]; bi5 = m2s } 829 m2s = m2s + 1 830 } 831 if bi5 >= 0 { 832 j4b[vs0*4+sl0] = mj[bi5] 833 w4b[vs0*4+sl0] = mw[bi5] 834 mw[bi5] = 0 835 } 836 if bi5 < 0 { j4b[vs0*4+sl0] = 0; w4b[vs0*4+sl0] = 0 } 837 sl0 = sl0 + 1 838 } 839 let ts5: i64 = w4b[vs0*4] + w4b[vs0*4+1] + w4b[vs0*4+2] + w4b[vs0*4+3] 840 if ts5 > 0 { 841 var an5: i64 = 0 842 var sr0: i64 = 0 843 while sr0 < 3 { 844 let nw5: i64 = w4b[vs0*4+sr0]*G_MAGIC_4096/ts5 845 w4b[vs0*4+sr0] = nw5 846 an5 = an5 + nw5 847 sr0 = sr0 + 1 848 } 849 w4b[vs0*4+3] = G_MAGIC_4096 - an5 850 } 851 if ts5 == 0 { j4b[vs0*4] = 0; w4b[vs0*4] = G_MAGIC_4096; w4b[vs0*4+1] = 0; w4b[vs0*4+2] = 0; w4b[vs0*4+3] = 0 } 852 } 853 vs0 = vs0 + 1 854 } 855 var cp0: i64 = 0 856 while cp0 < nv*4 { j4[cp0] = j4b[cp0]; w4[cp0] = w4b[cp0]; cp0 = cp0 + 1 } 857 it0 = it0 + 1 858 } 859 skw("weights_smoothed=2passes\n" as *u8) 860 skw("joints=" as *u8); skn(nj) 861 skw(" skinned=" as *u8); skn(skinned) 862 skw(" autoskinned=" as *u8); skn(autos) 863 skw("/" as *u8); skn(nv) 864 skw(" applied=" as *u8); skn(applied); skw("\n" as *u8) 865 // build SKEL + SKIN payloads 866 let skel: *i64 = sys_mmap((1 + nj*8)*8 + 64) as *i64 867 skel[0] = nj 868 var j1: i64 = 0 869 while j1 < nj { 870 skel[1 + j1*8] = jpar[j1] 871 skel[1 + j1*8 + 1] = jbind[j1*3] 872 skel[1 + j1*8 + 2] = jbind[j1*3 + 1] 873 skel[1 + j1*8 + 3] = jbind[j1*3 + 2] 874 skel[1 + j1*8 + 4] = 0 875 skel[1 + j1*8 + 5] = 0 876 skel[1 + j1*8 + 6] = 0 877 skel[1 + j1*8 + 7] = G_MAGIC_4096 878 j1 = j1 + 1 879 } 880 let skin: *i64 = sys_mmap((1 + nv*8)*8 + 64) as *i64 881 skin[0] = nv 882 var v1: i64 = 0 883 while v1 < nv { 884 var s2: i64 = 0 885 while s2 < 4 { 886 skin[1 + v1*8 + s2] = j4[v1*4 + s2] 887 skin[1 + v1*8 + 4 + s2] = w4[v1*4 + s2] 888 s2 = s2 + 1 889 } 890 v1 = v1 + 1 891 } 892 // emit the 5-section NXA 893 let fd: i64 = sys_openat_wr(argv[3] as *u8, 0x1a4) 894 if fd < 0 { skw("open out failed\n" as *u8); return 9 } 895 let vwl: i64 = 1 + nv*3 896 let twl: i64 = 1 + nt*3 897 let swl: i64 = 1 + nj*8 898 let kwl: i64 = 1 + nv*8 899 var ns: i64 = 4 900 if nclw > 0 { ns = 5 } 901 let hdr: *i64 = sys_mmap(64) as *i64 902 let toc: *i64 = sys_mmap(512) as *i64 903 var o: i64 = 32 + ns*32 904 var ti: i64 = 0 905 toc[ti*4] = nxa_tag4("VERT" as *u8) 906 toc[ti*4+1] = o 907 toc[ti*4+2] = vwl 908 toc[ti*4+3] = nxa_check2(1, ((nb as i64) + vwo*8) as *i64, vwl) 909 o = o + vwl*8 910 ti = ti + 1 911 toc[ti*4] = nxa_tag4("TRIS" as *u8) 912 toc[ti*4+1] = o 913 toc[ti*4+2] = twl 914 toc[ti*4+3] = nxa_check2(1, ((nb as i64) + two*8) as *i64, twl) 915 o = o + twl*8 916 ti = ti + 1 917 if nclw > 0 { 918 toc[ti*4] = nxa_tag4("CLUS" as *u8) 919 toc[ti*4+1] = o 920 toc[ti*4+2] = nclw 921 toc[ti*4+3] = nxa_check2(1, ((nb as i64) + cwo*8) as *i64, nclw) 922 o = o + nclw*8 923 ti = ti + 1 924 } 925 toc[ti*4] = nxa_tag4("SKEL" as *u8) 926 toc[ti*4+1] = o 927 toc[ti*4+2] = swl 928 toc[ti*4+3] = nxa_check2(1, skel, swl) 929 o = o + swl*8 930 ti = ti + 1 931 toc[ti*4] = nxa_tag4("SKIN" as *u8) 932 toc[ti*4+1] = o 933 toc[ti*4+2] = kwl 934 toc[ti*4+3] = nxa_check2(1, skin, kwl) 935 hdr[0] = nxa_magic() 936 hdr[1] = NXA_VER 937 hdr[2] = ns 938 hdr[3] = nxa_check2(1, toc, ns*4) 939 sys_write(fd, hdr as *u8, 32) 940 sys_write(fd, toc as *u8, ns*32) 941 sys_write(fd, ((nb as i64) + vwo*8) as *u8, vwl*8) 942 sys_write(fd, ((nb as i64) + two*8) as *u8, twl*8) 943 if nclw > 0 { sys_write(fd, ((nb as i64) + cwo*8) as *u8, nclw*8) } 944 sys_write(fd, skel as *u8, swl*8) 945 sys_write(fd, skin as *u8, kwl*8) 946 sys_close(fd) 947 skw("NXA5 written joints=" as *u8); skn(nj) 948 skw(" skin_verts=" as *u8); skn(nv); skw("\n" as *u8) 949 return 0 950}