nx_gltf_scene.nx source
↩ module page · 178 lines · 10158 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 let nrmOff: i64 = posOff + NV*12
79 a = 0; at = nrmOff
80 while a < NV {
81 tm_vnorm(a, vp)
82 var c: i64 = 0
83 while c < 3 { var s: i64 = vp[c]*8; if s>SC_MAGIC_32767 {s=SC_MAGIC_32767} if s<0-SC_MAGIC_32767 {s=0-SC_MAGIC_32767} at = gl_u16(bin, at, s & SC_MAGIC_65535); c = c+1 }
84 a = a + 1
85 }
86 let colOff: i64 = gl_align4(nrmOff + NV*6)
87 a = 0; at = colOff
88 while a < NV {
89 let col: i64 = tm_getvcol(a)
90 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)
91 a = a + 1
92 }
93 let idxOff: i64 = colOff + NV*4
94 var tix: i64 = 0; at = idxOff
95 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 }
96 SC_BINLEN = gl_align4(idxOff + NI*4)
97 let m: i64 = SC_M
98 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
99 let VC: *i64=SC_VCNT as *i64; let IC: *i64=SC_ICNT as *i64; let NM: *i64=SC_NAME as *i64
100 let MNX: *i64=SC_MINX as *i64; let MNY: *i64=SC_MINY as *i64; let MNZ: *i64=SC_MINZ as *i64
101 let MXX: *i64=SC_MAXX as *i64; let MXY: *i64=SC_MAXY as *i64; let MXZ: *i64=SC_MAXZ as *i64
102 PO[m]=posOff; NO[m]=nrmOff; CO[m]=colOff; IO[m]=idxOff
103 VC[m]=NV; IC[m]=NI; NM[m]=name as i64
104 MNX[m]=minx; MNY[m]=miny; MNZ[m]=minz
105 MXX[m]=maxx; MXY[m]=maxy; MXZ[m]=maxz
106 let RG: *i64=SC_ROUGH as *i64; let MT: *i64=SC_METAL as *i64
107 RG[m]=rough; MT[m]=metal
108 SC_M = m + 1
109 return 0
110}
111func sc_mesh_count() -> i64 { return SC_M }
112
113func sc_finalize(out: *u8) -> i64 {
114 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
115 let VC: *i64=SC_VCNT as *i64; let IC: *i64=SC_ICNT as *i64; let NM: *i64=SC_NAME as *i64
116 let MNX: *i64=SC_MINX as *i64; let MNY: *i64=SC_MINY as *i64; let MNZ: *i64=SC_MINZ as *i64
117 let MXX: *i64=SC_MAXX as *i64; let MXY: *i64=SC_MAXY as *i64; let MXZ: *i64=SC_MAXZ as *i64
118 let json: *u8 = sys_mmap(SC_MAGIC_131072)
119 var j: i64 = 0
120 j = jcat(json, j, "{\"asset\":{\"version\":\"2.0\",\"generator\":\"nishi nx_gltf_scene\"},\"scene\":0,\"scenes\":[{\"nodes\":[" as *u8)
121 var m: i64 = 0
122 while m < SC_M { if m>0 { j=jcat(json,j,","as *u8) } j=jnum(json,j,m); m=m+1 }
123 j = jcat(json, j, "]}],\"nodes\":[" as *u8)
124 m = 0
125 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 }
126 j = jcat(json, j, "],\"meshes\":[" as *u8)
127 m = 0
128 while m < SC_M {
129 if m>0 { j=jcat(json,j,","as *u8) }
130 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)
131 m=m+1
132 }
133 j = jcat(json, j, "],\"materials\":[" as *u8)
134 let RG2: *i64=SC_ROUGH as *i64; let MT2: *i64=SC_METAL as *i64
135 m = 0
136 while m < SC_M {
137 if m>0 { j=jcat(json,j,","as *u8) }
138 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)
139 m=m+1
140 }
141 j = jcat(json, j, "],\"accessors\":[" as *u8)
142 m = 0
143 while m < SC_M {
144 if m>0 { j=jcat(json,j,","as *u8) }
145 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)
146 j=jcat(json,j,"{\"bufferView\":"as *u8); j=jnum(json,j,4*m+1); j=jcat(json,j,",\"componentType\":5122,\"normalized\":true,\"count\":"as *u8); j=jnum(json,j,VC[m]); j=jcat(json,j,",\"type\":\"VEC3\"},"as *u8)
147 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)
148 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)
149 m=m+1
150 }
151 j = jcat(json, j, "],\"bufferViews\":[" as *u8)
152 m = 0
153 while m < SC_M {
154 if m>0 { j=jcat(json,j,","as *u8) }
155 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)
156 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)
157 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)
158 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)
159 m=m+1
160 }
161 j = jcat(json, j, "],\"buffers\":[{\"byteLength\":" as *u8); j = jnum(json, j, SC_BINLEN); j = jcat(json, j, "}]}" as *u8)
162 let jsonLen: i64 = j
163 let jsonPad: i64 = gl_align4(jsonLen)
164 // GLB
165 let bin: *u8 = SC_BIN as *u8
166 var o: i64 = 0
167 o = gl_str(out, o, "glTF" as *u8); o = gl_u32(out, o, 2)
168 let total: i64 = 12 + 8 + jsonPad + 8 + SC_BINLEN
169 o = gl_u32(out, o, total)
170 o = gl_u32(out, o, jsonPad); o = gl_str(out, o, "JSON" as *u8)
171 var q: i64 = 0
172 while q < jsonLen { out[o]=json[q]; o=o+1; q=q+1 }
173 while q < jsonPad { out[o]=32 as u8; o=o+1; q=q+1 }
174 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)
175 q = 0
176 while q < SC_BINLEN { out[o]=bin[q]; o=o+1; q=q+1 }
177 return o
178}