code wiki / (root) / nx_nxa_view_emit.nx

nx_nxa_view_emit.nx source

↩ module page · 71 lines · 9053 B

1// nx_nxa_view_emit.nx -- SOVEREIGN NXA browser-viewer emitter: reads a .nxa (our animated 3D 2// format, knowledge/nxa_format_spec.md), VALIDATES it (refuse corrupt/future at emit time -- 3// the same nxa_find the native reader uses), and emits a self-contained WebGL2 page whose JS 4// re-verifies the checksums IN THE BROWSER before building GPU buffers. The page is the proof 5// the format is interoperable end-to-end: FBX -> NXA -> any browser, no third-party code. 6// usage: nx_nxa_view_emit <in.nxa> <out.html> <title> 7// license_tier: ORIGINAL 8import "nx_syscalls.nx" 9import "nx_base64.nx" 10import "nx_nxa.nx" 11 12const NVE_OUT_CAP: i64 = 8388608 13 14func nve_ap(out: *u8, pos: i64, s: *u8) -> i64 { 15 var k: i64 = 0 16 var p: i64 = pos 17 while s[k] != (0 as u8) { out[p] = s[k]; p = p + 1; k = k + 1 } 18 return p 19} 20func nve_ap_n(out: *u8, pos: i64, s: *u8, n: i64) -> i64 { 21 var k: i64 = 0 22 var p: i64 = pos 23 while k < n { out[p] = s[k]; p = p + 1; k = k + 1 } 24 return p 25} 26func nve_w(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 } 27func nve_num(v: i64) -> i64 { 28 let t: *u8 = sys_mmap(32) as *u8 29 var m: i64 = v; var w: i64 = 0 30 if m==0 { t[0]=48 as u8; sys_write(1,t,1); return 0 } 31 let d: *u8 = sys_mmap(32) as *u8 32 var k: i64=0 33 while m>0 { d[k]=(48+(m%10)) as u8; m=m/10; k=k+1 } 34 var j: i64=0 35 while j<k { t[w]=d[k-1-j]; w=w+1; j=j+1 } 36 sys_write(1,t,w); return 0 37} 38 39func main(argc: i64, argv: *i64) -> i64 { 40 if argc < 4 { nve_w("usage: nx_nxa_view_emit <in.nxa> <out.html> <title>\n" as *u8); return 2 } 41 let lp: *i64 = sys_mmap(16) as *i64 42 let b: *u8 = sys_map_file(argv[1] as *u8, lp) 43 let flen: i64 = lp[0] 44 if flen < 96 { nve_w("unreadable\n" as *u8); return 3 } 45 // emit-time gatekeeping: a corrupt NXA never becomes a page 46 let vwo: i64 = nxa_find(b, flen, nxa_tag4("VERT" as *u8)) 47 if vwo == 0 - 2 { nve_w("NXA-FUTURE-VERSION: refusing\n" as *u8); return 6 } 48 if vwo < 0 { nve_w("NXA-CORRUPT: refusing\n" as *u8); return 5 } 49 let two: i64 = nxa_find(b, flen, nxa_tag4("TRIS" as *u8)) 50 if two < 0 { nve_w("NXA-CORRUPT: refusing\n" as *u8); return 5 } 51 let b64: *u8 = sys_mmap((flen/3 + 2)*4 + 64) 52 let bn: i64 = b64_encode(b, flen, b64) 53 let out: *u8 = sys_mmap(NVE_OUT_CAP) 54 var p: i64 = 0 55 p = nve_ap(out, p, "<!DOCTYPE html><html lang=\"en\"><head><meta charset=\"utf-8\"><title>" as *u8) 56 p = nve_ap(out, p, argv[3] as *u8) 57 p = nve_ap(out, p, "</title><meta name=\"viewport\" content=\"width=device-width,initial-scale=1\"><style>\nhtml{height:100%}\nbody{margin:0;min-height:100%;background:#08070f;color:#e9e5f5;font:14px/1.5 system-ui,sans-serif;\ndisplay:flex;flex-direction:column;align-items:center;justify-content:center;gap:12px;padding:12px 0;box-sizing:border-box}\ncanvas{width:min(94vw,560px);aspect-ratio:5/8;border:1px solid #2f2a4a;border-radius:4px;touch-action:none;background:#0b0a14}\nh1{margin:0;font:600 15px/1 ui-monospace,monospace;letter-spacing:.14em;text-transform:uppercase;color:#b9b1dc}\np{margin:0;color:#7d76a0;font:12px/1.6 ui-monospace,monospace;text-align:center;max-width:70ch}\n#st{color:#a8e6c0}</style></head><body><h1>" as *u8) 58 p = nve_ap(out, p, argv[3] as *u8) 59 p = nve_ap(out, p, "</h1><canvas id=\"c\"></canvas>\n<p id=\"st\">parsing NXA&hellip;</p>\n<p>This mesh travels as <b>NXA</b> &mdash; the sovereign animated 3D format (magic NXANIM01, sectioned,\nper-section checksums). The bytes below were emitted from an FBX by a NishiLang organ; this page\nre-verifies every checksum in your browser before a single triangle is drawn. Drag to rotate.</p>\n<script>\nconst B=\"" as *u8) 60 p = nve_ap_n(out, p, b64, bn) 61 p = nve_ap(out, p, "\";\nconst by=Uint8Array.from(atob(B),c=>c.charCodeAt(0));\nconst dv=new DataView(by.buffer);\nconst st=document.getElementById(\"st\");\nfunction w64(o){return dv.getBigInt64(o,true)}\nconst M=(1n<<64n)-1n;\nfunction ck(o,n){let c=1n;for(let i=0;i<n;i++){c=(c*1000003n+BigInt.asUintN(64,w64(o+i*8)))&M}return c}\nfunction tg(s){return s.charCodeAt(0)|(s.charCodeAt(1)<<8)|(s.charCodeAt(2)<<16)|(s.charCodeAt(3)<<24)}\ntry{\nconst mg=\"NXANIM01\";for(let i=0;i<8;i++)if(by[i]!=mg.charCodeAt(i))throw\"not an NXA file\";\nif(w64(8)>1n)throw\"future version \"+w64(8)+\" \\u2014 refusing\";\nconst ns=Number(w64(16));\nif(BigInt.asUintN(64,w64(24))!=ck(32,ns*4))throw\"TOC checksum mismatch \\u2014 refusing\";\nfunction find(t){for(let s=0;s<ns;s++){const e=32+s*32;\nif(Number(w64(e))===t){const off=Number(w64(e+8)),wl=Number(w64(e+16));\nif(BigInt.asUintN(64,w64(e+24))!=ck(off,wl))throw\"section checksum mismatch \\u2014 refusing\";\nreturn off}}throw\"section missing\"}\nconst vo=find(tg(\"VERT\")),to=find(tg(\"TRIS\"));\nconst nv=Number(w64(vo)),nt=Number(w64(to));\n" as *u8) 62 p = nve_ap(out, p, "const P=new Float32Array(nv*3);\nlet mn=[1e18,1e18,1e18],mx=[-1e18,-1e18,-1e18];\nfor(let i=0;i<nv*3;i++){const v=Number(w64(vo+8+i*8))/1000;P[i]=v;const a=i%3;if(v<mn[a])mn[a]=v;if(v>mx[a])mx[a]=v}\nconst I=new Uint32Array(nt*3);\nfor(let i=0;i<nt*3;i++)I[i]=Number(w64(to+8+i*8));\nconst N=new Float32Array(nv*3);\nfor(let t=0;t<nt;t++){const a=I[t*3],b2=I[t*3+1],c2=I[t*3+2];\nconst ax=P[a*3],ay=P[a*3+1],az=P[a*3+2];\nconst e1x=P[b2*3]-ax,e1y=P[b2*3+1]-ay,e1z=P[b2*3+2]-az;\nconst e2x=P[c2*3]-ax,e2y=P[c2*3+1]-ay,e2z=P[c2*3+2]-az;\nconst nx=e1y*e2z-e1z*e2y,ny=e1z*e2x-e1x*e2z,nz=e1x*e2y-e1y*e2x;\nN[a*3]+=nx;N[a*3+1]+=ny;N[a*3+2]+=nz;\nN[b2*3]+=nx;N[b2*3+1]+=ny;N[b2*3+2]+=nz;\nN[c2*3]+=nx;N[c2*3+1]+=ny;N[c2*3+2]+=nz}\nconst C=[(mn[0]+mx[0])/2,(mn[1]+mx[1])/2,(mn[2]+mx[2])/2];\nconst HH=mx[2]-mn[2];\n" as *u8) 63 p = nve_ap(out, p, "const cv=document.getElementById(\"c\");\nconst g=cv.getContext(\"webgl2\",{antialias:true,preserveDrawingBuffer:true});\nif(!g)throw\"no webgl2\";\nconst VS=`#version 300 es\nin vec3 aP;in vec3 aN;uniform vec2 uR;uniform vec2 uY;uniform vec3 uC;uniform float uS;out vec3 vN;\nvoid main(){vec3 p=aP-uC;\nfloat xr=p.x*uY.x+p.y*uY.y;float yr=-p.x*uY.y+p.y*uY.x;\nvec3 v=vec3(xr,p.z,yr)*uS;\nvN=vec3(aN.x*uY.x+aN.y*uY.y,aN.z,-aN.x*uY.y+aN.y*uY.x);\nvec3 e=vec3(v.x,v.y,v.z-2.3);\ngl_Position=vec4(e.x*1.6*uR.y/uR.x,e.y*1.6,-2.7647*e.z-5.647,-e.z);}`;\nconst FS=`#version 300 es\nprecision highp float;in vec3 vN;out vec4 fc;\nvoid main(){vec3 n=normalize(vN);vec3 L=normalize(vec3(-.45,.75,.55));\nfloat d=abs(dot(n,L));vec3 skin=vec3(.925,.77,.675);\nvec3 H2=normalize(L+vec3(0.,0.,1.));float sp=pow(abs(dot(n,H2)),24.);\nfloat rim=pow(1.-abs(n.z),3.);\nvec3 c=skin*(.30+.72*d)+vec3(1.,.97,.92)*sp*.18+vec3(.35,.30,.45)*rim*.25;\nfc=vec4(c,1.);}`;\nconst cs=(t,s)=>{const o=g.createShader(t);g.shaderSource(o,s);g.compileShader(o);\nif(!g.getShaderParameter(o,g.COMPILE_STATUS))throw g.getShaderInfoLog(o);return o};\nconst pr=g.createProgram();g.attachShader(pr,cs(g.VERTEX_SHADER,VS));g.attachShader(pr,cs(g.FRAGMENT_SHADER,FS));\ng.linkProgram(pr);if(!g.getProgramParameter(pr,g.LINK_STATUS))throw g.getProgramInfoLog(pr);\ng.useProgram(pr);\n" as *u8) 64 p = nve_ap(out, p, "const bp=g.createBuffer();g.bindBuffer(g.ARRAY_BUFFER,bp);g.bufferData(g.ARRAY_BUFFER,P,g.STATIC_DRAW);\ng.enableVertexAttribArray(0);g.vertexAttribPointer(0,3,g.FLOAT,false,0,0);\nconst bn2=g.createBuffer();g.bindBuffer(g.ARRAY_BUFFER,bn2);g.bufferData(g.ARRAY_BUFFER,N,g.STATIC_DRAW);\ng.enableVertexAttribArray(1);g.vertexAttribPointer(1,3,g.FLOAT,false,0,0);\nconst bi=g.createBuffer();g.bindBuffer(g.ELEMENT_ARRAY_BUFFER,bi);g.bufferData(g.ELEMENT_ARRAY_BUFFER,I,g.STATIC_DRAW);\ng.enable(g.DEPTH_TEST);\nconst L2=n=>g.getUniformLocation(pr,n);\ng.uniform3f(L2(\"uC\"),C[0],C[1],C[2]);g.uniform1f(L2(\"uS\"),1.5/HH);\nlet yaw=.35,auto=true,px0=0;\ncv.addEventListener(\"pointerdown\",e=>{auto=false;px0=e.clientX;cv.setPointerCapture(e.pointerId)});\ncv.addEventListener(\"pointermove\",e=>{if(e.buttons){yaw+=(e.clientX-px0)*.012;px0=e.clientX}});\ncv.addEventListener(\"pointerup\",()=>{setTimeout(()=>{auto=true},4000)});\nfunction rs(){const r=cv.getBoundingClientRect();const d2=devicePixelRatio||1;\ncv.width=Math.round(r.width*d2);cv.height=Math.round(r.height*d2);g.viewport(0,0,cv.width,cv.height);\ng.uniform2f(L2(\"uR\"),cv.width,cv.height)}\nrs();addEventListener(\"resize\",rs);\ng.clearColor(.045,.04,.07,1);\nfunction fr(){if(auto)yaw+=.004;\ng.uniform2f(L2(\"uY\"),Math.cos(yaw),Math.sin(yaw));\ng.clear(g.COLOR_BUFFER_BIT|g.DEPTH_BUFFER_BIT);\ng.drawElements(g.TRIANGLES,nt*3,g.UNSIGNED_INT,0);\nrequestAnimationFrame(fr)}\nfr();\nst.textContent=\"NXA v1 verified \\u2014 \"+nv+\" verts, \"+nt+\" tris, all checksums GREEN\";\nwindow.__nxa={ok:1,nv:nv,nt:nt};\n}catch(e){st.textContent=\"NXA REFUSED: \"+e;st.style.color=\"#e6919b\";window.__nxa={ok:0,err:String(e)}}\n</script></body></html>\n" as *u8) 65 let fd: i64 = sys_openat_wr(argv[2] as *u8, 0x1a4) 66 if fd < 0 { nve_w("open out failed\n" as *u8); return 9 } 67 sys_write(fd, out, p) 68 sys_close(fd) 69 nve_w("NXA-VIEW page bytes=" as *u8); nve_num(p); nve_w("\n" as *u8) 70 return 0 71}