nx_nxa_stream_emit.nx source
↩ module page · 63 lines · 11910 B
1// nx_nxa_stream_emit.nx -- SOVEREIGN STREAMING NXA viewer emitter. The embedded-base64 viewer
2// (nx_nxa_view_emit) proves small models; this one emits a page that FETCHES the .nxa over HTTP
3// with live progress, verifies every checksum in the browser (exact 64-bit rolling check done in
4// two 32-bit Number lanes -- no BigInt in the hot loop, ~10x faster on 9M-word files), auto-
5// detects the model's up axis, and renders MILLIONS of triangles in WebGL2 at device resolution.
6// This is the modern-polygon-count path: the file is served, not embedded, so size is unbounded.
7// The edge serves static files only up to ~4MB (measured: 4MB=200, 8MB=500), so big NXAs ship
8// as 4MB parts (<url>.pNN) the page refetches and reassembles -- transport chunking, the format
9// bytes untouched. nparts=1 means a single unsplit fetch.
10// INTEROP SYNC LAW: the page carries <meta name="nishi-nxa"> -- third-party browsers run the
11// emitted JS/WebGL2; the NISHI BROWSER reads the marker and renders the NXA NATIVELY instead.
12// usage: nx_nxa_stream_emit <out.html> <title> <nxa-url-base> <nparts> <total-bytes>
13// license_tier: ORIGINAL
14import "nx_syscalls.nx"
15
16const NSE_OUT_CAP: i64 = 1048576
17
18func nse_ap(out: *u8, pos: i64, s: *u8) -> i64 {
19 var k: i64 = 0
20 var p: i64 = pos
21 while s[k] != (0 as u8) { out[p] = s[k]; p = p + 1; k = k + 1 }
22 return p
23}
24func nse_w(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 }
25func nse_num(v: i64) -> i64 {
26 let t: *u8 = sys_mmap(32) as *u8
27 var m: i64 = v; var w: i64 = 0
28 if m==0 { t[0]=48 as u8; sys_write(1,t,1); return 0 }
29 let d: *u8 = sys_mmap(32) as *u8
30 var k: i64=0
31 while m>0 { d[k]=(48+(m%10)) as u8; m=m/10; k=k+1 }
32 var j: i64=0
33 while j<k { t[w]=d[k-1-j]; w=w+1; j=j+1 }
34 sys_write(1,t,w); return 0
35}
36
37func main(argc: i64, argv: *i64) -> i64 {
38 if argc < 6 { nse_w("usage: nx_nxa_stream_emit <out.html> <title> <nxa-url-base> <nparts> <total-bytes>\n" as *u8); return 2 }
39 let out: *u8 = sys_mmap(NSE_OUT_CAP)
40 var p: i64 = 0
41 p = nse_ap(out, p, "<!DOCTYPE html><html lang=\"en\"><head><meta charset=\"utf-8\"><title>" as *u8)
42 p = nse_ap(out, p, argv[2] as *u8)
43 p = nse_ap(out, p, "</title><meta name=\"nishi-nxa\" content=\"" as *u8)
44 p = nse_ap(out, p, argv[3] as *u8)
45 p = nse_ap(out, p, "\"><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:74ch}\n#st{color:#a8e6c0}</style></head><body><h1>" as *u8)
46 p = nse_ap(out, p, argv[2] as *u8)
47 p = nse_ap(out, p, "</h1><canvas id=\"c\"></canvas>\n<p id=\"st\">fetching NXA…</p>\n<p>STREAMED, not embedded: this page fetches a multi-megabyte <b>NXA</b> file (our sovereign animated\n3D format), verifies every checksum in your browser, then renders MILLIONS of triangles at device\nresolution in WebGL2. Drag to rotate.</p>\n<script>\nconst U=\"" as *u8)
48 p = nse_ap(out, p, argv[3] as *u8)
49 p = nse_ap(out, p, "\";\nconst NP=" as *u8)
50 p = nse_ap(out, p, argv[4] as *u8)
51 p = nse_ap(out, p, ";const TOT=" as *u8)
52 p = nse_ap(out, p, argv[5] as *u8)
53 p = nse_ap(out, p, ";\nconst st=document.getElementById(\"st\");\nconst y0=()=>new Promise(r=>setTimeout(r));\n// the edge caps static responses ~4MB, so big NXAs travel as .pNN parts reassembled here --\n// transport chunking only, the format bytes are untouched and re-verified below\nasync function fetchAll(){\nif(NP<2){const r=await fetch(U);if(!r.ok)throw\"fetch \"+r.status;return new Uint8Array(await r.arrayBuffer())}\nconst by=new Uint8Array(TOT);let got=0;\nfor(let i=0;i<NP;i++){const u=U+\".p\"+(i<10?\"0\":\"\")+i;\nconst r=await fetch(u);if(!r.ok)throw\"fetch \"+u+\" \"+r.status;\nconst a=new Uint8Array(await r.arrayBuffer());\nif(got+a.length>TOT)throw\"parts exceed declared size\";\nby.set(a,got);got+=a.length;\nst.textContent=\"fetching NXA\\u2026 \"+(got/1048576).toFixed(1)+\"/\"+(TOT/1048576).toFixed(1)+\" MB (part \"+(i+1)+\"/\"+NP+\")\";}\nif(got!=TOT)throw\"reassembly size \"+got+\" != \"+TOT;\nreturn by}\nasync function main(){\nconst by=await fetchAll();\nconst dv=new DataView(by.buffer);\nconst u32=o=>dv.getUint32(o,true);\n// signed-high decode: reconstructing negatives via +2^64 then subtracting quantizes to\n// f64's ulp at 2^64 = 4096 -- it stepped the NEGATIVE-coordinate half of the body into 4m\n// terraces. hi(signed)*2^32+lo is EXACT below 2^53.\nconst w=o=>u32(o)+dv.getInt32(o+4,true)*4294967296;\n// exact 64-bit rolling check (c=c*1000003+w mod 2^64) in two 32-bit lanes -- every\n// intermediate stays under 2^53 so plain Number math is EXACT, and ~10x faster than BigInt\nfunction ck(o,n){let lo=1,hi=0;\nfor(let i=0;i<n;i++){const a=lo*1000003+u32(o+i*8);lo=a>>>0;\nconst b=hi*1000003+u32(o+i*8+4)+Math.floor(a/4294967296);hi=b>>>0}\nreturn [lo,hi]}\nconst ckeq=(o,pr)=>u32(o)===pr[0]&&u32(o+4)===pr[1];\nconst t0=performance.now();\nconst mg=\"NXANIM01\";for(let i=0;i<8;i++)if(by[i]!=mg.charCodeAt(i))throw\"not an NXA file\";\nif(w(8)>1)throw\"future version \\u2014 refusing\";\nconst ns=Number(w(16));\nif(!ckeq(24,ck(32,ns*4)))throw\"TOC checksum mismatch \\u2014 refusing\";\nconst tg=s=>s.charCodeAt(0)|(s.charCodeAt(1)<<8)|(s.charCodeAt(2)<<16)|(s.charCodeAt(3)<<24);\nfunction find(t,req){for(let s2=0;s2<ns;s2++){const e=32+s2*32;\nif(u32(e)===(t>>>0)){const off=Number(w(e+8)),wl=Number(w(e+16));\nif(!ckeq(e+24,ck(off,wl)))throw\"section checksum mismatch \\u2014 refusing\";\nreturn off}}if(req)throw\"section missing\";return -1}\n" as *u8)
54 p = nse_ap(out, p, "st.textContent=\"verifying checksums\\u2026\";await y0();\nconst vo=find(tg(\"VERT\"),1),to=find(tg(\"TRIS\"),1),co=find(tg(\"CLUS\"),0);\nconst nv=Number(w(vo)),nt=Number(w(to)),ncl=co>=0?Number(w(co)):0;\nst.textContent=\"decoding \"+nv+\" verts\\u2026\";await y0();\nconst R=new Float64Array(nv*3);\nlet mn=[1e18,1e18,1e18],mx=[-1e18,-1e18,-1e18];\nfor(let i=0;i<nv*3;i++){const v=w(vo+8+i*8)/1000;R[i]=v;const a=i%3;if(v<mn[a])mn[a]=v;if(v>mx[a])mx[a]=v}\n// UP-AXIS AUTO-DETECT (the measurer's rule: a standing body's largest extent IS its up axis);\n// lat = larger of the rest. P is filled permuted to (lat, up, depth) so the shader is one view.\nconst ex=[mx[0]-mn[0],mx[1]-mn[1],mx[2]-mn[2]];\nlet up=0;if(ex[1]>ex[up])up=1;if(ex[2]>ex[up])up=2;\nlet lat=up===0?1:0;const oth0=3-up-lat;if(ex[oth0]>ex[lat])lat=oth0;\nconst oth=3-up-lat;\n// center in Float64 BEFORE the Float32 cast: models far from the origin otherwise quantize\n// to centimeters (f32 at 1e6 = 6cm steps -- the terraced-body bug; shader centering is too late)\nconst c0=(mn[lat]+mx[lat])/2,c1=(mn[up]+mx[up])/2,c2=(mn[oth]+mx[oth])/2;\nconst P=new Float32Array(nv*3);\nfor(let i=0;i<nv;i++){P[i*3]=R[i*3+lat]-c0;P[i*3+1]=R[i*3+up]-c1;P[i*3+2]=R[i*3+oth]-c2}\nst.textContent=\"decoding \"+nt+\" tris\\u2026\";await y0();\nconst I=new Uint32Array(nt*3);\nfor(let i=0;i<nt*3;i++)I[i]=u32(to+8+i*8);\nst.textContent=\"computing normals\\u2026\";await y0();\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=[0,0,0];\nconst HH=ex[up];\nconst pms=Math.round(performance.now()-t0);\n" as *u8)
55 p = nse_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.z*uY.y;float zr=-p.x*uY.y+p.z*uY.x;\nvec3 v=vec3(xr,p.y,zr)*uS;\nvN=vec3(aN.x*uY.x+aN.z*uY.y,aN.y,-aN.x*uY.y+aN.z*uY.x);\nvec3 e=vec3(v.x,v.y,v.z-2.3);\n// full-range depth mapping (near 1.5, far 3.2): squeezing z into a sliver of clip space\n// quantized a 280m model into visible 9cm terraces on the 16-bit depth buffer\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)
56 p = nse_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);\nlet fcnt=0;\nwindow.__nxa={ok:1,nv:nv,nt:nt,ncl:ncl,parse_ms:pms,fps:0};\nsetInterval(()=>{window.__nxa.fps=fcnt;fcnt=0;\nst.textContent=\"NXA v1 verified \\u2014 \"+nv+\" verts, \"+nt+\" tris, \"+ncl+\" clusters \\u00b7 parse \"+pms+\"ms \\u00b7 \"+window.__nxa.fps+\" fps\"},1000);\nfunction fr(){if(auto)yaw+=.004;fcnt++;\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 \\u00b7 parse \"+pms+\"ms\";\n}\nmain().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)
57 let fd: i64 = sys_openat_wr(argv[1] as *u8, 0x1a4)
58 if fd < 0 { nse_w("open out failed\n" as *u8); return 9 }
59 sys_write(fd, out, p)
60 sys_close(fd)
61 nse_w("NXA-STREAM page bytes=" as *u8); nse_num(p); nse_w("\n" as *u8)
62 return 0
63}