code wiki / _hdl_build / nx_render3d.nx

nx_render3d.nx source

↩ module page · 213 lines · 9482 B

1// nx_render3d.nx -- THE 3D RENDER ORGAN: sovereign first-byte-up 3D as an INVOCABLE SERVICE (CLI -> tools-api 2// MCP -> HTTP tools/call), composing the SAME Q14 core family (nx_render_core via nx_meshrender) that the live 3// browser wasm page runs -- one core, three surfaces: NishiOS native, Nishi tools/MCP, 3rd-party browser (wasm, 4// JS shim = last mile only). Renders a per-face-Lambert lit cube (mirrors the VM-parity-gated mv_render_cube) 5// or a z-buffer proof scene, at ANY size/angle, to PNG. Pure integer, no gcc/GL; runs natively on the NAS. 6// usage: nx_render3d <mode:cube|ztri> <angle_deg> <size_px> <out.png> [url] 7// stdout: one JSON line {tool,mode,angle,size,drawn,coverage,out,url} (the tools/call return). 8// license_tier: ORIGINAL 9import "nx_syscalls.nx" 10import "nx_meshrender.nx" 11import "nx_png_write.nx" 12const R3_MAGIC_16384000: i64 = 16384000 13const R3_MAGIC_4278190335: i64 = 4278190335 14const R3_MAGIC_4294901760: i64 = 4294901760 15const R3_MAGIC_12000: i64 = 12000 16const R3_MAGIC_2000: i64 = 2000 17const R3_MAGIC_65536: i64 = 65536 18const R3_MAGIC_2048: i64 = 2048 19 20const R3_FOVH: i64 = 30 // half-FOV degrees (matches the live wasm page) 21const R3_DIST: i64 = 65536 // camera distance 4.0 Q14 22const R3_HALF: i64 = 9830 // cube half-extent 0.6 Q14 23const R3_BASE: i64 = 4292004040 // cube base material (200,200,210) -- shading reveals form 24const R3_BG: i64 = 4280295456 // background (32,33,32)-ish, a255 25const R3_AMB: i64 = 2048 // ambient floor Q14 (~12.5%) 26const R3_LX: i64 = 9459 // unit light from upper-right-front (0.577,0.577,0.577) Q14 27const R3_MAXSZ: i64 = 1024 // size clamp: 1024x1024 fb = 8MB i64 -- bounded for the tools-api 28 29func hw(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 } 30func slen(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} return n } 31func seq(a: *u8, b: *u8) -> i64 { var i: i64=0; while a[i]!=(0 as u8) { if a[i]!=b[i] { return 0 } i=i+1 } if b[i]==(0 as u8) { return 1 } return 0 } 32func satoi(s: *u8) -> i64 { var v: i64=0; var i: i64=0; var sg: i64=1; if s[0]==(45 as u8){sg=0-1;i=1} while s[i]>=(48 as u8) { if s[i]>(57 as u8) { return v*sg } v=v*10+((s[i] as i64)-48); i=i+1 } return v*sg } 33func jput(dst: *u8, o: i64, s: *u8) -> i64 { var i: i64=0; while s[i]!=(0 as u8){dst[o+i]=s[i];i=i+1} return o+i } 34func jputn(dst: *u8, o: i64, v: i64) -> i64 { 35 var m: i64=v 36 var oo: i64=o 37 if m<0 { dst[oo]=45 as u8; oo=oo+1; m=0-m } 38 let t: *u8=sys_mmap(24) 39 var k: i64=0 40 if m==0 { t[0]=48 as u8; k=1 } 41 while m>0 { t[k]=(48+(m%10)) as u8; m=m/10; k=k+1 } 42 var j: i64=0 43 while j<k { dst[oo+j]=t[k-1-j]; j=j+1 } 44 return oo+k 45} 46 47// stage the 12-tri cube: verts (8x3) + tris (12x7: i0,i1,i2,nx,ny,nz,rgba) 48func r3_cube_scene(v: *i64, t: *i64) -> i64 { 49 let H: i64 = R3_HALF 50 let Q: i64 = RC_Q 51 v[0]=0-H; v[1]=0-H; v[2]=0-H 52 v[3]=H; v[4]=0-H; v[5]=0-H 53 v[6]=H; v[7]=H; v[8]=0-H 54 v[9]=0-H; v[10]=H; v[11]=0-H 55 v[12]=0-H; v[13]=0-H; v[14]=H 56 v[15]=H; v[16]=0-H; v[17]=H 57 v[18]=H; v[19]=H; v[20]=H 58 v[21]=0-H; v[22]=H; v[23]=H 59 var k: i64 = 0 60 while k < 84 { t[k]=0; k=k+1 } 61 // faces: -Z +Z -X +X -Y +Y (2 tris each), outward normals, base color 62 t[0]=0;t[1]=1;t[2]=2; t[3]=0;t[4]=0;t[5]=0-Q; t[6]=R3_BASE 63 t[7]=0;t[8]=2;t[9]=3; t[10]=0;t[11]=0;t[12]=0-Q; t[13]=R3_BASE 64 t[14]=4;t[15]=6;t[16]=5; t[17]=0;t[18]=0;t[19]=Q; t[20]=R3_BASE 65 t[21]=4;t[22]=7;t[23]=6; t[24]=0;t[25]=0;t[26]=Q; t[27]=R3_BASE 66 t[28]=0;t[29]=3;t[30]=7; t[31]=0-Q;t[32]=0;t[33]=0; t[34]=R3_BASE 67 t[35]=0;t[36]=7;t[37]=4; t[38]=0-Q;t[39]=0;t[40]=0; t[41]=R3_BASE 68 t[42]=1;t[43]=5;t[44]=6; t[45]=Q;t[46]=0;t[47]=0; t[48]=R3_BASE 69 t[49]=1;t[50]=6;t[51]=2; t[52]=Q;t[53]=0;t[54]=0; t[55]=R3_BASE 70 t[56]=0;t[57]=4;t[58]=5; t[59]=0;t[60]=0-Q;t[61]=0; t[62]=R3_BASE 71 t[63]=0;t[64]=5;t[65]=1; t[66]=0;t[67]=0-Q;t[68]=0; t[69]=R3_BASE 72 t[70]=3;t[71]=2;t[72]=6; t[73]=0;t[74]=Q;t[75]=0; t[76]=R3_BASE 73 t[77]=3;t[78]=6;t[79]=7; t[80]=0;t[81]=Q;t[82]=0; t[83]=R3_BASE 74 return 0 75} 76 77// lit cube at angle into fb/zb (w x h). Mirrors the VM-parity-gated mv_render_cube; parameterized buffers/size. 78func r3_render_cube(fb: *i64, zb: *i64, w: i64, h: i64, angle: i64) -> i64 { 79 rc_clear(fb, w, h, R3_BG) 80 rc_zclear(zb, w, h) 81 let v: *i64 = sys_mmap(8*3*8) as *i64 82 let tris: *i64 = sys_mmap(12*7*8) as *i64 83 r3_cube_scene(v, tris) 84 let proj: *i64 = sys_mmap(128) as *i64 85 let roty: *i64 = sys_mmap(128) as *i64 86 let mvm: *i64 = sys_mmap(128) as *i64 87 let trans: *i64 = sys_mmap(128) as *i64 88 let mvp: *i64 = sys_mmap(128) as *i64 89 let vbuf: *i64 = sys_mmap(32) as *i64 90 let clipbuf: *i64 = sys_mmap(32) as *i64 91 let scr: *i64 = sys_mmap(8*4*8) as *i64 92 let tri: *i64 = sys_mmap(96) as *i64 93 let nrm: *i64 = sys_mmap(32) as *i64 94 rc_perspective_cs(rc_cos_q14(R3_FOVH), rc_sin_q14(R3_FOVH), w*RC_Q/h, RC_Q, R3_MAGIC_16384000, proj) 95 let cc: i64 = rc_cos_q14(angle) 96 let ss: i64 = rc_sin_q14(angle) 97 var z: i64 = 0 98 while z < 16 { roty[z]=0; z=z+1 } 99 roty[0]=cc; roty[2]=ss; roty[5]=RC_Q; roty[8]=0-ss; roty[10]=cc; roty[15]=RC_Q 100 rc_translation_4x4(0, 0, 0-R3_DIST, trans) 101 rc_mat4_mul(trans, roty, mvm) 102 rc_mat4_mul(proj, mvm, mvp) 103 var vi: i64 = 0 104 while vi < 8 { mr_project(mvp, v[vi*3+0], v[vi*3+1], v[vi*3+2], w, h, vbuf, clipbuf, scr, vi*4); vi=vi+1 } 105 var drawn: i64 = 0 106 var ti: i64 = 0 107 while ti < 12 { 108 let a: i64 = tris[ti*7+0] 109 let b: i64 = tris[ti*7+1] 110 let c: i64 = tris[ti*7+2] 111 var vis: i64 = 0 112 if scr[a*4+3]==1 { if scr[b*4+3]==1 { if scr[c*4+3]==1 { vis=1 } } } 113 if vis==1 { 114 mr_rotn(cc, ss, tris[ti*7+3], tris[ti*7+4], tris[ti*7+5], nrm) 115 if nrm[2] > 0 { 116 let br: i64 = mr_lambert(nrm[0], nrm[1], nrm[2], R3_LX, R3_LX, R3_LX) 117 let col: i64 = mr_shade(tris[ti*7+6], br, R3_AMB) 118 tri[0]=scr[a*4+0]; tri[1]=scr[a*4+1]; tri[2]=scr[a*4+2] 119 tri[3]=scr[b*4+0]; tri[4]=scr[b*4+1]; tri[5]=scr[b*4+2] 120 tri[6]=scr[c*4+0]; tri[7]=scr[c*4+1]; tri[8]=scr[c*4+2] 121 tri[9]=col 122 rc_triangle_flat(fb, zb, w, h, tri) 123 drawn = drawn + 1 124 } 125 } 126 ti = ti + 1 127 } 128 return drawn 129} 130 131// z-buffer proof: near RED tri over far BLUE tri, overlapping centre -- screen-space, scaled by size 132func r3_render_ztri(fb: *i64, zb: *i64, w: i64, h: i64) -> i64 { 133 rc_clear(fb, w, h, R3_BG) 134 rc_zclear(zb, w, h) 135 let RED: i64 = R3_MAGIC_4278190335 136 let BLU: i64 = R3_MAGIC_4294901760 137 let tri: *i64 = sys_mmap(96) as *i64 138 // far BLUE first (z=12000), apex-up 139 tri[0]=w/12; tri[1]=h-h/12; tri[2]=R3_MAGIC_12000; tri[3]=BLU 140 tri[4]=w-w/12; tri[5]=h-h/12; tri[6]=R3_MAGIC_12000; tri[7]=BLU 141 tri[8]=w/2; tri[9]=h/8; tri[10]=R3_MAGIC_12000; tri[11]=BLU 142 rc_triangle(fb, zb, w, h, tri) 143 // near RED second (z=2000), apex-down -- must WIN the overlap 144 tri[0]=w/12; tri[1]=h/12; tri[2]=R3_MAGIC_2000; tri[3]=RED 145 tri[4]=w-w/12; tri[5]=h/12; tri[6]=R3_MAGIC_2000; tri[7]=RED 146 tri[8]=w/2; tri[9]=h-h/8; tri[10]=R3_MAGIC_2000; tri[11]=RED 147 rc_triangle(fb, zb, w, h, tri) 148 return 2 149} 150 151func main(argc: i64, argv: *i64) -> i64 { 152 if argc < 5 { 153 hw("{\"tool\":\"nx_render3d\",\"error\":\"usage: nx_render3d <cube|ztri> <angle> <size> <out.png> [url]\"}\n" as *u8) 154 sys_exit(2) 155 return 2 156 } 157 let mode: *u8 = argv[1] as *u8 158 let angle: i64 = satoi(argv[2] as *u8) 159 var size: i64 = satoi(argv[3] as *u8) 160 let outp: *u8 = argv[4] as *u8 161 if size < 16 { size = 16 } 162 if size > R3_MAXSZ { size = R3_MAXSZ } 163 let npix: i64 = size * size 164 let fb: *i64 = sys_mmap(npix * 8) as *i64 165 let zb: *i64 = sys_mmap(npix * 8) as *i64 166 167 var drawn: i64 = 0 168 var ok: i64 = 0 169 if seq(mode, "cube" as *u8) == 1 { drawn = r3_render_cube(fb, zb, size, size, angle); ok = 1 } 170 if seq(mode, "ztri" as *u8) == 1 { drawn = r3_render_ztri(fb, zb, size, size); ok = 1 } 171 if ok == 0 { 172 hw("{\"tool\":\"nx_render3d\",\"error\":\"unknown mode (cube|ztri)\"}\n" as *u8) 173 sys_exit(3) 174 return 3 175 } 176 177 // i64 packed (r + g<<8 + b<<16) -> RGB bytes -> PNG; count coverage (non-bg) 178 let rgb: *u8 = sys_mmap(npix * 3) 179 var cov: i64 = 0 180 var i: i64 = 0 181 while i < npix { 182 let px: i64 = fb[i] 183 if px != R3_BG { cov = cov + 1 } 184 rgb[i*3] = (px % 256) as u8 185 rgb[i*3+1] = ((px / 256) % 256) as u8 186 rgb[i*3+2] = ((px / R3_MAGIC_65536) % 256) as u8 187 i = i + 1 188 } 189 nx_png_write_rgb(outp, rgb, size, size) 190 191 let out: *u8 = sys_mmap(R3_MAGIC_2048) 192 var o: i64 = 0 193 o = jput(out, o, "{\"tool\":\"nx_render3d\",\"mode\":\"" as *u8) 194 o = jput(out, o, mode) 195 o = jput(out, o, "\",\"angle\":" as *u8) 196 o = jputn(out, o, angle) 197 o = jput(out, o, ",\"size\":" as *u8) 198 o = jputn(out, o, size) 199 o = jput(out, o, ",\"drawn\":" as *u8) 200 o = jputn(out, o, drawn) 201 o = jput(out, o, ",\"coverage\":" as *u8) 202 o = jputn(out, o, cov) 203 o = jput(out, o, ",\"out\":\"" as *u8) 204 o = jput(out, o, outp) 205 if argc >= 6 { 206 o = jput(out, o, "\",\"url\":\"" as *u8) 207 o = jput(out, o, argv[5] as *u8) 208 } 209 o = jput(out, o, "\"}\n" as *u8) 210 sys_write(1, out, o) 211 sys_exit(0) 212 return 0 213}