code wiki / _hdl_build / nx_meshview_page.nx

nx_meshview_page.nx source

↩ module page · 103 lines · 8751 B

1// nx_meshview_page.nx -- R3b: emit a self-contained, openable web page that renders our mesh IN THE BROWSER via 2// OUR sovereign WASM software rasterizer -- NO WebGL, NO NVIDIA, NO Emscripten, NO 3rd-party JS lib. Fork-compiles 3// nx_meshview_wasm.nx -> wasm (sovereign nx_compile_wat -> nx_wat_compiler), base64-embeds it (sovereign nx_base64), 4// and authors web_assets/meshview.html: a <canvas> that instantiates the wasm, calls mv_render(angle), reads the 5// i64 framebuffer straight from linear memory, and blits it (the browser's ONLY job is putImageData + the call; 6// ALL transform/projection/z-buffer rasterization is sovereign Nishi). Orbits on drag + auto-rotates. The scene 7// is the z-test pair (RED nearer stays in front of BLUE as you orbit = the z-buffer, live). license_tier: ORIGINAL 8import "nx_syscalls.nx" 9import "nx_g_puts_lib.nx" 10import "nx_base64.nx" 11 12const CWAT_ELF: *u8 = "/tmp/nx_compile_wat.sov.elf" 13const WATC_ELF: *u8 = "/tmp/nx_wat_compiler.sov.elf" 14const SRC_NX: *u8 = "/mnt/c/Users/elder/nishi-core/nxc2/runtime/nx_meshview_wasm.nx" 15const WAT_TMP: *u8 = "/tmp/mv.wat" 16const WASM_OUT: *u8 = "web_assets/mv.wasm" 17const HTML_OUT: *u8 = "web_assets/meshview.html" 18const CAP: i64 = 262144 19 20func run_elf(elf: *u8, a1: *u8, a2: *u8) -> i64 { 21 let pid: i64 = sys_fork() 22 if pid == 0 { 23 let argv: *i64 = sys_mmap(64) as *i64 24 argv[0] = elf as i64 25 var ai: i64 = 1 26 if (a1 as i64) != 0 { argv[ai] = a1 as i64; ai = ai + 1 } 27 if (a2 as i64) != 0 { argv[ai] = a2 as i64; ai = ai + 1 } 28 argv[ai] = 0 29 let envp: *i64 = sys_mmap(16) as *i64 30 envp[0] = "PATH=/usr/bin:/bin" as *u8 as i64 31 envp[1] = 0 32 sys_execve(elf, argv, envp) 33 sys_exit(127) 34 } 35 let st: *i64 = sys_mmap(16) as *i64 36 sys_wait4(pid, st, 0) 37 return (st[0] >> 8) & 0xff 38} 39func cat(dst: *u8, off: i64, s: *u8) -> i64 { var o: i64=off; var i: i64=0; while s[i]!=0 as u8 { dst[o]=s[i]; o=o+1; i=i+1 } return o } 40func main() -> i64 { 41 let rc1: i64 = run_elf(CWAT_ELF, SRC_NX, WAT_TMP) 42 let rc2: i64 = run_elf(WATC_ELF, WAT_TMP, WASM_OUT) 43 if rc1 != 0 { g_puts("FATAL: compile_wat failed\n" as *u8); sys_exit(2); return 2 } 44 if rc2 != 0 { g_puts("FATAL: wat_compiler failed\n" as *u8); sys_exit(2); return 2 } 45 let box: *i64 = sys_mmap(16) as *i64 46 let wbytes: *u8 = sys_read_file(WASM_OUT, box) 47 if (wbytes as i64) == 0 { g_puts("FATAL: no mv.wasm\n" as *u8); sys_exit(2); return 2 } 48 let wlen: i64 = box[0] 49 let b64: *u8 = sys_mmap(wlen * 2 + 64) 50 let b64len: i64 = b64_encode(wbytes, wlen, b64) 51 52 let h: *u8 = sys_mmap(CAP) 53 var w: i64 = 0 54 w = cat(h, w, "<!doctype html><html lang='en'><head><meta charset='utf-8'><meta name='viewport' content='width=device-width,initial-scale=1'>\n" as *u8) 55 w = cat(h, w, "<title>Nishi mesh viewer &mdash; sovereign WASM renderer</title>\n" as *u8) 56 w = cat(h, w, "<style>:root{--bg:#0b0f14;--ink:#e6edf3;--mut:#8aa0b4;--acc:#4cc2ff;--line:#243140}*{box-sizing:border-box}body{margin:0;background:var(--bg);color:var(--ink);font:15px/1.55 system-ui,Segoe UI,Roboto,sans-serif}\n" as *u8) 57 w = cat(h, w, "header{max-width:760px;margin:0 auto;padding:28px 20px 6px}h1{margin:0;font-size:26px}.sub{color:var(--mut);margin:.5em 0 0;max-width:66ch}main{max-width:760px;margin:0 auto;padding:0 20px 50px}\n" as *u8) 58 w = cat(h, w, "canvas{image-rendering:pixelated;width:512px;max-width:100%;background:#0b0f14;border:1px solid var(--line);border-radius:8px;margin:14px 0;display:block;cursor:grab}\n" as *u8) 59 w = cat(h, w, "code{color:var(--acc)}footer{max-width:760px;margin:0 auto;padding:8px 20px 40px;color:var(--mut);font-size:12.5px}</style></head><body>\n" as *u8) 60 w = cat(h, w, "<header><h1>Nishi mesh viewer</h1><p class='sub'>A 3D mesh LOADED into the browser &mdash; its geometry (vertices, normals, faces) is baked into a plain array and written into the WASM's linear memory by a few lines of JS, then drawn by our generic mesh renderer; this is the EXACT path a real CAD STL takes (parse &rarr; buffer &rarr; render). <b>DRAG to orbit it, SCROLL to zoom</b> &mdash; an interactive 3D viewport, Gouraud-lit with a glossy highlight, rendered entirely by the Nishi software rasterizer (perspective + z-buffer + per-vertex shading), compiled <code>.nx&rarr;wasm</code> by the sovereign toolchain &mdash; <b>no WebGL, no GPU driver, no Emscripten, no 3rd-party library</b>. The browser's entire job: instantiate the wasm, <code>putImageData</code>, <code>requestAnimationFrame</code> &mdash; nothing else. The light orbits, so the glossy glint sweeps across the ball &mdash; per-vertex shading + z-buffer, live.</p></header>\n" as *u8) 61 w = cat(h, w, "<main><canvas id='c'></canvas></main>\n" as *u8) 62 w = cat(h, w, "<footer>Sovereign Nishi stack &middot; renderer <code>nx_render_core</code>+<code>nx_meshview_wasm</code> &middot; <code>.nx&rarr;wasm</code> via <code>nx_compile_wat</code>+<code>nx_wat_compiler</code> &middot; verified in <code>nx_wasm_vm</code></footer>\n" as *u8) 63 w = cat(h, w, "<script>\n" as *u8) 64 // EXTERNAL geometry (an octahedron) baked here as plain arrays -- the page writes it into the WASM's linear 65 // memory below (the exact path a parsed STL takes). verts (Q14), per-vertex unit normals, face indices. 66 w = cat(h, w, "var GV=[8192,0,0,-8192,0,0,0,8192,0,0,-8192,0,0,0,8192,0,0,-8192];\n" as *u8) 67 w = cat(h, w, "var GN=[16384,0,0,-16384,0,0,0,16384,0,0,-16384,0,0,0,16384,0,0,-16384];\n" as *u8) 68 w = cat(h, w, "var GI=[0,2,4,0,4,3,0,3,5,0,5,2,1,4,2,1,3,4,1,5,3,1,2,5];\n" as *u8) 69 w = cat(h, w, "var NV=GV.length/3,NT=GI.length/3;\n" as *u8) 70 w = cat(h, w, "var B='" as *u8) 71 var k: i64 = 0 72 while k < b64len { h[w] = b64[k]; w = w + 1; k = k + 1 } 73 w = cat(h, w, "';\n" as *u8) 74 w = cat(h, w, "var bytes=Uint8Array.from(atob(B),function(c){return c.charCodeAt(0);});\n" as *u8) 75 w = cat(h, w, "WebAssembly.instantiate(bytes).then(function(r){var ex=r.instance.exports;\n" as *u8) 76 // LOAD the external geometry into the WASM's linear memory at the offsets the module exports, then render it. 77 w = cat(h, w, "var g=new BigInt64Array(ex.memory.buffer);var ov=Number(ex.mv_meshv_off())>>3,on=Number(ex.mv_meshn_off())>>3,oi=Number(ex.mv_meshi_off())>>3;var q;\n" as *u8) 78 w = cat(h, w, "for(q=0;q<GV.length;q++)g[ov+q]=BigInt(GV[q]);for(q=0;q<GN.length;q++)g[on+q]=BigInt(GN[q]);for(q=0;q<GI.length;q++)g[oi+q]=BigInt(GI[q]);\n" as *u8) 79 // MINIMAL browser surface: a W*H canvas (CSS scales it 'pixelated'), one 2D context, putImageData, RAF. No 80 // offscreen canvas, no drawImage, no event listeners -- the browser does the least possible; all render is ours. 81 w = cat(h, w, "var W=Number(ex.mv_w()),H=Number(ex.mv_h()),OFF=Number(ex.mv_fb_off());\n" as *u8) 82 w = cat(h, w, "var cv=document.getElementById('c');cv.width=W;cv.height=H;var ctx=cv.getContext('2d');var id=ctx.createImageData(W,H);\n" as *u8) 83 // INTERACTIVE ORBIT VIEWPORT: drag = orbit (yaw), scroll = zoom (dist), idle = slow auto-spin. The only added 84 // browser surface is the input events -- still no WebGL/drawImage; all transform + raster stays in our wasm. 85 w = cat(h, w, "var yaw=0,dist=65536,drag=0,lx=0,spin=1;\n" as *u8) 86 w = cat(h, w, "cv.addEventListener('mousedown',function(e){drag=1;lx=e.clientX;spin=0;});\n" as *u8) 87 w = cat(h, w, "window.addEventListener('mouseup',function(){drag=0;});\n" as *u8) 88 w = cat(h, w, "cv.addEventListener('mousemove',function(e){if(drag){yaw+=(e.clientX-lx)*1.5;lx=e.clientX;}});\n" as *u8) 89 w = cat(h, w, "cv.addEventListener('wheel',function(e){dist+=e.deltaY*120;if(dist<24000)dist=24000;if(dist>240000)dist=240000;e.preventDefault();});\n" as *u8) 90 w = cat(h, w, "function frame(){if(spin&&!drag)yaw+=0.6;ex.mv_render_loaded_cam(BigInt(Math.round(((yaw%360)+360)%360)),BigInt(Math.round(dist)),BigInt(NV),BigInt(NT));var mem=new Uint8Array(ex.memory.buffer);var i,p,n=W*H;\n" as *u8) 91 w = cat(h, w, "for(i=0;i<n;i++){p=OFF+i*8;id.data[i*4]=mem[p];id.data[i*4+1]=mem[p+1];id.data[i*4+2]=mem[p+2];id.data[i*4+3]=255;}\n" as *u8) 92 w = cat(h, w, "ctx.putImageData(id,0,0);requestAnimationFrame(frame);}\n" as *u8) 93 w = cat(h, w, "frame();}).catch(function(e){document.body.innerHTML+='<pre style=color:#f99>'+e+'</pre>';});\n" as *u8) 94 w = cat(h, w, "</script></body></html>\n" as *u8) 95 96 let fd: i64 = sys_openat_wr(HTML_OUT, 0x1a4) 97 if fd < 0 { g_puts("FATAL: cannot open meshview.html\n" as *u8); sys_exit(3); return 3 } 98 sys_write(fd, h, w) 99 sys_close(fd) 100 g_puts("[nx_meshview_page] wrote web_assets/meshview.html + web_assets/mv.wasm (sovereign, no 3rd-party)\n" as *u8) 101 sys_exit(0) 102 return 0 103}