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}