m3d.js 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441
  1. m3d={
  2. /* shaders */
  3. 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}",
  4. 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",
  5. /* matrix functions */
  6. identity:function(){
  7. var i,r=new Float32Array(16);
  8. for(i=0;i<16;i++)r[0]=0.0;
  9. r[0]=r[5]=r[10]=r[15]=1.0;
  10. return r;
  11. },
  12. rotate:function(a,b){
  13. 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;
  14. if(!d)return null;
  15. x/=d;y/=d;z/=d;
  16. s=Math.sin(a);
  17. c=Math.cos(a);
  18. t=1-c;
  19. r[0]=x*x*t+c;r[1]=y*x*t+z*s;r[2]=z*x*t-y*s;
  20. r[4]=x*y*t-z*s;r[5]=y*y*t+c;r[6]=z*y*t+x*s;
  21. r[8]=x*z*t+y*s;r[9]=y*z*t-x*s;
  22. r[10]=z*z*t+c;
  23. r[3]=r[7]=r[11]=r[12]=r[13]=r[14]=0.0;
  24. r[15]=1.0;
  25. return r;
  26. },
  27. multiply:function(a,b){
  28. var r=new Float32Array(16);
  29. r[0]=b[0]*a[0]+b[1]*a[4]+b[2]*a[8]+b[3]*a[12];
  30. r[1]=b[0]*a[1]+b[1]*a[5]+b[2]*a[9]+b[3]*a[13];
  31. r[2]=b[0]*a[2]+b[1]*a[6]+b[2]*a[10]+b[3]*a[14];
  32. r[3]=b[0]*a[3]+b[1]*a[7]+b[2]*a[11]+b[3]*a[15];
  33. r[4]=b[4]*a[0]+b[5]*a[4]+b[6]*a[8]+b[7]*a[12];
  34. r[5]=b[4]*a[1]+b[5]*a[5]+b[6]*a[9]+b[7]*a[13];
  35. r[6]=b[4]*a[2]+b[5]*a[6]+b[6]*a[10]+b[7]*a[14];
  36. r[7]=b[4]*a[3]+b[5]*a[7]+b[6]*a[11]+b[7]*a[15];
  37. r[8]=b[8]*a[0]+b[9]*a[4]+b[10]*a[8]+b[11]*a[12];
  38. r[9]=b[8]*a[1]+b[9]*a[5]+b[10]*a[9]+b[11]*a[13];
  39. r[10]=b[8]*a[2]+b[9]*a[6]+b[10]*a[10]+b[11]*a[14];
  40. r[11]=b[8]*a[3]+b[9]*a[7]+b[10]*a[11]+b[11]*a[15];
  41. r[12]=b[12]*a[0]+b[13]*a[4]+b[14]*a[8]+b[15]*a[12];
  42. r[13]=b[12]*a[1]+b[13]*a[5]+b[14]*a[9]+b[15]*a[13];
  43. r[14]=b[12]*a[2]+b[13]*a[6]+b[14]*a[10]+b[15]*a[14];
  44. r[15]=b[12]*a[3]+b[13]*a[7]+b[14]*a[11]+b[15]*a[15];
  45. return r;
  46. },
  47. perspective:function(y,a,n,f){
  48. var t=n*Math.tan(y*Math.PI/360.0),b=-t,ri=t*a,l=-ri;
  49. var rl=(ri-l),tb=(t-b),fn=(f-n),r=new Float32Array(16);
  50. r[0]=(n*2)/rl;r[5]=(n*2)/tb;
  51. r[8]=(ri+l)/rl;r[9]=(t+b)/tb;r[10]=-(f+n)/fn;r[11]=-1;
  52. r[14]=-(f*n*2)/fn;
  53. r[1]=r[2]=r[3]=r[4]=r[6]=r[7]=r[12]=r[13]=r[15]=0;
  54. return r;
  55. },
  56. /* renderer */
  57. render:function(canvas){
  58. var gl=canvas.gl;
  59. gl.viewport(0,0,gl.viewportWidth,gl.viewportHeight);
  60. gl.clear(gl.COLOR_BUFFER_BIT|gl.DEPTH_BUFFER_BIT);
  61. gl.useProgram(canvas.s);
  62. gl.uniformMatrix4fv(canvas.s.pu,false,canvas.p);
  63. gl.uniformMatrix4fv(canvas.s.mu,false,canvas.m);
  64. gl.bindBuffer(gl.ARRAY_BUFFER,canvas.v);
  65. gl.vertexAttribPointer(canvas.s.pa,3,gl.FLOAT,false,10*4,0);
  66. gl.bindBuffer(gl.ARRAY_BUFFER,canvas.c);
  67. gl.vertexAttribPointer(canvas.s.ca,4,gl.FLOAT,false,10*4,3*4);
  68. gl.bindBuffer(gl.ARRAY_BUFFER,canvas.n);
  69. gl.vertexAttribPointer(canvas.s.na,3,gl.FLOAT,false,10*4,7*4);
  70. gl.drawArrays(gl.TRIANGLES,0,canvas.i);
  71. },
  72. /* handle rotation events */
  73. drag:function(e){
  74. e.target.mx=e.clientX;
  75. e.target.my=e.clientY;
  76. e.target.d=true;
  77. e.preventDefault();
  78. },
  79. release:function(e){
  80. e.target.d=false;
  81. e.preventDefault();
  82. },
  83. move:function(e){
  84. e.preventDefault();
  85. if(e.type=="mousemove"&&!e.buttons)e.target.d=false;
  86. if(!e.target.d)return;
  87. var dx=e.clientX-e.target.mx,dy=e.target.my-e.clientY;
  88. e.target.mx=e.clientX;
  89. e.target.my=e.clientY;
  90. var r=m3d.rotate(Math.sqrt(dx*dx+dy*dy)*Math.PI/180,[-dy,dx,0]);
  91. if(r){
  92. var t=m3d.identity();
  93. t[14]=-5.0;
  94. e.target.r=m3d.multiply(r,e.target.r);
  95. e.target.m=m3d.multiply(t,e.target.r);
  96. m3d.render(e.target);
  97. }
  98. },
  99. /* decode M3D */
  100. /* this is pure evil, fucked up JS mess. We are using the SAME bytes in memory for Christ's sake! */
  101. ba2int8:function(ba){var u=new Int8Array(ba.slice(0,1));return u[0];},
  102. ba2int16:function(ba){var u=new Int16Array(ba.slice(0,2));return u[0];},
  103. ba2int32:function(ba){var u=new Int32Array(ba.slice(0,4));return u[0];},
  104. ba2uint8:function(ba){var u=new Uint8Array(ba.slice(0,1));return u[0];},
  105. ba2uint16:function(ba){var u=new Uint16Array(ba.slice(0,2));return u[0];},
  106. ba2uint32:function(ba){var u=new Uint32Array(ba.slice(0,4));return u[0];},
  107. ba2float:function(ba){var u=new Float32Array(ba.slice(0,4));return u[0];},
  108. ba2str:function(ba,o,s){return String.fromCharCode.apply(null,new Uint8Array(ba.slice(o,s)));},
  109. load:function(canvas,g,b){
  110. 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=[];
  111. var px,py,pz,sx,sy,sz,x,y,z,mix,miy,miz,max,may,maz;
  112. if(m3d.ba2str(b,0,4)!="3DMO")return;
  113. b=b.slice(8);
  114. if(m3d.ba2str(b,0,4)=="PRVW"){
  115. l=m3d.ba2uint32(b.slice(4,8));
  116. b=b.slice(l);
  117. }
  118. if(m3d.ba2str(b,0,4)!="HEAD"){
  119. try{b=pako.inflate(b).buffer;}catch(e){console.log("Unable to uncompress",e);return;}
  120. if(m3d.ba2str(b,0,4)!="HEAD")return;
  121. }
  122. l=m3d.ba2uint32(b.slice(4,8));
  123. n=m3d.ba2uint8(b.slice(12,13));
  124. vc_s=1<<((n>>0)&3);
  125. vi_s=1<<((n>>2)&3);
  126. si_s=1<<((n>>4)&3);
  127. ci_s=1<<((n>>6)&3);
  128. n=m3d.ba2uint8(b.slice(13,14));
  129. ti_s=1<<((n>>0)&3);
  130. sk_s=1<<((n>>6)&3);
  131. n=m3d.ba2uint8(b.slice(14,15));
  132. vd_s=1<<((n>>6)&3);
  133. n=m3d.ba2uint8(b.slice(15,16));
  134. vp_s=1<<((n>>0)&3);
  135. if(ci_s==8)ci_s=0;
  136. if(sk_s==8)sk_s=0;
  137. mix=miy=miz=2147483647;max=may=maz=-2147483647;
  138. while(l&&b.byteLength&&m3d.ba2str(b,0,4)!="OMD3"){
  139. b=b.slice(l);
  140. ma=m3d.ba2str(b,0,4);
  141. l=m3d.ba2uint32(b.slice(4,8));
  142. if(l<8)break;
  143. c=b.slice(8,l);
  144. if(ma=="CMAP"){cm=new Uint8Array(c);}else
  145. if(ma=="VRTS"){
  146. while(c.byteLength){
  147. switch(vc_s){
  148. case 1:
  149. v.push(m3d.ba2int8(c)/127.0);c=c.slice(1);
  150. v.push(m3d.ba2int8(c)/127.0);c=c.slice(1);
  151. v.push(m3d.ba2int8(c)/127.0);c=c.slice(2);
  152. break;
  153. case 2:
  154. v.push(m3d.ba2int16(c)/32767.0);c=c.slice(2);
  155. v.push(m3d.ba2int16(c)/32767.0);c=c.slice(2);
  156. v.push(m3d.ba2int16(c)/32767.0);c=c.slice(4);
  157. break;
  158. case 4:
  159. v.push(m3d.ba2float(c));c=c.slice(4);
  160. v.push(m3d.ba2float(c));c=c.slice(4);
  161. v.push(m3d.ba2float(c));c=c.slice(8);
  162. break;
  163. }
  164. col=[0x80,0x55,0x23,0xFF];
  165. switch(ci_s){
  166. 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;
  167. 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;
  168. case 4:col=[
  169. m3d.ba2uint8(c.slice(0,1)),
  170. m3d.ba2uint8(c.slice(1,2)),
  171. m3d.ba2uint8(c.slice(2,3)),
  172. m3d.ba2uint8(c.slice(3,4))];
  173. c=c.slice(4);
  174. break;
  175. }
  176. v.push(col[0]/255.0);
  177. v.push(col[1]/255.0);
  178. v.push(col[2]/255.0);
  179. v.push(col[3]/255.0);
  180. if(sk_s!=8)c=c.slice(sk_s);
  181. nv++;
  182. }
  183. }else
  184. if(ma=="MESH"){
  185. while(c.byteLength){
  186. var a=[];
  187. m=m3d.ba2uint8(c);
  188. c=c.slice(1);
  189. if(!(m>>4)){c=c.slice(si_s);continue;}
  190. for(i=0;i<(m>>4);i++){
  191. n=-1;
  192. switch(vi_s){
  193. case 1:n=m3d.ba2uint8(c);c=c.slice(1);break;
  194. case 2:n=m3d.ba2uint16(c);c=c.slice(2);break;
  195. case 4:n=m3d.ba2uint32(c);c=c.slice(4);break;
  196. }
  197. a.push(n);
  198. if((m&1)&&ti_s!=8)c=c.slice(ti_s);
  199. n=-1;
  200. if(m&2){
  201. switch(vi_s){
  202. case 1:n=m3d.ba2uint8(c);c=c.slice(1);break;
  203. case 2:n=m3d.ba2uint16(c);c=c.slice(2);break;
  204. case 4:n=m3d.ba2uint32(c);c=c.slice(4);break;
  205. }
  206. }
  207. if(n==-1)nm=true;
  208. a.push(n);
  209. }
  210. f.push(a);
  211. }
  212. }else
  213. if(ma=="VOXT"){
  214. while(c.byteLength){
  215. col=[0x80,0x55,0x23,0xFF];
  216. switch(ci_s){
  217. 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;
  218. 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;
  219. case 4:col=[
  220. m3d.ba2uint8(c.slice(0,1)),
  221. m3d.ba2uint8(c.slice(1,2)),
  222. m3d.ba2uint8(c.slice(2,3)),
  223. m3d.ba2uint8(c.slice(3,4))];
  224. c=c.slice(4);
  225. break;
  226. }
  227. vt.push(col[0]/255.0);
  228. vt.push(col[1]/255.0);
  229. vt.push(col[2]/255.0);
  230. vt.push(col[3]/255.0);
  231. if(si_s!=8)c=c.slice(si_s);
  232. c=c.slice(2);n=m3d.ba2uint8(c);c=c.slice(1);
  233. if(sk_s!=8)c=c.slice(sk_s);
  234. if(n>0&&si_s!=8)c=c.slice(n*(2+si_s));
  235. nt++;
  236. }
  237. }else
  238. if(ma=="VOXD"){
  239. if(si_s!=8)c=c.slice(si_s);
  240. px=py=pz=sx=sy=sz=x=y=z=0;
  241. switch(vd_s){
  242. case 1:
  243. px=m3d.ba2int8(c);c=c.slice(1);
  244. py=m3d.ba2int8(c);c=c.slice(1);
  245. pz=m3d.ba2int8(c);c=c.slice(1);
  246. sx=m3d.ba2uint8(c);c=c.slice(1);
  247. sy=m3d.ba2uint8(c);c=c.slice(1);
  248. sz=m3d.ba2uint8(c);c=c.slice(1);
  249. break;
  250. case 2:
  251. px=m3d.ba2int16(c);c=c.slice(2);
  252. py=m3d.ba2int16(c);c=c.slice(2);
  253. pz=m3d.ba2int16(c);c=c.slice(2);
  254. sx=m3d.ba2uint16(c);c=c.slice(2);
  255. sy=m3d.ba2uint16(c);c=c.slice(2);
  256. sz=m3d.ba2uint16(c);c=c.slice(2);
  257. break;
  258. case 4:
  259. px=m3d.ba2int32(c);c=c.slice(4);
  260. py=m3d.ba2int32(c);c=c.slice(4);
  261. pz=m3d.ba2int32(c);c=c.slice(4);
  262. sx=m3d.ba2uint32(c);c=c.slice(4);
  263. sy=m3d.ba2uint32(c);c=c.slice(4);
  264. sz=m3d.ba2uint32(c);c=c.slice(4);
  265. break;
  266. }
  267. if(px<mix)mix=px;if(py<miy)miy=py;if(pz<miz)miz=pz;
  268. if(px+sx>max)max=px+sx;if(py+sy>may)may=py+sy;if(pz+sz>maz)maz=pz+sz;
  269. c=c.slice(2);
  270. console.log(vp_s);
  271. while(c.byteLength){
  272. m=m3d.ba2uint8(c);c=c.slice(1);k=(m&127)+1;
  273. if(m>127){if(vp_s==1){n=m3d.ba2uint8(c);c=c.slice(1);}else{n=m3d.ba2uint16(c);c=c.slice(2);}}
  274. for(j=0;j<k;j++){
  275. if(m<128){if(vp_s==1){n=m3d.ba2uint8(c);c=c.slice(1);}else{n=m3d.ba2uint16(c);c=c.slice(2);}}
  276. if(n<nt){
  277. vd.push(px+x);vd.push(py+y);vd.push(pz+z);vd.push(n);
  278. }
  279. x++;if(x>=sx){x=0;z++;if(z>=sz){z=0;y++;}}
  280. }
  281. }
  282. }
  283. }
  284. if(vd.length>0){
  285. nm=true;
  286. l=(max-mix+1);if((may-miy+1)>l)l=(may-miy+1);/*if((maz-miz+1)>l)l=(maz-miz+1);*/
  287. if(l)l=1.0/l;else l=0.5;
  288. for(i=0;i<vd.length;i+=4){
  289. var a=[];
  290. x=vd[i];y=vd[i+1];z=vd[i+2];n=vd[i+3];
  291. v.push(x*l);v.push(y*l);v.push(z*l);
  292. v.push(vt[n*4]);v.push(vt[n*4+1]);v.push(vt[n*4+2]);v.push(vt[n*4+3]);nv++;
  293. v.push((x+1)*l);v.push(y*l);v.push(z*l);
  294. v.push(vt[n*4]);v.push(vt[n*4+1]);v.push(vt[n*4+2]);v.push(vt[n*4+3]);nv++;
  295. v.push(x*l);v.push(y*l);v.push((z+1)*l);
  296. v.push(vt[n*4]);v.push(vt[n*4+1]);v.push(vt[n*4+2]);v.push(vt[n*4+3]);nv++;
  297. v.push((x+1)*l);v.push(y*l);v.push((z+1)*l);
  298. v.push(vt[n*4]);v.push(vt[n*4+1]);v.push(vt[n*4+2]);v.push(vt[n*4+3]);nv++;
  299. v.push(x*l);v.push((y+1)*l);v.push(z*l);
  300. v.push(vt[n*4]);v.push(vt[n*4+1]);v.push(vt[n*4+2]);v.push(vt[n*4+3]);nv++;
  301. v.push((x+1)*l);v.push((y+1)*l);v.push(z*l);
  302. v.push(vt[n*4]);v.push(vt[n*4+1]);v.push(vt[n*4+2]);v.push(vt[n*4+3]);nv++;
  303. v.push(x*l);v.push((y+1)*l);v.push((z+1)*l);
  304. v.push(vt[n*4]);v.push(vt[n*4+1]);v.push(vt[n*4+2]);v.push(vt[n*4+3]);nv++;
  305. v.push((x+1)*l);v.push((y+1)*l);v.push((z+1)*l);
  306. v.push(vt[n*4]);v.push(vt[n*4+1]);v.push(vt[n*4+2]);v.push(vt[n*4+3]);nv++;
  307. a=[];a.push(nv-8);a.push(-1);a.push(nv-6);a.push(-1);a.push(nv-7);a.push(-1);f.push(a);
  308. a=[];a.push(nv-7);a.push(-1);a.push(nv-6);a.push(-1);a.push(nv-5);a.push(-1);f.push(a);
  309. a=[];a.push(nv-8);a.push(-1);a.push(nv-4);a.push(-1);a.push(nv-6);a.push(-1);f.push(a);
  310. a=[];a.push(nv-4);a.push(-1);a.push(nv-2);a.push(-1);a.push(nv-6);a.push(-1);f.push(a);
  311. a=[];a.push(nv-5);a.push(-1);a.push(nv-2);a.push(-1);a.push(nv-6);a.push(-1);f.push(a);
  312. a=[];a.push(nv-2);a.push(-1);a.push(nv-5);a.push(-1);a.push(nv-1);a.push(-1);f.push(a);
  313. a=[];a.push(nv-8);a.push(-1);a.push(nv-4);a.push(-1);a.push(nv-7);a.push(-1);f.push(a);
  314. a=[];a.push(nv-4);a.push(-1);a.push(nv-3);a.push(-1);a.push(nv-7);a.push(-1);f.push(a);
  315. a=[];a.push(nv-4);a.push(-1);a.push(nv-2);a.push(-1);a.push(nv-3);a.push(-1);f.push(a);
  316. a=[];a.push(nv-2);a.push(-1);a.push(nv-1);a.push(-1);a.push(nv-3);a.push(-1);f.push(a);
  317. a=[];a.push(nv-7);a.push(-1);a.push(nv-3);a.push(-1);a.push(nv-5);a.push(-1);f.push(a);
  318. a=[];a.push(nv-3);a.push(-1);a.push(nv-1);a.push(-1);a.push(nv-5);a.push(-1);f.push(a);
  319. }
  320. }
  321. if(v.length>0){
  322. if(nm){
  323. var o=[],ax,ay,az,bx,by,bz,cx,cy,cz,d;
  324. for(i=0;i<f.length;i++){
  325. ax=v[f[i][2]*7+0]-v[f[i][0]*7+0];
  326. ay=v[f[i][2]*7+1]-v[f[i][0]*7+1];
  327. az=v[f[i][2]*7+2]-v[f[i][0]*7+2];
  328. bx=v[f[i][4]*7+0]-v[f[i][0]*7+0];
  329. by=v[f[i][4]*7+1]-v[f[i][0]*7+1];
  330. bz=v[f[i][4]*7+2]-v[f[i][0]*7+2];
  331. cx=(ay*bz)-(az*by);
  332. cy=(az*bx)-(ax*bz);
  333. cz=(ax*by)-(ay*bx);
  334. d=Math.sqrt(cx*cx+cy*cy+cz*cz);
  335. if(d){cx/=d;cy/=d;cz/=d;}
  336. o[i]=[cx,cy,cz];
  337. f[i][1]=f[i][0]+nv;
  338. f[i][3]=f[i][2]+nv;
  339. f[i][5]=f[i][4]+nv;
  340. }
  341. for(i=0;i<nv*7;i++)v.push(0);
  342. for(i=0;i<f.length;i++){
  343. for(j=0;j<3;j++){
  344. v[f[i][j*2+1]*7+0]+=o[i][0];
  345. v[f[i][j*2+1]*7+1]+=o[i][1];
  346. v[f[i][j*2+1]*7+2]+=o[i][2];
  347. }
  348. }
  349. for(i=nv;i<2*nv;i++){
  350. d=Math.sqrt(v[i*7+0]*v[i*7+0]+v[i*7+1]*v[i*7+1]+v[i*7+2]*v[i*7+2]);
  351. if(d){v[i*7+0]/=d;v[i*7+1]/=d;v[i*7+2]/=d;}
  352. }
  353. }
  354. canvas.i=f.length*3;
  355. m=f.length*3*10;
  356. var gl=canvas.gl,VBO=new Float32Array(m);
  357. for(i=n=0;i<f.length;i++){
  358. for(j=0;j<3;j++){
  359. for(k=0;k<7;k++)
  360. VBO[n++]=v[f[i][j*2]*7+k];
  361. for(k=0;k<3;k++)
  362. VBO[n++]=v[f[i][j*2+1]*7+k];
  363. }
  364. }
  365. canvas.v=gl.createBuffer();
  366. gl.bindBuffer(gl.ARRAY_BUFFER,canvas.v);
  367. gl.bufferData(gl.ARRAY_BUFFER,VBO,gl.STATIC_DRAW);
  368. canvas.c=gl.createBuffer();
  369. gl.bindBuffer(gl.ARRAY_BUFFER,canvas.c);
  370. gl.bufferData(gl.ARRAY_BUFFER,VBO,gl.STATIC_DRAW);
  371. canvas.n=gl.createBuffer();
  372. gl.bindBuffer(gl.ARRAY_BUFFER,canvas.n);
  373. gl.bufferData(gl.ARRAY_BUFFER,VBO,gl.STATIC_DRAW);
  374. canvas.p=m3d.perspective(45,gl.viewportWidth/gl.viewportHeight,0.1,100.0);
  375. canvas.m=m3d.identity();
  376. canvas.m[14]=-5.0;
  377. canvas.r=m3d.identity();
  378. canvas.d=false;
  379. canvas.addEventListener('mousedown',m3d.drag,true);
  380. canvas.addEventListener('touchstart',m3d.drag,true);
  381. canvas.addEventListener('mousemove',m3d.move,true);
  382. canvas.addEventListener('touchmove',m3d.move,true);
  383. canvas.addEventListener('mouseup', m3d.release,true);
  384. canvas.addEventListener('touchend', m3d.release,true);
  385. m3d.render(canvas);
  386. g.parentNode.replaceChild(canvas,g);
  387. }
  388. },
  389. /* polyfill, replace IMGs with CANVASes */
  390. init:function(){
  391. var i,t=document.querySelectorAll("img[src$=\".m3d\"]");
  392. try{
  393. for(i=0;i<t.length;i++){
  394. var canvas=document.createElement("CANVAS"),gl,r;
  395. canvas.setAttribute("width",t[i].getAttribute("width"));
  396. canvas.setAttribute("height",t[i].getAttribute("height"));
  397. canvas.setAttribute("id",t[i].id?t[i].id:"m3d_"+i);
  398. if(t[i].className)canvas.setAttribute("class",t[i].className);
  399. gl=canvas.gl=canvas.getContext("experimental-webgl")||canvas.getContext("webgl");
  400. gl.viewportWidth=canvas.width;
  401. gl.viewportHeight=canvas.height;
  402. gl.clearColor(0.0,0.0,0.0,0.0);
  403. gl.enable(gl.DEPTH_TEST);
  404. var vs=gl.createShader(gl.VERTEX_SHADER);
  405. var fs=gl.createShader(gl.FRAGMENT_SHADER);
  406. gl.shaderSource(vs,unescape(encodeURI(m3d.vs)));
  407. gl.compileShader(vs);
  408. if(!gl.getShaderParameter(vs,gl.COMPILE_STATUS))throw "vertex shader compilation failed";
  409. gl.shaderSource(fs, unescape(encodeURI(m3d.fs)));
  410. gl.compileShader(fs);
  411. if(!gl.getShaderParameter(fs,gl.COMPILE_STATUS))throw "fragment shader compilation failed";
  412. canvas.s=gl.createProgram();
  413. gl.attachShader(canvas.s,vs);
  414. gl.attachShader(canvas.s,fs);
  415. gl.linkProgram(canvas.s);
  416. if(!gl.getProgramParameter(canvas.s,gl.LINK_STATUS))throw "failed to link shader with gl context";
  417. canvas.s.pa=gl.getAttribLocation(canvas.s,"v");
  418. gl.enableVertexAttribArray(canvas.s.pa);
  419. canvas.s.na=gl.getAttribLocation(canvas.s,"n");
  420. gl.enableVertexAttribArray(canvas.s.na);
  421. canvas.s.ca=gl.getAttribLocation(canvas.s,"c");
  422. gl.enableVertexAttribArray(canvas.s.ca);
  423. canvas.s.pu=gl.getUniformLocation(canvas.s,"p");
  424. canvas.s.mu=gl.getUniformLocation(canvas.s,"m");
  425. r=new XMLHttpRequest();
  426. r.open("GET",t[i].src,true);
  427. r.overrideMimeType("application/octet-stream");
  428. r.responseType="arraybuffer";
  429. r.c=canvas; /* dirty hack, but (function(e, canvas){})(event, canvas); does not work on firefox */
  430. r.i=t[i];
  431. r.onload=function(e){if(this.readyState==4)m3d.load(this.c,this.i,this.response||this.mozResponseArrayBuffer);};
  432. r.send(null);
  433. t[i].src='data:image/gif;base64,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';
  434. }
  435. }catch(e){console.log("Unable to initialize WebGL:",e);}
  436. }
  437. };
  438. document.addEventListener("DOMContentLoaded",m3d.init);