nx_mesh2glb_neutral_candidate_t346.nx
buildroot/runtime/nx_mesh2glb_neutral_candidate_t346.nx
about
nx_mesh2glb.nx -- NXMSH2 -> INTERACTIVE .glb (operator 2026-08-05: "a picture vs the other files'
full interactivity panel -- that's dumb"). The measurement organs emit NXMSH2 (per-tri colour = the
deviation heatmap lives there); the showcase viewer consumes .glb. This organ closes that seam, so a
FITTED body and a PAINTED HEATMAP both become drag-to-rotate panels, not screenshots -- an interactive
deviation map is a capability the reference industrial tools ship as static report pages.
Positions PASS THROUGH as raw f32 bits (zero re-quantisation); per-tri colour is replicated to the
tri's 3 vertices as normalized u8 VEC4; per-vertex normals are {VEC3, FLOAT} and UNIT.
CORRECTED 2026-08-25. That last clause used to read "normals transcode to normalized i16 -- the exact
accessor types our proven nishi_walk.glb already uses, so the viewer needs nothing new". nishi_walk.glb
was NOT proven; it was simply never checked against the specification. KhronosGroup/glTF-Validator
rejects {VEC3, SHORT normalized} for NORMAL outright (MESH_PRIMITIVE_ATTRIBUTES_ACCESSOR_INVALID_FORMAT)
and rejects its 6-byte element as unaligned (MESH_PRIMITIVE_ACCESSOR_UNALIGNED). So this exporter
inherited a defect BY CITING ANOTHER OF OUR FILES AS THE STANDARD -- which is how a house style becomes
indistinguishable from a specification. The bounds were wrong for the same reason: see the JSON below.
nx_mesh2glb <in.nxmesh> <out.glb> | selftest
license_tier: ORIGINAL expect_exit: 0
dependencies 6 imports · 2 importers
imports: nx_syscalls.nxnx_atomic_rewrite.nxnx_nxa.nxnx_glbnorm_lib.nxnx_nxmesh_lib.nxnx_asset_prov_lib.nx
imported by: nx_mesh_neutral_gate_t346.nxnx_mesh_winding_prepare_gate_t365.nx
call flow from main pre-order; caps 40 nodes / depth 6 declared; ↻ = already shown
structs
| none |
consts
| 25 | const MG_KEY_ABOVE_ALL: i64 = 4294967296 // one past the largest key gn_f32_key can return |
| 26 | const MG_KEY_BELOW_ALL: i64 = 0 - 1 // one below the smallest; keys are never negative |
| 27 | const MG_NRM_GAIN: i64 = 4 // permille x 4 = 4000 for a unit component: the largest |
| 30 | const MG_VEC3_F32_BYTES: i64 = 12 |
| 31 | const MG_V3: i64 = 3 |
| 59 | const MG_CONTAINER_NXMSH2: i64 = 1 |
| 60 | const MG_CONTAINER_NXA: i64 = 2 |
| 61 | const MG_NXA_HDR_BYTES: i64 = 32 // magic, version, nsect, toccheck |
| 62 | const MG_NXA_TOC_WORDS: i64 = 4 // tag, byte_off, word_len, check |
| 63 | const MG_NXA_UNITS_PER_M: i64 = 100000 // VERT/SKEL are 0.01 mm; 100000 of them per metre |
| 64 | const MG_Q12: i64 = 4096 // SKIN weights are q12 |
| 65 | const MG_SKEL_REC_WORDS: i64 = 8 |
| 66 | const MG_SKIN_REC_WORDS: i64 = 8 |
| 67 | const MG_SKEL_PARENT: i64 = 0 |
| 68 | const MG_SKEL_TX: i64 = 1 |
| 69 | const MG_SKEL_ROOT: i64 = 0 - 1 // parent = -1 marks a root joint (spec) |
| 70 | const MG_SKIN_W0: i64 = 4 // weights follow the four joint slots |
| 71 | const MG_GL_UNSIGNED_BYTE: i64 = 5121 // glTF componentType enum, named for what it is |
| 72 | const MG_GL_UNSIGNED_SHORT: i64 = 5123 |
| 73 | const MG_GL_UNSIGNED_INT: i64 = 5125 |
| 74 | const MG_GL_FLOAT: i64 = 5126 |
| 78 | const MG_GL_ARRAY_BUFFER: i64 = 34962 // vertex attribute data |
| 79 | const MG_GL_ELEMENT_ARRAY_BUFFER: i64 = 34963 // index data |
| 80 | const MG_U8_MAX: i64 = 255 // JOINTS_0 may be UNSIGNED_BYTE only while every index fits |
| 81 | const MG_U16_MAX: i64 = 65535 // UNSIGNED_SHORT ceiling: more joints REFUSES, never wraps |
| 82 | const MG_F32_EXP_BIAS: i64 = 127 |
| 83 | const MG_F32_MANT_BITS: i64 = 23 |
| 84 | const MG_F32_SIGN_SHIFT: i64 = 31 |
| 85 | const MG_VEC3: i64 = 3 |
| 86 | const MG_VEC4: i64 = 4 |
| 87 | const MG_F32_BYTES: i64 = 4 |
| 88 | const MG_U32_BYTES: i64 = 4 |
| 89 | const MG_U16_BYTES: i64 = 2 |
| 90 | const MG_U8_BYTES: i64 = 1 |
| 91 | const MG_MAT4_BYTES: i64 = 64 |
| 92 | const MG_GLB_HDR_BYTES: i64 = 12 |
| 93 | const MG_CHUNK_HDR_BYTES: i64 = 8 |
| 94 | const MG_GLB_VERSION: i64 = 2 |
| 95 | const MG_JSON_BASE: i64 = 4096 // the JSON that does not scale with joint count |
| 96 | const MG_JSON_PER_JOINT: i64 = 128 // worst case measured 105 B: a node (name + 3 translations of |
| 99 | const MG_PERMILLE: i64 = 1000 |
| 100 | const MG_ASCII_ZERO: i64 = 48 |
| 101 | const MG_ASCII_MINUS: i64 = 45 |
| 102 | const MG_ASCII_DOT: i64 = 46 |
| 103 | const MG_ASCII_SPACE: i64 = 32 |
| 104 | const MG_DECIMAL: i64 = 10 |
| 105 | const MG_EXIT_REFUSE: i64 = 3 // the exit the NXMSH2 path already uses for a refused input |
| 106 | const MG_EXIT_BUDGET: i64 = 4 |
| 107 | const MG_EXIT_IO: i64 = 6 |
| 108 | const MG_MAGIC_32767: i64 = 32767 |
| 109 | const MG_MAGIC_65535: i64 = 65535 |
| 110 | const MG_MAGIC_100000: i64 = 100000 |
| 122 | const MG_MSH_FIXED_HDR_BYTES: i64 = 16 // magic[8] + u32 nlay + u32 ntri: the bytes needed to read the counts |
| 123 | const MG_MSH_LAYROW_BYTES: i64 = 24 |
| 124 | const MG_MSH_TRIREC_BYTES: i64 = 84 // 9 position + 9 normal + 3 colour float32 |
| 129 | const MG_COL_DARK_SUM: i64 = 12 // at or below this the source carried no colour at all |
| 130 | const MG_BONE_R: i64 = 216 // the meshview bone fallback, inherited deliberately so that |
| 131 | const MG_BONE_G: i64 = 210 // a genuinely uncoloured mesh is never rendered invisible |
| 132 | const MG_BONE_B: i64 = 198 |
| 133 | const MG_ALLOC_SLACK_BYTES: i64 = 64 // mmap headroom past a DERIVED length; not a budget, not a cap |
| 134 | const MG_M8388607: i64 = 8388607 |
| 135 | const MG_M8388608: i64 = 8388608 |
| 136 | const MG_BIG: i64 = 4611686018427387903 |
functions
| 138 | func hw(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 } called by 8: mg_refusemg_nxa_refusemg_convert_nxamg_provenancemg_convert_msh_modemg_selftest+2 calls 1: sys_write |
| 139 | func 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 } called by 4: mg_convert_nxamg_convert_msh_modemg_selftestmg_convert_layer_neutral calls 2: sys_mmapsys_write |
| 140 | func mg_u32(b: *u8, o: i64) -> i64 { return (b[o] as i64) + ((b[o+1] as i64)<<8) + ((b[o+2] as i64)<<16) + ((b[o+3] as i64)<<24) } |
| 141 | func mg_w8(b: *u8, o: i64, v: i64) -> i64 { b[o] = (v&255) as u8; return o+1 } |
| 142 | func mg_w16(b: *u8, o: i64, v: i64) -> i64 { b[o]=(v&255) as u8; b[o+1]=((v>>8)&255) as u8; return o+2 } called by 1: mg_convert_nxa |
| 143 | func mg_w32(b: *u8, o: i64, v: i64) -> i64 { 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; return o+4 } |
| 144 | func mg_align4(x: i64) -> i64 { return (x+3)/4*4 } |
| 145 | func mg_cat(o: *u8, at: i64, s: *u8) -> i64 { var i: i64=0; var a: i64=at; while s[i]!=(0 as u8){o[a]=s[i]; a=a+1; i=i+1} return a } |
| 146 | func mg_num(o: *u8, at: i64, v: i64) -> i64 |
| 161 | func mg_f32i(w: i64, scale: i64) -> i64 called by 1: mg_convert_msh_mode |
| 186 | func mg_col_u8(w: i64) -> i64 { return nm_col_u8_of(w) } |
| 187 | func mg_refuse(reason: *u8) -> i64 { hw("MESH2GLB REFUSED: " as *u8); hw(reason); hw("\n" as *u8); return 0 } |
| 188 | func mg_nxa_refuse(reason: *u8) -> i64 { hw("MESH2GLB REFUSED (NXANIM01): " as *u8); hw(reason); hw("\n" as *u8); return 0 } |
| 193 | func mg_f32_frac(v: i64, den: i64) -> i64 |
| 210 | func mg_dec(o: *u8, at: i64, num: i64, den: i64) -> i64 |
| 234 | func mg_container(b: *u8, n: i64) -> i64 |
| 239 | func mg_nxa_wl(b: *u8, tag: i64) -> i64 called by 1: mg_convert_nxa |
| 247 | func mg_ibm_translate(bin: *u8, at0: i64, tx: i64, ty: i64, tz: i64) -> i64 |
| 260 | func mg_convert_nxa(b: *u8, n: i64, outp: *u8) -> i64 |
| 589 | func mg_provenance(b: *u8, n: i64, jrnl: *u8) -> i64 called by 2: mg_dispatchmg_dispatch_layer_neutral calls 5: sys_mmappv_hash_bytespv_verdicthwpv_print |
| 605 | func mg_dispatch(inp: *u8, outp: *u8, jrnl: *u8) -> i64 |
| 615 | func mg_convert(inp: *u8, outp: *u8) -> i64 |
| 624 | func mg_convert_msh(b:*u8,n:i64,outp:*u8)->i64{return mg_convert_msh_mode(b,n,outp,0)} |
| 625 | func mg_convert_msh_mode(b: *u8, n: i64, outp: *u8, neutral:i64) -> i64 called by 2: mg_convert_mshmg_convert_layer_neutral calls 21: mg_refusemg_u32mg_align4sys_mmapmg_w32gn_f32_key+15 |
| 831 | func st_enc1000(v: i64) -> i64 { return mg_f32_frac(v, MG_PERMILLE) } // the /1000 case of the ONE encoder |
| 832 | func st_fix(path: *u8) -> i64 |
| 857 | func mg_hasstr(b: *u8, n: i64, lit: *u8) -> i64 called by 1: mg_selftest |
| 870 | func mg_selftest() -> i64 |
| 898 | func mg_is_selftest(a: *u8) -> i64 called by 1: main |
| 908 | func mg_word_equal(a:*u8,b:*u8)->i64{var i:i64=0;while a[i]!=(0 as u8)&&b[i]!=(0 as u8){if a[i]!=b[i]{return 0};i=i+1};if a[i]!=b[i]{return 0};return 1} called by 1: main |
| 909 | func mg_layer_window(b:*u8,n:i64,name:*u8,range:*i64)->i64 called by 3: mg_convert_layer_neutralmainmain calls 5: nm_nlayersnm_ntrisnm_tri_basenm_u32mg_f32_frac |
| 927 | func mg_convert_layer_neutral(b:*u8,n:i64,layer:*u8,outp:*u8)->i64 |
| 939 | func mg_dispatch_layer_neutral(inp:*u8,outp:*u8,layer:*u8,jrnl:*u8)->i64 called by 3: mainmainmain calls 5: sys_mmap_trysys_read_filesys_munmap_directmg_provenancemg_convert_layer_neutral |
| 946 | func main(argc: i64, argv: *i64) -> i64 |