code wiki / (root) / nx_gltf_scene.nx

nx_gltf_scene.nx source

↩ module page · 176 lines · 10338 B

1// nx_gltf_scene.nx -- ★MULTI-MESH glTF export: assemble MANY nx_trimesh meshes (one per anatomical system) into ONE .glb 2// scene -- each a named node/mesh/material -> a PEELABLE holistic being as a single standard 3D asset. Reuses the byte + 3// float encoders from nx_gltf_mesh. Flow: sc_reset() ; for each system { build mesh in trimesh ; sc_add_mesh(name) } ; 4// sc_finalize(out). Each system is tm_reset separately so its indices are already local/0-based per mesh. license_tier: ORIGINAL 5import "nx_syscalls.nx" 6import "nx_trimesh.nx" 7import "nx_gltf_mesh.nx" 8const SC_MAGIC_16777216: i64 = 16777216 9const SC_MAGIC_2000000000: i64 = 2000000000 10const SC_MAGIC_32767: i64 = 32767 11const SC_MAGIC_65535: i64 = 65535 12const SC_MAGIC_131072: i64 = 131072 13 14const SC_MAXM: i64 = 16 15static SC_BIN: i64 16static SC_BINLEN: i64 17static SC_M: i64 18static SC_POSOFF: i64 19static SC_NRMOFF: i64 20static SC_COLOFF: i64 21static SC_IDXOFF: i64 22static SC_VCNT: i64 23static SC_ICNT: i64 24static SC_NAME: i64 25static SC_MINX: i64 26static SC_MINY: i64 27static SC_MINZ: i64 28static SC_MAXX: i64 29static SC_MAXY: i64 30static SC_MAXZ: i64 31static SC_ROUGH: i64 // ★PBR per-material roughness (milli, 0..1000) 32static SC_METAL: i64 // ★PBR per-material metalness (milli, 0..1000) 33// write milli/1000 as a JSON decimal (e.g. 750 -> "0.750", 1000 -> "1.000") 34func sc_jfrac(o: *u8, at: i64, milli: i64) -> i64 { 35 var a: i64 = at 36 let whole: i64 = milli/1000 37 o[a] = (48+whole) as u8; a = a+1 38 o[a] = 46 as u8; a = a+1 // '.' 39 var f: i64 = milli%1000 40 o[a] = (48 + f/100) as u8; a = a+1 41 o[a] = (48 + (f/10)%10) as u8; a = a+1 42 o[a] = (48 + f%10) as u8; a = a+1 43 return a 44} 45 46func sc_reset() -> i64 { 47 if SC_BIN == 0 { 48 SC_BIN = sys_mmap(SC_MAGIC_16777216) // 16 MB bin 49 SC_POSOFF = sys_mmap(SC_MAXM*8) as i64; SC_NRMOFF = sys_mmap(SC_MAXM*8) as i64; SC_COLOFF = sys_mmap(SC_MAXM*8) as i64; SC_IDXOFF = sys_mmap(SC_MAXM*8) as i64 50 SC_VCNT = sys_mmap(SC_MAXM*8) as i64; SC_ICNT = sys_mmap(SC_MAXM*8) as i64; SC_NAME = sys_mmap(SC_MAXM*8) as i64 51 SC_MINX = sys_mmap(SC_MAXM*8) as i64; SC_MINY = sys_mmap(SC_MAXM*8) as i64; SC_MINZ = sys_mmap(SC_MAXM*8) as i64 52 SC_MAXX = sys_mmap(SC_MAXM*8) as i64; SC_MAXY = sys_mmap(SC_MAXM*8) as i64; SC_MAXZ = sys_mmap(SC_MAXM*8) as i64 53 SC_ROUGH = sys_mmap(SC_MAXM*8) as i64; SC_METAL = sys_mmap(SC_MAXM*8) as i64 54 } 55 SC_BINLEN = 0; SC_M = 0 56 return 0 57} 58// append the CURRENT trimesh as a named mesh in the scene 59func sc_add_mesh(name: *u8, rough: i64, metal: i64) -> i64 { 60 let NV: i64 = tm_nv(); let NT: i64 = tm_nt(); let NI: i64 = NT*3 61 if NV == 0 { return 0 } 62 if SC_M >= SC_MAXM { return 0 } 63 let bin: *u8 = SC_BIN as *u8 64 let vp: *i64 = sys_mmap(24) as *i64 65 let tt: *i64 = sys_mmap(24) as *i64 66 let posOff: i64 = SC_BINLEN 67 var minx: i64 = SC_MAGIC_2000000000; var miny: i64 = SC_MAGIC_2000000000; var minz: i64 = SC_MAGIC_2000000000 68 var maxx: i64 = 0-SC_MAGIC_2000000000; var maxy: i64 = 0-SC_MAGIC_2000000000; var maxz: i64 = 0-SC_MAGIC_2000000000 69 var a: i64 = 0; var at: i64 = posOff 70 while a < NV { 71 tm_vpos(a, vp) 72 at = gl_f32(bin, at, vp[0]); at = gl_f32(bin, at, vp[1]); at = gl_f32(bin, at, vp[2]) 73 if vp[0]<minx {minx=vp[0]} if vp[0]>maxx {maxx=vp[0]} 74 if vp[1]<miny {miny=vp[1]} if vp[1]>maxy {maxy=vp[1]} 75 if vp[2]<minz {minz=vp[2]} if vp[2]>maxz {maxz=vp[2]} 76 a = a + 1 77 } 78 // SPEC FIX 2026-08-25: {VEC3, FLOAT} unit normals via the SHARED emitter. This was the FOURTH copy of 79 // the same normalized-int16 loop in this estate, and it was found only because removing the other three 80 // left gl_u16 apparently unwired -- and it was not. glTF 2.0 permits only {VEC3, FLOAT} for NORMAL, and 81 // a tightly packed VEC3 of SHORT is a 6-byte element the 4-byte alignment rule forbids. 82 let nrmOff: i64 = posOff + NV*GL_VEC3_F32_BYTES 83 at = gl_emit_normals(bin, nrmOff, NV) 84 let colOff: i64 = gl_align4(nrmOff + NV*GL_VEC3_F32_BYTES) 85 a = 0; at = colOff 86 while a < NV { 87 let col: i64 = tm_getvcol(a) 88 at = gl_u8(bin, at, col&255); at = gl_u8(bin, at, (col>>8)&255); at = gl_u8(bin, at, (col>>16)&255); at = gl_u8(bin, at, 255) 89 a = a + 1 90 } 91 let idxOff: i64 = colOff + NV*4 92 var tix: i64 = 0; at = idxOff 93 while tix < NT { tm_tget(tix, tt); at = gl_u32(bin, at, tt[0]); at = gl_u32(bin, at, tt[1]); at = gl_u32(bin, at, tt[2]); tix = tix+1 } 94 SC_BINLEN = gl_align4(idxOff + NI*4) 95 let m: i64 = SC_M 96 let PO: *i64=SC_POSOFF as *i64; let NO: *i64=SC_NRMOFF as *i64; let CO: *i64=SC_COLOFF as *i64; let IO: *i64=SC_IDXOFF as *i64 97 let VC: *i64=SC_VCNT as *i64; let IC: *i64=SC_ICNT as *i64; let NM: *i64=SC_NAME as *i64 98 let MNX: *i64=SC_MINX as *i64; let MNY: *i64=SC_MINY as *i64; let MNZ: *i64=SC_MINZ as *i64 99 let MXX: *i64=SC_MAXX as *i64; let MXY: *i64=SC_MAXY as *i64; let MXZ: *i64=SC_MAXZ as *i64 100 PO[m]=posOff; NO[m]=nrmOff; CO[m]=colOff; IO[m]=idxOff 101 VC[m]=NV; IC[m]=NI; NM[m]=name as i64 102 MNX[m]=minx; MNY[m]=miny; MNZ[m]=minz 103 MXX[m]=maxx; MXY[m]=maxy; MXZ[m]=maxz 104 let RG: *i64=SC_ROUGH as *i64; let MT: *i64=SC_METAL as *i64 105 RG[m]=rough; MT[m]=metal 106 SC_M = m + 1 107 return 0 108} 109func sc_mesh_count() -> i64 { return SC_M } 110 111func sc_finalize(out: *u8) -> i64 { 112 let PO: *i64=SC_POSOFF as *i64; let NO: *i64=SC_NRMOFF as *i64; let CO: *i64=SC_COLOFF as *i64; let IO: *i64=SC_IDXOFF as *i64 113 let VC: *i64=SC_VCNT as *i64; let IC: *i64=SC_ICNT as *i64; let NM: *i64=SC_NAME as *i64 114 let MNX: *i64=SC_MINX as *i64; let MNY: *i64=SC_MINY as *i64; let MNZ: *i64=SC_MINZ as *i64 115 let MXX: *i64=SC_MAXX as *i64; let MXY: *i64=SC_MAXY as *i64; let MXZ: *i64=SC_MAXZ as *i64 116 let json: *u8 = sys_mmap(SC_MAGIC_131072) 117 var j: i64 = 0 118 j = jcat(json, j, "{\"asset\":{\"version\":\"2.0\",\"generator\":\"nishi nx_gltf_scene\"},\"scene\":0,\"scenes\":[{\"nodes\":[" as *u8) 119 var m: i64 = 0 120 while m < SC_M { if m>0 { j=jcat(json,j,","as *u8) } j=jnum(json,j,m); m=m+1 } 121 j = jcat(json, j, "]}],\"nodes\":[" as *u8) 122 m = 0 123 while m < SC_M { if m>0 { j=jcat(json,j,","as *u8) } j=jcat(json,j,"{\"mesh\":"as *u8); j=jnum(json,j,m); j=jcat(json,j,",\"name\":\""as *u8); j=jcat(json,j,NM[m] as *u8); j=jcat(json,j,"\"}"as *u8); m=m+1 } 124 j = jcat(json, j, "],\"meshes\":[" as *u8) 125 m = 0 126 while m < SC_M { 127 if m>0 { j=jcat(json,j,","as *u8) } 128 j=jcat(json,j,"{\"primitives\":[{\"attributes\":{\"POSITION\":"as *u8); j=jnum(json,j,4*m); j=jcat(json,j,",\"NORMAL\":"as *u8); j=jnum(json,j,4*m+1); j=jcat(json,j,",\"COLOR_0\":"as *u8); j=jnum(json,j,4*m+2); j=jcat(json,j,"},\"indices\":"as *u8); j=jnum(json,j,4*m+3); j=jcat(json,j,",\"material\":"as *u8); j=jnum(json,j,m); j=jcat(json,j,"}]}"as *u8) 129 m=m+1 130 } 131 j = jcat(json, j, "],\"materials\":[" as *u8) 132 let RG2: *i64=SC_ROUGH as *i64; let MT2: *i64=SC_METAL as *i64 133 m = 0 134 while m < SC_M { 135 if m>0 { j=jcat(json,j,","as *u8) } 136 j=jcat(json,j,"{\"pbrMetallicRoughness\":{\"metallicFactor\":"as *u8); j=sc_jfrac(json,j,MT2[m]); j=jcat(json,j,",\"roughnessFactor\":"as *u8); j=sc_jfrac(json,j,RG2[m]); j=jcat(json,j,"},\"doubleSided\":true}"as *u8) 137 m=m+1 138 } 139 j = jcat(json, j, "],\"accessors\":[" as *u8) 140 m = 0 141 while m < SC_M { 142 if m>0 { j=jcat(json,j,","as *u8) } 143 j=jcat(json,j,"{\"bufferView\":"as *u8); j=jnum(json,j,4*m); j=jcat(json,j,",\"componentType\":5126,\"count\":"as *u8); j=jnum(json,j,VC[m]); j=jcat(json,j,",\"type\":\"VEC3\",\"min\":["as *u8); j=jnum(json,j,MNX[m]); j=jcat(json,j,","as *u8); j=jnum(json,j,MNY[m]); j=jcat(json,j,","as *u8); j=jnum(json,j,MNZ[m]); j=jcat(json,j,"],\"max\":["as *u8); j=jnum(json,j,MXX[m]); j=jcat(json,j,","as *u8); j=jnum(json,j,MXY[m]); j=jcat(json,j,","as *u8); j=jnum(json,j,MXZ[m]); j=jcat(json,j,"]},"as *u8) 144 j=jcat(json,j,"{\"bufferView\":"as *u8); j=jnum(json,j,4*m+1); j=jcat(json,j,",\"componentType\":5126,\"count\":"as *u8); j=jnum(json,j,VC[m]); j=jcat(json,j,",\"type\":\"VEC3\"},"as *u8) 145 j=jcat(json,j,"{\"bufferView\":"as *u8); j=jnum(json,j,4*m+2); j=jcat(json,j,",\"componentType\":5121,\"normalized\":true,\"count\":"as *u8); j=jnum(json,j,VC[m]); j=jcat(json,j,",\"type\":\"VEC4\"},"as *u8) 146 j=jcat(json,j,"{\"bufferView\":"as *u8); j=jnum(json,j,4*m+3); j=jcat(json,j,",\"componentType\":5125,\"count\":"as *u8); j=jnum(json,j,IC[m]); j=jcat(json,j,",\"type\":\"SCALAR\"}"as *u8) 147 m=m+1 148 } 149 j = jcat(json, j, "],\"bufferViews\":[" as *u8) 150 m = 0 151 while m < SC_M { 152 if m>0 { j=jcat(json,j,","as *u8) } 153 j=jcat(json,j,"{\"buffer\":0,\"byteOffset\":"as *u8); j=jnum(json,j,PO[m]); j=jcat(json,j,",\"byteLength\":"as *u8); j=jnum(json,j,VC[m]*12); j=jcat(json,j,",\"target\":34962},"as *u8) 154 j=jcat(json,j,"{\"buffer\":0,\"byteOffset\":"as *u8); j=jnum(json,j,NO[m]); j=jcat(json,j,",\"byteLength\":"as *u8); j=jnum(json,j,VC[m]*6); j=jcat(json,j,",\"target\":34962},"as *u8) 155 j=jcat(json,j,"{\"buffer\":0,\"byteOffset\":"as *u8); j=jnum(json,j,CO[m]); j=jcat(json,j,",\"byteLength\":"as *u8); j=jnum(json,j,VC[m]*4); j=jcat(json,j,",\"target\":34962},"as *u8) 156 j=jcat(json,j,"{\"buffer\":0,\"byteOffset\":"as *u8); j=jnum(json,j,IO[m]); j=jcat(json,j,",\"byteLength\":"as *u8); j=jnum(json,j,IC[m]*4); j=jcat(json,j,",\"target\":34963}"as *u8) 157 m=m+1 158 } 159 j = jcat(json, j, "],\"buffers\":[{\"byteLength\":" as *u8); j = jnum(json, j, SC_BINLEN); j = jcat(json, j, "}]}" as *u8) 160 let jsonLen: i64 = j 161 let jsonPad: i64 = gl_align4(jsonLen) 162 // GLB 163 let bin: *u8 = SC_BIN as *u8 164 var o: i64 = 0 165 o = gl_str(out, o, "glTF" as *u8); o = gl_u32(out, o, 2) 166 let total: i64 = 12 + 8 + jsonPad + 8 + SC_BINLEN 167 o = gl_u32(out, o, total) 168 o = gl_u32(out, o, jsonPad); o = gl_str(out, o, "JSON" as *u8) 169 var q: i64 = 0 170 while q < jsonLen { out[o]=json[q]; o=o+1; q=q+1 } 171 while q < jsonPad { out[o]=32 as u8; o=o+1; q=q+1 } 172 o = gl_u32(out, o, SC_BINLEN); o = gl_u8(out, o, 66); o = gl_u8(out, o, 73); o = gl_u8(out, o, 78); o = gl_u8(out, o, 0) 173 q = 0 174 while q < SC_BINLEN { out[o]=bin[q]; o=o+1; q=q+1 } 175 return o 176}