m3d={ /* shaders */ vs:"attribute vec3 v;\nattribute vec3 n;\nattribute vec4 c;\nuniform mat4 m;\nuniform mat4 p;\nvarying vec3 V;\nvarying vec3 N;\nvarying vec4 C;\nvoid main(void) {\nvec4 w = vec4(v, 1.0);\ngl_Position = p * m * w;\nV = vec3(m * w);\nN = vec3(m * vec4(n, 0));\nC = c;\n}", fs:"precision highp float;\nvarying vec3 V;\nvarying vec3 N;\nvarying vec4 C;\nvoid main(void) {\nvec3 no = normalize(N);\nvec3 l = normalize(vec3(-1,2,2)-V);\nfloat d = max(dot(no,l), 0.0);\ngl_FragColor = vec4(d * 1.1 * vec3(1.0,1.0,0.5) * vec3(C), C.w);\n}\n", /* matrix functions */ identity:function(){ var i,r=new Float32Array(16); for(i=0;i<16;i++)r[0]=0.0; r[0]=r[5]=r[10]=r[15]=1.0; return r; }, rotate:function(a,b){ var r=new Float32Array(16),x=b[0],y=b[1],z=b[2],d=Math.sqrt(x*x+y*y+z*z),s,c,t; if(!d)return null; x/=d;y/=d;z/=d; s=Math.sin(a); c=Math.cos(a); t=1-c; r[0]=x*x*t+c;r[1]=y*x*t+z*s;r[2]=z*x*t-y*s; r[4]=x*y*t-z*s;r[5]=y*y*t+c;r[6]=z*y*t+x*s; r[8]=x*z*t+y*s;r[9]=y*z*t-x*s; r[10]=z*z*t+c; r[3]=r[7]=r[11]=r[12]=r[13]=r[14]=0.0; r[15]=1.0; return r; }, multiply:function(a,b){ var r=new Float32Array(16); r[0]=b[0]*a[0]+b[1]*a[4]+b[2]*a[8]+b[3]*a[12]; r[1]=b[0]*a[1]+b[1]*a[5]+b[2]*a[9]+b[3]*a[13]; r[2]=b[0]*a[2]+b[1]*a[6]+b[2]*a[10]+b[3]*a[14]; r[3]=b[0]*a[3]+b[1]*a[7]+b[2]*a[11]+b[3]*a[15]; r[4]=b[4]*a[0]+b[5]*a[4]+b[6]*a[8]+b[7]*a[12]; r[5]=b[4]*a[1]+b[5]*a[5]+b[6]*a[9]+b[7]*a[13]; r[6]=b[4]*a[2]+b[5]*a[6]+b[6]*a[10]+b[7]*a[14]; r[7]=b[4]*a[3]+b[5]*a[7]+b[6]*a[11]+b[7]*a[15]; r[8]=b[8]*a[0]+b[9]*a[4]+b[10]*a[8]+b[11]*a[12]; r[9]=b[8]*a[1]+b[9]*a[5]+b[10]*a[9]+b[11]*a[13]; r[10]=b[8]*a[2]+b[9]*a[6]+b[10]*a[10]+b[11]*a[14]; r[11]=b[8]*a[3]+b[9]*a[7]+b[10]*a[11]+b[11]*a[15]; r[12]=b[12]*a[0]+b[13]*a[4]+b[14]*a[8]+b[15]*a[12]; r[13]=b[12]*a[1]+b[13]*a[5]+b[14]*a[9]+b[15]*a[13]; r[14]=b[12]*a[2]+b[13]*a[6]+b[14]*a[10]+b[15]*a[14]; r[15]=b[12]*a[3]+b[13]*a[7]+b[14]*a[11]+b[15]*a[15]; return r; }, perspective:function(y,a,n,f){ var t=n*Math.tan(y*Math.PI/360.0),b=-t,ri=t*a,l=-ri; var rl=(ri-l),tb=(t-b),fn=(f-n),r=new Float32Array(16); r[0]=(n*2)/rl;r[5]=(n*2)/tb; r[8]=(ri+l)/rl;r[9]=(t+b)/tb;r[10]=-(f+n)/fn;r[11]=-1; r[14]=-(f*n*2)/fn; r[1]=r[2]=r[3]=r[4]=r[6]=r[7]=r[12]=r[13]=r[15]=0; return r; }, /* renderer */ render:function(canvas){ var gl=canvas.gl; gl.viewport(0,0,gl.viewportWidth,gl.viewportHeight); gl.clear(gl.COLOR_BUFFER_BIT|gl.DEPTH_BUFFER_BIT); gl.useProgram(canvas.s); gl.uniformMatrix4fv(canvas.s.pu,false,canvas.p); gl.uniformMatrix4fv(canvas.s.mu,false,canvas.m); gl.bindBuffer(gl.ARRAY_BUFFER,canvas.v); gl.vertexAttribPointer(canvas.s.pa,3,gl.FLOAT,false,10*4,0); gl.bindBuffer(gl.ARRAY_BUFFER,canvas.c); gl.vertexAttribPointer(canvas.s.ca,4,gl.FLOAT,false,10*4,3*4); gl.bindBuffer(gl.ARRAY_BUFFER,canvas.n); gl.vertexAttribPointer(canvas.s.na,3,gl.FLOAT,false,10*4,7*4); gl.drawArrays(gl.TRIANGLES,0,canvas.i); }, /* handle rotation events */ drag:function(e){ e.target.mx=e.clientX; e.target.my=e.clientY; e.target.d=true; e.preventDefault(); }, release:function(e){ e.target.d=false; e.preventDefault(); }, move:function(e){ e.preventDefault(); if(e.type=="mousemove"&&!e.buttons)e.target.d=false; if(!e.target.d)return; var dx=e.clientX-e.target.mx,dy=e.target.my-e.clientY; e.target.mx=e.clientX; e.target.my=e.clientY; var r=m3d.rotate(Math.sqrt(dx*dx+dy*dy)*Math.PI/180,[-dy,dx,0]); if(r){ var t=m3d.identity(); t[14]=-5.0; e.target.r=m3d.multiply(r,e.target.r); e.target.m=m3d.multiply(t,e.target.r); m3d.render(e.target); } }, /* decode M3D */ /* this is pure evil, fucked up JS mess. We are using the SAME bytes in memory for Christ's sake! */ ba2int8:function(ba){var u=new Int8Array(ba.slice(0,1));return u[0];}, ba2int16:function(ba){var u=new Int16Array(ba.slice(0,2));return u[0];}, ba2int32:function(ba){var u=new Int32Array(ba.slice(0,4));return u[0];}, ba2uint8:function(ba){var u=new Uint8Array(ba.slice(0,1));return u[0];}, ba2uint16:function(ba){var u=new Uint16Array(ba.slice(0,2));return u[0];}, ba2uint32:function(ba){var u=new Uint32Array(ba.slice(0,4));return u[0];}, ba2float:function(ba){var u=new Float32Array(ba.slice(0,4));return u[0];}, ba2str:function(ba,o,s){return String.fromCharCode.apply(null,new Uint8Array(ba.slice(o,s)));}, load:function(canvas,g,b){ var vc_s,vi_s,si_s,ci_s,ti_s,sk_s,vd_s,vp_s,i,j,k,l,n,m,nv=0,nt=0,nm=false,ma,c,cm=[],v=[],f=[],vt=[],vd=[]; var px,py,pz,sx,sy,sz,x,y,z,mix,miy,miz,max,may,maz; if(m3d.ba2str(b,0,4)!="3DMO")return; b=b.slice(8); if(m3d.ba2str(b,0,4)=="PRVW"){ l=m3d.ba2uint32(b.slice(4,8)); b=b.slice(l); } if(m3d.ba2str(b,0,4)!="HEAD"){ try{b=pako.inflate(b).buffer;}catch(e){console.log("Unable to uncompress",e);return;} if(m3d.ba2str(b,0,4)!="HEAD")return; } l=m3d.ba2uint32(b.slice(4,8)); n=m3d.ba2uint8(b.slice(12,13)); vc_s=1<<((n>>0)&3); vi_s=1<<((n>>2)&3); si_s=1<<((n>>4)&3); ci_s=1<<((n>>6)&3); n=m3d.ba2uint8(b.slice(13,14)); ti_s=1<<((n>>0)&3); sk_s=1<<((n>>6)&3); n=m3d.ba2uint8(b.slice(14,15)); vd_s=1<<((n>>6)&3); n=m3d.ba2uint8(b.slice(15,16)); vp_s=1<<((n>>0)&3); if(ci_s==8)ci_s=0; if(sk_s==8)sk_s=0; mix=miy=miz=2147483647;max=may=maz=-2147483647; while(l&&b.byteLength&&m3d.ba2str(b,0,4)!="OMD3"){ b=b.slice(l); ma=m3d.ba2str(b,0,4); l=m3d.ba2uint32(b.slice(4,8)); if(l<8)break; c=b.slice(8,l); if(ma=="CMAP"){cm=new Uint8Array(c);}else if(ma=="VRTS"){ while(c.byteLength){ switch(vc_s){ case 1: v.push(m3d.ba2int8(c)/127.0);c=c.slice(1); v.push(m3d.ba2int8(c)/127.0);c=c.slice(1); v.push(m3d.ba2int8(c)/127.0);c=c.slice(2); break; case 2: v.push(m3d.ba2int16(c)/32767.0);c=c.slice(2); v.push(m3d.ba2int16(c)/32767.0);c=c.slice(2); v.push(m3d.ba2int16(c)/32767.0);c=c.slice(4); break; case 4: v.push(m3d.ba2float(c));c=c.slice(4); v.push(m3d.ba2float(c));c=c.slice(4); v.push(m3d.ba2float(c));c=c.slice(8); break; } col=[0x80,0x55,0x23,0xFF]; switch(ci_s){ case 1:n=m3d.ba2uint8(c);c=c.slice(1);col=[cm[n*4],cm[n*4+1],cm[n*4+2],cm[n*4+3]];break; case 2:n=m3d.ba2uint16(c);c=c.slice(2);col=[cm[n*4],cm[n*4+1],cm[n*4+2],cm[n*4+3]];break; case 4:col=[ m3d.ba2uint8(c.slice(0,1)), m3d.ba2uint8(c.slice(1,2)), m3d.ba2uint8(c.slice(2,3)), m3d.ba2uint8(c.slice(3,4))]; c=c.slice(4); break; } v.push(col[0]/255.0); v.push(col[1]/255.0); v.push(col[2]/255.0); v.push(col[3]/255.0); if(sk_s!=8)c=c.slice(sk_s); nv++; } }else if(ma=="MESH"){ while(c.byteLength){ var a=[]; m=m3d.ba2uint8(c); c=c.slice(1); if(!(m>>4)){c=c.slice(si_s);continue;} for(i=0;i<(m>>4);i++){ n=-1; switch(vi_s){ case 1:n=m3d.ba2uint8(c);c=c.slice(1);break; case 2:n=m3d.ba2uint16(c);c=c.slice(2);break; case 4:n=m3d.ba2uint32(c);c=c.slice(4);break; } a.push(n); if((m&1)&&ti_s!=8)c=c.slice(ti_s); n=-1; if(m&2){ switch(vi_s){ case 1:n=m3d.ba2uint8(c);c=c.slice(1);break; case 2:n=m3d.ba2uint16(c);c=c.slice(2);break; case 4:n=m3d.ba2uint32(c);c=c.slice(4);break; } } if(n==-1)nm=true; a.push(n); } f.push(a); } }else if(ma=="VOXT"){ while(c.byteLength){ col=[0x80,0x55,0x23,0xFF]; switch(ci_s){ case 1:n=m3d.ba2uint8(c);c=c.slice(1);col=[cm[n*4],cm[n*4+1],cm[n*4+2],cm[n*4+3]];break; case 2:n=m3d.ba2uint16(c);c=c.slice(2);col=[cm[n*4],cm[n*4+1],cm[n*4+2],cm[n*4+3]];break; case 4:col=[ m3d.ba2uint8(c.slice(0,1)), m3d.ba2uint8(c.slice(1,2)), m3d.ba2uint8(c.slice(2,3)), m3d.ba2uint8(c.slice(3,4))]; c=c.slice(4); break; } vt.push(col[0]/255.0); vt.push(col[1]/255.0); vt.push(col[2]/255.0); vt.push(col[3]/255.0); if(si_s!=8)c=c.slice(si_s); c=c.slice(2);n=m3d.ba2uint8(c);c=c.slice(1); if(sk_s!=8)c=c.slice(sk_s); if(n>0&&si_s!=8)c=c.slice(n*(2+si_s)); nt++; } }else if(ma=="VOXD"){ if(si_s!=8)c=c.slice(si_s); px=py=pz=sx=sy=sz=x=y=z=0; switch(vd_s){ case 1: px=m3d.ba2int8(c);c=c.slice(1); py=m3d.ba2int8(c);c=c.slice(1); pz=m3d.ba2int8(c);c=c.slice(1); sx=m3d.ba2uint8(c);c=c.slice(1); sy=m3d.ba2uint8(c);c=c.slice(1); sz=m3d.ba2uint8(c);c=c.slice(1); break; case 2: px=m3d.ba2int16(c);c=c.slice(2); py=m3d.ba2int16(c);c=c.slice(2); pz=m3d.ba2int16(c);c=c.slice(2); sx=m3d.ba2uint16(c);c=c.slice(2); sy=m3d.ba2uint16(c);c=c.slice(2); sz=m3d.ba2uint16(c);c=c.slice(2); break; case 4: px=m3d.ba2int32(c);c=c.slice(4); py=m3d.ba2int32(c);c=c.slice(4); pz=m3d.ba2int32(c);c=c.slice(4); sx=m3d.ba2uint32(c);c=c.slice(4); sy=m3d.ba2uint32(c);c=c.slice(4); sz=m3d.ba2uint32(c);c=c.slice(4); break; } if(pxmax)max=px+sx;if(py+sy>may)may=py+sy;if(pz+sz>maz)maz=pz+sz; c=c.slice(2); console.log(vp_s); while(c.byteLength){ m=m3d.ba2uint8(c);c=c.slice(1);k=(m&127)+1; if(m>127){if(vp_s==1){n=m3d.ba2uint8(c);c=c.slice(1);}else{n=m3d.ba2uint16(c);c=c.slice(2);}} for(j=0;j=sx){x=0;z++;if(z>=sz){z=0;y++;}} } } } } if(vd.length>0){ nm=true; l=(max-mix+1);if((may-miy+1)>l)l=(may-miy+1);/*if((maz-miz+1)>l)l=(maz-miz+1);*/ if(l)l=1.0/l;else l=0.5; for(i=0;i0){ if(nm){ var o=[],ax,ay,az,bx,by,bz,cx,cy,cz,d; for(i=0;i