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