code wiki / (root) / nx_gltf2mesh_normal_candidate_t337.nx

nx_gltf2mesh_normal_candidate_t337.nx source

↩ module page · 1816 lines · 90684 B

1// nx_gltf2mesh.nx -- GLB/VRM -> NXMSH2 mesh-oracle extractor (debt 1785902685, the D2 POSITION slice). 2// The whole bench suite (nx_bodybench / nx_twinbench / nx_curvebench / nx_facemark) judges .nxmesh 3// oracles, but NO organ could turn a donor .glb/.vrm into one -- donor FORM was invisible to every 4// instrument we own (operator 2026-08-05: the T2 being is still a clay blob because the ruler only 5// reads skeletons). This organ reads ONLY what a form oracle needs: every TRIANGLES primitive's 6// POSITION + indices (u16 AND u32, tight or strided bufferViews), multi-mesh multi-primitive concat. 7// FAIL-CLOSED at every offset (D1): a file this cannot parse REFUSES with a named reason and a 8// nonzero exit -- never a segfault, never a silent empty mesh (zero accepted tris = REFUSAL). 9// Morph-target POSITIONs are excluded by scoping the attribute scan to the primitive's attributes{}. 10// Skinned bind-pose positions are model-space per the glTF spec (node transforms ignored for skinned 11// meshes); VRM avatars are skinned throughout -- reported in the status line, never silent. 12// nx_gltf2mesh <in.glb|.vrm> <out.nxmesh> | nx_gltf2mesh selftest 13// nx_gltf2mesh <in.glb|.vrm> <out.nxa> -- R22 RIG-CARRYING INGEST (charsim.plan, contract 14// symbol g2_skin_weights): when the OUTPUT name ends in .nxa the donor's skin is carried into 15// the estate's rig container NXANIM01 -- VERT (shared vertex table, mm) / TRIS (index triples) 16// / SKEL (one record per skins[].joints entry: parent, bind position from inverseBindMatrices, 17// identity quat) / SKIN (per vertex four joint indices + four Q12 weights summing to EXACTLY 18// 4096). That layout is the one nx_nxa_skin WRITES, nx_nxa_check ENFORCES and nx_nxa_rig_emit 19// DIVIDES BY -- read from those three, never invented here. NXMSH2 structurally cannot carry a 20// rig (84-byte triangle soup, no joint section, 17 consumers hardcode that arithmetic), which 21// is why the round trip measured 2026-08-22 lost every named part of every rigged donor. 22// An unskinned donor asked for .nxa is REFUSED by name; the .nxmesh path is byte-identical. 23// license_tier: ORIGINAL expect_exit: 0 24import "nx_syscalls.nx" 25import "nx_nxa.nx" 26import "nx_vecmath.nx" 27import "nx_glbnorm_lib.nx" 28const G2_MAGIC_2000000000: i64 = 2000000000 29const G2_MAGIC_4096: i64 = 4096 30 31// ---- UNIT DETERMINATION (see g2_pick_scale for the whole argument) ---- 32// glTF 2.0 fixes the unit of length as the METRE, so a conformant donor needs no guessing at all. 33// The sniffing below exists only for donors authored in some other power of 1000 (mm is common). 34const G2_SCALE_STEP: i64 = 1000 35const G2_MAX_SCALE_TRIES: i64 = 4 36const G2_DEF_SLIVER_FLOOR_MM: i64 = 100 37const G2_ASCII_EQ: i64 = 61 38const G2_ASCII_NL: i64 = 10 39const G2_ASCII_ZERO: i64 = 48 40const G2_ASCII_NINE: i64 = 57 41const G2_CONFBUF: i64 = 16 42const G2_UNITS_CONF: *u8 = "knowledge/gltf2mesh_units.conf" 43const G2_UCONF_PFXLEN: i64 = 11 // len("units_conf=") 44 45const G2_CAP: i64 = 33554432 46const G2_MAXEL: i64 = 1024 47const G2_MAXTRI: i64 = 400000 48const G2_Q14: i64 = 16384 49const G2_M8388607: i64 = 8388607 50const G2_M8388608: i64 = 8388608 51const G2_GREY: i64 = 780 52const G2_CT_F32: i64 = 5126 53const G2_CT_U16: i64 = 5123 54const G2_CT_U32: i64 = 5125 55const G2_MODE_TRIS: i64 = 4 56const G2_HDR: i64 = 16 57const G2_LAYROW: i64 = 24 58const G2_TRIREC: i64 = 84 59 60// ---- R22 rig-carrying ingest (g2_skin_weights) -- every bound named for what it is ---- 61const G2_CT_U8: i64 = 5121 // glTF UNSIGNED_BYTE: JOINTS_0, normalized WEIGHTS_0 62const G2_Q12: i64 = 4096 // SKIN weight unit AND SKEL quat unit (nx_nxa_check: sum == 4096) 63const G2_VEC4_SLOTS: i64 = 4 // JOINTS_0/WEIGHTS_0 are VEC4: four influences per vertex 64const G2_U8_MAX: i64 = 255 // normalized u8 denominator (glTF: v/255) 65const G2_U16_MAX: i64 = 65535 // normalized u16 denominator (glTF: v/65535) 66const G2_F32_MANT_DENOM: i64 = 16777216 // 2^24: a float32 weight in [0,1] is exact to below 1/2^24 67const G2_F32_BYTES: i64 = 4 68const G2_U16_BYTES: i64 = 2 69const G2_U32_BYTES: i64 = 4 70const G2_VEC3_F32_BYTES: i64 = 12 71const G2_MAT4_BYTES: i64 = 64 72const G2_MAT4_COL: i64 = 4 // column-major: element (row r, col c) sits at c*4 + r 73const G2_IBM_T_COL: i64 = 3 // the translation column of a MAT4 74const G2_IBM_W_ROW: i64 = 3 // the affine row: must decode to 0 0 0 1 75const G2_Q12_IDENT_TOL: i64 = 1 // f32 1.0 / 0.0 decode EXACTLY to 4096 / 0 and the decode truncates below one unit, so any rotation or scale in a bind matrix shows as a deviation above ONE unit 76const G2_NXA_HDR_BYTES: i64 = 32 // magic, version, section count, TOC check 77const G2_NXA_TOC_BYTES: i64 = 32 // tag, byte offset, wordlen, payload check 78const G2_NXA_TOC_WORDS: i64 = 4 79const G2_NXA_SECS: i64 = 4 // VERT TRIS SKEL SKIN 80const G2_SKEL_WORDS: i64 = 8 // parent, tx, ty, tz, qx, qy, qz, qw 81const G2_SKIN_WORDS: i64 = 8 // j0 j1 j2 j3 w0 w1 w2 w3 82const G2_VERT_WORDS: i64 = 3 83const G2_TRI_WORDS: i64 = 3 84const G2_NXA_EXT_LEN: i64 = 4 // ".nxa" 85const G2_IBM_DEFAULT_IDENTITY: i64 = 1 // glTF: absent inverseBindMatrices == identity == every joint binds at the origin 86const G2_CX_WORDS: i64 = 32 // the emitter's context record 87// g2_skin_weights / g2_ibm_bind return codes (the caller names each one in its refusal) 88const G2_SW_OK: i64 = 0 89const G2_SW_SHAPE: i64 = 1 90const G2_SW_JOINT_RANGE: i64 = 2 91const G2_SW_SUM_TOL: i64 = 3 92const G2_SW_ZERO_WEIGHT: i64 = 4 93const G2_SW_NEGATIVE: i64 = 5 94const G2_IB_NONIDENT: i64 = 2 95const G2_IB_SHEAR: i64 = 3 96const G2_MAT3_DIM: i64 = 3 97// A^T A off-diagonal (SHEAR) tolerance, DERIVED from decode error: each A element truncates below 98// one Q12 unit, a product of two carries error below two units after the Q12 rescale, three summed 99// terms below six, plus one truncating division = 7. Measured on the reference VRM (seed-san, 100// 132 IBMs): every off-diagonal decodes to 0.00 q12 -- the bound is decode headroom, not a fit. 101const G2_SHEAR_TOL_Q12: i64 = 7 102// two truncating mm-decodes of nearly-equal f32 values differ by at most ONE unit 103const G2_IBM_CONFLICT_TOL_MM: i64 = 1 104 105func hw(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 } 106func 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 } 107 108// ---- bounds-checked little-endian readers (D1: refuse, never wander) ---- 109static G2_LEN: i64 110static G2_ERR: i64 111func g2_u16(b: *u8, o: i64) -> i64 { 112 if o < 0 { G2_ERR = 1; return 0 } 113 if o + 2 > G2_LEN { G2_ERR = 1; return 0 } 114 return (b[o] as i64) + ((b[o+1] as i64)<<8) 115} 116func g2_u32(b: *u8, o: i64) -> i64 { 117 if o < 0 { G2_ERR = 1; return 0 } 118 if o + 4 > G2_LEN { G2_ERR = 1; return 0 } 119 return (b[o] as i64) + ((b[o+1] as i64)<<8) + ((b[o+2] as i64)<<16) + ((b[o+3] as i64)<<24) 120} 121// IEEE754 float32 bits -> integer at `scale` units per 1.0 (truncating), the nx_fbx_measure recipe 122// generalised: scale=1000 is millimetres-from-metres (g2_f32mm), scale=G2_Q12 is the SKIN/SKEL unit. 123// ONE decoder for every f32 this organ reads -- a second copy for weights would be the duplicate 124// ruler, and the two would drift. 125func g2_f32s(w: i64, scale: i64) -> i64 { 126 let sign: i64 = (w >> 31) & 1 127 let expo: i64 = (w >> 23) & 255 128 if expo == 0 { return 0 } 129 var mant: i64 = (w & G2_M8388607) | G2_M8388608 130 let sh: i64 = expo - 127 131 var v: i64 = 0 132 if sh >= 23 { if sh - 23 > 30 { G2_ERR = 1; return 0 } } 133 if sh >= 23 { v = mant * scale * (1 << (sh - 23)) } 134 if sh < 23 { if 23 - sh > 62 { return 0 } } 135 if sh < 23 { v = (mant * scale) >> (23 - sh) } 136 if sign == 1 { return 0 - v } 137 return v 138} 139// IEEE754 float32 bits -> integer millimetres (metres*1000) 140func g2_f32mm(w: i64) -> i64 { return g2_f32s(w, 1000) } 141func g2_ceil_div(a: i64, d: i64) -> i64 { return (a + d - 1) / d } 142// ---- conf read: line-anchored key=value. An unanchored match would read a number out of a 143// comment and answer confidently with the wrong bound. Returns `miss` when the key is absent, so 144// an ABSENT key stays distinguishable from a key whose value is legitimately zero. 145func g2_conf_i64(path: *u8, key: *u8, miss: i64) -> i64 { 146 let lp: *i64 = sys_mmap(G2_CONFBUF) as *i64 147 let cb: *u8 = sys_read_file(path, lp) 148 if (cb as i64) == 0 { return miss } 149 let n: i64 = lp[0] 150 var i: i64 = 0 151 var ls: i64 = 1 152 while i < n { 153 if ls == 1 { 154 var k: i64 = 0 155 var m: i64 = 1 156 while key[k] != (0 as u8) { 157 if i + k >= n { m = 0 } 158 if m == 1 { if cb[i+k] != key[k] { m = 0 } } 159 k = k + 1 160 } 161 if m == 1 { if i + k < n { if (cb[i+k] as i64) == G2_ASCII_EQ { 162 var o: i64 = i + k + 1 163 var v: i64 = 0 164 var d: i64 = 0 165 var go: i64 = 1 166 while go == 1 { 167 if o >= n { go = 0 } 168 if go == 1 { 169 let c: i64 = cb[o] as i64 170 if c < G2_ASCII_ZERO { go = 0 } 171 if c > G2_ASCII_NINE { go = 0 } 172 if go == 1 { v = v*10 + (c - G2_ASCII_ZERO); d = d + 1; o = o + 1 } 173 } 174 } 175 if d > 0 { return v } 176 } } } 177 } 178 if (cb[i] as i64) == G2_ASCII_NL { ls = 1 } else { ls = 0 } 179 i = i + 1 180 } 181 return miss 182} 183 184// ---- pick the authoring scale. Returns the divisor, or 0 if no power of 1000 lands the body 185// above the sliver floor. 186// 187// WHY THE OLD 500-2500mm WINDOW WAS WRONG, AND IT WAS NOT THE NUMBERS. That window asserted "the 188// subject is a HUMAN between 0.5 and 2.5 metres" -- ANTHROPOMETRY welded into a FORMAT CONVERTER. 189// It refused human.glb at 2.615 m (measured 2026-08-22 over the full 18-file GLB population, 190// corpus_complete=1) for being 115 mm too tall. HEIGHT IS NOT A DEFECT, and this organ also 191// converts wolves and direwolves, for which a human band is meaningless. 192// 193// The two questions were CONFLATED: (a) which power of 1000 is this donor authored in, and (b) is 194// the result a plausible body. Only (a) is the converter's business. The single MEASURED failure 195// is the SLIVER -- a metre-scale float read unscaled decodes to a ~1.6 mm body that renders as 196// ~2 px and collapses every IoU judge (2026-08-05, recorded in this file's own staging comment). 197// So the FLOOR is load-bearing and the CEILING IS DERIVED FROM IT: ceil = floor*STEP - 1. That 198// makes the per-scale bands TILE THE NUMBER LINE EXACTLY -- no overlap, so a height can never be 199// ambiguous between two scales, and no gap, so no legitimate asset falls between them. A tiled 200// partition is a decision procedure; the old pair of disjoint windows was two guesses with a hole 201// between them, and human.glb fell in the hole. 202// 203// THE IMPRECISION I CHOSE TO LIVE WITH, STATED RATHER THAN HIDDEN: one floor sets BOTH ends. At 204// floor=100mm the organ handles assets from 10 cm to 100 m authored in metres; something larger 205// than 100 m would be misread one scale down. That is a real limit, it is why the value lives in 206// a conf instead of here, and it is why the chosen scale is ANNOUNCED on every run. 207func g2_pick_scale(hgt: i64, floor_mm: i64) -> i64 { 208 var dv: i64 = 1 209 var tries: i64 = 0 210 while tries < G2_MAX_SCALE_TRIES { 211 let h: i64 = hgt / dv 212 if h >= floor_mm { if h <= floor_mm*G2_SCALE_STEP - 1 { return dv } } 213 dv = dv * G2_SCALE_STEP 214 tries = tries + 1 215 } 216 return 0 217} 218 219// integer/scale -> IEEE754 float32 bits (the nx_body_gen encoder) 220func g2_enc(v: i64, scale: i64) -> i64 { 221 if v == 0 { return 0 } 222 var neg: i64 = 0 223 var m: i64 = v 224 if m < 0 { neg = 1; m = 0-m } 225 var e: i64 = 0 226 var num: i64 = m 227 var den: i64 = scale 228 while num >= den*2 { den = den*2; e = e+1 } 229 while num < den { num = num*2; e = e-1 } 230 let frac: i64 = ((num - den)*G2_M8388608)/den 231 var bits: i64 = ((e+127) << 23) | (frac & G2_M8388607) 232 if neg == 1 { bits = bits | (1<<31) } 233 return bits 234} 235func g2_wr32(b: *u8, o: i64, v: i64) -> i64 { 236 b[o]=(v&255) as u8; b[o+1]=((v>>8)&255) as u8; b[o+2]=((v>>16)&255) as u8; b[o+3]=((v>>24)&255) as u8 237 return 0 238} 239// RETIRED ONTO THE SHARED OWNER 2026-08-24: was a private Newton floor-sqrt with a different seed; same floor 240// for every x >= 0, and vm_isqrt is gate-proven exact over 20,000 inputs. 241func g2_isqrt(x: i64) -> i64 { return vm_isqrt(x) } 242 243// ---- string-aware JSON scanning (machine-emitted glb JSON; strings honoured, depth tracked) ---- 244func g2_lit_at(b: *u8, o: i64, e: i64, lit: *u8) -> i64 { 245 var m: i64 = 0 246 while lit[m] != (0 as u8) { m = m + 1 } 247 if o + m > e { return 0 } 248 var i: i64 = 0 249 while i < m { if b[o+i] != lit[i] { return 0 } i = i + 1 } 250 return m 251} 252// find a top-level (depth 1) key `lit` (pass WITH quotes+colon e.g. "\x22meshes\x22:") in [s,e) -> offset AFTER the colon, or -1 253func g2_topkey(b: *u8, s: i64, e: i64, lit: *u8) -> i64 { 254 var i: i64 = s 255 var depth: i64 = 0 256 var instr: i64 = 0 257 while i < e { 258 let c: i64 = b[i] as i64 259 if instr == 1 { 260 if c == 92 { i = i + 1 } 261 if c == 34 { instr = 0 } 262 } else { 263 if c == 34 { 264 if depth == 1 { 265 let m: i64 = g2_lit_at(b, i, e, lit) 266 if m > 0 { return i + m } 267 } 268 instr = 1 269 } 270 if c == 123 { depth = depth + 1 } 271 if c == 91 { depth = depth + 1 } 272 if c == 125 { depth = depth - 1 } 273 if c == 93 { depth = depth - 1 } 274 } 275 i = i + 1 276 } 277 return 0 - 1 278} 279// given off at the '[' of an array, fill starts/ends with each top element object range. -> count (or -1 refuse) 280func g2_elems(b: *u8, arr: i64, e: i64, starts: *i64, ends: *i64, maxn: i64) -> i64 { 281 if arr >= e { return 0 - 1 } 282 if b[arr] != (91 as u8) { return 0 - 1 } 283 var i: i64 = arr + 1 284 var depth: i64 = 1 285 var instr: i64 = 0 286 var cur: i64 = 0 - 1 287 var n: i64 = 0 288 while i < e { 289 let c: i64 = b[i] as i64 290 if instr == 1 { 291 if c == 92 { i = i + 1 } 292 if c == 34 { instr = 0 } 293 } else { 294 if c == 34 { instr = 1 } 295 if c == 123 { if depth == 1 { cur = i } depth = depth + 1 } 296 if c == 91 { depth = depth + 1 } 297 if c == 125 { 298 depth = depth - 1 299 if depth == 1 { 300 if cur >= 0 { 301 if n >= maxn { return 0 - 2 } 302 starts[n] = cur 303 ends[n] = i + 1 304 n = n + 1 305 cur = 0 - 1 306 } 307 } 308 } 309 if c == 93 { 310 depth = depth - 1 311 if depth == 0 { return n } 312 } 313 } 314 i = i + 1 315 } 316 return 0 - 1 317} 318// find `lit` (WITH quotes+colon) inside [s,e) at any depth, string-aware -> offset AFTER colon, or -1 319func g2_key(b: *u8, s: i64, e: i64, lit: *u8) -> i64 { 320 var i: i64 = s 321 var instr: i64 = 0 322 while i < e { 323 let c: i64 = b[i] as i64 324 if instr == 1 { 325 if c == 92 { i = i + 1 } 326 if c == 34 { instr = 0 } 327 } else { 328 if c == 34 { 329 let m: i64 = g2_lit_at(b, i, e, lit) 330 if m > 0 { return i + m } 331 instr = 1 332 } 333 } 334 i = i + 1 335 } 336 return 0 - 1 337} 338func g2_ifield(b: *u8, s: i64, e: i64, lit: *u8, def: i64) -> i64 { 339 let o: i64 = g2_key(b, s, e, lit) 340 if o < 0 { return def } 341 var i: i64 = o 342 var sk: i64 = 1 343 while sk == 1 { 344 if i >= e { sk = 0 } else { if b[i] == (32 as u8) { i = i + 1 } else { sk = 0 } } 345 } 346 var v: i64 = 0 347 var any: i64 = 0 348 var go: i64 = 1 349 while go == 1 { 350 if i >= e { go = 0 } else { 351 let c: i64 = b[i] as i64 352 if c >= 48 { if c <= 57 { v = v*10 + (c-48); any = 1; i = i + 1 } else { go = 0 } } else { go = 0 } 353 } 354 } 355 if any == 0 { return def } 356 return v 357} 358// object range starting at the '{' found at/after off -> end offset (past '}'), or -1 359func g2_objend(b: *u8, off: i64, e: i64) -> i64 { 360 var i: i64 = off 361 var found: i64 = 0 - 1 362 var sk: i64 = 1 363 while sk == 1 { 364 if i >= e { sk = 0 } else { if b[i] == (123 as u8) { found = i; sk = 0 } else { i = i + 1 } } 365 } 366 if found < 0 { return 0 - 1 } 367 i = found 368 var depth: i64 = 0 369 var instr: i64 = 0 370 while i < e { 371 let c: i64 = b[i] as i64 372 if instr == 1 { 373 if c == 92 { i = i + 1 } 374 if c == 34 { instr = 0 } 375 } else { 376 if c == 34 { instr = 1 } 377 if c == 123 { depth = depth + 1 } 378 if c == 125 { depth = depth - 1 } 379 if depth == 0 { return i + 1 } 380 } 381 i = i + 1 382 } 383 return 0 - 1 384} 385func g2_hasstr(b: *u8, s: i64, e: i64, lit: *u8) -> i64 { 386 var i: i64 = s 387 while i < e { if g2_lit_at(b, i, e, lit) > 0 { return 1 } i = i + 1 } 388 return 0 389} 390 391func g2_refuse(reason: *u8) -> i64 { 392 hw("GLTF2MESH REFUSED: " as *u8) 393 hw(reason) 394 hw("\n" as *u8) 395 return 0 396} 397 398// does the mesh object's "name" string contain `skip`? (byte substring on the name range) 399func g2_name_has(b: *u8, s: i64, e: i64, skip: *u8) -> i64 { 400 let no: i64 = g2_key(b, s, e, "\x22name\x22:" as *u8) 401 if no < 0 { return 0 } 402 var i: i64 = no 403 var sk: i64 = 1 404 while sk == 1 { if i >= e { sk = 0 } else { if b[i] == (34 as u8) { sk = 0 } else { i = i + 1 } } } 405 if i >= e { return 0 } 406 var j: i64 = i + 1 407 var ne: i64 = 0 - 1 408 sk = 1 409 while sk == 1 { if j >= e { sk = 0 } else { if b[j] == (34 as u8) { ne = j; sk = 0 } else { j = j + 1 } } } 410 if ne < 0 { return 0 } 411 return g2_hasstr(b, i + 1, ne, skip) 412} 413 414// filter arg classifier (R2 apparatus separation, debt 1785935557): each of up to two filter args is 415// "report" (print per-prim index/tris/bbox, v0-sampled) | "skipprims=i,j,k" (drop prims by REPORTED 416// global index) | any other string = skip meshes whose name contains it. 417static G2_REP: i64 418static G2_SKL: i64 419static G2_SKN: i64 420// units_conf=<path> override, as a *u8 held in an i64. 0 means "use G2_UNITS_CONF". 421// This exists so a GATE can force the refusal branch with its own /tmp conf instead of 422// editing the production one -- a gate that shares a fixture with a production beat ends up 423// reporting on the fixture rather than on the code. 424static G2_UCONF: i64 425func g2_filter(f: *u8) -> i64 { 426 if (f as i64) == 0 { return 0 } 427 if G2_SKL == 0 { G2_SKL = sys_mmap(64*8) as i64 } 428 if g2_lit_at(f, 0, 6, "report" as *u8) == 6 { G2_REP = 1; return 0 } 429 if g2_lit_at(f, 0, G2_UCONF_PFXLEN, "units_conf=" as *u8) == G2_UCONF_PFXLEN { G2_UCONF = (f as i64) + G2_UCONF_PFXLEN; return 0 } 430 if g2_lit_at(f, 0, 10, "skipprims=" as *u8) == 10 { 431 let sl: *i64 = G2_SKL as *i64 432 var sp: i64 = 10 433 var go2: i64 = 1 434 while go2 == 1 { 435 var v: i64 = 0 436 var any2: i64 = 0 437 var going: i64 = 1 438 while going == 1 { 439 let c2: i64 = f[sp] as i64 440 if c2 >= 48 { if c2 <= 57 { v = v*10 + (c2-48); any2 = 1; sp = sp + 1 } else { going = 0 } } else { going = 0 } 441 } 442 if any2 == 1 { if G2_SKN < 64 { sl[G2_SKN] = v; G2_SKN = G2_SKN + 1 } } 443 if f[sp] == (44 as u8) { sp = sp + 1 } else { go2 = 0 } 444 } 445 return 0 446 } 447 return 1 448} 449 450// parse a JSON int array at `arr` (pointing at '[') into out[]; returns count or -1 451func g2_intarray(b: *u8, arr: i64, e: i64, out: *i64, maxn: i64) -> i64 { 452 if arr >= e { return 0 - 1 } 453 var i: i64 = arr 454 var sk: i64 = 1 455 while sk == 1 { if i >= e { sk = 0 } else { if b[i] == (91 as u8) { sk = 0 } else { i = i + 1 } } } 456 if i >= e { return 0 - 1 } 457 i = i + 1 458 var n: i64 = 0 459 var go: i64 = 1 460 while go == 1 { 461 if i >= e { go = 0 } else { 462 let c: i64 = b[i] as i64 463 if c == 93 { go = 0 } else { 464 if c >= 48 { if c <= 57 { 465 var v: i64 = 0 466 var d: i64 = 1 467 while d == 1 { 468 let c2: i64 = b[i] as i64 469 if c2 >= 48 { if c2 <= 57 { v = v*10 + (c2-48); i = i + 1 } else { d = 0 } } else { d = 0 } 470 if i >= e { d = 0 } 471 } 472 if n >= maxn { return 0 - 2 } 473 out[n] = v 474 n = n + 1 475 } else { i = i + 1 } } else { i = i + 1 } 476 } 477 } 478 } 479 return n 480} 481// find the "name" string range of a node object; returns 1 and fills s/e via the out pair 482func g2_nodename(b: *u8, s: i64, e: i64, out: *i64) -> i64 { 483 let no: i64 = g2_key(b, s, e, "\x22name\x22:" as *u8) 484 out[0] = 0 485 out[1] = 0 486 if no < 0 { return 0 } 487 var i: i64 = no 488 var sk: i64 = 1 489 while sk == 1 { if i >= e { sk = 0 } else { if b[i] == (34 as u8) { sk = 0 } else { i = i + 1 } } } 490 if i >= e { return 0 } 491 var j: i64 = i + 1 492 var f: i64 = 0 493 while f == 0 { if j >= e { f = 1 } else { if b[j] == (34 as u8) { f = 1 } else { j = j + 1 } } } 494 if j >= e { return 0 } 495 out[0] = i + 1 496 out[1] = j 497 return 1 498} 499 500// does `path` end in ".nxa"? The NXA mode selector is the OUTPUT's own name -- explicit, readable in 501// every call site, and impossible to turn on by accident for a .nxmesh consumer. 502func g2_ends_nxa(path: *u8) -> i64 { 503 var n: i64 = 0 504 while path[n] != (0 as u8) { n = n + 1 } 505 if n < G2_NXA_EXT_LEN { return 0 } 506 let ext: *u8 = ".nxa" as *u8 507 var i: i64 = 0 508 while i < G2_NXA_EXT_LEN { if path[n - G2_NXA_EXT_LEN + i] != ext[i] { return 0 } i = i + 1 } 509 return 1 510} 511 512// ---- the emitter's context record: pointers and counts handed over in one i64 array so the 513// NXA functions stay under the estate's proven parameter count instead of carrying 20 arguments. 514// cx[0]=b cx[1]=bino cx[2]=accBV cx[3]=accBO cx[4]=accCT cx[5]=accN cx[6]=bvBO cx[7]=bvST cx[8]=nap 515// cx[9]=apPOS cx[10]=apIDX cx[11]=apJOI cx[12]=apWEI cx[13]=apMI cx[14]=mskin cx[15]=nskin cx[16]=skJ0 516// cx[17]=skJN cx[18]=skIBM cx[19]=jn cx[20]=parentOf cx[21]=nnodes cx[22]=dv cx[23]=outp cx[24]=na 517// cx[25]=nbv cx[26]=aS cx[27]=aE cx[28]=rem (skin-local joint -> UNION SKEL index, filled per 518// primitive by the emitter) cx[29]=aq (3x3 Q12 scratch for g2_ibm_one) 519 520// ---- g2_skin_weights: THE R22 CONTRACT SYMBOL. Decodes one primitive's JOINTS_0 + WEIGHTS_0 into 521// the estate's SKIN record layout, writing DIRECTLY into the SKIN payload words: for vertex v the 522// eight words at skin[1 + (vbase+v)*8] are [j0 j1 j2 j3][w0 w1 w2 w3], weights in Q12 summing to 523// EXACTLY 4096 -- the invariant nx_nxa_check REFUSES on (wsum must equal 4096) and nx_nxa_rig_emit 524// divides by. Joint indices are skin-local (JOINTS_0 indexes skins[].joints, per the glTF spec), 525// which is also the SKEL record order, so no remap is needed or performed. 526// 527// TOLERANCE IS DERIVED, NOT PICKED. Each weight is truncated to a Q12 unit (error below 1 unit, four 528// of them), plus the SOURCE quantisation: a normalized u8 weight is exact to 1/255 (error at most 529// 1/510), u16 to 1/65535, a float32 in [0,1] to below 2^-24. The per-vertex sum may therefore miss 530// 4096 by at most G2_VEC4_SLOTS + ceil(4096*G2_VEC4_SLOTS / (2*denominator)). A donor whose sum 531// misses by MORE is non-conformant (the spec says weights SHOULD sum to 1) and is REFUSED by name 532// rather than silently renormalised into something it never said. Within tolerance the residual is 533// folded into the largest weight, so the stored sum is exactly 4096. 534// 535// st: [0]=worst |sum-4096| before renormalisation [1]=tolerance used [2]=zero-weight vertices 536// [3]=first zero-weight vertex [4]=weights componentType [5]=vertices decoded 537func g2_skin_weights(cx: *i64, joi: i64, wei: i64, nvp: i64, vbase: i64, nj: i64, skin: *i64, st: *i64) -> i64 { 538 let b: *u8 = cx[0] as *u8 539 let bino: i64 = cx[1] 540 let accBV: *i64 = cx[2] as *i64 541 let accBO: *i64 = cx[3] as *i64 542 let accCT: *i64 = cx[4] as *i64 543 let bvBO: *i64 = cx[6] as *i64 544 let bvST: *i64 = cx[7] as *i64 545 let rem: *i64 = cx[28] as *i64 546 let jbv: i64 = accBV[joi] 547 let wbv: i64 = accBV[wei] 548 var jsz: i64 = 1 549 if accCT[joi] == G2_CT_U16 { jsz = 2 } 550 if accCT[joi] != G2_CT_U8 { if accCT[joi] != G2_CT_U16 { return G2_SW_SHAPE } } 551 var wsz: i64 = 1 552 var wden: i64 = G2_U8_MAX 553 if accCT[wei] == G2_CT_U16 { wsz = 2; wden = G2_U16_MAX } 554 if accCT[wei] == G2_CT_F32 { wsz = G2_F32_BYTES; wden = G2_F32_MANT_DENOM } 555 if accCT[wei] != G2_CT_U8 { if accCT[wei] != G2_CT_U16 { if accCT[wei] != G2_CT_F32 { return G2_SW_SHAPE } } } 556 var jstride: i64 = bvST[jbv] 557 if jstride == 0 { jstride = jsz*G2_VEC4_SLOTS } 558 var wstride: i64 = bvST[wbv] 559 if wstride == 0 { wstride = wsz*G2_VEC4_SLOTS } 560 let jbase: i64 = bino + bvBO[jbv] + accBO[joi] 561 let wbase: i64 = bino + bvBO[wbv] + accBO[wei] 562 let tol: i64 = G2_VEC4_SLOTS + g2_ceil_div(G2_Q12*G2_VEC4_SLOTS, 2*wden) 563 st[1] = tol 564 st[4] = accCT[wei] 565 var v: i64 = 0 566 while v < nvp { 567 let rec: i64 = 1 + (vbase + v)*G2_SKIN_WORDS 568 var sum: i64 = 0 569 var big: i64 = 0 570 var bigw: i64 = 0 - 1 571 var s: i64 = 0 572 while s < G2_VEC4_SLOTS { 573 var jv: i64 = 0 574 if jsz == 1 { jv = b[jbase + v*jstride + s] as i64 } 575 if jsz == 2 { jv = g2_u16(b, jbase + v*jstride + s*2) } 576 if jv < 0 { return G2_SW_JOINT_RANGE } 577 if jv >= nj { return G2_SW_JOINT_RANGE } 578 var wq: i64 = 0 579 if wsz == 1 { wq = (b[wbase + v*wstride + s] as i64)*G2_Q12/G2_U8_MAX } 580 if wsz == 2 { wq = g2_u16(b, wbase + v*wstride + s*2)*G2_Q12/G2_U16_MAX } 581 if wsz == G2_F32_BYTES { wq = g2_f32s(g2_u32(b, wbase + v*wstride + s*G2_F32_BYTES), G2_Q12) } 582 if G2_ERR != 0 { return G2_SW_SHAPE } 583 if wq < 0 { return G2_SW_NEGATIVE } 584 if rem[jv] != jv { st[6] = st[6] + 1 } 585 skin[rec + s] = rem[jv] 586 skin[rec + G2_VEC4_SLOTS + s] = wq 587 sum = sum + wq 588 if wq > bigw { bigw = wq; big = s } 589 s = s + 1 590 } 591 if sum == 0 { 592 if st[2] == 0 { st[3] = vbase + v } 593 st[2] = st[2] + 1 594 } else { 595 var dev: i64 = sum - G2_Q12 596 if dev < 0 { dev = 0 - dev } 597 if dev > st[0] { st[0] = dev } 598 if dev > tol { return G2_SW_SUM_TOL } 599 skin[rec + G2_VEC4_SLOTS + big] = skin[rec + G2_VEC4_SLOTS + big] + (G2_Q12 - sum) 600 } 601 v = v + 1 602 } 603 st[5] = st[5] + nvp 604 if st[2] > 0 { return G2_SW_ZERO_WEIGHT } 605 return G2_SW_OK 606} 607 608// ---- ONE bind matrix -> ONE SKEL record's pivot. glTF: skinMatrix = globalJointTransform * IBM, 609// so joint k's BIND world transform is IBM^-1; for IBM = [A | c] with A = R*diag(s) (rotation and 610// per-axis scale, NO shear) the bind position r-component is exactly -(A^T c)_r / (A^T A)_rr -- 611// which reduces BIT-FOR-BIT to the old -c_r when A is identity (numerator -4096*c_r over 4096). 612// The bind ROTATION is DROPPED to the identity quaternion the estate's SKEL declares (every 613// shipping writer emits identity; the runtime LBS reads only the bind translation) -- the same 614// convention the EXPORT leg already announces as `bind_rotation=dropped-identity-convention`. 615// MEASURED NECESSITY, 2026-08-23: the reference VRM's 132 IBMs ALL carry rotation (median |A-I| 616// 1.76 -- VRoid orients bones along their axes), so the previous identity-only refusal admitted 617// no VRoid avatar at all; rotations are counted (st[3]) and the worst deviation reported (st[0]), 618// never silently eaten. SHEAR has no exact pivot and REFUSES by name (off-diagonal A^T A above 619// the derived decode bound). The absent-IBM case is handled by the CALLER (spec: identity). 620// st: [0]=worst rotation deviation q12 (accumulated) [3]=joints whose rotation was dropped 621func g2_ibm_one(cx: *i64, ibi: i64, kloc: i64, dv: i64, out3: *i64, st: *i64) -> i64 { 622 let b: *u8 = cx[0] as *u8 623 let bino: i64 = cx[1] 624 let accBV: *i64 = cx[2] as *i64 625 let accBO: *i64 = cx[3] as *i64 626 let accCT: *i64 = cx[4] as *i64 627 let accN: *i64 = cx[5] as *i64 628 let bvBO: *i64 = cx[6] as *i64 629 let bvST: *i64 = cx[7] as *i64 630 let aq: *i64 = cx[29] as *i64 631 if accCT[ibi] != G2_CT_F32 { return G2_SW_SHAPE } 632 if accN[ibi] <= kloc { return G2_SW_SHAPE } 633 let bv: i64 = accBV[ibi] 634 var stride: i64 = bvST[bv] 635 if stride == 0 { stride = G2_MAT4_BYTES } 636 let mb: i64 = bino + bvBO[bv] + accBO[ibi] + kloc*stride 637 var r: i64 = 0 638 while r < G2_MAT3_DIM { 639 var c: i64 = 0 640 while c < G2_MAT3_DIM { 641 aq[r*G2_MAT3_DIM + c] = g2_f32s(g2_u32(b, mb + (c*G2_MAT4_COL + r)*G2_F32_BYTES), G2_Q12) 642 c = c + 1 643 } 644 r = r + 1 645 } 646 let w33: i64 = g2_f32s(g2_u32(b, mb + (G2_IBM_T_COL*G2_MAT4_COL + G2_IBM_W_ROW)*G2_F32_BYTES), G2_Q12) 647 if G2_ERR != 0 { return G2_SW_SHAPE } 648 var d33: i64 = w33 - G2_Q12 649 if d33 < 0 { d33 = 0 - d33 } 650 if d33 > G2_Q12_IDENT_TOL { return G2_SW_SHAPE } 651 var dev: i64 = 0 652 r = 0 653 while r < G2_MAT3_DIM { 654 var c2: i64 = 0 655 while c2 < G2_MAT3_DIM { 656 var want: i64 = 0 657 if r == c2 { want = G2_Q12 } 658 var d: i64 = aq[r*G2_MAT3_DIM + c2] - want 659 if d < 0 { d = 0 - d } 660 if d > dev { dev = d } 661 c2 = c2 + 1 662 } 663 r = r + 1 664 } 665 if dev > st[0] { st[0] = dev } 666 if dev > G2_Q12_IDENT_TOL { st[3] = st[3] + 1 } 667 var i2: i64 = 0 668 while i2 < G2_MAT3_DIM { 669 var j2: i64 = 0 670 while j2 < G2_MAT3_DIM { 671 if i2 != j2 { 672 var g: i64 = 0 673 var k2: i64 = 0 674 while k2 < G2_MAT3_DIM { g = g + aq[k2*G2_MAT3_DIM + i2]*aq[k2*G2_MAT3_DIM + j2]; k2 = k2 + 1 } 675 g = g / G2_Q12 676 if g < 0 { g = 0 - g } 677 if g > G2_SHEAR_TOL_Q12 { return G2_IB_SHEAR } 678 } 679 j2 = j2 + 1 680 } 681 i2 = i2 + 1 682 } 683 r = 0 684 while r < G2_MAT3_DIM { 685 var num: i64 = 0 686 var grr: i64 = 0 687 var k3: i64 = 0 688 while k3 < G2_MAT3_DIM { 689 let cm: i64 = g2_f32mm(g2_u32(b, mb + (G2_IBM_T_COL*G2_MAT4_COL + k3)*G2_F32_BYTES)) 690 num = num - aq[k3*G2_MAT3_DIM + r]*cm 691 grr = grr + aq[k3*G2_MAT3_DIM + r]*aq[k3*G2_MAT3_DIM + r] 692 k3 = k3 + 1 693 } 694 grr = grr / G2_Q12 695 if grr <= 0 { return G2_SW_SHAPE } 696 if G2_ERR != 0 { return G2_SW_SHAPE } 697 out3[r] = (num/grr)/dv 698 r = r + 1 699 } 700 return G2_SW_OK 701} 702 703func g2_toc(toc: *i64, ti: i64, tag: *u8, off: i64, wl: i64, words: *i64) -> i64 { 704 let e: i64 = ti*G2_NXA_TOC_WORDS 705 toc[e] = nxa_tag4(tag) 706 toc[e+1] = off 707 toc[e+2] = wl 708 toc[e+3] = nxa_check2(1, words, wl) 709 return off + wl*8 710} 711 712// ---- R22: emit NXANIM01 carrying the donor's rig. Layout per nx_nxa_skin (writer), nx_nxa_check 713// (fsck) and nx_nxa_rig_emit (browser LBS): 32-byte header [magic][ver][ns][toc check], ns 32-byte 714// TOC rows [tag][byte off][wordlen][payload check], then payloads VERT TRIS SKEL SKIN. Every 715// checksum is nxa_check2 from nx_nxa.nx -- the ONE definition the readers import too. The buffer is 716// sized FROM THE DATA (counts summed over the accepted primitives); there is no cap to hit here, and 717// the one cap upstream (G2_MAXEL accepted primitives) REFUSES and announces rather than truncating. 718func g2_emit_nxa(cx: *i64) -> i64 { 719 let b: *u8 = cx[0] as *u8 720 let bino: i64 = cx[1] 721 let accBV: *i64 = cx[2] as *i64 722 let accBO: *i64 = cx[3] as *i64 723 let accCT: *i64 = cx[4] as *i64 724 let accN: *i64 = cx[5] as *i64 725 let bvBO: *i64 = cx[6] as *i64 726 let bvST: *i64 = cx[7] as *i64 727 let nap: i64 = cx[8] 728 let apPOS: *i64 = cx[9] as *i64 729 let apIDX: *i64 = cx[10] as *i64 730 let apJOI: *i64 = cx[11] as *i64 731 let apWEI: *i64 = cx[12] as *i64 732 let apMI: *i64 = cx[13] as *i64 733 let mskin: *i64 = cx[14] as *i64 734 let nskin: i64 = cx[15] 735 let skJ0: *i64 = cx[16] as *i64 736 let skJN: *i64 = cx[17] as *i64 737 let skIBM: *i64 = cx[18] as *i64 738 let jn: *i64 = cx[19] as *i64 739 let parentOf: *i64 = cx[20] as *i64 740 let nnodes: i64 = cx[21] 741 let dv: i64 = cx[22] 742 let outp: *u8 = cx[23] as *u8 743 let nacc: i64 = cx[24] 744 let nbv: i64 = cx[25] 745 let aS: *i64 = cx[26] as *i64 746 let aE: *i64 = cx[27] as *i64 747 if nap <= 0 { g2_refuse("nxa: no accepted primitive" as *u8); return 5 } 748 // R22b MULTI-SKIN UNION (the VRoid case). A VRM exports one skins[] entry PER MESH (body, 749 // face, hair, clothing) over ONE shared skeleton -- measured on the reference VRM: 5 skins, 750 // joints 23/7/1/21/80, union 128 distinct nodes, IBMs agreeing on every shared node. NXANIM01 751 // carries one SKEL, so the UNION of the used skins' joints IS the skeleton and each 752 // primitive's skin-local JOINTS_0 is remapped through its skins[].joints to the union index. 753 // Skins that share a skeleton form ONE component under joint OVERLAP; the overlap graph is 754 // NOT all-pairs even on a genuine single character (hair and clothing may share only the head 755 // node), so the refusal keys on CONNECTIVITY -- never on any single pair. 756 var nv: i64 = 0 757 var nt: i64 = 0 758 let used: *i64 = sys_mmap(G2_MAXEL*8) as *i64 759 var nused: i64 = 0 760 let ufp: *i64 = sys_mmap(G2_MAXEL*8) as *i64 761 let uidx: *i64 = sys_mmap(G2_MAXEL*8) as *i64 762 let ujNode: *i64 = sys_mmap(G2_MAXEL*8) as *i64 763 let ownSkin: *i64 = sys_mmap(G2_MAXEL*8) as *i64 764 let ownLoc: *i64 = sys_mmap(G2_MAXEL*8) as *i64 765 var nuj: i64 = 0 766 var q6: i64 = 0 767 while q6 < G2_MAXEL { ufp[q6] = q6; uidx[q6] = 0 - 1; q6 = q6 + 1 } 768 var p: i64 = 0 769 while p < nap { 770 var s2: i64 = 0 - 1 771 if apMI[p] < G2_MAXEL { s2 = mskin[apMI[p]] } 772 if s2 < 0 { g2_refuse("nxa: an accepted primitive belongs to no skin -- not a rigged donor; write .nxmesh for a form oracle" as *u8); return 10 } 773 if s2 >= nskin { g2_refuse("nxa: owning skin index outside skins[]" as *u8); return 10 } 774 if apJOI[p] < 0 { g2_refuse("nxa: primitive has no JOINTS_0" as *u8); return 10 } 775 if apWEI[p] < 0 { g2_refuse("nxa: primitive has no WEIGHTS_0" as *u8); return 10 } 776 if apJOI[p] >= nacc { g2_refuse("nxa: JOINTS_0 names an accessor outside the table" as *u8); return 10 } 777 if apWEI[p] >= nacc { g2_refuse("nxa: WEIGHTS_0 names an accessor outside the table" as *u8); return 10 } 778 if g2_hasstr(b, aS[apJOI[p]], aE[apJOI[p]], "VEC4" as *u8) == 0 { g2_refuse("nxa: JOINTS_0 is not VEC4" as *u8); return 10 } 779 if g2_hasstr(b, aS[apWEI[p]], aE[apWEI[p]], "VEC4" as *u8) == 0 { g2_refuse("nxa: WEIGHTS_0 is not VEC4" as *u8); return 10 } 780 if accBV[apJOI[p]] < 0 { g2_refuse("nxa: JOINTS_0 has no bufferView" as *u8); return 10 } 781 if accBV[apWEI[p]] < 0 { g2_refuse("nxa: WEIGHTS_0 has no bufferView" as *u8); return 10 } 782 if accBV[apJOI[p]] >= nbv { g2_refuse("nxa: JOINTS_0 bufferView outside the table" as *u8); return 10 } 783 if accBV[apWEI[p]] >= nbv { g2_refuse("nxa: WEIGHTS_0 bufferView outside the table" as *u8); return 10 } 784 if accN[apJOI[p]] != accN[apPOS[p]] { g2_refuse("nxa: JOINTS_0 count differs from POSITION count -- the skin does not cover the vertex table" as *u8); return 11 } 785 if accN[apWEI[p]] != accN[apPOS[p]] { g2_refuse("nxa: WEIGHTS_0 count differs from POSITION count -- the skin does not cover the vertex table" as *u8); return 11 } 786 nv = nv + accN[apPOS[p]] 787 nt = nt + accN[apIDX[p]]/3 788 var seen: i64 = 0 789 var u2: i64 = 0 790 while u2 < nused { if used[u2] == s2 { seen = 1 } u2 = u2 + 1 } 791 if seen == 0 { 792 if skJN[s2] <= 0 { g2_refuse("nxa: a used skin declares zero joints" as *u8); return 10 } 793 var k4: i64 = 0 794 while k4 < skJN[s2] { 795 let node: i64 = jn[skJ0[s2] + k4] 796 if node < 0 { g2_refuse("nxa: skins[].joints names a negative node" as *u8); return 10 } 797 if node >= G2_MAXEL { g2_refuse("nxa: skins[].joints names a node outside the parsed table" as *u8); return 10 } 798 if uidx[node] < 0 { 799 uidx[node] = nuj 800 ujNode[nuj] = node 801 ownSkin[nuj] = s2 802 ownLoc[nuj] = k4 803 nuj = nuj + 1 804 } else { 805 var ra: i64 = s2 806 while ufp[ra] != ra { ra = ufp[ra] } 807 var rb: i64 = ownSkin[uidx[node]] 808 while ufp[rb] != rb { rb = ufp[rb] } 809 if ra != rb { ufp[ra] = rb } 810 } 811 k4 = k4 + 1 812 } 813 used[nused] = s2 814 nused = nused + 1 815 } 816 p = p + 1 817 } 818 var comps: i64 = 0 819 var u3: i64 = 0 820 while u3 < nused { 821 var rr: i64 = used[u3] 822 while ufp[rr] != rr { rr = ufp[rr] } 823 if rr == used[u3] { comps = comps + 1 } 824 u3 = u3 + 1 825 } 826 if comps > 1 { 827 g2_refuse("nxa: the used skins do not share a skeleton (joint-overlap components > 1) -- not one rigged character; split the donor" as *u8) 828 hw(" skins_used=" as *u8); pn(nused); hw(" components=" as *u8); pn(comps); hw("\n" as *u8) 829 return 10 830 } 831 let nj: i64 = nuj 832 // sizes FROM THE DATA 833 let vwl: i64 = 1 + nv*G2_VERT_WORDS 834 let twl: i64 = 1 + nt*G2_TRI_WORDS 835 let swl: i64 = 1 + nj*G2_SKEL_WORDS 836 let kwl: i64 = 1 + nv*G2_SKIN_WORDS 837 let head: i64 = G2_NXA_HDR_BYTES + G2_NXA_SECS*G2_NXA_TOC_BYTES 838 let total: i64 = head + (vwl + twl + swl + kwl)*8 839 let ob: *i64 = sys_mmap(total + 64) as *i64 840 let vert: *i64 = ((ob as i64) + head) as *i64 841 let tris: *i64 = ((vert as i64) + vwl*8) as *i64 842 let skel: *i64 = ((tris as i64) + twl*8) as *i64 843 let skin: *i64 = ((skel as i64) + swl*8) as *i64 844 vert[0] = nv 845 tris[0] = nt 846 skel[0] = nj 847 skin[0] = nv 848 let st: *i64 = sys_mmap(8*8) as *i64 849 let rem: *i64 = sys_mmap(G2_MAXEL*8) as *i64 850 cx[28] = rem as i64 851 let aqbuf: *i64 = sys_mmap(G2_MAT3_DIM*G2_MAT3_DIM*8) as *i64 852 cx[29] = aqbuf as i64 853 var vbase: i64 = 0 854 var tbase: i64 = 0 855 p = 0 856 while p < nap { 857 let posi: i64 = apPOS[p] 858 let idxi: i64 = apIDX[p] 859 let pb: i64 = accBV[posi] 860 var pstride: i64 = bvST[pb] 861 if pstride == 0 { pstride = G2_VEC3_F32_BYTES } 862 let pbase: i64 = bino + bvBO[pb] + accBO[posi] 863 let pcount: i64 = accN[posi] 864 var v: i64 = 0 865 while v < pcount { 866 let vw: i64 = 1 + (vbase + v)*G2_VERT_WORDS 867 vert[vw] = g2_f32mm(g2_u32(b, pbase + v*pstride))/dv 868 vert[vw+1] = g2_f32mm(g2_u32(b, pbase + v*pstride + G2_F32_BYTES))/dv 869 vert[vw+2] = g2_f32mm(g2_u32(b, pbase + v*pstride + 2*G2_F32_BYTES))/dv 870 v = v + 1 871 } 872 let ib2: i64 = accBV[idxi] 873 let ibase: i64 = bino + bvBO[ib2] + accBO[idxi] 874 var isz: i64 = G2_U16_BYTES 875 if accCT[idxi] == G2_CT_U32 { isz = G2_U32_BYTES } 876 let nix: i64 = accN[idxi] 877 var q: i64 = 0 878 while q < nix { 879 var ix: i64 = 0 880 if isz == G2_U16_BYTES { ix = g2_u16(b, ibase + q*G2_U16_BYTES) } 881 if isz == G2_U32_BYTES { ix = g2_u32(b, ibase + q*G2_U32_BYTES) } 882 if ix >= pcount { g2_refuse("nxa: index outside its POSITION accessor" as *u8); return 7 } 883 tris[1 + tbase*G2_TRI_WORDS + q] = vbase + ix 884 q = q + 1 885 } 886 var s5: i64 = 0 - 1 887 if apMI[p] < G2_MAXEL { s5 = mskin[apMI[p]] } 888 var k6: i64 = 0 889 while k6 < skJN[s5] { rem[k6] = uidx[jn[skJ0[s5] + k6]]; k6 = k6 + 1 } 890 let wrc: i64 = g2_skin_weights(cx, apJOI[p], apWEI[p], pcount, vbase, skJN[s5], skin, st) 891 if wrc == G2_SW_SHAPE { g2_refuse("nxa: JOINTS_0/WEIGHTS_0 shape unsupported (need VEC4 u8/u16 joints, u8/u16/f32 weights, data in bounds)" as *u8); return 11 } 892 if wrc == G2_SW_JOINT_RANGE { g2_refuse("nxa: JOINTS_0 names a joint outside skins[].joints" as *u8); return 11 } 893 if wrc == G2_SW_NEGATIVE { g2_refuse("nxa: a NEGATIVE weight -- non-conformant donor" as *u8); return 11 } 894 if wrc == G2_SW_SUM_TOL { 895 g2_refuse("nxa: a vertex's weights miss 4096 by more than the DERIVED tolerance -- non-conformant donor, refusing to renormalise what it did not say" as *u8) 896 hw(" worst_dev_q12=" as *u8); pn(st[0]); hw(" tolerance_q12=" as *u8); pn(st[1]); hw("\n" as *u8) 897 return 11 898 } 899 if G2_ERR != 0 { g2_refuse("nxa: out-of-bounds read while copying vertices or indices" as *u8); return 7 } 900 vbase = vbase + pcount 901 tbase = tbase + nix/3 902 p = p + 1 903 } 904 if st[2] > 0 { 905 g2_refuse("nxa: vertices with ZERO total weight -- unbound vertices cannot be represented (SKIN demands a 4096 sum)" as *u8) 906 hw(" zero_weight_vertices=" as *u8); pn(st[2]); hw(" first=" as *u8); pn(st[3]); hw("\n" as *u8) 907 return 11 908 } 909 // SKEL: parent from the node hierarchy (UNION index, -1 for a root), bind pivot from the 910 // owning skin's IBM via g2_ibm_one; a node carried by SEVERAL skins must bind at the SAME 911 // position across them (two truncating decodes of one bind differ by at most one mm unit) or 912 // the donor is refused by name -- the skins would disagree on the skeleton. 913 let ist: *i64 = sys_mmap(8*8) as *i64 914 let p3: *i64 = sys_mmap(G2_MAT3_DIM*8) as *i64 915 let p4: *i64 = sys_mmap(G2_MAT3_DIM*8) as *i64 916 var conflicts: i64 = 0 917 var conflict_worst: i64 = 0 918 var absent_ident: i64 = 0 919 var k: i64 = 0 920 while k < nj { 921 let node: i64 = ujNode[k] 922 var par: i64 = 0 - 1 923 if node < nnodes { 924 let pnode: i64 = parentOf[node] 925 if pnode >= 0 { if pnode < G2_MAXEL { if uidx[pnode] >= 0 { par = uidx[pnode] } } } 926 } 927 let jw: i64 = 1 + k*G2_SKEL_WORDS 928 skel[jw] = par 929 let sOwn: i64 = ownSkin[k] 930 if skIBM[sOwn] < 0 { 931 p3[0] = 0; p3[1] = 0; p3[2] = 0 932 absent_ident = absent_ident + 1 933 } else { 934 let irc: i64 = g2_ibm_one(cx, skIBM[sOwn], ownLoc[k], dv, p3, ist) 935 if irc == G2_SW_SHAPE { g2_refuse("nxa: inverseBindMatrices is not a float MAT4 accessor readable at this joint" as *u8); return 11 } 936 if irc == G2_IB_SHEAR { 937 g2_refuse("nxa: bind matrix carries SHEAR (A^T A off-diagonal above the derived decode bound) -- no exact pivot exists; refusing rather than guessing" as *u8) 938 return 12 939 } 940 } 941 var u4: i64 = 0 942 while u4 < nused { 943 let s4: i64 = used[u4] 944 if s4 != sOwn { if skIBM[s4] >= 0 { 945 var fnd: i64 = 0 946 var k5: i64 = 0 947 while k5 < skJN[s4] { 948 if fnd == 0 { if jn[skJ0[s4] + k5] == node { 949 fnd = 1 950 let irc2: i64 = g2_ibm_one(cx, skIBM[s4], k5, dv, p4, ist) 951 if irc2 == G2_SW_OK { 952 var ax: i64 = 0 953 while ax < G2_MAT3_DIM { 954 var dd: i64 = p4[ax] - p3[ax] 955 if dd < 0 { dd = 0 - dd } 956 if dd > conflict_worst { conflict_worst = dd } 957 if dd > G2_IBM_CONFLICT_TOL_MM { conflicts = conflicts + 1 } 958 ax = ax + 1 959 } 960 } 961 } } 962 k5 = k5 + 1 963 } 964 } } 965 u4 = u4 + 1 966 } 967 skel[jw+1] = p3[0] 968 skel[jw+2] = p3[1] 969 skel[jw+3] = p3[2] 970 skel[jw+4] = 0; skel[jw+5] = 0; skel[jw+6] = 0; skel[jw+7] = G2_Q12 971 k = k + 1 972 } 973 if conflicts > 0 { 974 g2_refuse("nxa: a joint shared by two skins binds at DIFFERENT positions (beyond one decode unit) -- the skins disagree on the skeleton; split the donor" as *u8) 975 hw(" ibm_conflicts=" as *u8); pn(conflicts); hw(" worst_mm=" as *u8); pn(conflict_worst); hw("\n" as *u8) 976 return 12 977 } 978 ist[2] = 0 979 if absent_ident > 0 { ist[2] = G2_IBM_DEFAULT_IDENTITY } 980 // header + TOC, checksums from the ONE definition 981 ob[0] = nxa_magic() 982 ob[1] = NXA_VER 983 ob[2] = G2_NXA_SECS 984 let toc: *i64 = ((ob as i64) + G2_NXA_HDR_BYTES) as *i64 985 var off: i64 = head 986 off = g2_toc(toc, 0, "VERT" as *u8, off, vwl, vert) 987 off = g2_toc(toc, 1, "TRIS" as *u8, off, twl, tris) 988 off = g2_toc(toc, 2, "SKEL" as *u8, off, swl, skel) 989 off = g2_toc(toc, 3, "SKIN" as *u8, off, kwl, skin) 990 ob[3] = nxa_check2(1, toc, G2_NXA_SECS*G2_NXA_TOC_WORDS) 991 if off != total { g2_refuse("nxa: internal -- payload offsets do not close on the buffer size" as *u8); return 13 } 992 let ofd: i64 = sys_openat_wr(outp, MODE_0644) 993 if ofd < 0 { g2_refuse("output path unwritable" as *u8); return 6 } 994 let wr: i64 = sys_write(ofd, ob as *u8, total) 995 sys_close(ofd) 996 if wr != total { g2_refuse("nxa: short write" as *u8); hw(" wrote=" as *u8); pn(wr); hw(" of=" as *u8); pn(total); hw("\n" as *u8); return 6 } 997 hw("{\x22organ\x22:\x22nx_gltf2mesh\x22,\x22mode\x22:\x22nxa\x22,\x22contract\x22:\x22g2_skin_weights\x22,\x22prims_accepted\x22:" as *u8); pn(nap) 998 hw(",\x22verts\x22:" as *u8); pn(nv) 999 hw(",\x22tris\x22:" as *u8); pn(nt) 1000 hw(",\x22joints\x22:" as *u8); pn(nj) 1001 hw(",\x22skins_used\x22:" as *u8); pn(nused) 1002 hw(",\x22skin_joints_union\x22:" as *u8); pn(nuj) 1003 hw(",\x22joints_remapped\x22:" as *u8); pn(st[6]) 1004 hw(",\x22ibm_conflicts\x22:" as *u8); pn(conflicts) 1005 hw(",\x22ibm_conflict_worst_mm\x22:" as *u8); pn(conflict_worst) 1006 hw(",\x22bind_rot_dropped_joints\x22:" as *u8); pn(ist[3]) 1007 hw(",\x22weights_componentType\x22:" as *u8); pn(st[4]) 1008 hw(",\x22weight_sum_worst_dev_q12\x22:" as *u8); pn(st[0]) 1009 hw(",\x22weight_tolerance_q12\x22:" as *u8); pn(st[1]) 1010 hw(",\x22ibm_absent_identity\x22:" as *u8); pn(ist[2]) 1011 hw(",\x22bind_rot_worst_dev_q12\x22:" as *u8); pn(ist[0]) 1012 hw(",\x22scale_div\x22:" as *u8); pn(dv) 1013 hw(",\x22bytes\x22:" as *u8); pn(total) 1014 hw(",\x22note\x22:\x22NXANIM01 VERT/TRIS/SKEL/SKIN; degenerate index triples KEPT (an index list is data); bind pivot exact for rotation plus per-axis scale, bind ROTATION dropped to the identity quat the estate declares (counted above, matching the export leg); multi-skin donors union their shared skeleton; axes as authored, not remapped\x22}" as *u8) 1015 hw("\n" as *u8) 1016 return 0 1017} 1018 1019// ---- the conversion ---- 1020func g2_convert(inp: *u8, outp: *u8, skip: *u8) -> i64 { 1021 G2_ERR = 0 1022 let fd: i64 = sys_openat_rd(inp) 1023 if fd < 0 { g2_refuse("input unreadable" as *u8); return 3 } 1024 let b: *u8 = sys_mmap(G2_CAP + 64) 1025 var n: i64 = 0 1026 var go: i64 = 1 1027 while go == 1 { 1028 let r: i64 = sys_read(fd, ((b as i64) + n) as *u8, G2_CAP - n) 1029 if r <= 0 { go = 0 } else { n = n + r } 1030 if n >= G2_CAP { go = 0 } 1031 } 1032 sys_close(fd) 1033 if n >= G2_CAP { g2_refuse("input exceeds 32MiB cap" as *u8); return 3 } 1034 if n < 28 { g2_refuse("too small for a glb" as *u8); return 3 } 1035 G2_LEN = n 1036 if b[0] != (103 as u8) { g2_refuse("bad magic (not glTF)" as *u8); return 3 } 1037 if b[1] != (108 as u8) { g2_refuse("bad magic (not glTF)" as *u8); return 3 } 1038 if b[2] != (84 as u8) { g2_refuse("bad magic (not glTF)" as *u8); return 3 } 1039 if b[3] != (70 as u8) { g2_refuse("bad magic (not glTF)" as *u8); return 3 } 1040 let total: i64 = g2_u32(b, 8) 1041 if total != n { g2_refuse("length field disagrees with file size" as *u8); return 3 } 1042 let jlen: i64 = g2_u32(b, 12) 1043 if 20 + jlen > n { g2_refuse("JSON chunk overruns file" as *u8); return 3 } 1044 let js: i64 = 20 1045 let je: i64 = 20 + jlen 1046 var bino: i64 = 0 - 1 1047 var binn: i64 = 0 1048 if je + 8 <= n { 1049 binn = g2_u32(b, je) 1050 if b[je+4] != (66 as u8) { g2_refuse("second chunk is not BIN" as *u8); return 3 } 1051 bino = je + 8 1052 if bino + binn > n { 1053 g2_refuse("BIN chunk overruns file" as *u8) 1054 hw(" bino=" as *u8); pn(bino); hw(" binn=" as *u8); pn(binn); hw(" n=" as *u8); pn(n); hw(" jlen=" as *u8); pn(jlen); hw("\n" as *u8) 1055 return 3 1056 } 1057 } 1058 if bino < 0 { g2_refuse("no BIN chunk (external buffers unsupported)" as *u8); return 3 } 1059 if G2_ERR != 0 { g2_refuse("header read out of bounds" as *u8); return 3 } 1060 1061 // top-level tables 1062 let accA: i64 = g2_topkey(b, js, je, "\x22accessors\x22:" as *u8) 1063 let bvA: i64 = g2_topkey(b, js, je, "\x22bufferViews\x22:" as *u8) 1064 let meA: i64 = g2_topkey(b, js, je, "\x22meshes\x22:" as *u8) 1065 if accA < 0 { g2_refuse("no accessors array" as *u8); return 4 } 1066 if bvA < 0 { g2_refuse("no bufferViews array" as *u8); return 4 } 1067 if meA < 0 { g2_refuse("no meshes array" as *u8); return 4 } 1068 let aS: *i64 = sys_mmap(G2_MAXEL*8) as *i64 1069 let aE: *i64 = sys_mmap(G2_MAXEL*8) as *i64 1070 let na: i64 = g2_elems(b, accA, je, aS, aE, G2_MAXEL) 1071 if na <= 0 { g2_refuse("accessors array unparseable or empty" as *u8); return 4 } 1072 let vS: *i64 = sys_mmap(G2_MAXEL*8) as *i64 1073 let vE: *i64 = sys_mmap(G2_MAXEL*8) as *i64 1074 let nv: i64 = g2_elems(b, bvA, je, vS, vE, G2_MAXEL) 1075 if nv <= 0 { g2_refuse("bufferViews array unparseable or empty" as *u8); return 4 } 1076 let mS: *i64 = sys_mmap(G2_MAXEL*8) as *i64 1077 let mE: *i64 = sys_mmap(G2_MAXEL*8) as *i64 1078 let nm: i64 = g2_elems(b, meA, je, mS, mE, G2_MAXEL) 1079 if nm <= 0 { g2_refuse("meshes array unparseable or empty" as *u8); return 4 } 1080 1081 // accessor + bufferView flat tables 1082 let accBV: *i64 = sys_mmap(na*8) as *i64 1083 let accBO: *i64 = sys_mmap(na*8) as *i64 1084 let accCT: *i64 = sys_mmap(na*8) as *i64 1085 let accN: *i64 = sys_mmap(na*8) as *i64 1086 let accV3: *i64 = sys_mmap(na*8) as *i64 1087 var i: i64 = 0 1088 while i < na { 1089 accBV[i] = g2_ifield(b, aS[i], aE[i], "\x22bufferView\x22:" as *u8, 0 - 1) 1090 accBO[i] = g2_ifield(b, aS[i], aE[i], "\x22byteOffset\x22:" as *u8, 0) 1091 accCT[i] = g2_ifield(b, aS[i], aE[i], "\x22componentType\x22:" as *u8, 0) 1092 accN[i] = g2_ifield(b, aS[i], aE[i], "\x22count\x22:" as *u8, 0) 1093 accV3[i] = g2_hasstr(b, aS[i], aE[i], "VEC3" as *u8) 1094 i = i + 1 1095 } 1096 let bvBO: *i64 = sys_mmap(nv*8) as *i64 1097 let bvLN: *i64 = sys_mmap(nv*8) as *i64 1098 let bvST: *i64 = sys_mmap(nv*8) as *i64 1099 i = 0 1100 while i < nv { 1101 bvBO[i] = g2_ifield(b, vS[i], vE[i], "\x22byteOffset\x22:" as *u8, 0) 1102 bvLN[i] = g2_ifield(b, vS[i], vE[i], "\x22byteLength\x22:" as *u8, 0) 1103 bvST[i] = g2_ifield(b, vS[i], vE[i], "\x22byteStride\x22:" as *u8, 0) 1104 i = i + 1 1105 } 1106 1107 // ---- L2 NAMED PARTS (semantic ladder 1785954089): the donor ALREADY CARRIES its own segmentation 1108 // in the skin. JOINTS_0 indexes skins[].joints[], which indexes nodes[], which carry NAMES. So a 1109 // rigged donor segments itself for free -- no clustering heuristic, no invented vocabulary, the 1110 // parts are named by whoever built the asset. 1111 let jn: *i64 = sys_mmap(G2_MAXEL*8) as *i64 1112 var njoint: i64 = 0 1113 let nn0: *i64 = sys_mmap(G2_MAXEL*8) as *i64 1114 let nn1: *i64 = sys_mmap(G2_MAXEL*8) as *i64 1115 var nnodes: i64 = 0 1116 // ★A MULTI-MESH DONOR HAS ONE SKIN PER MESH: taking skins[0] labelled all 34k triangles with the 1117 // HAIR rig (measured 2026-08-05). The skin that owns a primitive is the one on the NODE that 1118 // instantiates its mesh, so resolve mesh -> node -> skin, and label by NODE INDEX (globally unique) 1119 // rather than by a skin-local joint index (which means a different bone in every skin). 1120 let skJ0: *i64 = sys_mmap(G2_MAXEL*8) as *i64 1121 let skJN: *i64 = sys_mmap(G2_MAXEL*8) as *i64 1122 let skIBM: *i64 = sys_mmap(G2_MAXEL*8) as *i64 // R22: each skin's inverseBindMatrices accessor (-1 = absent) 1123 var nskin: i64 = 0 1124 let skA: i64 = g2_topkey(b, js, je, "\x22skins\x22:" as *u8) 1125 if skA >= 0 { 1126 let sS: *i64 = sys_mmap(G2_MAXEL*8) as *i64 1127 let sE: *i64 = sys_mmap(G2_MAXEL*8) as *i64 1128 let ns: i64 = g2_elems(b, skA, je, sS, sE, G2_MAXEL) 1129 var si: i64 = 0 1130 while si < ns { 1131 let jA: i64 = g2_key(b, sS[si], sE[si], "\x22joints\x22:" as *u8) 1132 skJ0[si] = njoint 1133 skJN[si] = 0 1134 skIBM[si] = g2_ifield(b, sS[si], sE[si], "\x22inverseBindMatrices\x22:" as *u8, 0 - 1) 1135 if jA >= 0 { 1136 let r: i64 = g2_intarray(b, jA, sE[si], ((jn as i64) + njoint*8) as *i64, G2_MAXEL - njoint) 1137 if r > 0 { skJN[si] = r; njoint = njoint + r } 1138 } 1139 si = si + 1 1140 } 1141 nskin = ns 1142 } 1143 let mskin: *i64 = sys_mmap(G2_MAXEL*8) as *i64 1144 var q4: i64 = 0 1145 while q4 < G2_MAXEL { mskin[q4] = 0 - 1; q4 = q4 + 1 } 1146 // R22: parent-of map from nodes[].children -- the hierarchy the SKEL parent column is read from 1147 let parentOf: *i64 = sys_mmap(G2_MAXEL*8) as *i64 1148 var q5: i64 = 0 1149 while q5 < G2_MAXEL { parentOf[q5] = 0 - 1; q5 = q5 + 1 } 1150 let chbuf: *i64 = sys_mmap(G2_MAXEL*8) as *i64 1151 let ndA: i64 = g2_topkey(b, js, je, "\x22nodes\x22:" as *u8) 1152 if ndA >= 0 { 1153 let dS: *i64 = sys_mmap(G2_MAXEL*8) as *i64 1154 let dE: *i64 = sys_mmap(G2_MAXEL*8) as *i64 1155 let nd: i64 = g2_elems(b, ndA, je, dS, dE, G2_MAXEL) 1156 let pr: *i64 = sys_mmap(16) as *i64 1157 var q3: i64 = 0 1158 while q3 < nd { 1159 g2_nodename(b, dS[q3], dE[q3], pr) 1160 nn0[q3] = pr[0] 1161 nn1[q3] = pr[1] 1162 let chA: i64 = g2_key(b, dS[q3], dE[q3], "\x22children\x22:" as *u8) 1163 if chA >= 0 { 1164 let nch: i64 = g2_intarray(b, chA, dE[q3], chbuf, G2_MAXEL) 1165 var ci: i64 = 0 1166 while ci < nch { if chbuf[ci] >= 0 { if chbuf[ci] < G2_MAXEL { parentOf[chbuf[ci]] = q3 } } ci = ci + 1 } 1167 } 1168 let mh: i64 = g2_ifield(b, dS[q3], dE[q3], "\x22mesh\x22:" as *u8, 0 - 1) 1169 let sk2: i64 = g2_ifield(b, dS[q3], dE[q3], "\x22skin\x22:" as *u8, 0 - 1) 1170 if mh >= 0 { if mh < G2_MAXEL { if sk2 >= 0 { mskin[mh] = sk2 } } } 1171 q3 = q3 + 1 1172 } 1173 nnodes = nd 1174 } 1175 let trij: *i64 = sys_mmap(G2_MAXTRI*8 + 64) as *i64 1176 1177 // output buffer + mm staging (positions are held as integer mm and unit-normalized BEFORE encoding: 1178 // the NXMSH2 ecosystem convention is f32 MILLIMETRES -- raw meter-scale VRM floats decode to a 1179 // 1.6mm sliver that renders as ~2px and collapses every IoU judge; measured 2026-08-05) 1180 let hdr: i64 = G2_HDR + G2_LAYROW 1181 let ob: *u8 = sys_mmap(hdr + G2_MAXTRI*G2_TRIREC + G2_MAXTRI*4 + 64) 1182 let stg: *i64 = sys_mmap(G2_MAXTRI*12*8 + 64) as *i64 1183 var nt: i64 = 0 1184 var prims: i64 = 0 1185 var accepted: i64 = 0 1186 var skipped: i64 = 0 1187 var degen: i64 = 0 1188 var trunc: i64 = 0 1189 var vseen: i64 = 0 1190 var miny: i64 = G2_MAGIC_2000000000 1191 var maxy: i64 = 0 - G2_MAGIC_2000000000 1192 // R22: the accepted-primitive list, consumed by the NXA emitter AFTER the acceptance predicate 1193 // has run exactly once. Recording is unconditional and output-neutral on the NXMSH2 path. 1194 let nxa_mode: i64 = g2_ends_nxa(outp) 1195 let apPOS: *i64 = sys_mmap(G2_MAXEL*8) as *i64 1196 let apIDX: *i64 = sys_mmap(G2_MAXEL*8) as *i64 1197 let apJOI: *i64 = sys_mmap(G2_MAXEL*8) as *i64 1198 let apWEI: *i64 = sys_mmap(G2_MAXEL*8) as *i64 1199 let apMI: *i64 = sys_mmap(G2_MAXEL*8) as *i64 1200 var ap_over: i64 = 0 1201 1202 let pS: *i64 = sys_mmap(G2_MAXEL*8) as *i64 1203 let pE: *i64 = sys_mmap(G2_MAXEL*8) as *i64 1204 var mi: i64 = 0 1205 var meshes_skipped: i64 = 0 1206 while mi < nm { 1207 var mesh_ok: i64 = 1 1208 if (skip as i64) != 0 { if g2_name_has(b, mS[mi], mE[mi], skip) == 1 { mesh_ok = 0; meshes_skipped = meshes_skipped + 1 } } 1209 var prA: i64 = 0 - 1 1210 if mesh_ok == 1 { prA = g2_key(b, mS[mi], mE[mi], "\x22primitives\x22:" as *u8) } 1211 if prA >= 0 { 1212 let np: i64 = g2_elems(b, prA, mE[mi], pS, pE, G2_MAXEL) 1213 var pi: i64 = 0 1214 while pi < np { 1215 prims = prims + 1 1216 var ok: i64 = 1 1217 let mode: i64 = g2_ifield(b, pS[pi], pE[pi], "\x22mode\x22:" as *u8, G2_MODE_TRIS) 1218 if mode != G2_MODE_TRIS { ok = 0 } 1219 let atA: i64 = g2_key(b, pS[pi], pE[pi], "\x22attributes\x22:" as *u8) 1220 var posi: i64 = 0 - 1 1221 if atA < 0 { ok = 0 } 1222 if ok == 1 { 1223 let atE2: i64 = g2_objend(b, atA, pE[pi]) 1224 if atE2 < 0 { ok = 0 } else { posi = g2_ifield(b, atA, atE2, "\x22POSITION\x22:" as *u8, 0 - 1) } 1225 } 1226 var joi: i64 = 0 - 1 1227 if ok == 1 { if atA >= 0 { let atE3: i64 = g2_objend(b, atA, pE[pi]); if atE3 > 0 { joi = g2_ifield(b, atA, atE3, "\x22JOINTS_0\x22:" as *u8, 0 - 1) } } } 1228 var wei: i64 = 0 - 1 1229 if ok == 1 { if atA >= 0 { let atE4: i64 = g2_objend(b, atA, pE[pi]); if atE4 > 0 { wei = g2_ifield(b, atA, atE4, "\x22WEIGHTS_0\x22:" as *u8, 0 - 1) } } } 1230 let idxi: i64 = g2_ifield(b, pS[pi], pE[pi], "\x22indices\x22:" as *u8, 0 - 1) 1231 if posi < 0 { ok = 0 } 1232 if idxi < 0 { ok = 0 } 1233 if posi >= na { ok = 0 } 1234 if idxi >= na { ok = 0 } 1235 if ok == 1 { if accCT[posi] != G2_CT_F32 { ok = 0 } } 1236 if ok == 1 { if accV3[posi] != 1 { ok = 0 } } 1237 if ok == 1 { if accCT[idxi] != G2_CT_U16 { if accCT[idxi] != G2_CT_U32 { ok = 0 } } } 1238 if ok == 1 { if accN[idxi] % 3 != 0 { ok = 0 } } 1239 if ok == 1 { if accBV[posi] < 0 { ok = 0 } } 1240 if ok == 1 { if accBV[idxi] < 0 { ok = 0 } } 1241 if ok == 1 { if accBV[posi] >= nv { ok = 0 } } 1242 if ok == 1 { if accBV[idxi] >= nv { ok = 0 } } 1243 if ok == 1 { if G2_SKN > 0 { let sl2: *i64 = G2_SKL as *i64; var si2: i64 = 0; while si2 < G2_SKN { if sl2[si2] == prims - 1 { ok = 0 } si2 = si2 + 1 } } } 1244 if ok == 0 { skipped = skipped + 1 } else { 1245 let pb: i64 = accBV[posi] 1246 let ib2: i64 = accBV[idxi] 1247 var pstride: i64 = bvST[pb] 1248 if pstride == 0 { pstride = 12 } 1249 let pbase: i64 = bino + bvBO[pb] + accBO[posi] 1250 let ibase: i64 = bino + bvBO[ib2] + accBO[idxi] 1251 var isz: i64 = 2 1252 if accCT[idxi] == G2_CT_U32 { isz = 4 } 1253 let pcount: i64 = accN[posi] 1254 vseen = vseen + pcount 1255 let ntri: i64 = accN[idxi] / 3 1256 var pmnx: i64 = G2_MAGIC_2000000000 1257 var pmxx: i64 = 0 - G2_MAGIC_2000000000 1258 var pmny: i64 = G2_MAGIC_2000000000 1259 var pmxy: i64 = 0 - G2_MAGIC_2000000000 1260 var pmnz: i64 = G2_MAGIC_2000000000 1261 var pmxz: i64 = 0 - G2_MAGIC_2000000000 1262 var t: i64 = 0 1263 while t < ntri { 1264 if nt >= G2_MAXTRI { trunc = 1; t = t + ntri } else { 1265 var i0: i64 = 0 1266 var i1: i64 = 0 1267 var i2: i64 = 0 1268 if isz == 2 { i0 = g2_u16(b, ibase + (t*3)*2); i1 = g2_u16(b, ibase + (t*3+1)*2); i2 = g2_u16(b, ibase + (t*3+2)*2) } 1269 if isz == 4 { i0 = g2_u32(b, ibase + (t*3)*4); i1 = g2_u32(b, ibase + (t*3+1)*4); i2 = g2_u32(b, ibase + (t*3+2)*4) } 1270 var okv: i64 = 1 1271 if i0 >= pcount { okv = 0 } 1272 if i1 >= pcount { okv = 0 } 1273 if i2 >= pcount { okv = 0 } 1274 if G2_ERR != 0 { okv = 0 } 1275 if okv == 1 { 1276 let w00: i64 = g2_u32(b, pbase + i0*pstride) 1277 let w01: i64 = g2_u32(b, pbase + i0*pstride + 4) 1278 let w02: i64 = g2_u32(b, pbase + i0*pstride + 8) 1279 let w10: i64 = g2_u32(b, pbase + i1*pstride) 1280 let w11: i64 = g2_u32(b, pbase + i1*pstride + 4) 1281 let w12: i64 = g2_u32(b, pbase + i1*pstride + 8) 1282 let w20: i64 = g2_u32(b, pbase + i2*pstride) 1283 let w21: i64 = g2_u32(b, pbase + i2*pstride + 4) 1284 let w22: i64 = g2_u32(b, pbase + i2*pstride + 8) 1285 if G2_ERR != 0 { okv = 0 } else { 1286 let x0: i64 = g2_f32mm(w00) 1287 let y0: i64 = g2_f32mm(w01) 1288 let z0: i64 = g2_f32mm(w02) 1289 let x1: i64 = g2_f32mm(w10) 1290 let y1: i64 = g2_f32mm(w11) 1291 let z1: i64 = g2_f32mm(w12) 1292 let x2: i64 = g2_f32mm(w20) 1293 let y2: i64 = g2_f32mm(w21) 1294 let z2: i64 = g2_f32mm(w22) 1295 if y0 < miny { miny = y0 } 1296 if y0 > maxy { maxy = y0 } 1297 if y1 < miny { miny = y1 } 1298 if y1 > maxy { maxy = y1 } 1299 if y2 < miny { miny = y2 } 1300 if y2 > maxy { maxy = y2 } 1301 if x0 < pmnx { pmnx = x0 } 1302 if x0 > pmxx { pmxx = x0 } 1303 if y0 < pmny { pmny = y0 } 1304 if y0 > pmxy { pmxy = y0 } 1305 if z0 < pmnz { pmnz = z0 } 1306 if z0 > pmxz { pmxz = z0 } 1307 let e1x: i64 = x1-x0 1308 let e1y: i64 = y1-y0 1309 let e1z: i64 = z1-z0 1310 let e2x: i64 = x2-x0 1311 let e2y: i64 = y2-y0 1312 let e2z: i64 = z2-z0 1313 var cx: i64 = e1y*e2z - e1z*e2y 1314 var cy: i64 = e1z*e2x - e1x*e2z 1315 var cz: i64 = e1x*e2y - e1y*e2x 1316 // Degeneracy is a zero cross product, not an overflowed squared norm. 1317 if cx == 0 && cy == 0 && cz == 0 { degen = degen + 1 } else { 1318 let so: i64 = nt*12 1319 stg[so]=x0; stg[so+1]=y0; stg[so+2]=z0 1320 stg[so+3]=x1; stg[so+4]=y1; stg[so+5]=z1 1321 stg[so+6]=x2; stg[so+7]=y2; stg[so+8]=z2 1322 // part label = the joint bound to vertex 0 (rigid-dominant proxy; 1323 // full weight-max over 3 verts is the named refinement) 1324 var lab: i64 = 0 - 1 1325 if joi >= 0 { if joi < na { if accBV[joi] >= 0 { if accBV[joi] < nv { 1326 var jstride: i64 = bvST[accBV[joi]] 1327 var jsz: i64 = 1 1328 if accCT[joi] == G2_CT_U16 { jsz = 2 } 1329 if jstride == 0 { jstride = jsz*4 } 1330 let jbase: i64 = bino + bvBO[accBV[joi]] + accBO[joi] 1331 if jsz == 1 { lab = b[jbase + i0*jstride] as i64 } 1332 if jsz == 2 { lab = g2_u16(b, jbase + i0*jstride) } 1333 // skin-local joint -> NODE index, via the skin that owns THIS mesh 1334 var sk3: i64 = 0 - 1 1335 if mi < G2_MAXEL { sk3 = mskin[mi] } 1336 if sk3 >= 0 { if sk3 < nskin { if lab >= 0 { if lab < skJN[sk3] { lab = jn[skJ0[sk3] + lab] } else { lab = 0 - 1 } } } } else { lab = 0 - 1 } 1337 } } } } 1338 trij[nt] = lab 1339 gn_unit3(cx, cy, cz, ((stg as i64) + (so + 9)*8) as *i64) 1340 // Shared normal owner writes all three Q23 components. 1341 // No squared i64 norm is formed in this converter. 1342 nt = nt + 1 1343 } 1344 } 1345 } 1346 t = t + 1 1347 } 1348 } 1349 if G2_REP == 1 { hw("PRIM " as *u8); pn(prims - 1); hw(" mesh " as *u8); pn(mi); hw(" tris " as *u8); pn(ntri); hw(" x " as *u8); pn(pmnx); hw(".." as *u8); pn(pmxx); hw(" y " as *u8); pn(pmny); hw(".." as *u8); pn(pmxy); hw(" z " as *u8); pn(pmnz); hw(".." as *u8); pn(pmxz); hw("\n" as *u8) } 1350 if accepted < G2_MAXEL { apPOS[accepted] = posi; apIDX[accepted] = idxi; apJOI[accepted] = joi; apWEI[accepted] = wei; apMI[accepted] = mi } else { ap_over = 1 } 1351 accepted = accepted + 1 1352 } 1353 pi = pi + 1 1354 } 1355 } 1356 mi = mi + 1 1357 } 1358 1359 if nt == 0 { g2_refuse("zero triangles accepted -- a form oracle with no surface is vacuous" as *u8); return 5 } 1360 if trunc == 1 { g2_refuse("tri cap hit -- a truncated oracle is a lying ruler (raise G2_MAXTRI deliberately)" as *u8); return 7 } 1361 if G2_ERR != 0 { g2_refuse("out-of-bounds read during extraction -- file declares data it does not carry" as *u8); return 7 } 1362 // unit normalization: determine the AUTHORING SCALE (see g2_pick_scale), then emit. The bound 1363 // is DATA, not code, and its provenance is printed -- the estate's own build governor prints 1364 // envelope_src= for exactly this reason: a bound whose source is unstated gets trusted as 1365 // measured when it may be a built-in fallback. 1366 let hgt: i64 = maxy - miny 1367 var cpath: *u8 = G2_UNITS_CONF 1368 if G2_UCONF != 0 { cpath = G2_UCONF as *u8 } 1369 var floor_mm: i64 = g2_conf_i64(cpath, "sliver_floor_mm" as *u8, 0 - 1) 1370 var bsrc: *u8 = "conf" as *u8 1371 if floor_mm <= 0 { floor_mm = G2_DEF_SLIVER_FLOOR_MM; bsrc = "builtin-default" as *u8 } 1372 let dv: i64 = g2_pick_scale(hgt, floor_mm) 1373 hw(" units: height_raw=" as *u8); pn(hgt) 1374 hw(" sliver_floor_mm=" as *u8); pn(floor_mm) 1375 hw(" ceil_mm=" as *u8); pn(floor_mm*G2_SCALE_STEP - 1) 1376 hw(" bounds_src=" as *u8); hw(bsrc) 1377 hw(" bounds_file=" as *u8); hw(cpath) 1378 hw(" scale_div=" as *u8); pn(dv); hw("\n" as *u8) 1379 if dv == 0 { g2_refuse("no power-of-1000 scale lands the body above the sliver floor -- refusing to guess units" as *u8); hw(" height_raw=" as *u8); pn(hgt); hw(" sliver_floor_mm=" as *u8); pn(floor_mm); hw("\n" as *u8); return 8 } 1380 // ---- R22: an .nxa output leaves the NXMSH2 path here, AFTER the shared acceptance predicate and 1381 // unit determination, and carries the rig into NXANIM01. Nothing below this branch runs for it. 1382 if nxa_mode == 1 { 1383 if ap_over == 1 { g2_refuse("nxa: accepted-primitive list exceeded G2_MAXEL -- a prefix would be a truncated rig; raise it deliberately" as *u8); return 7 } 1384 let cx: *i64 = sys_mmap(G2_CX_WORDS*8) as *i64 1385 cx[0] = b as i64; cx[1] = bino; cx[2] = accBV as i64; cx[3] = accBO as i64; cx[4] = accCT as i64 1386 cx[5] = accN as i64; cx[6] = bvBO as i64; cx[7] = bvST as i64; cx[8] = accepted 1387 cx[9] = apPOS as i64; cx[10] = apIDX as i64; cx[11] = apJOI as i64; cx[12] = apWEI as i64; cx[13] = apMI as i64 1388 cx[14] = mskin as i64; cx[15] = nskin; cx[16] = skJ0 as i64; cx[17] = skJN as i64; cx[18] = skIBM as i64 1389 cx[19] = jn as i64; cx[20] = parentOf as i64; cx[21] = nnodes; cx[22] = dv; cx[23] = outp as i64 1390 cx[24] = na; cx[25] = nv; cx[26] = aS as i64; cx[27] = aE as i64 1391 let rcn: i64 = g2_emit_nxa(cx) 1392 return rcn 1393 } 1394 // ---- layer plan: one layer per USED joint, contiguous by construction (NXMSH2 requires ranges). 1395 // A donor with no skin emits the single "skin" layer exactly as before (additive, never a regression). 1396 var nlay: i64 = 1 1397 let lj: *i64 = sys_mmap(G2_MAXEL*8) as *i64 1398 let lcnt: *i64 = sys_mmap(G2_MAXEL*8) as *i64 1399 if njoint > 0 { 1400 var u: i64 = 0 1401 while u < G2_MAXEL { lcnt[u] = 0; u = u + 1 } 1402 var t3: i64 = 0 1403 while t3 < nt { let L: i64 = trij[t3]; if L >= 0 { if L < G2_MAXEL { lcnt[L] = lcnt[L] + 1 } } t3 = t3 + 1 } 1404 nlay = 0 1405 u = 0 1406 while u < G2_MAXEL { if lcnt[u] > 0 { lj[nlay] = u; nlay = nlay + 1 } u = u + 1 } 1407 if nlay == 0 { nlay = 1 } 1408 } 1409 let hdr2: i64 = G2_HDR + nlay*G2_LAYROW 1410 let gc: i64 = g2_enc(G2_GREY, 1000) 1411 var oc: i64 = 0 1412 var Lx: i64 = 0 1413 while Lx < nlay { 1414 var wt: i64 = 0 1415 while wt < nt { 1416 var take: i64 = 1 1417 if nlay > 1 { take = 0; if trij[wt] == lj[Lx] { take = 1 } } 1418 if take == 1 { 1419 let so2: i64 = wt*12 1420 let o: i64 = hdr2 + oc*G2_TRIREC 1421 var pc: i64 = 0 1422 while pc < 9 { g2_wr32(ob, o + pc*4, g2_enc(stg[so2+pc]/dv, 1)); pc = pc + 1 } 1423 let nb: i64 = gn_f32(stg[so2+9]) 1424 let nb2: i64 = gn_f32(stg[so2+10]) 1425 let nb3: i64 = gn_f32(stg[so2+11]) 1426 var q: i64 = 0 1427 while q < 3 { g2_wr32(ob, o+36+q*12, nb); g2_wr32(ob, o+40+q*12, nb2); g2_wr32(ob, o+44+q*12, nb3); q = q + 1 } 1428 g2_wr32(ob, o+72, gc); g2_wr32(ob, o+76, gc); g2_wr32(ob, o+80, gc) 1429 oc = oc + 1 1430 } 1431 wt = wt + 1 1432 } 1433 Lx = Lx + 1 1434 } 1435 miny = miny/dv 1436 maxy = maxy/dv 1437 // header + single layer "skin" + per-tri layer ids 1438 ob[0]=78 as u8; ob[1]=88 as u8; ob[2]=77 as u8; ob[3]=83 as u8 1439 ob[4]=72 as u8; ob[5]=50 as u8; ob[6]=0 as u8; ob[7]=0 as u8 1440 g2_wr32(ob, 8, nlay); g2_wr32(ob, 12, nt) 1441 // layer table: 16-byte name from the donor's own node name, then offset+count 1442 var run: i64 = 0 1443 var Ly: i64 = 0 1444 while Ly < nlay { 1445 let lb: i64 = G2_HDR + Ly*G2_LAYROW 1446 var q2: i64 = 0 1447 while q2 < 16 { ob[lb+q2] = 0 as u8; q2 = q2 + 1 } 1448 var cnt2: i64 = nt 1449 if nlay > 1 { 1450 let jidx: i64 = lj[Ly] 1451 cnt2 = lcnt[jidx] 1452 let nd2: i64 = jidx 1453 if nd2 >= 0 { if nd2 < nnodes { if nn1[nd2] > nn0[nd2] { 1454 var w2: i64 = 0 1455 while w2 < 15 { if nn0[nd2]+w2 < nn1[nd2] { ob[lb+w2] = b[nn0[nd2]+w2] } w2 = w2 + 1 } 1456 } } } 1457 if ob[lb] == (0 as u8) { ob[lb]=106 as u8; ob[lb+1]=111 as u8; ob[lb+2]=105 as u8; ob[lb+3]=110 as u8; ob[lb+4]=116 as u8 } 1458 } else { ob[lb]=115 as u8; ob[lb+1]=107 as u8; ob[lb+2]=105 as u8; ob[lb+3]=110 as u8 } 1459 g2_wr32(ob, lb+16, run); g2_wr32(ob, lb+20, cnt2) 1460 run = run + cnt2 1461 Ly = Ly + 1 1462 } 1463 var z: i64 = 0 1464 var Lz: i64 = 0 1465 var zc: i64 = 0 1466 while Lz < nlay { 1467 var cz: i64 = nt 1468 if nlay > 1 { cz = lcnt[lj[Lz]] } 1469 var k2: i64 = 0 1470 while k2 < cz { g2_wr32(ob, hdr2 + nt*G2_TRIREC + zc*4, Lz); zc = zc + 1; k2 = k2 + 1 } 1471 Lz = Lz + 1 1472 } 1473 let bytes: i64 = hdr2 + nt*G2_TRIREC + nt*4 1474 let ofd: i64 = sys_openat_wr(outp, MODE_0644) 1475 if ofd < 0 { g2_refuse("output path unwritable" as *u8); return 6 } 1476 sys_write(ofd, ob, bytes) 1477 sys_close(ofd) 1478 1479 hw("{\x22organ\x22:\x22nx_gltf2mesh\x22,\x22prims\x22:" as *u8); pn(prims) 1480 hw(",\x22prims_accepted\x22:" as *u8); pn(accepted) 1481 hw(",\x22prims_skipped\x22:" as *u8); pn(skipped) 1482 hw(",\x22verts_seen\x22:" as *u8); pn(vseen) 1483 hw(",\x22tris\x22:" as *u8); pn(nt) 1484 hw(",\x22degenerate_dropped\x22:" as *u8); pn(degen) 1485 hw(",\x22meshes_skipped_by_name\x22:" as *u8); pn(meshes_skipped) 1486 hw(",\x22skin_joints\x22:" as *u8); pn(njoint) 1487 hw(",\x22named_parts_emitted\x22:" as *u8); pn(nlay) 1488 hw(",\x22miny_mm\x22:" as *u8); pn(miny) 1489 hw(",\x22maxy_mm\x22:" as *u8); pn(maxy) 1490 hw(",\x22scale_div\x22:" as *u8); pn(dv) 1491 hw(",\x22bytes\x22:" as *u8); pn(bytes) 1492 hw(",\x22note\x22:\x22bind-pose model space; node transforms not applied (skinned donors); morph-target POSITIONs excluded by attributes-scope\x22}" as *u8) 1493 hw("\n" as *u8) 1494 return 0 1495} 1496 1497// ---- selftest: build a real 1-tri glb on disk, convert it, then three malformed inputs must REFUSE ---- 1498func st_wr(path: *u8, buf: *u8, n: i64) -> i64 { 1499 let fd: i64 = sys_openat_wr(path, 420) 1500 if fd < 0 { return 0 - 1 } 1501 sys_write(fd, buf, n) 1502 sys_close(fd) 1503 return 0 1504} 1505func st_mkglb(buf: *u8, breakmode: i64) -> i64 { 1506 // JSON (compact, machine-shape) 1507 let j: *u8 = "{\x22asset\x22:{\x22version\x22:\x222.0\x22},\x22meshes\x22:[{\x22primitives\x22:[{\x22attributes\x22:{\x22POSITION\x22:0},\x22indices\x22:1}]}],\x22accessors\x22:[{\x22bufferView\x22:0,\x22componentType\x22:5126,\x22count\x22:3,\x22type\x22:\x22VEC3\x22},{\x22bufferView\x22:1,\x22componentType\x22:5123,\x22count\x22:3,\x22type\x22:\x22SCALAR\x22}],\x22bufferViews\x22:[{\x22buffer\x22:0,\x22byteOffset\x22:0,\x22byteLength\x22:36},{\x22buffer\x22:0,\x22byteOffset\x22:36,\x22byteLength\x22:6}],\x22buffers\x22:[{\x22byteLength\x22:44}]}" as *u8 1508 var jl: i64 = 0 1509 while j[jl] != (0 as u8) { jl = jl + 1 } 1510 var jp: i64 = jl 1511 while jp % 4 != 0 { jp = jp + 1 } 1512 // bin length appears ONLY as a literal below: locals in this frame mis-read (nx_cc bug 1785936860) 1513 let total: i64 = 12 + 8 + jp + 8 + 44 1514 var o: i64 = 0 1515 buf[0]=103 as u8; buf[1]=108 as u8; buf[2]=84 as u8; buf[3]=70 as u8 1516 if breakmode == 2 { buf[0]=88 as u8 } 1517 g2_wr32(buf, 4, 2) 1518 g2_wr32(buf, 8, total) 1519 g2_wr32(buf, 12, jp) 1520 buf[16]=74 as u8; buf[17]=83 as u8; buf[18]=79 as u8; buf[19]=78 as u8 1521 var i: i64 = 0 1522 while i < jl { buf[20+i] = j[i]; i = i + 1 } 1523 while i < jp { buf[20+i] = 32 as u8; i = i + 1 } 1524 o = 20 + jp 1525 g2_wr32(buf, o, 44) 1526 buf[o+4]=66 as u8; buf[o+5]=73 as u8; buf[o+6]=78 as u8; buf[o+7]=0 as u8 1527 // verts (0,0,0) (1,0,0) (0,1,0) as f32 -- offsets all o+N literals, NO further locals (nx_cc bug 1785936860) 1528 g2_wr32(buf, o+8, 0); g2_wr32(buf, o+12, 0); g2_wr32(buf, o+16, 0) 1529 g2_wr32(buf, o+20, g2_enc(1000, 1000)); g2_wr32(buf, o+24, 0); g2_wr32(buf, o+28, 0) 1530 g2_wr32(buf, o+32, 0); g2_wr32(buf, o+36, g2_enc(1000, 1000)); g2_wr32(buf, o+40, 0) 1531 buf[o+44]=0 as u8; buf[o+45]=0 as u8; buf[o+46]=1 as u8; buf[o+47]=0 as u8 1532 buf[o+48]=2 as u8; buf[o+49]=0 as u8; buf[o+50]=0 as u8; buf[o+51]=0 as u8 1533 if breakmode == 1 { return total - 9 } 1534 return total 1535} 1536func g2_selftest() -> i64 { 1537 var fails: i64 = 0 1538 let buf: *u8 = sys_mmap(G2_MAGIC_4096) 1539 let n0: i64 = st_mkglb(buf, 0) 1540 st_wr("/tmp/g2_ok.glb" as *u8, buf, n0) 1541 let r0: i64 = g2_convert("/tmp/g2_ok.glb" as *u8, "/tmp/g2_ok.nxmesh" as *u8, 0 as *u8) 1542 if r0 == 0 { 1543 let vb: *u8 = sys_mmap(G2_MAGIC_4096) 1544 let vfd: i64 = sys_openat_rd("/tmp/g2_ok.nxmesh" as *u8) 1545 let vn: i64 = sys_read(vfd, vb, G2_MAGIC_4096) 1546 sys_close(vfd) 1547 var t0: i64 = 0 1548 if vn > 40 { if vb[0] == (78 as u8) { if vb[5] == (50 as u8) { t0 = 1 } } } 1549 if t0 == 1 { hw("T0 PASS convert emits valid NXMSH2 (1 tri)\n" as *u8) } else { fails = fails + 1; hw("T0 FAIL output not NXMSH2\n" as *u8) } 1550 } else { fails = fails + 1; hw("T0 FAIL convert refused a valid glb\n" as *u8) } 1551 let n1: i64 = st_mkglb(buf, 1) 1552 st_wr("/tmp/g2_trunc.glb" as *u8, buf, n1) 1553 if g2_convert("/tmp/g2_trunc.glb" as *u8, "/tmp/g2_x1.nxmesh" as *u8, 0 as *u8) != 0 { hw("T1 PASS truncated glb refused\n" as *u8) } else { fails = fails + 1; hw("T1 FAIL truncated glb accepted\n" as *u8) } 1554 let n2: i64 = st_mkglb(buf, 2) 1555 st_wr("/tmp/g2_badmagic.glb" as *u8, buf, n2) 1556 if g2_convert("/tmp/g2_badmagic.glb" as *u8, "/tmp/g2_x2.nxmesh" as *u8, 0 as *u8) != 0 { hw("T2 PASS bad magic refused\n" as *u8) } else { fails = fails + 1; hw("T2 FAIL bad magic accepted\n" as *u8) } 1557 if g2_convert("/tmp/g2_absent_zz.glb" as *u8, "/tmp/g2_x3.nxmesh" as *u8, 0 as *u8) != 0 { hw("T3 PASS absent input refused\n" as *u8) } else { fails = fails + 1; hw("T3 FAIL absent input accepted\n" as *u8) } 1558 if fails == 0 { hw("GLTF2MESH-SELFTEST GREEN 4/4\n" as *u8); return 0 } 1559 hw("GLTF2MESH-SELFTEST RED fails=" as *u8); pn(fails); hw("\n" as *u8) 1560 return 1 1561} 1562 1563 1564// Additive preservation-only command. Legacy mesh/NXA conversion remains separate. 1565import "nx_gltf_load.nx" 1566import "nx_bundle_ingest.nx" 1567const GPN_CTX_WORDS:i64=18 1568// GLB stores total byte length in uint32; reserve normalization header/alignment headroom. 1569const GPN_GLB_LENGTH_MAX:i64=4294967295 1570const GPN_NORMALIZATION_HEADROOM:i64=64 1571func gpn_reason(code:i64)->*u8 { 1572 if code==-1{return "invalid-or-overlapping-buffers"} 1573 if code==-10{return "invalid-json"} 1574 if code==-11{return "asset-version-field-refused"} 1575 if code==-12{return "gltf-version-unsupported"} 1576 if code==-13{return "buffers-field-refused"} 1577 if code==-14{return "multiple-buffers-unsupported"} 1578 if code==-15{return "buffer-byte-length-refused"} 1579 if code==-16{return "output-capacity-refused"} 1580 if code==-17{return "buffer-uri-field-refused"} 1581 if code==-18{return "buffer-uri-form-unsupported"} 1582 if code==-19{return "base64-or-decoded-length-refused"} 1583 if code==-20{return "allocation-failed"} 1584 return "normalization-refused" 1585} 1586 1587// External image references are preserved, never fetched. Receipt points to exact source literals. 1588func gpn_deps(cx:*i64,w:*JsonWriter)->i64 { 1589 let src:*u8=cx[14] as *u8;let n:i64=cx[6] 1590 if (src as i64)<=0{return 0} 1591 let states:*u8=sys_mmap(n);let t:*NxJsonTok=nx_json_new(src,n);let sp:*i64=sys_mmap(32) as *i64 1592 var result:i64=-1 1593 if (states as i64)>0 && (t as i64)>0 && (sp as i64)>0 { 1594 glp_reset(t,src,n,0) 1595 let have:i64=glp_member(t,"images" as *u8,sp,states,n) 1596 if have==0{result=0} 1597 if have==1 { 1598 glp_reset(t,src,n,sp[0]) 1599 if t.kind==NX_JSON_LBRACKET { 1600 nx_json_next(t);result=0;var index:i64=0;var unresolved:i64=0 1601 while t.kind!=NX_JSON_RBRACKET { 1602 let hasuri:i64=glp_member(t,"uri" as *u8,sp,states,n) 1603 if hasuri<0{result=-1;break} 1604 let next:i64=t.tok_off 1605 if hasuri==1 { 1606 glp_reset(t,src,n,sp[0]) 1607 if t.kind!=NX_JSON_STRING{result=-1;break} 1608 var embedded:i64=0 1609 if t.tok_len>=7 { 1610 let p:*u8=(src as i64+t.tok_off+1) as *u8 1611 if p[0]==100 as u8 && p[1]==97 as u8 && p[2]==116 as u8 && p[3]==97 as u8 && p[4]==58 as u8{embedded=1} 1612 } 1613 if embedded==0 { 1614 unresolved=unresolved+1;result=result+t.tok_len*6+BIX_JSON_ROW_ROOM 1615 if (w as i64)>0 { 1616 var rc:i64=json_begin_object(w) 1617 rc=rc | bix_num(w,"image_index",index) 1618 rc=rc | bix_key(w,"state","external-uri-unresolved-not-fetched") 1619 rc=rc | json_emit_key(w,"uri_json_literal",16) 1620 rc=rc | json_emit_string(w,(src as i64+t.tok_off) as *u8,t.tok_len) 1621 rc=rc | json_end_object(w) 1622 if rc<0{result=-1;break} 1623 } 1624 } 1625 } 1626 glp_reset(t,src,n,next);index=index+1 1627 if t.kind==NX_JSON_RBRACKET{break} 1628 if t.kind!=NX_JSON_COMMA{result=-1;break};nx_json_next(t) 1629 } 1630 cx[16]=unresolved;cx[17]=index 1631 } 1632 } 1633 } 1634 if (sp as i64)>0{sys_munmap(sp as *u8,32)} 1635 if (t as i64)>0{sys_munmap(t as *u8,NX_JSONTOK_BYTES)} 1636 if (states as i64)>0{sys_munmap(states,n)} 1637 return result 1638} 1639 1640func gpn_receipt(cx:*i64)->i64 { 1641 if sys_clock_gettime_real((cx as i64+12*8) as *i64)!=0{return -1} 1642 let cap:i64=BIX_JSON_BASE_ROOM+cx[15]+6*(bic_len(cx[0] as *u8)+bic_len(cx[1] as *u8)) 1643 let buf:*u8=sys_mmap(cap) 1644 if (buf as i64)<=0{return -1} 1645 let w:*JsonWriter=sys_mmap(40) as *JsonWriter 1646 if (w as i64)<=0{sys_munmap(buf,cap);return -1} 1647 let prior:*u8=sys_mmap(JE_MAX_DEPTH+16) 1648 if (prior as i64)<=0{sys_munmap(w as *u8,40);sys_munmap(buf,cap);return -1} 1649 w.buf=buf;w.pos=0;w.cap=cap;w.depth=0;w.prior=prior 1650 var rc:i64=json_begin_object(w) 1651 rc=rc | bix_key(w,"schema","nishi.gltf.normalization.v1") 1652 rc=rc | bix_key(w,"state",cx[9] as *u8) 1653 rc=rc | bix_key(w,"source",cx[0] as *u8) 1654 rc=rc | bix_key(w,"source_expected_sha256",cx[3] as *u8) 1655 rc=rc | bix_key(w,"source_sha256",cx[4] as *u8) 1656 rc=rc | bix_num(w,"source_bytes",cx[6]) 1657 rc=rc | bix_key(w,"output",cx[1] as *u8) 1658 rc=rc | bix_key(w,"output_sha256",cx[5] as *u8) 1659 rc=rc | bix_num(w,"output_bytes",cx[7]) 1660 rc=rc | bix_num(w,"code",cx[8]) 1661 rc=rc | bix_num(w,"exit_code",cx[11]) 1662 rc=rc | bix_num(w,"max_input_bytes",cx[10]) 1663 rc=rc | bix_key(w,"preservation","exact authored JSON except buffers[0].uri; exact decoded BIN; images and animation retained") 1664 rc=rc | bix_key(w,"scope","single embedded glTF2 buffer; canonical Base64; no full glTF schema validation or rendering acceptance") 1665 rc=rc | bix_num(w,"observed_unix",cx[12]) 1666 var depstate:*u8="not-inspected" 1667 if cx[14]!=0{depstate="source-inspected"} 1668 rc=rc | bix_key(w,"dependency_inventory_state",depstate) 1669 var outkind:*u8="candidate-only" 1670 if fsx_seq(cx[9] as *u8,"normalized-verified")==1{outkind="verified-written-or-identical"} 1671 rc=rc | bix_key(w,"output_identity_kind",outkind) 1672 rc=rc | bix_num(w,"images",cx[17]) 1673 rc=rc | bix_num(w,"external_image_uris_unresolved",cx[16]) 1674 rc=rc | json_emit_key(w,"unresolved_dependencies",23) 1675 rc=rc | json_begin_array(w) 1676 if gpn_deps(cx,w)<0{rc=-1} 1677 rc=rc | json_end_array(w) 1678 rc=rc | json_end_object(w) 1679 if rc>=0 {rc=bix_receipt(cx[2] as *u8,w)} 1680 sys_munmap(prior,JE_MAX_DEPTH+16);sys_munmap(w as *u8,40);sys_munmap(buf,cap) 1681 return rc 1682} 1683func gpn_convert(cx:*i64,src:*u8,out:*u8,sha:*u8,digest:*u8)->i64 { 1684 let n:i64=cx[6] 1685 if cgo_read(cx[0] as *u8,src,n+1)!=n{cx[9]="source-read-or-size-changed" as i64;return 3} 1686 sha256_digest(src,n,digest);pv_hex(digest,sha);cx[4]=sha as i64 1687 if fsx_seq(sha,cx[3] as *u8)!=1{cx[9]="source-identity-mismatch" as i64;return 3} 1688 cx[14]=src as i64 1689 let depcap:i64=gpn_deps(cx,0 as *JsonWriter) 1690 if depcap<0{cx[14]=0;cx[9]="image-dependency-inventory-refused" as i64;return 3} 1691 cx[15]=depcap 1692 let built:i64=gltf_json_to_glb(src,n,out,n+GPN_NORMALIZATION_HEADROOM) 1693 if built<0{cx[8]=built;cx[9]=gpn_reason(built) as i64;return 3} 1694 cx[7]=built 1695 let outsha:*u8=(sha as i64+PV_SHA_HEX+1) as *u8 1696 sha256_digest(out,built,digest);pv_hex(digest,outsha);cx[5]=outsha as i64 1697 cx[9]="validated-output-pending" as i64 1698 if gpn_receipt(cx)!=0{cx[9]="intent-receipt-failed" as i64;return 4} 1699 let stored:i64=bix_store(cx[1] as *u8,out,built) 1700 if stored!=0{cx[8]=stored;cx[9]=bix_store_state(stored) as i64;return 4} 1701 cx[9]="normalized-verified" as i64;return 0 1702} 1703func gpn_main(argc:i64,argv:*i64)->i64 { 1704 if argc!=7{hw("{\"schema\":\"nishi.gltf.normalization.v1\",\"state\":\"usage-refused\",\"usage\":\"normalize-json input.gltf output.glb receipt.jsonl max_input_bytes expected_input_sha256\"}\n" as *u8);return 2} 1705 let maximum:i64=bix_uint(argv[5] as *u8) 1706 if maximum<=0{hw("{\"state\":\"invalid-input-limit\"}\n" as *u8);return 2} 1707 if maximum>GPN_GLB_LENGTH_MAX-GPN_NORMALIZATION_HEADROOM{hw("{\"state\":\"invalid-input-limit\"}\n" as *u8);return 2} 1708 if pv_is_sha_hex(argv[6] as *u8)!=1{hw("{\"state\":\"invalid-expected-sha256\"}\n" as *u8);return 2} 1709 let input:*u8=argv[2] as *u8;let output:*u8=argv[3] as *u8;let receipt:*u8=argv[4] as *u8 1710 if fsx_denied(input)==1 || fsx_write_denied(output)==1 || fsx_write_denied(receipt)==1 {hw("{\"state\":\"path-policy-refused\"}\n" as *u8);return 5} 1711 if bix_alias(input,output)!=0 || bix_alias(input,receipt)!=0 || bix_alias(output,receipt)!=0 {hw("{\"state\":\"path-alias-or-metadata-refused\"}\n" as *u8);return 5} 1712 let cx:*i64=sys_mmap(GPN_CTX_WORDS*8) as *i64 1713 if (cx as i64)<=0{return 4} 1714 cx[0]=input as i64;cx[1]=output as i64;cx[2]=receipt as i64;cx[3]=argv[6] 1715 cx[4]="" as i64;cx[5]="" as i64;cx[9]="source-open-failed" as i64;cx[10]=maximum 1716 var result:i64=3;let fd:i64=sys_openat_rd(input) 1717 if fd>=0 { 1718 let n:i64=sys_lseek(fd,0,2);sys_close(fd);cx[6]=n 1719 cx[9]="source-empty-or-over-limit" as i64 1720 if n>0 && n<=maximum { 1721 let src:*u8=sys_mmap(n+1);let out:*u8=sys_mmap(n+GPN_NORMALIZATION_HEADROOM) 1722 let sha:*u8=sys_mmap((PV_SHA_HEX+1)*2);let digest:*u8=sys_mmap(PV_SHA_BYTES) 1723 cx[9]="allocation-failed" as i64;result=4 1724 if (src as i64)>0 && (out as i64)>0 && (sha as i64)>0 && (digest as i64)>0 { 1725 result=gpn_convert(cx,src,out,sha,digest) 1726 } 1727 // Receipt consumes hash buffers before their release, including refusal evidence. 1728 cx[11]=result;if gpn_receipt(cx)!=0{result=4} 1729 if (digest as i64)>0{sys_munmap(digest,PV_SHA_BYTES)} 1730 if (sha as i64)>0{sys_munmap(sha,(PV_SHA_HEX+1)*2)} 1731 if (out as i64)>0{sys_munmap(out,n+GPN_NORMALIZATION_HEADROOM)} 1732 if (src as i64)>0{sys_munmap(src,n+1)} 1733 sys_munmap(cx as *u8,GPN_CTX_WORDS*8);return result 1734 } 1735 } 1736 cx[11]=result;if gpn_receipt(cx)!=0{result=4};sys_munmap(cx as *u8,GPN_CTX_WORDS*8);return result 1737} 1738 1739 1740func gli_report(src:*u8,n:i64,stats:*i64,input:*u8,receipt:*u8,sha:*u8)->i64 { 1741 let cap:i64=stats[1]+BIX_JSON_BASE_ROOM+GLI_STATS_WORDS*BIX_JSON_ROW_ROOM+6*(bic_len(input)+bic_len(receipt)) 1742 let buf:*u8=sys_mmap(cap);let w:*JsonWriter=sys_mmap(40) as *JsonWriter;let prior:*u8=sys_mmap(JE_MAX_DEPTH+16) 1743 if (buf as i64)<=0 || (w as i64)<=0 || (prior as i64)<=0{return 4} 1744 w.buf=buf;w.cap=cap;w.pos=0;w.depth=0;w.prior=prior 1745 var rc:i64=json_begin_object(w) 1746 rc=rc|bix_key(w,"schema","nishi.gltf.inventory.v1") 1747 rc=rc|bix_key(w,"state","complete-structural-inventory") 1748 rc=rc|bix_key(w,"source",input);rc=rc|bix_key(w,"source_sha256",sha);rc=rc|bix_num(w,"source_bytes",n) 1749 rc=rc|bix_key(w,"scope","GLB container and JSON structural inventory; no accessor-value validation, no rig/material/animation conversion, no rendering or physical-unit qualification") 1750 rc=rc|bix_key(w,"preservation","source unchanged; authored_json is exact complete source JSON including materials, channels, morph targets, transforms and extensions") 1751 rc=rc|bix_num(w,"json_bytes",stats[1]);rc=rc|bix_num(w,"bin_bytes",stats[2]);rc=rc|bix_num(w,"chunks",stats[3]) 1752 rc=rc|json_emit_key(w,"counts",6);rc=rc|json_begin_object(w) 1753 var i:i64=4;while i<GLI_STATS_WORDS{rc=rc|bix_num(w,gli_name(i),stats[i]);i=i+1} 1754 rc=rc|json_end_object(w) 1755 rc=rc|json_emit_key(w,"authored_json",13);rc=rc|je_sep(w) 1756 rc=rc|je_emit_literal(w,(src as i64+stats[0]) as *u8,stats[1]);rc=rc|json_end_object(w) 1757 if rc>=0 {rc=bix_store(receipt,buf,w.pos)} 1758 if rc==0 { 1759 bic_w(1,"{\"schema\":\"nishi.gltf.inventory.result.v1\",\"state\":\"stored-verified\",\"report_bytes\":");nxi_out(w.pos) 1760 bic_w(1,",\"source_bytes\":");nxi_out(n);bic_w(1,"}\n") 1761 } 1762 sys_munmap(prior,JE_MAX_DEPTH+16);sys_munmap(w as *u8,40);sys_munmap(buf,cap) 1763 if rc!=0{return 4};return 0 1764} 1765func gli_main(argc:i64,argv:*i64)->i64 { 1766 if argc!=6 {bic_w(1,"{\"state\":\"usage-refused\",\"usage\":\"inspect-glb input.glb receipt.json max_input_bytes expected_sha256\"}\n");return 2} 1767 let input:*u8=argv[2] as *u8;let receipt:*u8=argv[3] as *u8 1768 let maximum:i64=bix_uint(argv[4] as *u8) 1769 if maximum<=0 || maximum>GPN_GLB_LENGTH_MAX || pv_is_sha_hex(argv[5] as *u8)!=1{return 2} 1770 if fsx_denied(input)==1 || fsx_write_denied(receipt)==1 || bix_alias(input,receipt)!=0{return 5} 1771 let fd:i64=sys_openat_rd(input);if fd<0{return 3} 1772 let n:i64=sys_lseek(fd,0,2);sys_close(fd) 1773 if n<=0 || n>maximum {bic_w(1,"{\"state\":\"input-size-refused\"}\n");return 3} 1774 let src:*u8=sys_mmap(n+1);let stats:*i64=sys_mmap(GLI_STATS_WORDS*8) as *i64 1775 let digest:*u8=sys_mmap(PV_SHA_BYTES);let sha:*u8=sys_mmap(PV_SHA_HEX+1) 1776 var result:i64=4 1777 if (src as i64)>0 && (stats as i64)>0 && (digest as i64)>0 && (sha as i64)>0 { 1778 if cgo_read(input,src,n+1)==n { 1779 if sha256_digest_checked_native(src,n,digest)==0 { 1780 pv_hex(digest,sha) 1781 if fsx_seq(sha,argv[5] as *u8)==1 { 1782 let inspected:i64=gltf_inventory_glb(src,n,stats) 1783 if inspected==0 {result=gli_report(src,n,stats,input,receipt,sha)} else { 1784 bic_w(1,"{\"state\":\"inventory-refused\",\"code\":");nxi_out(inspected);bic_w(1,"}\n");result=3 1785 } 1786 } else {bic_w(1,"{\"state\":\"source-hash-mismatch\"}\n");result=3} 1787 } 1788 } 1789 } 1790 if (sha as i64)>0{sys_munmap(sha,PV_SHA_HEX+1)} 1791 if (digest as i64)>0{sys_munmap(digest,PV_SHA_BYTES)} 1792 if (stats as i64)>0{sys_munmap(stats as *u8,GLI_STATS_WORDS*8)} 1793 if (src as i64)>0{sys_munmap(src,n+1)} 1794 return result 1795} 1796 1797func main(argc: i64, argv: *i64) -> i64 { 1798 if argc>=2 {if fsx_seq(argv[1] as *u8,"inspect-glb")==1{return gli_main(argc,argv)}} 1799 if argc>=2 {if fsx_seq(argv[1] as *u8,"normalize-json")==1 {return gpn_main(argc,argv)}} 1800 if argc >= 2 { 1801 let a1: *u8 = argv[1] as *u8 1802 if g2_lit_at(a1, 0, 8, "selftest" as *u8) == 8 { let rc: i64 = g2_selftest(); sys_exit(rc); return rc } 1803 } 1804 if argc < 3 { 1805 hw("usage: nx_gltf2mesh <in.glb|.vrm> <out.nxmesh> [skip-mesh-name-substr] | selftest\n" as *u8) 1806 hw(" nx_gltf2mesh <in.glb|.vrm> <out.nxa> -- rigged donor -> NXANIM01 VERT/TRIS/SKEL/SKIN (R22, g2_skin_weights)\n" as *u8) 1807 sys_exit(2) 1808 return 2 1809 } 1810 var skip: *u8 = 0 as *u8 1811 if argc >= 4 { if g2_filter(argv[3] as *u8) == 1 { skip = argv[3] as *u8 } } 1812 if argc >= 5 { if g2_filter(argv[4] as *u8) == 1 { skip = argv[4] as *u8 } } 1813 let rc2: i64 = g2_convert(argv[1] as *u8, argv[2] as *u8, skip) 1814 sys_exit(rc2) 1815 return rc2 1816}