code wiki / (root) / nx_nxa_hair.nx

nx_nxa_hair.nx source

↩ module page · 426 lines · 14999 B

1// nx_nxa_hair.nx -- HAIR MESH INGEST (SOTA rung 3): extracts the character's REAL groomed 2// hair asset (FBX Geometry connected to a Hair-named Model; Eyelash excluded) and appends it 3// to the NXA as HVRT/HTRI sections in the SAME mesh space as VERT -- viewers attach it via 4// the head joint's delta matrix. TOOLING not handcraft: candidates are enumerated with names 5// and sizes, the largest hair geometry wins, every step printed. 6// usage: nx_nxa_hair <in.fbx> <in.nxa> <out.nxa> 7// rc: 0 ok, 2 usage, 3 fbx unreadable, 4 no hair mesh found, 5 bad nxa, 9 io 8// license_tier: ORIGINAL 9import "nx_syscalls.nx" 10import "nx_zlib_wrap.nx" 11import "nx_nxa.nx" 12const B_MAGIC_2047: i64 = 2047 13const B_MAGIC_1048575: i64 = 1048575 14const B_MAGIC_4503599627370496: i64 = 4503599627370496 15const B_MAGIC_99990: i64 = 99990 16const B_MAGIC_4096: i64 = 4096 17const B_MAGIC_7500: i64 = 7500 18const B_MAGIC_500000: i64 = 500000 19const B_MAGIC_2147483647: i64 = 2147483647 20const B_MAGIC_4294967296: i64 = 4294967296 21 22// G: 0=mcount 1=gcount 2=conncount 23const B_MO: i64 = 16 // model ids x512 24const B_MN: i64 = 528 // model name off x512 25const B_ML: i64 = 1040 // model name len x512 26const B_GI: i64 = 1552 // geometry ids x512 27const B_GV: i64 = 2064 // geometry Vertices meta (off,alen,enc,clen) x512x4 28const B_GP: i64 = 4112 // geometry PolygonVertexIndex meta x512x4 29const B_CONN: i64 = 6160 // conns (src,dst) x100000x2 30const B_WORDS: i64 = 210000 31 32func hw(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 } 33func hn(v: i64) -> i64 { 34 let t: *u8 = sys_mmap(32) as *u8 35 var m: i64 = v; var w: i64 = 0 36 if m<0 { t[w]=45 as u8; w=w+1; m=0-m } 37 if m==0 { t[0]=48 as u8; sys_write(1,t,1); return 0 } 38 let d: *u8 = sys_mmap(32) as *u8 39 var k: i64=0 40 while m>0 { d[k]=(48+(m%10)) as u8; m=m/10; k=k+1 } 41 var j: i64=0 42 while j<k { t[w]=d[k-1-j]; w=w+1; j=j+1 } 43 sys_write(1,t,w); return 0 44} 45func h_u32(b: *u8, o: i64) -> i64 { 46 return ((b[o] & 0xff) as i64) | (((b[o+1] & 0xff) as i64) << 8) 47 | (((b[o+2] & 0xff) as i64) << 16) | (((b[o+3] & 0xff) as i64) << 24) 48} 49func h_u64(b: *u8, o: i64) -> i64 { return h_u32(b, o) | (h_u32(b, o + 4) << 32) } 50func h_f64(b: *u8, o: i64, scale: i64) -> i64 { 51 let lo: i64 = h_u32(b, o) 52 let hi: i64 = h_u32(b, o + 4) 53 let sign: i64 = (hi >> 31) & 1 54 let expo: i64 = (hi >> 20) & B_MAGIC_2047 55 if expo == 0 { return 0 } 56 var mant: i64 = ((hi & B_MAGIC_1048575) << 32) | lo 57 mant = mant | B_MAGIC_4503599627370496 58 let sh: i64 = expo - 1023 59 var v: i64 = 0 60 if sh >= 52 { v = mant * scale * (1 << (sh - 52)) } 61 if sh < 52 { 62 let rs: i64 = 52 - sh 63 if rs > 62 { return 0 } 64 v = (mant * scale) >> rs 65 } 66 if sign == 1 { return 0 - v } 67 return v 68} 69func h_namehas(b: *u8, off: i64, len: i64, pat: *u8) -> i64 { 70 var pl: i64 = 0 71 while pat[pl] != (0 as u8) { pl = pl + 1 } 72 if pl == 0 { return 0 } 73 var i: i64 = 0 74 while i + pl <= len { 75 var k: i64 = 0 76 var hit: i64 = 1 77 while k < pl { 78 if (b[off+i+k] & 0xff) != (pat[k] & 0xff) { hit = 0; k = pl } 79 k = k + 1 80 } 81 if hit == 1 { return 1 } 82 i = i + 1 83 } 84 return 0 85} 86func h_wname(b: *u8, off: i64, len: i64) -> i64 { 87 var n: i64 = 0 88 while n < len { 89 if (b[off+n] & 0xff) == 0 { len = n } 90 if n < len { n = n + 1 } 91 } 92 if n > 40 { n = 40 } 93 sys_write(1, ((b as i64) + off) as *u8, n) 94 return 0 95} 96 97func h_walk(b: *u8, flen: i64, off0: i64, big: i64, G: *i64, gctx: i64) -> i64 { 98 let off: i64 = off0 99 var endo: i64 = 0 100 var nprops: i64 = 0 101 var plen: i64 = 0 102 var nlen: i64 = 0 103 var p: i64 = 0 104 if big == 1 { 105 endo = h_u64(b, off) 106 nprops = h_u64(b, off + 8) 107 plen = h_u64(b, off + 16) 108 nlen = (b[off + 24] & 0xff) as i64 109 p = off + 25 110 } 111 if big == 0 { 112 endo = h_u32(b, off) 113 nprops = h_u32(b, off + 4) 114 plen = h_u32(b, off + 8) 115 nlen = (b[off + 12] & 0xff) as i64 116 p = off + 13 117 } 118 if endo == 0 { return off } 119 if endo > flen { return flen } 120 var kind: i64 = 0 121 if nlen == 5 { if (b[p]&0xff)==77 { if (b[p+4]&0xff)==108 { kind = 1 } } } // Model 122 if nlen == 8 { 123 if (b[p]&0xff)==71 { if (b[p+7]&0xff)==121 { kind = 2 } } // Geometry 124 if (b[p]&0xff)==86 { if (b[p+7]&0xff)==115 { kind = 3 } } // Vertices 125 } 126 if nlen == 18 { if (b[p]&0xff)==80 { if (b[p+17]&0xff)==120 { kind = 4 } } } // PolygonVertexIndex 127 if nlen == 1 { if (b[p]&0xff)==67 { kind = 5 } } // C 128 p = p + nlen 129 let pstart: i64 = p 130 var id1: i64 = 0 131 var lseen: i64 = 0 132 var s1l: i64 = 0 133 var s1o: i64 = 0 134 var sseen: i64 = 0 135 var arro: i64 = 0 136 var arrl: i64 = 0 137 var arre: i64 = 0 138 var arrc: i64 = 0 139 var id2: i64 = 0 140 var pi: i64 = 0 141 var stop: i64 = 0 142 while pi < nprops { 143 if stop == 0 { 144 let t: i64 = (b[p] & 0xff) as i64 145 p = p + 1 146 var adv: i64 = 0 - 1 147 if t == 83 { 148 let l: i64 = h_u32(b, p) 149 sseen = sseen + 1 150 if sseen == 1 { s1o = p + 4; s1l = l } 151 adv = 4 + l 152 } 153 if t == 82 { adv = 4 + h_u32(b, p) } 154 if t == 89 { adv = 2 } 155 if t == 67 { adv = 1 } 156 if t == 73 { adv = 4 } 157 if t == 70 { adv = 4 } 158 if t == 68 { adv = 8 } 159 if t == 76 { 160 lseen = lseen + 1 161 if lseen == 1 { id1 = h_u64(b, p) } 162 if lseen == 2 { id2 = h_u64(b, p) } 163 adv = 8 164 } 165 var isarr: i64 = 0 166 if t == 100 { isarr = 1 } 167 if t == 102 { isarr = 1 } 168 if t == 108 { isarr = 1 } 169 if t == 105 { isarr = 1 } 170 if t == 98 { isarr = 1 } 171 if isarr == 1 { 172 arrl = h_u32(b, p) 173 arre = h_u32(b, p + 4) 174 arrc = h_u32(b, p + 8) 175 arro = p + 12 176 adv = 12 + arrc 177 } 178 if adv < 0 { stop = 1 } 179 if adv >= 0 { p = p + adv } 180 } 181 pi = pi + 1 182 } 183 var childg: i64 = gctx 184 if kind == 1 { if G[0] < 510 { 185 G[B_MO + G[0]] = id1 186 G[B_MN + G[0]] = s1o 187 G[B_ML + G[0]] = s1l 188 G[0] = G[0] + 1 189 } } 190 if kind == 2 { if G[1] < 510 { 191 G[B_GI + G[1]] = id1 192 childg = G[1] 193 G[1] = G[1] + 1 194 } } 195 if kind == 3 { if gctx >= 0 { if G[B_GV + gctx*4 + 1] == 0 { 196 G[B_GV + gctx*4] = arro 197 G[B_GV + gctx*4 + 1] = arrl 198 G[B_GV + gctx*4 + 2] = arre 199 G[B_GV + gctx*4 + 3] = arrc 200 } } } 201 if kind == 4 { if gctx >= 0 { if G[B_GP + gctx*4 + 1] == 0 { 202 G[B_GP + gctx*4] = arro 203 G[B_GP + gctx*4 + 1] = arrl 204 G[B_GP + gctx*4 + 2] = arre 205 G[B_GP + gctx*4 + 3] = arrc 206 } } } 207 if kind == 5 { if G[2] < B_MAGIC_99990 { 208 G[B_CONN + G[2]*2] = id1 209 G[B_CONN + G[2]*2 + 1] = id2 210 G[2] = G[2] + 1 211 } } 212 p = pstart + plen 213 var sent: i64 = 13 214 if big == 1 { sent = 25 } 215 while p < endo - sent { 216 p = h_walk(b, flen, p, big, G, childg) 217 if p >= flen { return flen } 218 } 219 return endo 220} 221 222func h_arr(b: *u8, off: i64, alen: i64, enc: i64, clen: i64, esz: i64) -> *u8 { 223 if enc == 0 { return ((b as i64) + off) as *u8 } 224 let zr: *NxZlibResult = nx_zlib_inflate(((b as i64) + off) as *u8, clen, alen*esz + B_MAGIC_4096) 225 if zr.error_code != 0 { return 0 as *u8 } 226 return zr.output_data 227} 228 229func main(argc: i64, argv: *i64) -> i64 { 230 if argc < 4 { hw("usage: nx_nxa_hair <in.fbx> <in.nxa> <out.nxa>\n" as *u8); return 2 } 231 let lpf: *i64 = sys_mmap(16) as *i64 232 let fb: *u8 = sys_map_file(argv[1] as *u8, lpf) 233 let flen: i64 = lpf[0] 234 if flen < 64 { hw("fbx unreadable\n" as *u8); return 3 } 235 let ver: i64 = h_u32(fb, 23) 236 var big: i64 = 0 237 if ver >= B_MAGIC_7500 { big = 1 } 238 let G: *i64 = sys_mmap(B_WORDS*8) as *i64 239 var pos: i64 = 27 240 var guard: i64 = 0 241 while pos < flen - 200 { 242 if guard > B_MAGIC_500000 { break } 243 let e: i64 = h_walk(fb, flen, pos, big, G, 0 - 1) 244 if e <= pos { break } 245 pos = e 246 guard = guard + 1 247 } 248 let mc: i64 = G[0] 249 let gc: i64 = G[1] 250 let nc: i64 = G[2] 251 hw("models=" as *u8); hn(mc) 252 hw(" geoms=" as *u8); hn(gc) 253 hw(" conns=" as *u8); hn(nc); hw("\n" as *u8) 254 // enumerate EVERY geometry with its connected model name + vert count (tool honesty) 255 var ge0: i64 = 0 256 while ge0 < gc { 257 if G[B_GV + ge0*4 + 1]/3 >= 1000 { 258 hw("GEO " as *u8); hn(ge0) 259 hw(" verts=" as *u8); hn(G[B_GV + ge0*4 + 1]/3) 260 var km: i64 = 0 261 while km < nc { 262 if G[B_CONN + km*2] == G[B_GI + ge0] { 263 var mm0: i64 = 0 264 while mm0 < mc { 265 if G[B_MO + mm0] == G[B_CONN + km*2 + 1] { 266 hw(" model=" as *u8) 267 h_wname(fb, G[B_MN + mm0], G[B_ML + mm0]) 268 mm0 = mc 269 km = nc 270 } 271 mm0 = mm0 + 1 272 } 273 } 274 km = km + 1 275 } 276 hw("\n" as *u8) 277 } 278 ge0 = ge0 + 1 279 } 280 // hair models: name contains Hair, not Eyelash; find each one's geometry via C geo->model 281 var best: i64 = 0 - 1 282 var bestn: i64 = 0 283 var m0: i64 = 0 284 while m0 < mc { 285 if h_namehas(fb, G[B_MN + m0], G[B_ML + m0], "Hair" as *u8) == 1 { 286 if h_namehas(fb, G[B_MN + m0], G[B_ML + m0], "Eyelash" as *u8) == 0 { 287 let mid: i64 = G[B_MO + m0] 288 var gi: i64 = 0 - 1 289 var k0: i64 = 0 290 while k0 < nc { 291 if G[B_CONN + k0*2 + 1] == mid { 292 var g0: i64 = 0 293 while g0 < gc { 294 if G[B_GI + g0] == G[B_CONN + k0*2] { gi = g0; g0 = gc; k0 = nc } 295 g0 = g0 + 1 296 } 297 } 298 k0 = k0 + 1 299 } 300 // group node: geometry may hang off a CHILD model (one hop down) 301 if gi < 0 { 302 var k1: i64 = 0 303 while k1 < nc { 304 if G[B_CONN + k1*2 + 1] == mid { 305 let cid: i64 = G[B_CONN + k1*2] 306 var k2: i64 = 0 307 while k2 < nc { 308 if G[B_CONN + k2*2 + 1] == cid { 309 var g2: i64 = 0 310 while g2 < gc { 311 if G[B_GI + g2] == G[B_CONN + k2*2] { gi = g2; g2 = gc; k2 = nc; k1 = nc } 312 g2 = g2 + 1 313 } 314 } 315 k2 = k2 + 1 316 } 317 } 318 k1 = k1 + 1 319 } 320 } 321 hw("HAIR-CAND " as *u8) 322 h_wname(fb, G[B_MN + m0], G[B_ML + m0]) 323 hw(" geo=" as *u8); hn(gi) 324 if gi >= 0 { 325 hw(" verts=" as *u8); hn(G[B_GV + gi*4 + 1]/3) 326 if G[B_GV + gi*4 + 1] > bestn { bestn = G[B_GV + gi*4 + 1]; best = gi } 327 } 328 hw("\n" as *u8) 329 } 330 } 331 m0 = m0 + 1 332 } 333 if best < 0 { hw("no hair mesh found\n" as *u8); return 4 } 334 let nvh: i64 = bestn/3 335 let va: *u8 = h_arr(fb, G[B_GV + best*4], bestn, G[B_GV + best*4 + 2], G[B_GV + best*4 + 3], 8) 336 let npi: i64 = G[B_GP + best*4 + 1] 337 let pa: *u8 = h_arr(fb, G[B_GP + best*4], npi, G[B_GP + best*4 + 2], G[B_GP + best*4 + 3], 4) 338 if (va as i64) == 0 { hw("vert inflate failed\n" as *u8); return 4 } 339 if (pa as i64) == 0 { hw("pvi inflate failed\n" as *u8); return 4 } 340 // verts -> units 341 let hv: *i64 = sys_mmap((1 + nvh*3)*8 + 64) as *i64 342 hv[0] = nvh 343 var v0: i64 = 0 344 while v0 < nvh*3 { 345 hv[1 + v0] = h_f64(va, v0*8, 1000) 346 v0 = v0 + 1 347 } 348 // fan-triangulate PVI (negative = last index of polygon, value xor -1) 349 let ht: *i64 = sys_mmap((1 + npi*3)*8 + 64) as *i64 350 var nt: i64 = 0 351 var fanA: i64 = 0 - 1 352 var prev: i64 = 0 - 1 353 var pi0: i64 = 0 354 while pi0 < npi { 355 var ix: i64 = h_u32(pa, pi0*4) 356 if ix > B_MAGIC_2147483647 { ix = ix - B_MAGIC_4294967296 } 357 var last: i64 = 0 358 if ix < 0 { ix = 0 - ix - 1; last = 1 } 359 if fanA < 0 { fanA = ix } 360 if fanA >= 0 { if prev >= 0 { if ix != fanA { 361 if prev != fanA { 362 ht[1 + nt*3] = fanA 363 ht[1 + nt*3 + 1] = prev 364 ht[1 + nt*3 + 2] = ix 365 nt = nt + 1 366 } 367 } } } 368 prev = ix 369 if last == 1 { fanA = 0 - 1; prev = 0 - 1 } 370 pi0 = pi0 + 1 371 } 372 ht[0] = nt 373 hw("hair verts=" as *u8); hn(nvh) 374 hw(" tris=" as *u8); hn(nt); hw("\n" as *u8) 375 // append HVRT/HTRI to the nxa 376 let lpn: *i64 = sys_mmap(16) as *i64 377 let nb: *u8 = sys_map_file(argv[2] as *u8, lpn) 378 let nlen2: i64 = lpn[0] 379 let nh: *i64 = nb as *i64 380 if nh[0] != nxa_magic() { hw("in.nxa bad\n" as *u8); return 5 } 381 let ons: i64 = nh[2] 382 let otoc: *i64 = ((nb as i64) + 32) as *i64 383 let ns2: i64 = ons + 2 384 let hdr: *i64 = sys_mmap(64) as *i64 385 let toc: *i64 = sys_mmap(ns2*32 + 64) as *i64 386 var o: i64 = 32 + ns2*32 387 var ti: i64 = 0 388 while ti < ons { 389 toc[ti*4] = otoc[ti*4] 390 toc[ti*4+1] = o 391 toc[ti*4+2] = otoc[ti*4+2] 392 toc[ti*4+3] = otoc[ti*4+3] 393 o = o + otoc[ti*4+2]*8 394 ti = ti + 1 395 } 396 let hvl: i64 = 1 + nvh*3 397 let htl: i64 = 1 + nt*3 398 toc[ti*4] = nxa_tag4("HVRT" as *u8) 399 toc[ti*4+1] = o 400 toc[ti*4+2] = hvl 401 toc[ti*4+3] = nxa_check2(1, hv, hvl) 402 o = o + hvl*8 403 ti = ti + 1 404 toc[ti*4] = nxa_tag4("HTRI" as *u8) 405 toc[ti*4+1] = o 406 toc[ti*4+2] = htl 407 toc[ti*4+3] = nxa_check2(1, ht, htl) 408 hdr[0] = nxa_magic() 409 hdr[1] = NXA_VER 410 hdr[2] = ns2 411 hdr[3] = nxa_check2(1, toc, ns2*4) 412 let fd: i64 = sys_openat_wr(argv[3] as *u8, 0x1a4) 413 if fd < 0 { hw("open out failed\n" as *u8); return 9 } 414 sys_write(fd, hdr as *u8, 32) 415 sys_write(fd, toc as *u8, ns2*32) 416 var ci: i64 = 0 417 while ci < ons { 418 sys_write(fd, ((nb as i64) + otoc[ci*4+1]) as *u8, otoc[ci*4+2]*8) 419 ci = ci + 1 420 } 421 sys_write(fd, hv as *u8, hvl*8) 422 sys_write(fd, ht as *u8, htl*8) 423 sys_close(fd) 424 hw("NXA+HAIR written sections=" as *u8); hn(ns2); hw("\n" as *u8) 425 return 0 426}