code wiki / (root) / nx_mesh_view.nx

nx_mesh_view.nx source

↩ module page · 274 lines · 11343 B

1// nx_mesh_view.nx -- SOVEREIGN full-detail mesh renderer: loads a .nxmesh (every vertex, every 2// triangle -- the 1:1 capture of the reference model) and software-rasterizes it to PNG with a 3// z-buffer, barycentric depth, and two-light lambert. This is the proof the sovereign pipeline 4// CARRIES reference-class detail: 28k triangles, not 30 primitives. 5// usage: nx_mesh_view <in.nxmesh> <out.png> [yaw_deg] 6// license_tier: ORIGINAL 7import "nx_syscalls.nx" 8import "nx_itrig.nx" 9import "nx_png_write.nx" 10import "nx_nxa.nx" 11const MV_MAGIC_1314016334: i64 = 1314016334 12const MV_MAGIC_4611686018427387903: i64 = 4611686018427387903 13const MV_MAGIC_4096: i64 = 4096 14 15const MV_W: i64 = 640 16const MV_H: i64 = 1024 17 18func mvw(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 } 19func mvn(v: i64) -> i64 { 20 let t: *u8 = sys_mmap(32) as *u8 21 var m: i64 = v; var w: i64 = 0 22 if m<0 { t[w]=45 as u8; w=w+1; m=0-m } 23 if m==0 { t[w]=48 as u8; sys_write(1,t,w+1); return 0 } 24 let d: *u8 = sys_mmap(32) as *u8 25 var k: i64=0 26 while m>0 { d[k]=(48+(m%10)) as u8; m=m/10; k=k+1 } 27 var j: i64=0 28 while j<k { t[w]=d[k-1-j]; w=w+1; j=j+1 } 29 sys_write(1,t,w); return 0 30} 31func mv_isqrt(v: i64) -> i64 { 32 if v <= 0 { return 0 } 33 var x: i64 = v 34 var y: i64 = (x + 1) / 2 35 var g: i64 = 0 36 while g < 40 { if y < x { x = y; y = (x + v/x)/2 } g = g + 1 } 37 return x 38} 39func mv_min3(a: i64, b: i64, c: i64) -> i64 { var m: i64 = a; if b < m { m = b } if c < m { m = c } return m } 40func mv_max3(a: i64, b: i64, c: i64) -> i64 { var m: i64 = a; if b > m { m = b } if c > m { m = c } return m } 41 42func main(argc: i64, argv: *i64) -> i64 { 43 if argc < 3 { mvw("usage: nx_mesh_view <in.nxmesh> <out.png> [yaw_deg]\n" as *u8); return 2 } 44 var yawdeg: i64 = 20 45 if argc >= 4 { 46 let a3: *u8 = argv[3] as *u8 47 yawdeg = 0 48 var q: i64 = 0 49 while a3[q] != (0 as u8) { yawdeg = yawdeg*10 + ((a3[q] & 0xff) as i64) - 48; q = q + 1 } 50 } 51 let lp: *i64 = sys_mmap(16) as *i64 52 let b: *u8 = sys_map_file(argv[1] as *u8, lp) 53 if lp[0] < 24 { mvw("unreadable\n" as *u8); return 3 } 54 let hdr: *i64 = b as *i64 55 var nv: i64 = 0 56 var nt: i64 = 0 57 var vx: *i64 = 0 as *i64 58 var tr: *i64 = 0 as *i64 59 if hdr[0] == MV_MAGIC_1314016334 { 60 // legacy .nxmesh v0 (additive-only: old artifacts keep rendering) 61 nv = hdr[1] 62 nt = hdr[2] 63 vx = ((b as i64) + 24) as *i64 64 tr = ((b as i64) + 24 + nv*24) as *i64 65 } 66 if hdr[0] == nxa_magic() { 67 let vwo: i64 = nxa_find(b, lp[0], nxa_tag4("VERT" as *u8)) 68 if vwo == 0 - 2 { mvw("NXA-FUTURE-VERSION: refusing\n" as *u8); return 6 } 69 if vwo < 0 { mvw("NXA-CORRUPT: refusing\n" as *u8); return 5 } 70 let two: i64 = nxa_find(b, lp[0], nxa_tag4("TRIS" as *u8)) 71 if two < 0 { mvw("NXA-CORRUPT: refusing\n" as *u8); return 5 } 72 nv = hdr[vwo] 73 nt = hdr[two] 74 vx = ((b as i64) + vwo*8 + 8) as *i64 75 tr = ((b as i64) + two*8 + 8) as *i64 76 } 77 if nv < 3 { mvw("bad magic\n" as *u8); return 4 } 78 mvw("verts=" as *u8); mvn(nv); mvw(" tris=" as *u8); mvn(nt); mvw("\n" as *u8) 79 // bounds (fbx z-up: x=lat, y=depth, z=up) 80 var mnx: i64 = MV_MAGIC_4611686018427387903 81 var mxx: i64 = 0 - mnx 82 var mny: i64 = mnx 83 var mxy: i64 = 0 - mnx 84 var mnz: i64 = mnx 85 var mxz: i64 = 0 - mnx 86 var i: i64 = 0 87 while i < nv { 88 let X: i64 = vx[i*3] 89 let Y: i64 = vx[i*3+1] 90 let Z: i64 = vx[i*3+2] 91 if X < mnx { mnx = X } if X > mxx { mxx = X } 92 if Y < mny { mny = Y } if Y > mxy { mxy = Y } 93 if Z < mnz { mnz = Z } if Z > mxz { mxz = Z } 94 i = i + 1 95 } 96 // UP-AXIS AUTO-DETECT (parity with the browser viewer and fm_measure): a standing body's 97 // largest extent IS its up axis; lat = larger of the rest. FBX files arrive both z-up and 98 // y-up -- assuming z-up framed the y-up 2M-tri model as a lying close-up. 99 let exv: *i64 = sys_mmap(64) as *i64 100 exv[0] = mxx - mnx 101 exv[1] = mxy - mny 102 exv[2] = mxz - mnz 103 var iu: i64 = 0 104 if exv[1] > exv[iu] { iu = 1 } 105 if exv[2] > exv[iu] { iu = 2 } 106 var il: i64 = 0 107 if iu == 0 { il = 1 } 108 let io0: i64 = 3 - iu - il 109 if exv[io0] > exv[il] { il = io0 } 110 let io: i64 = 3 - iu - il 111 let mnv: *i64 = sys_mmap(64) as *i64 112 mnv[0] = mnx 113 mnv[1] = mny 114 mnv[2] = mnz 115 let mxv: *i64 = sys_mmap(64) as *i64 116 mxv[0] = mxx 117 mxv[1] = mxy 118 mxv[2] = mxz 119 let H: i64 = exv[iu] 120 let cx: i64 = (mnv[il] + mxv[il])/2 121 let cy: i64 = (mnv[io] + mxv[io])/2 122 // yaw the model around the up axis so the view angle is a parameter 123 let ya: i64 = yawdeg * IT_PI / 180 124 let sy: i64 = it_sin4096(ya) 125 let cyw: i64 = it_cos4096(ya) 126 // scale: fit height to 94% of canvas 127 let scale_n: i64 = MV_H * 94 / 100 128 let fb: *i64 = sys_mmap(MV_W*MV_H*8) as *i64 129 let zb: *i64 = sys_mmap(MV_W*MV_H*8) as *i64 130 var p0: i64 = 0 131 while p0 < MV_W*MV_H { 132 let g: i64 = 26 + p0/(MV_W*MV_H/14) 133 fb[p0] = g | ((g+4) << 8) | ((g+10) << 16) 134 zb[p0] = 0 - MV_MAGIC_4611686018427387903 135 p0 = p0 + 1 136 } 137 // screen coords per vertex (mm -> px), rotated: xr = (x-cx)*cos + (y-cy)*sin; depth = -(x-cx)*sin + (y-cy)*cos 138 let sxp: *i64 = sys_mmap(nv*8) as *i64 139 let syp: *i64 = sys_mmap(nv*8) as *i64 140 let szp: *i64 = sys_mmap(nv*8) as *i64 141 var i2: i64 = 0 142 while i2 < nv { 143 let rx: i64 = ((vx[i2*3+il] - cx)*cyw + (vx[i2*3+io] - cy)*sy)/MV_MAGIC_4096 144 let rd: i64 = (0 - (vx[i2*3+il] - cx)*sy + (vx[i2*3+io] - cy)*cyw)/MV_MAGIC_4096 145 sxp[i2] = MV_W/2 + rx*scale_n/H 146 syp[i2] = MV_H - (MV_H - scale_n)/2 - (vx[i2*3+iu] - mnv[iu])*scale_n/H 147 szp[i2] = rd 148 i2 = i2 + 1 149 } 150 // rasterize with barycentric z; two lights (key upper-left-front, fill right) 151 var t: i64 = 0 152 var drawn: i64 = 0 153 while t < nt { 154 let a: i64 = tr[t*3] 155 let bb: i64 = tr[t*3+1] 156 let c: i64 = tr[t*3+2] 157 let x0: i64 = sxp[a] 158 let y0: i64 = syp[a] 159 let x1: i64 = sxp[bb] 160 let y1: i64 = syp[bb] 161 let x2: i64 = sxp[c] 162 let y2: i64 = syp[c] 163 let area: i64 = (x1-x0)*(y2-y0) - (x2-x0)*(y1-y0) 164 if area != 0 { 165 // world-space normal for lighting (mm coords, rotated frame) 166 let e1x: i64 = (vx[bb*3]-vx[a*3]) 167 let e1y: i64 = (vx[bb*3+1]-vx[a*3+1]) 168 let e1z: i64 = (vx[bb*3+2]-vx[a*3+2]) 169 let e2x: i64 = (vx[c*3]-vx[a*3]) 170 let e2y: i64 = (vx[c*3+1]-vx[a*3+1]) 171 let e2z: i64 = (vx[c*3+2]-vx[a*3+2]) 172 var nxv: i64 = e1y*e2z - e1z*e2y 173 var nyv: i64 = e1z*e2x - e1x*e2z 174 var nzv: i64 = e1x*e2y - e1y*e2x 175 let nl: i64 = mv_isqrt(nxv*nxv/256 + nyv*nyv/256 + nzv*nzv/256)*16 176 if nl > 0 { 177 nxv = nxv*1000/nl 178 nyv = nyv*1000/nl 179 nzv = nzv*1000/nl 180 // key light dir ~ (-.4,-.75,.53) front-upper-left (y = toward viewer at yaw 0) 181 var lam: i64 = (0-400)*nxv + (0-750)*nyv + 530*nzv 182 if lam < 0 { lam = 0 - lam } // double-sided (raw scan meshes flip) 183 lam = lam/1000 184 var lit: i64 = 300 + lam*720/1000 185 if lit > 1000 { lit = 1000 } 186 let rr: i64 = 236*lit/1000 187 let gg: i64 = 196*lit/1000 188 let bl: i64 = 172*lit/1000 189 let col: i64 = rr | (gg << 8) | (bl << 16) 190 var miny: i64 = mv_min3(y0, y1, y2) 191 var maxy: i64 = mv_max3(y0, y1, y2) 192 var minx: i64 = mv_min3(x0, x1, x2) 193 var maxx: i64 = mv_max3(x0, x1, x2) 194 if miny < 0 { miny = 0 } 195 if minx < 0 { minx = 0 } 196 if maxy > MV_H-1 { maxy = MV_H-1 } 197 if maxx > MV_W-1 { maxx = MV_W-1 } 198 var py: i64 = miny 199 while py <= maxy { 200 var px: i64 = minx 201 while px <= maxx { 202 let w0: i64 = (x1-px)*(y2-py) - (x2-px)*(y1-py) 203 let w1: i64 = (x2-px)*(y0-py) - (x0-px)*(y2-py) 204 let w2: i64 = (x0-px)*(y1-py) - (x1-px)*(y0-py) 205 var inside: i64 = 0 206 if w0 >= 0 { if w1 >= 0 { if w2 >= 0 { inside = 1 } } } 207 if w0 <= 0 { if w1 <= 0 { if w2 <= 0 { inside = 1 } } } 208 if inside == 1 { 209 let z: i64 = (w0*szp[a] + w1*szp[bb] + w2*szp[c]) / area 210 let o: i64 = py*MV_W + px 211 if z > zb[o] { 212 zb[o] = z 213 fb[o] = col 214 } 215 } 216 px = px + 1 217 } 218 py = py + 1 219 } 220 drawn = drawn + 1 221 } 222 } 223 t = t + 1 224 } 225 mvw("drawn=" as *u8); mvn(drawn); mvw("\n" as *u8) 226 // SKELETON OVERLAY: if SKEL is present, draw bones (parent->joint) as bright segments 227 // through the SAME projection -- the proof that binds share the mesh's space: a coherent 228 // armature INSIDE the figure, or the import is wrong. 229 let swo: i64 = nxa_find(b, lp[0], nxa_tag4("SKEL" as *u8)) 230 if swo >= 0 { 231 let njj: i64 = hdr[swo] 232 let sk: *i64 = ((b as i64) + swo*8 + 8) as *i64 233 var jb: i64 = 0 234 var bones: i64 = 0 235 while jb < njj { 236 let par: i64 = sk[jb*8] 237 if par >= 0 { 238 // project both ends with the same axis permutation + yaw 239 var seg: i64 = 0 240 while seg <= 100 { 241 let bx3: i64 = (sk[par*8+1]*(100-seg) + sk[jb*8+1]*seg)/100 242 let by3: i64 = (sk[par*8+2]*(100-seg) + sk[jb*8+2]*seg)/100 243 let bz3: i64 = (sk[par*8+3]*(100-seg) + sk[jb*8+3]*seg)/100 244 let co: *i64 = sys_mmap(32) as *i64 245 co[0] = bx3 246 co[1] = by3 247 co[2] = bz3 248 let rx2: i64 = ((co[il] - cx)*cyw + (co[io] - cy)*sy)/MV_MAGIC_4096 249 let px3: i64 = MV_W/2 + rx2*scale_n/H 250 let py3: i64 = MV_H - (MV_H - scale_n)/2 - (co[iu] - mnv[iu])*scale_n/H 251 if px3 >= 1 { if px3 < MV_W-1 { if py3 >= 1 { if py3 < MV_H-1 { 252 fb[py3*MV_W + px3] = 60 | (255 << 8) | (120 << 16) 253 fb[py3*MV_W + px3 + 1] = 60 | (255 << 8) | (120 << 16) 254 } } } } 255 seg = seg + 1 256 } 257 bones = bones + 1 258 } 259 jb = jb + 1 260 } 261 mvw("bones=" as *u8); mvn(bones); mvw("\n" as *u8) 262 } 263 let rgb: *u8 = sys_mmap(MV_W*MV_H*3) as *u8 264 var p2: i64 = 0 265 while p2 < MV_W*MV_H { 266 rgb[p2*3] = (fb[p2] & 255) as u8 267 rgb[p2*3+1] = ((fb[p2] >> 8) & 255) as u8 268 rgb[p2*3+2] = ((fb[p2] >> 16) & 255) as u8 269 p2 = p2 + 1 270 } 271 nx_png_write_rgb(argv[2] as *u8, rgb, MV_W, MV_H) 272 mvw("PNG written\n" as *u8) 273 return 0 274}