// gl-matrix 1.3.7 - https://github.com/toji/gl-matrix/blob/master/LICENSE.md // https://github.com/toji/gl-matrix (function(w,D){"object"===typeof exports?module.exports=D(global):"function"===typeof define&&define.amd?define([],function(){return D(w)}):D(w)})(this,function(w){function D(a){return o=a}function G(){return o="undefined"!==typeof Float32Array?Float32Array:Array}var E={};(function(){if("undefined"!=typeof Float32Array){var a=new Float32Array(1),b=new Int32Array(a.buffer);E.invsqrt=function(c){a[0]=c;b[0]=1597463007-(b[0]>>1);var d=a[0];return d*(1.5-0.5*c*d*d)}}else E.invsqrt=function(a){return 1/ Math.sqrt(a)}})();var o=null;G();var r={create:function(a){var b=new o(3);a?(b[0]=a[0],b[1]=a[1],b[2]=a[2]):b[0]=b[1]=b[2]=0;return b},createFrom:function(a,b,c){var d=new o(3);d[0]=a;d[1]=b;d[2]=c;return d},set:function(a,b){b[0]=a[0];b[1]=a[1];b[2]=a[2];return b},equal:function(a,b){return a===b||1.0E-6>Math.abs(a[0]-b[0])&&1.0E-6>Math.abs(a[1]-b[1])&&1.0E-6>Math.abs(a[2]-b[2])},add:function(a,b,c){if(!c||a===c)return a[0]+=b[0],a[1]+=b[1],a[2]+=b[2],a;c[0]=a[0]+b[0];c[1]=a[1]+b[1];c[2]=a[2]+b[2]; return c},subtract:function(a,b,c){if(!c||a===c)return a[0]-=b[0],a[1]-=b[1],a[2]-=b[2],a;c[0]=a[0]-b[0];c[1]=a[1]-b[1];c[2]=a[2]-b[2];return c},multiply:function(a,b,c){if(!c||a===c)return a[0]*=b[0],a[1]*=b[1],a[2]*=b[2],a;c[0]=a[0]*b[0];c[1]=a[1]*b[1];c[2]=a[2]*b[2];return c},negate:function(a,b){b||(b=a);b[0]=-a[0];b[1]=-a[1];b[2]=-a[2];return b},scale:function(a,b,c){if(!c||a===c)return a[0]*=b,a[1]*=b,a[2]*=b,a;c[0]=a[0]*b;c[1]=a[1]*b;c[2]=a[2]*b;return c},normalize:function(a,b){b||(b=a);var c= a[0],d=a[1],e=a[2],g=Math.sqrt(c*c+d*d+e*e);if(!g)return b[0]=0,b[1]=0,b[2]=0,b;if(1===g)return b[0]=c,b[1]=d,b[2]=e,b;g=1/g;b[0]=c*g;b[1]=d*g;b[2]=e*g;return b},cross:function(a,b,c){c||(c=a);var d=a[0],e=a[1],a=a[2],g=b[0],f=b[1],b=b[2];c[0]=e*b-a*f;c[1]=a*g-d*b;c[2]=d*f-e*g;return c},length:function(a){var b=a[0],c=a[1],a=a[2];return Math.sqrt(b*b+c*c+a*a)},squaredLength:function(a){var b=a[0],c=a[1],a=a[2];return b*b+c*c+a*a},dot:function(a,b){return a[0]*b[0]+a[1]*b[1]+a[2]*b[2]},direction:function(a, b,c){c||(c=a);var d=a[0]-b[0],e=a[1]-b[1],a=a[2]-b[2],b=Math.sqrt(d*d+e*e+a*a);if(!b)return c[0]=0,c[1]=0,c[2]=0,c;b=1/b;c[0]=d*b;c[1]=e*b;c[2]=a*b;return c},lerp:function(a,b,c,d){d||(d=a);d[0]=a[0]+c*(b[0]-a[0]);d[1]=a[1]+c*(b[1]-a[1]);d[2]=a[2]+c*(b[2]-a[2]);return d},dist:function(a,b){var c=b[0]-a[0],d=b[1]-a[1],e=b[2]-a[2];return Math.sqrt(c*c+d*d+e*e)}},H=null,y=new o(4);r.unproject=function(a,b,c,d,e){e||(e=a);H||(H=x.create());var g=H;y[0]=2*(a[0]-d[0])/d[2]-1;y[1]=2*(a[1]-d[1])/d[3]-1;y[2]= 2*a[2]-1;y[3]=1;x.multiply(c,b,g);if(!x.inverse(g))return null;x.multiplyVec4(g,y);if(0===y[3])return null;e[0]=y[0]/y[3];e[1]=y[1]/y[3];e[2]=y[2]/y[3];return e};var L=r.createFrom(1,0,0),M=r.createFrom(0,1,0),N=r.createFrom(0,0,1),z=r.create();r.rotationTo=function(a,b,c){c||(c=k.create());var d=r.dot(a,b);if(1<=d)k.set(O,c);else if(-0.999999>d)r.cross(L,a,z),1.0E-6>r.length(z)&&r.cross(M,a,z),1.0E-6>r.length(z)&&r.cross(N,a,z),r.normalize(z),k.fromAngleAxis(Math.PI,z,c);else{var d=Math.sqrt(2*(1+ d)),e=1/d;r.cross(a,b,z);c[0]=z[0]*e;c[1]=z[1]*e;c[2]=z[2]*e;c[3]=0.5*d;k.normalize(c)}1c[3]&&(c[3]=-1);return c};r.str=function(a){return"["+a[0]+", "+a[1]+", "+a[2]+"]"};var A={create:function(a){var b=new o(9);a?(b[0]=a[0],b[1]=a[1],b[2]=a[2],b[3]=a[3],b[4]=a[4],b[5]=a[5],b[6]=a[6],b[7]=a[7],b[8]=a[8]):b[0]=b[1]=b[2]=b[3]=b[4]=b[5]=b[6]=b[7]=b[8]=0;return b},createFrom:function(a,b,c,d,e,g,f,h,j){var i=new o(9);i[0]=a;i[1]=b;i[2]=c;i[3]=d;i[4]=e;i[5]=g;i[6]=f;i[7]=h;i[8]=j;return i}, determinant:function(a){var b=a[3],c=a[4],d=a[5],e=a[6],g=a[7],f=a[8];return a[0]*(f*c-d*g)+a[1]*(-f*b+d*e)+a[2]*(g*b-c*e)},inverse:function(a,b){var c=a[0],d=a[1],e=a[2],g=a[3],f=a[4],h=a[5],j=a[6],i=a[7],m=a[8],l=m*f-h*i,C=-m*g+h*j,q=i*g-f*j,n=c*l+d*C+e*q;if(!n)return null;n=1/n;b||(b=A.create());b[0]=l*n;b[1]=(-m*d+e*i)*n;b[2]=(h*d-e*f)*n;b[3]=C*n;b[4]=(m*c-e*j)*n;b[5]=(-h*c+e*g)*n;b[6]=q*n;b[7]=(-i*c+d*j)*n;b[8]=(f*c-d*g)*n;return b},multiply:function(a,b,c){c||(c=a);var d=a[0],e=a[1],g=a[2], f=a[3],h=a[4],j=a[5],i=a[6],m=a[7],a=a[8],l=b[0],C=b[1],q=b[2],n=b[3],k=b[4],p=b[5],o=b[6],s=b[7],b=b[8];c[0]=l*d+C*f+q*i;c[1]=l*e+C*h+q*m;c[2]=l*g+C*j+q*a;c[3]=n*d+k*f+p*i;c[4]=n*e+k*h+p*m;c[5]=n*g+k*j+p*a;c[6]=o*d+s*f+b*i;c[7]=o*e+s*h+b*m;c[8]=o*g+s*j+b*a;return c},multiplyVec2:function(a,b,c){c||(c=b);var d=b[0],b=b[1];c[0]=d*a[0]+b*a[3]+a[6];c[1]=d*a[1]+b*a[4]+a[7];return c},multiplyVec3:function(a,b,c){c||(c=b);var d=b[0],e=b[1],b=b[2];c[0]=d*a[0]+e*a[3]+b*a[6];c[1]=d*a[1]+e*a[4]+b*a[7];c[2]= d*a[2]+e*a[5]+b*a[8];return c},set:function(a,b){b[0]=a[0];b[1]=a[1];b[2]=a[2];b[3]=a[3];b[4]=a[4];b[5]=a[5];b[6]=a[6];b[7]=a[7];b[8]=a[8];return b},equal:function(a,b){return a===b||1.0E-6>Math.abs(a[0]-b[0])&&1.0E-6>Math.abs(a[1]-b[1])&&1.0E-6>Math.abs(a[2]-b[2])&&1.0E-6>Math.abs(a[3]-b[3])&&1.0E-6>Math.abs(a[4]-b[4])&&1.0E-6>Math.abs(a[5]-b[5])&&1.0E-6>Math.abs(a[6]-b[6])&&1.0E-6>Math.abs(a[7]-b[7])&&1.0E-6>Math.abs(a[8]-b[8])},identity:function(a){a||(a=A.create());a[0]=1;a[1]=0;a[2]=0;a[3]=0; a[4]=1;a[5]=0;a[6]=0;a[7]=0;a[8]=1;return a},transpose:function(a,b){if(!b||a===b){var c=a[1],d=a[2],e=a[5];a[1]=a[3];a[2]=a[6];a[3]=c;a[5]=a[7];a[6]=d;a[7]=e;return a}b[0]=a[0];b[1]=a[3];b[2]=a[6];b[3]=a[1];b[4]=a[4];b[5]=a[7];b[6]=a[2];b[7]=a[5];b[8]=a[8];return b},toMat4:function(a,b){b||(b=x.create());b[15]=1;b[14]=0;b[13]=0;b[12]=0;b[11]=0;b[10]=a[8];b[9]=a[7];b[8]=a[6];b[7]=0;b[6]=a[5];b[5]=a[4];b[4]=a[3];b[3]=0;b[2]=a[2];b[1]=a[1];b[0]=a[0];return b},str:function(a){return"["+a[0]+", "+a[1]+ ", "+a[2]+", "+a[3]+", "+a[4]+", "+a[5]+", "+a[6]+", "+a[7]+", "+a[8]+"]"}},x={create:function(a){var b=new o(16);a&&(b[0]=a[0],b[1]=a[1],b[2]=a[2],b[3]=a[3],b[4]=a[4],b[5]=a[5],b[6]=a[6],b[7]=a[7],b[8]=a[8],b[9]=a[9],b[10]=a[10],b[11]=a[11],b[12]=a[12],b[13]=a[13],b[14]=a[14],b[15]=a[15]);return b},createFrom:function(a,b,c,d,e,g,f,h,j,i,m,l,C,q,n,k){var p=new o(16);p[0]=a;p[1]=b;p[2]=c;p[3]=d;p[4]=e;p[5]=g;p[6]=f;p[7]=h;p[8]=j;p[9]=i;p[10]=m;p[11]=l;p[12]=C;p[13]=q;p[14]=n;p[15]=k;return p},set:function(a, b){b[0]=a[0];b[1]=a[1];b[2]=a[2];b[3]=a[3];b[4]=a[4];b[5]=a[5];b[6]=a[6];b[7]=a[7];b[8]=a[8];b[9]=a[9];b[10]=a[10];b[11]=a[11];b[12]=a[12];b[13]=a[13];b[14]=a[14];b[15]=a[15];return b},equal:function(a,b){return a===b||1.0E-6>Math.abs(a[0]-b[0])&&1.0E-6>Math.abs(a[1]-b[1])&&1.0E-6>Math.abs(a[2]-b[2])&&1.0E-6>Math.abs(a[3]-b[3])&&1.0E-6>Math.abs(a[4]-b[4])&&1.0E-6>Math.abs(a[5]-b[5])&&1.0E-6>Math.abs(a[6]-b[6])&&1.0E-6>Math.abs(a[7]-b[7])&&1.0E-6>Math.abs(a[8]-b[8])&&1.0E-6>Math.abs(a[9]-b[9])&&1.0E-6> Math.abs(a[10]-b[10])&&1.0E-6>Math.abs(a[11]-b[11])&&1.0E-6>Math.abs(a[12]-b[12])&&1.0E-6>Math.abs(a[13]-b[13])&&1.0E-6>Math.abs(a[14]-b[14])&&1.0E-6>Math.abs(a[15]-b[15])},identity:function(a){a||(a=x.create());a[0]=1;a[1]=0;a[2]=0;a[3]=0;a[4]=0;a[5]=1;a[6]=0;a[7]=0;a[8]=0;a[9]=0;a[10]=1;a[11]=0;a[12]=0;a[13]=0;a[14]=0;a[15]=1;return a},transpose:function(a,b){if(!b||a===b){var c=a[1],d=a[2],e=a[3],g=a[6],f=a[7],h=a[11];a[1]=a[4];a[2]=a[8];a[3]=a[12];a[4]=c;a[6]=a[9];a[7]=a[13];a[8]=d;a[9]=g;a[11]= a[14];a[12]=e;a[13]=f;a[14]=h;return a}b[0]=a[0];b[1]=a[4];b[2]=a[8];b[3]=a[12];b[4]=a[1];b[5]=a[5];b[6]=a[9];b[7]=a[13];b[8]=a[2];b[9]=a[6];b[10]=a[10];b[11]=a[14];b[12]=a[3];b[13]=a[7];b[14]=a[11];b[15]=a[15];return b},determinant:function(a){var b=a[0],c=a[1],d=a[2],e=a[3],g=a[4],f=a[5],h=a[6],j=a[7],i=a[8],m=a[9],l=a[10],C=a[11],q=a[12],n=a[13],k=a[14],a=a[15];return q*m*h*e-i*n*h*e-q*f*l*e+g*n*l*e+i*f*k*e-g*m*k*e-q*m*d*j+i*n*d*j+q*c*l*j-b*n*l*j-i*c*k*j+b*m*k*j+q*f*d*C-g*n*d*C-q*c*h*C+b*n*h*C+ g*c*k*C-b*f*k*C-i*f*d*a+g*m*d*a+i*c*h*a-b*m*h*a-g*c*l*a+b*f*l*a},inverse:function(a,b){b||(b=a);var c=a[0],d=a[1],e=a[2],g=a[3],f=a[4],h=a[5],j=a[6],i=a[7],m=a[8],l=a[9],k=a[10],q=a[11],n=a[12],o=a[13],p=a[14],r=a[15],s=c*h-d*f,v=c*j-e*f,t=c*i-g*f,u=d*j-e*h,w=d*i-g*h,x=e*i-g*j,y=m*o-l*n,z=m*p-k*n,F=m*r-q*n,A=l*p-k*o,D=l*r-q*o,E=k*r-q*p,B=s*E-v*D+t*A+u*F-w*z+x*y;if(!B)return null;B=1/B;b[0]=(h*E-j*D+i*A)*B;b[1]=(-d*E+e*D-g*A)*B;b[2]=(o*x-p*w+r*u)*B;b[3]=(-l*x+k*w-q*u)*B;b[4]=(-f*E+j*F-i*z)*B;b[5]= (c*E-e*F+g*z)*B;b[6]=(-n*x+p*t-r*v)*B;b[7]=(m*x-k*t+q*v)*B;b[8]=(f*D-h*F+i*y)*B;b[9]=(-c*D+d*F-g*y)*B;b[10]=(n*w-o*t+r*s)*B;b[11]=(-m*w+l*t-q*s)*B;b[12]=(-f*A+h*z-j*y)*B;b[13]=(c*A-d*z+e*y)*B;b[14]=(-n*u+o*v-p*s)*B;b[15]=(m*u-l*v+k*s)*B;return b},toRotationMat:function(a,b){b||(b=x.create());b[0]=a[0];b[1]=a[1];b[2]=a[2];b[3]=a[3];b[4]=a[4];b[5]=a[5];b[6]=a[6];b[7]=a[7];b[8]=a[8];b[9]=a[9];b[10]=a[10];b[11]=a[11];b[12]=0;b[13]=0;b[14]=0;b[15]=1;return b},toMat3:function(a,b){b||(b=A.create());b[0]= a[0];b[1]=a[1];b[2]=a[2];b[3]=a[4];b[4]=a[5];b[5]=a[6];b[6]=a[8];b[7]=a[9];b[8]=a[10];return b},toInverseMat3:function(a,b){var c=a[0],d=a[1],e=a[2],g=a[4],f=a[5],h=a[6],j=a[8],i=a[9],m=a[10],l=m*f-h*i,k=-m*g+h*j,q=i*g-f*j,n=c*l+d*k+e*q;if(!n)return null;n=1/n;b||(b=A.create());b[0]=l*n;b[1]=(-m*d+e*i)*n;b[2]=(h*d-e*f)*n;b[3]=k*n;b[4]=(m*c-e*j)*n;b[5]=(-h*c+e*g)*n;b[6]=q*n;b[7]=(-i*c+d*j)*n;b[8]=(f*c-d*g)*n;return b},multiply:function(a,b,c){c||(c=a);var d=a[0],e=a[1],g=a[2],f=a[3],h=a[4],j=a[5], i=a[6],m=a[7],l=a[8],k=a[9],q=a[10],n=a[11],o=a[12],p=a[13],r=a[14],a=a[15],s=b[0],v=b[1],t=b[2],u=b[3];c[0]=s*d+v*h+t*l+u*o;c[1]=s*e+v*j+t*k+u*p;c[2]=s*g+v*i+t*q+u*r;c[3]=s*f+v*m+t*n+u*a;s=b[4];v=b[5];t=b[6];u=b[7];c[4]=s*d+v*h+t*l+u*o;c[5]=s*e+v*j+t*k+u*p;c[6]=s*g+v*i+t*q+u*r;c[7]=s*f+v*m+t*n+u*a;s=b[8];v=b[9];t=b[10];u=b[11];c[8]=s*d+v*h+t*l+u*o;c[9]=s*e+v*j+t*k+u*p;c[10]=s*g+v*i+t*q+u*r;c[11]=s*f+v*m+t*n+u*a;s=b[12];v=b[13];t=b[14];u=b[15];c[12]=s*d+v*h+t*l+u*o;c[13]=s*e+v*j+t*k+u*p;c[14]=s*g+ v*i+t*q+u*r;c[15]=s*f+v*m+t*n+u*a;return c},multiplyVec3:function(a,b,c){c||(c=b);var d=b[0],e=b[1],b=b[2];c[0]=a[0]*d+a[4]*e+a[8]*b+a[12];c[1]=a[1]*d+a[5]*e+a[9]*b+a[13];c[2]=a[2]*d+a[6]*e+a[10]*b+a[14];return c},multiplyVec4:function(a,b,c){c||(c=b);var d=b[0],e=b[1],g=b[2],b=b[3];c[0]=a[0]*d+a[4]*e+a[8]*g+a[12]*b;c[1]=a[1]*d+a[5]*e+a[9]*g+a[13]*b;c[2]=a[2]*d+a[6]*e+a[10]*g+a[14]*b;c[3]=a[3]*d+a[7]*e+a[11]*g+a[15]*b;return c},translate:function(a,b,c){var d=b[0],e=b[1],b=b[2],g,f,h,j,i,m,l,k,q, n,o,p;if(!c||a===c)return a[12]=a[0]*d+a[4]*e+a[8]*b+a[12],a[13]=a[1]*d+a[5]*e+a[9]*b+a[13],a[14]=a[2]*d+a[6]*e+a[10]*b+a[14],a[15]=a[3]*d+a[7]*e+a[11]*b+a[15],a;g=a[0];f=a[1];h=a[2];j=a[3];i=a[4];m=a[5];l=a[6];k=a[7];q=a[8];n=a[9];o=a[10];p=a[11];c[0]=g;c[1]=f;c[2]=h;c[3]=j;c[4]=i;c[5]=m;c[6]=l;c[7]=k;c[8]=q;c[9]=n;c[10]=o;c[11]=p;c[12]=g*d+i*e+q*b+a[12];c[13]=f*d+m*e+n*b+a[13];c[14]=h*d+l*e+o*b+a[14];c[15]=j*d+k*e+p*b+a[15];return c},scale:function(a,b,c){var d=b[0],e=b[1],b=b[2];if(!c||a===c)return a[0]*= d,a[1]*=d,a[2]*=d,a[3]*=d,a[4]*=e,a[5]*=e,a[6]*=e,a[7]*=e,a[8]*=b,a[9]*=b,a[10]*=b,a[11]*=b,a;c[0]=a[0]*d;c[1]=a[1]*d;c[2]=a[2]*d;c[3]=a[3]*d;c[4]=a[4]*e;c[5]=a[5]*e;c[6]=a[6]*e;c[7]=a[7]*e;c[8]=a[8]*b;c[9]=a[9]*b;c[10]=a[10]*b;c[11]=a[11]*b;c[12]=a[12];c[13]=a[13];c[14]=a[14];c[15]=a[15];return c},rotate:function(a,b,c,d){var e=c[0],g=c[1],c=c[2],f=Math.sqrt(e*e+g*g+c*c),h,j,i,m,l,k,q,n,o,p,r,s,v,t,u,w,x,y,z,A;if(!f)return null;1!==f&&(f=1/f,e*=f,g*=f,c*=f);h=Math.sin(b);j=Math.cos(b);i=1-j;b=a[0]; f=a[1];m=a[2];l=a[3];k=a[4];q=a[5];n=a[6];o=a[7];p=a[8];r=a[9];s=a[10];v=a[11];t=e*e*i+j;u=g*e*i+c*h;w=c*e*i-g*h;x=e*g*i-c*h;y=g*g*i+j;z=c*g*i+e*h;A=e*c*i+g*h;e=g*c*i-e*h;g=c*c*i+j;d?a!==d&&(d[12]=a[12],d[13]=a[13],d[14]=a[14],d[15]=a[15]):d=a;d[0]=b*t+k*u+p*w;d[1]=f*t+q*u+r*w;d[2]=m*t+n*u+s*w;d[3]=l*t+o*u+v*w;d[4]=b*x+k*y+p*z;d[5]=f*x+q*y+r*z;d[6]=m*x+n*y+s*z;d[7]=l*x+o*y+v*z;d[8]=b*A+k*e+p*g;d[9]=f*A+q*e+r*g;d[10]=m*A+n*e+s*g;d[11]=l*A+o*e+v*g;return d},rotateX:function(a,b,c){var d=Math.sin(b), b=Math.cos(b),e=a[4],g=a[5],f=a[6],h=a[7],j=a[8],i=a[9],m=a[10],l=a[11];c?a!==c&&(c[0]=a[0],c[1]=a[1],c[2]=a[2],c[3]=a[3],c[12]=a[12],c[13]=a[13],c[14]=a[14],c[15]=a[15]):c=a;c[4]=e*b+j*d;c[5]=g*b+i*d;c[6]=f*b+m*d;c[7]=h*b+l*d;c[8]=e*-d+j*b;c[9]=g*-d+i*b;c[10]=f*-d+m*b;c[11]=h*-d+l*b;return c},rotateY:function(a,b,c){var d=Math.sin(b),b=Math.cos(b),e=a[0],g=a[1],f=a[2],h=a[3],j=a[8],i=a[9],m=a[10],l=a[11];c?a!==c&&(c[4]=a[4],c[5]=a[5],c[6]=a[6],c[7]=a[7],c[12]=a[12],c[13]=a[13],c[14]=a[14],c[15]= a[15]):c=a;c[0]=e*b+j*-d;c[1]=g*b+i*-d;c[2]=f*b+m*-d;c[3]=h*b+l*-d;c[8]=e*d+j*b;c[9]=g*d+i*b;c[10]=f*d+m*b;c[11]=h*d+l*b;return c},rotateZ:function(a,b,c){var d=Math.sin(b),b=Math.cos(b),e=a[0],g=a[1],f=a[2],h=a[3],j=a[4],i=a[5],m=a[6],l=a[7];c?a!==c&&(c[8]=a[8],c[9]=a[9],c[10]=a[10],c[11]=a[11],c[12]=a[12],c[13]=a[13],c[14]=a[14],c[15]=a[15]):c=a;c[0]=e*b+j*d;c[1]=g*b+i*d;c[2]=f*b+m*d;c[3]=h*b+l*d;c[4]=e*-d+j*b;c[5]=g*-d+i*b;c[6]=f*-d+m*b;c[7]=h*-d+l*b;return c},frustum:function(a,b,c,d,e,g,f){f|| (f=x.create());var h=b-a,j=d-c,i=g-e;f[0]=2*e/h;f[1]=0;f[2]=0;f[3]=0;f[4]=0;f[5]=2*e/j;f[6]=0;f[7]=0;f[8]=(b+a)/h;f[9]=(d+c)/j;f[10]=-(g+e)/i;f[11]=-1;f[12]=0;f[13]=0;f[14]=-(2*g*e)/i;f[15]=0;return f},perspective:function(a,b,c,d,e){a=c*Math.tan(a*Math.PI/360);b*=a;return x.frustum(-b,b,-a,a,c,d,e)},ortho:function(a,b,c,d,e,g,f){f||(f=x.create());var h=b-a,j=d-c,i=g-e;f[0]=2/h;f[1]=0;f[2]=0;f[3]=0;f[4]=0;f[5]=2/j;f[6]=0;f[7]=0;f[8]=0;f[9]=0;f[10]=-2/i;f[11]=0;f[12]=-(a+b)/h;f[13]=-(d+c)/j;f[14]= -(g+e)/i;f[15]=1;return f},lookAt:function(a,b,c,d){d||(d=x.create());var e,g,f,h,j,i,m,l,k=a[0],o=a[1],a=a[2];f=c[0];h=c[1];g=c[2];m=b[0];c=b[1];e=b[2];if(k===m&&o===c&&a===e)return x.identity(d);b=k-m;c=o-c;m=a-e;l=1/Math.sqrt(b*b+c*c+m*m);b*=l;c*=l;m*=l;e=h*m-g*c;g=g*b-f*m;f=f*c-h*b;(l=Math.sqrt(e*e+g*g+f*f))?(l=1/l,e*=l,g*=l,f*=l):f=g=e=0;h=c*f-m*g;j=m*e-b*f;i=b*g-c*e;(l=Math.sqrt(h*h+j*j+i*i))?(l=1/l,h*=l,j*=l,i*=l):i=j=h=0;d[0]=e;d[1]=h;d[2]=b;d[3]=0;d[4]=g;d[5]=j;d[6]=c;d[7]=0;d[8]=f;d[9]= i;d[10]=m;d[11]=0;d[12]=-(e*k+g*o+f*a);d[13]=-(h*k+j*o+i*a);d[14]=-(b*k+c*o+m*a);d[15]=1;return d},fromRotationTranslation:function(a,b,c){c||(c=x.create());var d=a[0],e=a[1],g=a[2],f=a[3],h=d+d,j=e+e,i=g+g,a=d*h,m=d*j,d=d*i,k=e*j,e=e*i,g=g*i,h=f*h,j=f*j,f=f*i;c[0]=1-(k+g);c[1]=m+f;c[2]=d-j;c[3]=0;c[4]=m-f;c[5]=1-(a+g);c[6]=e+h;c[7]=0;c[8]=d+j;c[9]=e-h;c[10]=1-(a+k);c[11]=0;c[12]=b[0];c[13]=b[1];c[14]=b[2];c[15]=1;return c},str:function(a){return"["+a[0]+", "+a[1]+", "+a[2]+", "+a[3]+", "+a[4]+", "+ a[5]+", "+a[6]+", "+a[7]+", "+a[8]+", "+a[9]+", "+a[10]+", "+a[11]+", "+a[12]+", "+a[13]+", "+a[14]+", "+a[15]+"]"}},k={create:function(a){var b=new o(4);a?(b[0]=a[0],b[1]=a[1],b[2]=a[2],b[3]=a[3]):b[0]=b[1]=b[2]=b[3]=0;return b},createFrom:function(a,b,c,d){var e=new o(4);e[0]=a;e[1]=b;e[2]=c;e[3]=d;return e},set:function(a,b){b[0]=a[0];b[1]=a[1];b[2]=a[2];b[3]=a[3];return b},equal:function(a,b){return a===b||1.0E-6>Math.abs(a[0]-b[0])&&1.0E-6>Math.abs(a[1]-b[1])&&1.0E-6>Math.abs(a[2]-b[2])&&1.0E-6> Math.abs(a[3]-b[3])},identity:function(a){a||(a=k.create());a[0]=0;a[1]=0;a[2]=0;a[3]=1;return a}},O=k.identity();k.calculateW=function(a,b){var c=a[0],d=a[1],e=a[2];if(!b||a===b)return a[3]=-Math.sqrt(Math.abs(1-c*c-d*d-e*e)),a;b[0]=c;b[1]=d;b[2]=e;b[3]=-Math.sqrt(Math.abs(1-c*c-d*d-e*e));return b};k.dot=function(a,b){return a[0]*b[0]+a[1]*b[1]+a[2]*b[2]+a[3]*b[3]};k.inverse=function(a,b){var c=a[0],d=a[1],e=a[2],g=a[3],c=(c=c*c+d*d+e*e+g*g)?1/c:0;if(!b||a===b)return a[0]*=-c,a[1]*=-c,a[2]*=-c,a[3]*= c,a;b[0]=-a[0]*c;b[1]=-a[1]*c;b[2]=-a[2]*c;b[3]=a[3]*c;return b};k.conjugate=function(a,b){if(!b||a===b)return a[0]*=-1,a[1]*=-1,a[2]*=-1,a;b[0]=-a[0];b[1]=-a[1];b[2]=-a[2];b[3]=a[3];return b};k.length=function(a){var b=a[0],c=a[1],d=a[2],a=a[3];return Math.sqrt(b*b+c*c+d*d+a*a)};k.normalize=function(a,b){b||(b=a);var c=a[0],d=a[1],e=a[2],g=a[3],f=Math.sqrt(c*c+d*d+e*e+g*g);if(0===f)return b[0]=0,b[1]=0,b[2]=0,b[3]=0,b;f=1/f;b[0]=c*f;b[1]=d*f;b[2]=e*f;b[3]=g*f;return b};k.add=function(a,b,c){if(!c|| a===c)return a[0]+=b[0],a[1]+=b[1],a[2]+=b[2],a[3]+=b[3],a;c[0]=a[0]+b[0];c[1]=a[1]+b[1];c[2]=a[2]+b[2];c[3]=a[3]+b[3];return c};k.multiply=function(a,b,c){c||(c=a);var d=a[0],e=a[1],g=a[2],a=a[3],f=b[0],h=b[1],j=b[2],b=b[3];c[0]=d*b+a*f+e*j-g*h;c[1]=e*b+a*h+g*f-d*j;c[2]=g*b+a*j+d*h-e*f;c[3]=a*b-d*f-e*h-g*j;return c};k.multiplyVec3=function(a,b,c){c||(c=b);var d=b[0],e=b[1],g=b[2],b=a[0],f=a[1],h=a[2],a=a[3],j=a*d+f*g-h*e,i=a*e+h*d-b*g,k=a*g+b*e-f*d,d=-b*d-f*e-h*g;c[0]=j*a+d*-b+i*-h-k*-f;c[1]=i*a+ d*-f+k*-b-j*-h;c[2]=k*a+d*-h+j*-f-i*-b;return c};k.scale=function(a,b,c){if(!c||a===c)return a[0]*=b,a[1]*=b,a[2]*=b,a[3]*=b,a;c[0]=a[0]*b;c[1]=a[1]*b;c[2]=a[2]*b;c[3]=a[3]*b;return c};k.toMat3=function(a,b){b||(b=A.create());var c=a[0],d=a[1],e=a[2],g=a[3],f=c+c,h=d+d,j=e+e,i=c*f,k=c*h,c=c*j,l=d*h,d=d*j,e=e*j,f=g*f,h=g*h,g=g*j;b[0]=1-(l+e);b[1]=k+g;b[2]=c-h;b[3]=k-g;b[4]=1-(i+e);b[5]=d+f;b[6]=c+h;b[7]=d-f;b[8]=1-(i+l);return b};k.toMat4=function(a,b){b||(b=x.create());var c=a[0],d=a[1],e=a[2],g= a[3],f=c+c,h=d+d,j=e+e,i=c*f,k=c*h,c=c*j,l=d*h,d=d*j,e=e*j,f=g*f,h=g*h,g=g*j;b[0]=1-(l+e);b[1]=k+g;b[2]=c-h;b[3]=0;b[4]=k-g;b[5]=1-(i+e);b[6]=d+f;b[7]=0;b[8]=c+h;b[9]=d-f;b[10]=1-(i+l);b[11]=0;b[12]=0;b[13]=0;b[14]=0;b[15]=1;return b};k.slerp=function(a,b,c,d){d||(d=a);var e=a[0]*b[0]+a[1]*b[1]+a[2]*b[2]+a[3]*b[3],g,f;if(1<=Math.abs(e))return d!==a&&(d[0]=a[0],d[1]=a[1],d[2]=a[2],d[3]=a[3]),d;g=Math.acos(e);f=Math.sqrt(1-e*e);if(0.001>Math.abs(f))return d[0]=0.5*a[0]+0.5*b[0],d[1]=0.5*a[1]+0.5*b[1], d[2]=0.5*a[2]+0.5*b[2],d[3]=0.5*a[3]+0.5*b[3],d;e=Math.sin((1-c)*g)/f;c=Math.sin(c*g)/f;d[0]=a[0]*e+b[0]*c;d[1]=a[1]*e+b[1]*c;d[2]=a[2]*e+b[2]*c;d[3]=a[3]*e+b[3]*c;return d};k.fromRotationMatrix=function(a,b){b||(b=k.create());var c=a[0]+a[4]+a[8],d;if(0a[0]&&(c=1);a[8]>a[3*c+c]&&(c=2);var e=d[c],g=d[e];d=Math.sqrt(a[3*c+ c]-a[3*e+e]-a[3*g+g]+1);b[c]=0.5*d;d=0.5/d;b[3]=(a[3*g+e]-a[3*e+g])*d;b[e]=(a[3*e+c]+a[3*c+e])*d;b[g]=(a[3*g+c]+a[3*c+g])*d}return b};A.toQuat4=k.fromRotationMatrix;(function(){var a=A.create();k.fromAxes=function(b,c,d,e){a[0]=c[0];a[3]=c[1];a[6]=c[2];a[1]=d[0];a[4]=d[1];a[7]=d[2];a[2]=b[0];a[5]=b[1];a[8]=b[2];return k.fromRotationMatrix(a,e)}})();k.identity=function(a){a||(a=k.create());a[0]=0;a[1]=0;a[2]=0;a[3]=1;return a};k.fromAngleAxis=function(a,b,c){c||(c=k.create());var a=0.5*a,d=Math.sin(a); c[3]=Math.cos(a);c[0]=d*b[0];c[1]=d*b[1];c[2]=d*b[2];return c};k.toAngleAxis=function(a,b){b||(b=a);var c=a[0]*a[0]+a[1]*a[1]+a[2]*a[2];0Math.abs(a[0]- b[0])&&1.0E-6>Math.abs(a[1]-b[1])},negate:function(a,b){b||(b=a);b[0]=-a[0];b[1]=-a[1];return b},normalize:function(a,b){b||(b=a);var c=a[0]*a[0]+a[1]*a[1];0Math.abs(a[0]-b[0])&&1.0E-6>Math.abs(a[1]-b[1])&&1.0E-6>Math.abs(a[2]-b[2])&&1.0E-6>Math.abs(a[3]-b[3])},identity:function(a){a||(a=I.create());a[0]=1;a[1]=0;a[2]=0;a[3]=1;return a},transpose:function(a,b){if(!b||a===b){var c=a[1];a[1]=a[2];a[2]=c;return a}b[0]=a[0];b[1]=a[2];b[2]=a[1];b[3]=a[3];return b},determinant:function(a){return a[0]*a[3]-a[2]*a[1]},inverse:function(a,b){b||(b=a);var c=a[0],d=a[1],e=a[2],g=a[3],f=c*g-e* d;if(!f)return null;f=1/f;b[0]=g*f;b[1]=-d*f;b[2]=-e*f;b[3]=c*f;return b},multiply:function(a,b,c){c||(c=a);var d=a[0],e=a[1],g=a[2],a=a[3];c[0]=d*b[0]+e*b[2];c[1]=d*b[1]+e*b[3];c[2]=g*b[0]+a*b[2];c[3]=g*b[1]+a*b[3];return c},rotate:function(a,b,c){c||(c=a);var d=a[0],e=a[1],g=a[2],a=a[3],f=Math.sin(b),b=Math.cos(b);c[0]=d*b+e*f;c[1]=d*-f+e*b;c[2]=g*b+a*f;c[3]=g*-f+a*b;return c},multiplyVec2:function(a,b,c){c||(c=b);var d=b[0],b=b[1];c[0]=d*a[0]+b*a[1];c[1]=d*a[2]+b*a[3];return c},scale:function(a, b,c){c||(c=a);var d=a[1],e=a[2],g=a[3],f=b[0],b=b[1];c[0]=a[0]*f;c[1]=d*b;c[2]=e*f;c[3]=g*b;return c},str:function(a){return"["+a[0]+", "+a[1]+", "+a[2]+", "+a[3]+"]"}},K={create:function(a){var b=new o(4);a?(b[0]=a[0],b[1]=a[1],b[2]=a[2],b[3]=a[3]):(b[0]=0,b[1]=0,b[2]=0,b[3]=0);return b},createFrom:function(a,b,c,d){var e=new o(4);e[0]=a;e[1]=b;e[2]=c;e[3]=d;return e},add:function(a,b,c){c||(c=b);c[0]=a[0]+b[0];c[1]=a[1]+b[1];c[2]=a[2]+b[2];c[3]=a[3]+b[3];return c},subtract:function(a,b,c){c||(c= b);c[0]=a[0]-b[0];c[1]=a[1]-b[1];c[2]=a[2]-b[2];c[3]=a[3]-b[3];return c},multiply:function(a,b,c){c||(c=b);c[0]=a[0]*b[0];c[1]=a[1]*b[1];c[2]=a[2]*b[2];c[3]=a[3]*b[3];return c},divide:function(a,b,c){c||(c=b);c[0]=a[0]/b[0];c[1]=a[1]/b[1];c[2]=a[2]/b[2];c[3]=a[3]/b[3];return c},scale:function(a,b,c){c||(c=a);c[0]=a[0]*b;c[1]=a[1]*b;c[2]=a[2]*b;c[3]=a[3]*b;return c},set:function(a,b){b[0]=a[0];b[1]=a[1];b[2]=a[2];b[3]=a[3];return b},equal:function(a,b){return a===b||1.0E-6>Math.abs(a[0]-b[0])&&1.0E-6> Math.abs(a[1]-b[1])&&1.0E-6>Math.abs(a[2]-b[2])&&1.0E-6>Math.abs(a[3]-b[3])},negate:function(a,b){b||(b=a);b[0]=-a[0];b[1]=-a[1];b[2]=-a[2];b[3]=-a[3];return b},length:function(a){var b=a[0],c=a[1],d=a[2],a=a[3];return Math.sqrt(b*b+c*c+d*d+a*a)},squaredLength:function(a){var b=a[0],c=a[1],d=a[2],a=a[3];return b*b+c*c+d*d+a*a},lerp:function(a,b,c,d){d||(d=a);d[0]=a[0]+c*(b[0]-a[0]);d[1]=a[1]+c*(b[1]-a[1]);d[2]=a[2]+c*(b[2]-a[2]);d[3]=a[3]+c*(b[3]-a[3]);return d},str:function(a){return"["+a[0]+", "+ a[1]+", "+a[2]+", "+a[3]+"]"}};w&&(w.glMatrixArrayType=o,w.MatrixArray=o,w.setMatrixArrayType=D,w.determineMatrixArrayType=G,w.glMath=E,w.vec2=J,w.vec3=r,w.vec4=K,w.mat2=I,w.mat3=A,w.mat4=x,w.quat4=k);return{glMatrixArrayType:o,MatrixArray:o,setMatrixArrayType:D,determineMatrixArrayType:G,glMath:E,vec2:J,vec3:r,vec4:K,mat2:I,mat3:A,mat4:x,quat4:k}}); function Node(newitem){ this.item = newitem; } Node.prototype.item = null; Node.prototype.link = null; function List(){ } List.prototype.head = null; List.prototype.tail = null; List.prototype.length = 0; List.prototype.push = function(object){ var newnode = new Node(object); if(this.head === null){ this.head = newnode; }else{ this.tail.link = newnode; } this.tail = newnode; this.length++; } List.prototype.push_front = function(object){ var newnode = new Node(object); if(this.head === null){ this.tail = newnode; }else{ newNode.link = head; } this.head = newnode; this.length++; } List.prototype.pop = function(){ var item = null; if(this.head != null){ item = this.head.item; this.head = this.head.link; } return item; } List.prototype.remove = function(object){ if(this.head != null){ if(this.head.item === object){ this.head = this.head.link; this.length--; return true; } var prev = this.head; var curr = this.head.link; while(curr !== null){ if(curr.item === object){ prev.link = curr.link; if(this.tail.item === object){ this.tail = prev; } this.length--; return true; } prev = curr; curr = curr.link; } } return false; } List.prototype.find = function(object){ for(var node = this.head; node !== null; node = node.link){ if(node.item == object){ return true; } } return false; } List.prototype.getAt = function(index){ var cur = this.head; while(index > 0 && cur != null){ cur = cur.link; index--; } return cur.item; } List.prototype.foreach = function(func, params){ for(var node = this.head; node !== null; node = node.link){ func(node.item, params); } } List.prototype.toString = function(){ var count = 0; var curr = this.head; var dbgstring = ""; while(curr !== null){ dbgstring += "["+count+": "; dbgstring += curr.item+"]"; //dbgstring += "--Link: "+curr.link+"\n"; curr = curr.link; count++; } return dbgstring; } function Vector(x, y, z){ this.x = x; this.y = y; this.z = z ? z : 0; this.w = 0; } //Vector.prototype.x = 0; Vector.prototype = { get r(){ return this.x; }, set r(val){ this.x = val; }, get g(){ return this.y; }, set g(val){ this.y = val; }, get b(){ return this.z; }, set b(val){ this.z = val; }, get a(){ return this.w; }, set a(val){ this.w = val; }, get length(){ return Math.sqrt((this.x*this.x)+(this.y*this.y)+(this.z*this.z)+(this.w*this.w)); } } /*Vector.prototype = { get g(){ return this.y; }, set g(val){ this.y = val; } } Vector.prototype = { get b(){ return this.z; }, set b(val){ this.z = val; } } Vector.prototype = { get a(){ return this.w; }, set a(val){ this.w = val; } } Vector.prototype = { get length(){ return Math.sqrt(this.x*this.x+this.y*this.y+this.z*this.z+this.w*this.w); } }*/ Vector.prototype.add = function(val){ var temp = new Vector(0,0,0); temp.x = this.x+val.x; temp.y = this.y+val.y; temp.z = this.z+val.z; temp.w = this.w+val.w; return temp; } Vector.prototype.sub = function(val){ var temp = new Vector(0,0,0); temp.x = this.x-val.x; temp.y = this.y-val.y; temp.z = this.z-val.z; temp.w = this.w-val.w; return temp; } Vector.prototype.mult = function(val){ var temp = new Vector(0,0,0); if(val instanceof Vector){ temp.x = this.x*val.x; temp.y = this.y*val.y; temp.z = this.z*val.z; temp.w = this.w*val.w; }else{ temp.x = this.x*val; temp.y = this.y*val; temp.z = this.z*val; temp.w = this.w*val; } return temp; } Vector.prototype.div = function(val){ var temp = new Vector(0,0,0); if(val instanceof Vector){ temp.x = this.x/val.x; temp.y = this.y/val.y; temp.z = this.z/val.z; temp.w = this.w/val.w; }else{ temp.x = this.x/val; temp.y = this.y/val; temp.z = this.z/val; temp.w = this.w/val; } return temp; } Vector.prototype.neg = function(){ var temp = new Vector(0,0,0); temp.x = -this.x; temp.y = -this.y; temp.z = -this.z; temp.w = -this.w; return temp; } Vector.prototype.equals = function(val){ if(this.x != val.x){ return false; } if(this.y != val.y){ return false; } if(this.z != val.z){ return false; } if(this.w != val.w){ return false; } return true; } Vector.prototype.cross = function(val){ var temp = new Vector(0,0,0); temp.x = this.y*val.z-this.z*val.y; temp.y = this.z*val.x-this.x*val.z; temp.z = this.x*val.y-this.y*val.x; return temp; } Vector.prototype.dot = function(val){ return this.x*val.x+this.y*val.y+this.z*val.z+this.w*val.w; } Vector.prototype.normalize = function(){ var length = this.length; var temp = new Vector(0,0,0); temp.x = this.x/length; temp.y = this.y/length; temp.z = this.z/length; temp.w = this.w/length; return temp; } Vector.prototype.toString = function(){ return "["+this.x+","+this.y+","+this.z+","+this.w+"]"; } function arrayVector(arr){ var vec = new Vector(arr[0],arr[1], arr[2] ? arr[2] : 0); vec.w = arr[3] ? arr[3] : 0; return vec; } //http://www.w3schools.com/ajax/ajax_browsers.asp function xmlRequest(){ var xmlHttp; try{ // Firefox, Opera 8.0+, Safari xmlHttp=new XMLHttpRequest(); } catch (e){ // Internet Explorer try{ xmlHttp=new ActiveXObject("Msxml2.XMLHTTP"); } catch (e){ try{ xmlHttp=new ActiveXObject("Microsoft.XMLHTTP"); } catch (e){ alert("Your browser does not support AJAX!"); return false; } } } return xmlHttp; } var Resources = new Object(); Resources.loadList = new List(); Resources.totalItems = 0; Resources.leftToLoad = 0; Resources.addToLoad = function(){ this.totalItems++; this.leftToLoad++; } //Returns the number of items that are still loading. Resources.getLeftToLoad = function(){ for(var font in Fonts.fonts){ //for(var font = 0; font < Fonts.fonts.length; font++){ if(!Fonts.fonts[font].loaded){ Fonts.fonts[font].checkIfLoaded(); } } return this.leftToLoad; } //Textures var Textures = new Object(); Textures.imgs = new Array(); Textures.waitingList = new List(); //Returns an image if it is already loaded, otherwise it starts loading the image source and returns a new image Textures.load = function(src, crossDomain, logOnLoad){ if(this.imgs[src] == undefined){ Resources.addToLoad(); this.imgs[src] = new Image(); this.imgs[src].loaded = false; if(crossDomain){ Textures.imgs[src].crossOrigin = "anonymous"; } this.imgs[src].src = src; this.imgs[src].onload = function(){ if(logOnLoad == undefined || logOnLoad){ println(this.src+" loaded"); } Resources.leftToLoad--; if(!createTexture(this)){ Textures.waitingList.push(this); } this.loaded = true; } this.imgs[src].onabort= function(){ alert("there was an error"); } } return this.imgs[src]; } Textures.create = function(){ this.waitingList.foreach(createTexture); } //Creates a WebGL texture from the given image. Useful if you want to draw somehting with a 2D context and then use it with WebGL function createTexture(image){ if(ctx != undefined){ if(ctx.createTexture){ var texture = image.texture; if(texture == undefined){ texture = ctx.createTexture(); } texture.image = image; ctx.bindTexture(ctx.TEXTURE_2D, texture); ctx.pixelStorei(ctx.UNPACK_FLIP_Y_WEBGL, true); ctx.pixelStorei(ctx.UNPACK_PREMULTIPLY_ALPHA_WEBGL, true); ctx.texImage2D(ctx.TEXTURE_2D, 0, ctx.RGBA, ctx.RGBA, ctx.UNSIGNED_BYTE, texture.image); //ctx.texParameteri(ctx.TEXTURE_2D, ctx.TEXTURE_MAG_FILTER, ctx.NEAREST); //ctx.texParameteri(ctx.TEXTURE_2D, ctx.TEXTURE_MIN_FILTER, ctx.NEAREST); ctx.texParameteri(ctx.TEXTURE_2D, ctx.TEXTURE_WRAP_S, ctx.CLAMP_TO_EDGE); ctx.texParameteri(ctx.TEXTURE_2D, ctx.TEXTURE_WRAP_T, ctx.CLAMP_TO_EDGE); ctx.texParameteri(ctx.TEXTURE_2D, ctx.TEXTURE_MIN_FILTER, ctx.LINEAR); ctx.texParameteri(ctx.TEXTURE_2D, ctx.TEXTURE_MAG_FILTER, ctx.LINEAR); //ctx.generateMipmap(ctx.TEXTURE_2D); ctx.bindTexture(ctx.TEXTURE_2D, null); image.texture = texture; return true; } } return false; } //Audio var Sounds = new Object(); Sounds.snds = new Array(); Sounds.muted = false; //Returns a sound if it is already loaded and there is a sound object that is not playing (creates a pool of sound objects), otherwise it starts loading the sound source and returns a new sound Sounds.load = function(src){ if(this.snds[src] == undefined){ Resources.addToLoad(); this.snds[src] = new List(); return makeNewAudio(src, true); } for(var node = this.snds[src].head; node != null; node = node.link){ var snd = node.item; //if(!snd.isPlaying){ if(!snd.isPlaying || snd.currentTime == snd.duration){ return snd; } } return makeNewAudio(src, false); } function makeNewAudio(src, loading){ var newAudio = new Audio(); newAudio.loaded = false; newAudio.isPlaying = false; newAudio.muted = Sounds.muted; newAudio.addEventListener("canplaythrough", function(){ //newAudio.oncanplaythrough = function(e){ if(loading && !this.loaded){ println(this.src+" loaded"); Resources.leftToLoad--; this.loaded = true; } } , false); newAudio.play = function(){ this.isPlaying = true; this.__proto__.play.call(this); } newAudio.pause = function(){ this.isPlaying = false; this.__proto__.pause.call(this); } newAudio.ended = function(){ this.isPlaying = false; //println("ended"); //Audio.pause.call(this); } newAudio.src = src; Sounds.snds[src].push(newAudio); return newAudio; } //Creates a new audio object Sounds.play = function(src){ var audio = this.load(src); audio.play(); //println(Sounds.snds[src].length); return audio; } Sounds.loop = function(src){ var audio = this.load(src); audio.loop = true; audio.play(); return audio; } Sounds.toggleMuted = function(){ this.muted = !this.muted; for(src in Sounds.snds){ //for(var i=0; i < Sounds.snds.length; i++){ Sounds.snds[src].foreach(toggleSounds,{}); } } function toggleSounds(sound, params){ sound.muted = Sounds.muted; } //fonts var Fonts = new Object(); Fonts.fonts = new Array(); //Makes sure the given font is loaded Fonts.load = function(fontName){ if(Fonts.fonts[fontName] == undefined){ Resources.addToLoad(); var fontDiv = document.createElement("p"); fontDiv.loaded = false; fontDiv.font = fontName; fontDiv.innerHTML = "AAAAAAAAAA"; fontDiv.style.position = "absolute"; fontDiv.style.visibility = "hidden"; fontDiv.style.top = 0; fontDiv.style.display = "inline-block"; fontDiv.style.font = "20px "+fontName+",cursive"; fontDiv.checkIfLoaded = function(){ document.body.appendChild(this); this.style.font = "20px Arial,cursive"; println(this.offsetWidth); var preWidth = this.offsetWidth; this.style.font = "20px "+this.font+",cursive"; println(this.offsetWidth); if(this.offsetWidth != preWidth){ this.loaded = true; Resources.leftToLoad--; return true; } document.body.removeChild(this); return false; } Fonts.fonts[fontName] = fontDiv; } //return Fonts.fonts[fontName].checkIfLoaded(); } //Other files var Files = new Object(); Files.files = new Array(); //Returns an object with the file accessible through the text and xml properties if the file is loaded. Otherwise starts loading the files and returns the files object Files.load = function(fileName, onLoadFunc){ if(this.files[fileName] == undefined){ this.files[fileName] = new Object(); Resources.addToLoad(); var xml = xmlRequest(); xml.onreadystatechange = function(){ if(xml.readyState == 4){ Files.files[fileName].text = String(xml.responseText); Files.files[fileName].xml = xml.responseXML; //Files.files[fileName].onLoadComplete(); if(onLoadFunc != null){ onLoadFunc(Files.files[fileName]); } Resources.leftToLoad--; } } try{ xml.open("GET",fileName,true); xml.send(null); }catch(e){ } } return this.files[fileName]; } //Based on the tutorials found here: http://learningwebgl.com/blog/?page_id=1217 //This has a lot of redundent code and needs to be cleaned up //Global matrices var mvMatrix = mat4.create(); var pMatrix = mat4.create(); //Default shader var shaderProgram; var vertShader; var fragShader; //Pointer to the current sprite shader, allows custome effects when drawing sprites (normal mapping) var spriteShader; //Sprite vertex buffers var spriteVPB; var spriteVTB; var spriteVIB; //Default draw buffers var colorBuffer; var stateBuffer; //Holds a pool of screen buffers for use with screen shaders var sBuffers = new Object(); //Define some global blending modes BLEND_ALPHA = {a:"SRC_ALPHA", b:"ONE_MINUS_SRC_ALPHA"}; BLEND_ADD = {a:"SRC_ALPHA", b:"ONE"}; BLEND_MULTIPLY = {a:"DST_COLOR", b:"ZERO"}; //Initializes some WebGL stuff function initGL(canvas){ try{ ctx.viewportWidth = canvas.width; ctx.viewportHeight = canvas.height; initBuffers(ctx); //Initialize default shader fragShader = compileShader(ctx, defaultFragSrc); vertShader = compileShader(ctx, defaultVertSrc); shaderProgram = createShaderProgram(); setupSpriteShader(shaderProgram); spriteShader = shaderProgram; colorBuffer = createRenderTarget(ctx, canvas.width, canvas.height); stateBuffer = createRenderTarget(ctx, canvas.width, canvas.height); ctx.clearColor(0.0, 0.0, 0.0, 1.0); ctx.blendFunc(ctx.SRC_ALPHA, ctx.ONE_MINUS_SRC_ALPHA); ctx.enable(ctx.BLEND); }catch(e){ } } //Pushes the current matrices to the given vertex shader function setMatrixUniforms(program){ ctx.uniformMatrix4fv(program.pMatrixUniform, false, pMatrix); ctx.uniformMatrix4fv(program.mvMatrixUniform, false, mvMatrix); } //Pulls the shader source from the given embedded shader function getShaderSrc(id){ if(!use2D){ var shaderScript = document.getElementById(id); if(!shaderScript){ return null; } var code = ""; var k = shaderScript.firstChild; while(k){ if(k.nodeType == 3){ code += k.textContent; } k = k.nextSibling; } var type; if(shaderScript.type == "x-shader/x-fragment"){ type = "frag"; }else if(shaderScript.type == "x-shader/x-vertex"){ type = "vert"; }else{ return null; } return {code: code, type:type}; } return null; } //Compiles a shader from the given source function compileShader(gl, source){ if(!use2D){ if(!source){ println("no src"); return null; } var shader; if(source.type == "frag"){ shader = gl.createShader(gl.FRAGMENT_SHADER); }else if(source.type == "vert"){ shader = gl.createShader(gl.VERTEX_SHADER); }else{ println("no type: "+source.type); return null; } gl.shaderSource(shader, source.code); gl.compileShader(shader); if(!gl.getShaderParameter(shader, gl.COMPILE_STATUS)){ alert(gl.getShaderInfoLog(shader)); return null; } return shader; } return null; } //Creates a shader program function createShaderProgram(fragSrc, vertSrc){ if(!use2D){ var frag; var vert; if(!fragSrc){ frag = fragShader; }else{ frag = compileShader(ctx, fragSrc); } if(!vertSrc){ vert = vertShader; }else{ vert = compileShader(ctx, vertSrc); } var newProgram = ctx.createProgram(); ctx.attachShader(newProgram, vert); ctx.attachShader(newProgram, frag); ctx.linkProgram(newProgram); if(!ctx.getProgramParameter(newProgram, ctx.LINK_STATUS)){ alert("Could not initiate shaders"); } newProgram.vertexPositionAttribute = ctx.getAttribLocation(newProgram, "aVertexPosition"); ctx.enableVertexAttribArray(newProgram.vertexPositionAttribute); newProgram.textureCoordAttribute = ctx.getAttribLocation(newProgram, "aTextureCoord"); ctx.enableVertexAttribArray(newProgram.textureCoordAttribute); newProgram.pMatrixUniform = ctx.getUniformLocation(newProgram, "uPMatrix"); newProgram.mvMatrixUniform = ctx.getUniformLocation(newProgram, "uMVMatrix"); return newProgram; } return null; } //Set up sprite shader helpers function setupSpriteShader(program){ if(!use2D){ program.vertexPositionAttribute = ctx.getAttribLocation(program, "aVertexPosition"); ctx.enableVertexAttribArray(program.vertexPositionAttribute); program.textureCoordAttribute = ctx.getAttribLocation(program, "aTextureCoord"); ctx.enableVertexAttribArray(program.textureCoordAttribute); program.pMatrixUniform = ctx.getUniformLocation(program, "uPMatrix"); program.mvMatrixUniform = ctx.getUniformLocation(program, "uMVMatrix"); program.frameOffset = ctx.getUniformLocation(program, "frameOffset"); program.frameDims = ctx.getUniformLocation(program, "frameDims"); program.tiles = ctx.getUniformLocation(program, "tiles"); program.scroll = ctx.getUniformLocation(program, "scroll"); //shaderProgram.alphaMap = ctx.getUniformLocation(shaderProgram, "alphaMap"); program.multColor = ctx.getUniformLocation(program, "multColor"); program.alpha = ctx.getUniformLocation(program, "alpha"); } } //Initializes the sprite vertex buffers function initBuffers(gl){ //Sprite spriteVPB = gl.createBuffer(); gl.bindBuffer(gl.ARRAY_BUFFER, spriteVPB); var vertices = [ 0, -1, 0, 1, -1, 0, 1, 0, 0, 0, 0, 0, ]; gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW); spriteVPB.itemSize = 3, spriteVPB.numItems = 4; spriteVTB = gl.createBuffer(); gl.bindBuffer(gl.ARRAY_BUFFER, spriteVTB); var texCoords = [ 0.0, 0.0, 1.0, 0.0, 1.0, 1.0, 0.0, 1.0 ]; gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(texCoords), gl.STATIC_DRAW); spriteVTB.itemSize = 2; spriteVTB.numItems = 4; spriteVIB = gl.createBuffer(); gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, spriteVIB); var spriteVertexIndices = [0, 1, 2, 0, 2, 3]; gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(spriteVertexIndices), gl.STATIC_DRAW); spriteVIB.itemSize = 1; spriteVIB.numItems = 6; } //Creates a new render target, returns a screen buffer with a texture property function createRenderTarget(gl, width, height){ var rtBuffer = gl.createFramebuffer(); gl.bindFramebuffer(gl.FRAMEBUFFER, rtBuffer); rtBuffer.width = width; rtBuffer.height = height; var rtTexture = gl.createTexture(); gl.bindTexture(gl.TEXTURE_2D, rtTexture); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); //gl.generateMipmap(gl.TEXTURE_2D); gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, rtBuffer.width, rtBuffer.height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null); gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, rtTexture, 0); rtBuffer.texture = rtTexture; gl.bindTexture(gl.TEXTURE_2D, null); gl.bindRenderbuffer(gl.RENDERBUFFER, null); gl.bindFramebuffer(gl.FRAMEBUFFER, null); return rtBuffer; } //Sets up a pool of screen buffers sBuffers.buffers = new Array(); //Returns either the first unlocked buffer in the array or creates a new one, pushes it into the array, and returns it. sBuffers.getBuffer = function(){ for(var i=0; i < this.buffers.length; i++){ if(!this.buffers[i].locked){ //this.buffers[buf].locked = true; return this.buffers[i]; } } var newBuffer = createRenderTarget(ctx, canvas.width, canvas.height); newBuffer.locked = false; newBuffer.lock = function(){ this.locked = true; } newBuffer.unlock = function(){ this.locked = false; } this.buffers.push(newBuffer); return newBuffer; } var defaultVertSrc = new Object(); defaultVertSrc.code = "attribute vec3 aVertexPosition; attribute vec2 aTextureCoord; uniform mat4 uMVMatrix; uniform mat4 uPMatrix; varying vec2 vTextureCoord; void main(void){ gl_Position = uPMatrix * uMVMatrix * vec4(aVertexPosition, 1.0); vTextureCoord = aTextureCoord; }"; defaultVertSrc.type = "vert"; var defaultFragSrc = new Object(); defaultFragSrc.code = "precision mediump float; varying vec2 vTextureCoord; uniform sampler2D uSampler; uniform vec2 frameOffset; uniform vec2 frameDims; uniform vec2 tiles; uniform vec2 scroll; uniform vec3 multColor; uniform float alpha; void main(void){ vec2 pos = mod((vTextureCoord+scroll)*tiles+vec2(0, 1.0-tiles.y),vec2(1.0,1.0)); pos = pos*frameDims; pos.y += (1.0-frameDims.y); pos.y -= frameOffset.y; pos.x += frameOffset.x; vec4 color = texture2D(uSampler, pos); gl_FragColor.rgb = color.rgb*multColor; gl_FragColor.a = color.a*alpha; }"; defaultFragSrc.type = "frag"; function PostFXChain(){ this.effects = new List(); } PostFXChain.prototype.push = function(effect){ this.effects.push(effect); } PostFXChain.prototype.remove = function(effect){ this.effects.remove(effect); } //Runs through the list of effects applying each one to the input buffer PostFXChain.prototype.apply = function(ctx, input){ var effect; for(var node = this.effects.head; node != null; node = node.link){ effect = node.item; if(effect != undefined && effect != null){ effect.apply(ctx, input); } } } function PostFX(){ } PostFX.prototype.apply = function(ctx){ } var spriteindex = 0; function Sprite(){ this.children = new List(); this.image = new Image(); this.pos = vec3.create(); this.index = 0; this.blendFunction = {a:"SRC_ALPHA", b:"ONE_MINUS_SRC_ALPHA"}; this.multColor = vec3.create([1,1,1]); } Sprite.prototype = { get x(){ return this.pos.x; }, set x(val){ this.pos.x = val; }, get y(){ return this.pos.y; }, set y(val){ this.pos.y = val; }, get z(){ return this.pos.z; }, set z(val){ this.pos.z = val; }, get worldRotation(){ return this.parent ? this.parent.worldRotation+this.rotation : this.rotation; }, set worldRotation(val){ this.rotation = this.parent ? val-this.parent.worldRotation : val; }, get blendFunc(){ return this.blendFunction; }, set blendFunc(func){ this.blendFunction.a = func.a; this.blendFunction.b = func.b; }, /*get alpha(){ if(this.parent != undefined){ return this.parent.alpha*this.a; } return this.a; }, set alpha(val){ this.a = val; },*/ } Sprite.prototype.width = 100; Sprite.prototype.height = 100; Sprite.prototype.xoffset = 0; Sprite.prototype.yoffset = 0; Sprite.prototype.xscale = 1.0; Sprite.prototype.yscale = 1.0; Sprite.prototype.rotation = 0; Sprite.prototype.frameCount = 1; Sprite.prototype.frameWidth = -1; Sprite.prototype.frameHeight = -1; Sprite.prototype.frame = 0; Sprite.prototype.xtiles = 1; Sprite.prototype.ytiles = 1; Sprite.prototype.xscroll = 0; Sprite.prototype.yscroll = 0; Sprite.prototype.xslice = 0; Sprite.prototype.yslice = 0; Sprite.prototype.sliceWidth = undefined; Sprite.prototype.sliceHeight = undefined; Sprite.prototype.visible = true; Sprite.prototype.alpha = 1.0; Sprite.prototype.preAlpha = 1.0; Sprite.prototype.blendMode = "source-over"; Sprite.prototype.parent = undefined; Sprite.prototype.childindex = 0; Sprite.prototype.index = 0; Sprite.prototype.children; //When inheriting from sprite, call this in the new object's constructor Sprite.prototype.init = function(){ this.children = new List(); this.image = new Image(); this.pos = vec3.create(); this.multColor = vec3.create([1,1,1]); } Sprite.prototype.addChild = function(child){ //child.childindex = this.children.length; this.children.push(child); child.parent = this; } Sprite.prototype.removeChild = function(child){ this.children.remove(child); } //Called before drawing to apply the sprite's transformations Sprite.prototype.transform = function(ctx){ this.preAlpha = ctx.alpha; ctx.alpha *= this.alpha; var xpos = this.x; var ypos = this.y; var xscale = this.xscale == 0 ? 0.0000001 : this.xscale; var yscale = this.yscale == 0 ? 0.0000001 : this.yscale; ctx.translate(xpos,ypos); //ctx.scale(this.getXScale()/Math.abs(this.getXScale()),this.getYScale()/Math.abs(this.getYScale())); ctx.rotate(this.rotation); //ctx.scale(Math.abs(this.getXScale())*this.getXScale()/Math.abs(this.getXScale()),Math.abs(this.getYScale())*this.getYScale()/Math.abs(this.getYScale())); ctx.scale(xscale,yscale); } //If overriding make sure to call either Sprite.draw.call(this, ctx) or this.__proto__.draw.call(this, ctx) or just call drawChildren(ctx) Sprite.prototype.draw = function(ctx){ if(this.image != undefined && this.image != null){ try{ if(this.frameCount <= 1){ ctx.drawSprite(this); }else{ ctx.drawSprite(this, this.frame); this.frame = (this.frame+1)%this.frameCount; } }catch(e){ //println("image isn't loaded"); } } this.drawChildren(ctx); } Sprite.prototype.drawChildren = function(ctx){ //println("drawing children: "+this.children.length); var sprites = new Array(); for(var child = this.children.head; child !== null; child = child.link){ var sprite = child.item; if(sprite.visible){ //if(sprite.x>=0 && sprite.x<=canvas.width){ sprites.push(sprite); //} } } sprites.sort(sortByZ); //for(sprite in sprites){ for(var i=0; i < sprites.length; i++){ sprites[i].transform(ctx); sprites[i].draw(ctx); sprites[i].unTransform(ctx); } } //Called after drawing to unapply the sprite's transformations Sprite.prototype.unTransform = function(ctx){ var xpos = this.x; var ypos = this.y; var xscale = this.xscale == 0 ? 0.0000001 : this.xscale; var yscale = this.yscale == 0 ? 0.0000001 : this.yscale; ctx.scale(1/xscale,1/yscale); ctx.rotate(-this.rotation); //ctx.scale(this.getXScale()/Math.abs(this.getXScale()),this.getYScale()/Math.abs(this.getYScale())); ctx.translate(-xpos,-ypos); ctx.alpha = this.preAlpha; } //If overriding update make sure to call either Sprite.update.call(this, ctx) or this.__proto__.update.call(this, ctx) or just call updateChildren(ctx) Sprite.prototype.update = function(delta){ this.updateChildren(delta); } Sprite.prototype.updateChildren = function(delta){ this.children.foreach(this.updateChild, {delta:delta}); } Sprite.prototype.updateChild = function(child, params){ child.update(params.delta); } Sprite.prototype.getXScale = function(){ if(this.parent != undefined){ return this.parent.getXScale()*this.xscale; } return this.xscale; } Sprite.prototype.getYScale = function(){ if(this.parent != undefined){ return this.parent.getYScale()*this.yscale; } return this.yscale; } Sprite.prototype.getWorldMatrix = function(){ var mat = mat4.create(); mat4.identity(mat); if(this.parent != undefined){ mat = this.parent.getWorldMatrix(); } mat4.translate(mat,this.pos); mat4.rotateZ(mat, this.rotation); mat4.scale(mat, [this.xscale,this.yscale, 1.0]); return mat; } Sprite.prototype.getWorldPos = function(){ return mat4.multiplyVec3(this.getWorldMatrix(), [0,0,0]); } Sprite.prototype.localToWorld = function(x,y){ return mat4.multiplyVec3(this.getWorldMatrix(), [x,y,0]); } Sprite.prototype.worldToLocal = function(x,y){ var pos = vec3.subtract([x,y,0], this.getWorldPos()); //println(pos); var xscale = this.xscale == 0 ? 0.0000001 : this.xscale; var yscale = this.yscale == 0 ? 0.0000001 : this.yscale; var mat = mat4.scale(mat4.rotateZ(mat4.identity(mat4.create()), -this.worldRotation), [this.getXScale(),this.getYScale(), 1.0]); //var mat = mat4.rotateZ(mat4.scale(mat4.identity(mat4.create()), [this.getXScale,this.getYScale, 1.0]), -this.worldRotation); //var mat = mat4.create();//mat4.rotateZ(mat4.create(), -this.rotation); return mat4.multiplyVec3(mat, pos); } Sprite.prototype.getWorldRot = function(){ if(this.parent != undefined){ return this.parent.getWorldRot()+this.rotation; } return this.rotation; } Sprite.prototype.remove = function(){ for(var child = this.children.head; child !== null; child = child.link){ child.item.remove(); } if(this.parent != undefined){ this.parent.removeChild(this); } } function sortByZ(a,b){ return b.index-a.index; } function BBox(x,y,z,width,height,depth){ this.pos = new Vector(x,y,z); this.dims = new Vector(width,height,depth); this.offsets = new Vector(0,0,0); this.vel = new Vector(0,0,0); this.solid = false; } BBox.prototype = { get x(){ return this.pos.x; }, set x(val){ this.pos.x = val; }, get y(){ return this.pos.y; }, set y(val){ this.pos.y = val; }, get z(){ return this.pos.z; }, set z(val){ this.pos.z = val; }, get width(){ return this.dims.x; }, set width(val){ this.dims.x = val; }, get height(){ return this.dims.y; }, set height(val){ this.dims.y = val; }, get depth(){ return this.dims.z; }, set depth(val){ this.dims.z = val; }, } BBox.prototype.checkPoint = function(point){ var xpos = this.pos.x+this.offsets.x; var ypos = this.pos.y+this.offsets.y; var zpos = this.pos.z+this.offsets.z; var minx = xpos-this.dims.x/2; var maxx =xpos+this.dims.x/2; var minz = zpos-this.dims.z/2; var maxz = zpos+this.dims.z/2; var miny = ypos-this.dims.y/2; var maxy = ypos+this.dims.y/2; if(point.x >= minx && point.x <= maxx && point.z >= minz && point.z <= maxz && point.y >= miny && point.y <= maxy){ return true; } return false; } BBox.prototype.checkBBox = function(bbox){ var col = {occurred:false}; var points = bbox.getPoints(); for(var point in points){ if(this.checkPoint(points[point])){ col.occurred = true; col.normal = new Vector(0,0,1); return col; } } return col; } BBox.prototype.intersect = function(bbox){ var col = {occurred:false}; var points = bbox.getPoints(); for(var point in points){ if(this.checkPoint(points[point])){ col.occurred = true; col.normal = new Vector(0,0,1); return col; } } points = this.getPoints(); for(var point in points){ if(bbox.checkPoint(points[point])){ col.occurred = true; col.normal = new Vector(0,0,1); return col; } } return col; } BBox.prototype.getPoints = function(){ var points = new Array(); var point = this.pos.add(this.offsets).add(this.dims.div(2)); points.push(point); point = this.pos.add(this.offsets).add(this.dims.div(-2)); points.push(point); point = this.pos.add(this.offsets).add(this.dims.div(new Vector(2,2,-2))); points.push(point); point = this.pos.add(this.offsets).add(this.dims.div(new Vector(-2,2,2))); points.push(point); point = this.pos.add(this.offsets).add(this.dims.div(new Vector(-2,2,-2))); points.push(point); point = this.pos.add(this.offsets).add(this.dims.div(new Vector(2,-2,2))); points.push(point); point = this.pos.add(this.offsets).add(this.dims.div(new Vector(-2,-2,2))); points.push(point); point = this.pos.add(this.offsets).add(this.dims.div(new Vector(2,-2,-2))); points.push(point); return points; } //BRect function BRect(x,y,width,height){ this.pos = new Vector(x,y,0); this.dims = new Vector(width,height,0); this.offsets = new Vector(0,0,0); this.solid = false; } BRect.prototype = new BBox(); BRect.prototype.checkPoint = function(point){ var xpos = this.pos.x+this.offsets.x; var ypos = this.pos.y+this.offsets.y; var minx = xpos;//-this.dims.x/2; var maxx = xpos+this.dims.x;//+this.dims.x/2; var miny = ypos;//-this.dims.y/2; var maxy = ypos+this.dims.y;//+this.dims.y/2; if(point.x >= minx && point.x <= maxx && point.y >= miny && point.y <= maxy){ return true; } return false; } /*BRect.prototype.checkBBox = function(bbox){ var points = bbox.getPoints(); for(var point in points){ if(this.checkPoint(points[point])){ return true; } } return false; }*/ BRect.prototype.getPoints = function(){ var points = new Array(); var point = this.pos.add(this.offsets);//.add(this.dims.div(2)); points.push(point); point = this.pos.add(this.offsets).add(this.dims); points.push(point); point = this.pos.add(this.offsets).add(new Vector(this.dims.x,0,0)); points.push(point); point = this.pos.add(this.offsets).add(new Vector(0,this.dims.y,0)); points.push(point); return points; } function CollisionGrid(x, z, width, depth, cols, rows){ this.x = x; this.z = z; this.width = width; this.depth = depth; this.cols = cols; this.rows = rows; this.size = cols*rows; this.cells = new Array(); for(var i = 0; i < this.size; i++){ this.cells.push(new List()); } this.visible = false; } CollisionGrid.prototype.reset = function(x, z, width, depth, cols, rows){ this.x = x; this.z = z; this.width = width; this.depth = depth; this.cols = cols; this.rows = rows; this.size = cols*rows; this.cells = new Array(); for(var i = 0; i < this.size; i++){ this.cells.push(new List()); } } CollisionGrid.prototype.insert = function(obj){ var xdiff = obj.x-this.x; var zdiff = obj.z-this.z; var x = Math.max(0, Math.min(this.cols-1, Math.floor(xdiff/(this.width/this.cols)))); var z = Math.max(0, Math.min(this.rows-1, Math.floor(zdiff/(this.depth/this.rows))))*this.cols; var index = Math.max(0, Math.min(this.size-1, x+z)); //println(index); this.cells[index].push(obj); } CollisionGrid.prototype.clear = function(){ for(var cell in this.cells){ this.cells[cell] = new List(); } } CollisionGrid.prototype.update = function(delta){ } CollisionGrid.prototype.transform = function(ctx){ } CollisionGrid.prototype.unTransform = function(ctx){ } CollisionGrid.prototype.draw = function(ctx){ var dot = new IsoSprite(); dot.width = this.width/this.cols*2; dot.height = this.depth/this.rows*2; dot.xoffset = -dot.width/2; //dot.yoffset = dot.height/2; dot.image = textures.load("mats/diffuse/crate_wire.png"); for(var i = 0; i < this.size; i++){ dot.x = this.x+(i%this.cols)*this.width/this.cols; dot.y = 0; dot.z = this.z+Math.floor(i/this.rows)*this.depth/this.rows; dot.transform(ctx); dot.draw(ctx); dot.unTransform(ctx); } } //var mouse = {x:0,y:0}; function Input(){ this.printKey = false; this.keys = new Array(); this.bools = new Array(); this.funcs = new Array(); this.repeats = new Array(); this.mouse = new Vector(0,0,0); this.shift = false; this.lBtn = false; this.mBtn = false; this.rBtn = false; this.lBtnFuncs = new Array(); this.mBtnFuncs = new Array(); this.rBtnFuncs = new Array(); this.mdListens = new Array(); this.muListens = new Array(); this.mmListens = new Array(); this.keyListens = new Array(); } //Sets all bools to false Input.prototype.blur = function(){ //for(bool in this.bools){ for(var i=0; i < this.bools.length; i++){ this.bools[i] = false; } } //Adds a key-bool set. When the given key is pressed the bool is set to true and set to false when it is released Input.prototype.addBool = function(keyCode, boolName){ this.keys[keyCode] = boolName; this.bools[boolName] = false; this.__defineGetter__(boolName, function(){ return this.bools[boolName]; }); } //Adds a function to be called when the given key is pressed. Repeats until released is repeat is true Input.prototype.addFunc = function(keyCode, func, repeat){ this.funcs[keyCode] = func; this.repeats[keyCode] = repeat; } //Adds a function to be called when the left mouse button is pressed Input.prototype.addLBtnFunc = function(func){ this.lBtnFuncs.push(func); } //Adds a function to be called when the middle mouse button is pressed Input.prototype.addMBtnFunc = function(func){ this.lBtnFuncs.push(func); } //Adds a function to be called when the right mouse button is pressed Input.prototype.addRBtnFunc = function(func){ this.rBtnFuncs.push(func); } //Adds an object to be notified when a mouse button is pressed. The object must have the function onMouseDown(buttonNumber) Input.prototype.addMouseDownListener = function(obj){ this.mdListens.push(obj); } //Adds an object to be notified when a mouse button is released Input.prototype.addMouseUpListener = function(obj){ this.muListens.push(obj); } //Adds an object to be notified when the mouse is moved. The object must have the function onMouseMove() Input.prototype.addMouseMoveListener = function(obj){ this.mmListens.push(obj); } //Adds an object to be notified when a key is pressed. The object must have the function onKeyDown(key) Input.prototype.addKeyboardListener = function(obj){ this.keyListens.push(obj); } Input.prototype.mouseMove = function(e){ if(!e) e = window.event; //println(e.pageY); this.mouse.x = e.pageX-canvas.offsetLeft; this.mouse.y = e.pageY-canvas.offsetTop; if(display != undefined && display.style.position == "relative"){ this.mouse.x -= display.offsetLeft; this.mouse.y -= display.offsetTop; } //for(var obj in this.mmListens){ for(var obj = 0; obj < this.mmListens.length; obj++){ this.mmListens[obj].onMouseMove(); } return false; } Input.prototype.mouseDown = function(e){ if(!e) e = window.event; switch(e.button){ case 0: this.lBtn = true; break; case 1: this.mBtn = true; break; case 2: this.rBtn = true; break; default: break; } this.mouse.x = e.pageX-canvas.offsetLeft; this.mouse.y = e.pageY-canvas.offsetTop; if(display != undefined && display.style.position == "relative"){ this.mouse.x -= display.offsetLeft; this.mouse.y -= display.offsetTop; } //for(var obj in this.mdListens){ for(var obj = 0; obj < this.mdListens.length; obj++){ this.mdListens[obj].onMouseDown(e.button); } return false; } Input.prototype.mouseUp = function(e){ if(!e) e = window.event; //println(e.button); switch(e.button){ case 0: this.lBtn = false; //for(var func in this.lBtnFuncs){ for(var func = 0; func < this.lBtnFuncs.length; func++){ this.lBtnFuncs[func](); } break; case 1: this.mBtn = false; //for(var func in this.mBtnFuncs){ for(var func = 0; func < this.mBtnFuncs.length; func++){ this.mBtnFuncs[func](); } break; case 2: this.rBtn = false; //for(var func in this.rBtnFuncs){ for(var func = 0; func < this.rBtnFuncs.length; func++){ this.rBtnFuncs[func](); } break; default: break; } this.mouse.x = e.pageX-canvas.offsetLeft; this.mouse.y = e.pageY-canvas.offsetTop; if(display != undefined && display.style.position == "relative"){ this.mouse.x -= display.offsetLeft; this.mouse.y -= display.offsetTop; } //for(var obj in this.muListens){ for(var obj = 0; obj < this.muListens.length; obj++){ this.muListens[obj].onMouseUp(e.button); } return false; } Input.prototype.handleKeyDown = function(e){ var key = e.keyCode; if(this.printKey){ println("down: "+key);//+": "+e.keyIdentifier); } if(key == 16){ this.shift = true; } if(this.keys[key] != undefined){ this.bools[this.keys[key]] = true; } if(this.funcs[key] != undefined){ if(this.repeats[key]){ this.funcs[key](); } } //for(var obj in this.keyListens){ for(var obj=0; obj < this.keyListens.length; obj++){ this.keyListens[obj].onKeyDown(key); } //Event.stop(e); if(e.keyCode == 32){ e.preventDefault(); e.space = true; this.handleKeyPress(e); } if(e.keyCode == 8 || e.keyCode == 37 || e.keyCode == 38 || e.keyCode == 39 || e.keyCode == 40){ e.preventDefault(); } //this.handleKeyPress(e); //e.returnValue = (e.keyCode != 8); //e.returnValue = !(e.keyCode == 8 || e.keyCode == 32); //this.handleKeyPress(e); //e.keyCode = 0; //println(window.event); //return e.keyCode != 8; } Input.prototype.handleKeyUp = function(e){ var key = e.keyCode; if(this.printKey){ println("up: "+key); } if(key == 16){ this.shift = false; } if(this.keys[key] != undefined){ this.bools[this.keys[key]] = false; } if(this.funcs[key] != undefined){ if(!this.repeats[key]){ this.funcs[key](); } } } Input.prototype.handleKeyPress = function(e){ var key = e.which; if(key == 32 && !e.space){ return true; } if(this.printKey){ println("press: "+key); } //for(var obj in this.keyListens){ for(var obj = 0; obj < this.keyListens.length; obj++){ this.keyListens[obj].onKeyPress(key); } if(e.keyCode == 8 || e.keyCode == 32){ //e.preventDefault(); } } function GUI(state){ this.init(); this.state = state; state.input.addMouseDownListener(this); state.input.addMouseUpListener(this); state.input.addMouseMoveListener(this); state.input.addKeyboardListener(this); } GUI.prototype = new Sprite(); GUI.prototype.focus = null; GUI.prototype.onMouseDown = function(button){ if(this.visible){ if(button == 0){ if(this.focus != null){ this.focus.focussed = false; this.focus.blur(); this.focus = null; } this.children.foreach(this.childMouseDown, {gui:this, mouse:this.state.input.mouse.sub(this.pos)}); } } } GUI.prototype.childMouseDown = function(child, params){ if(child.onMouseDown != undefined){ if(child.bbox.checkPoint(params.mouse)){ params.gui.focus = child; child.focussed = true; child.focus(); child.onMouseDown(); } } } GUI.prototype.onMouseUp = function(button){ //println(this.children); if(this.visible){ if(button == 0){ /*if(this.focus != null){ this.focus.focussed = false; this.focus.blur(); this.focus = null; }*/ this.children.foreach(this.childMouseUp, {gui:this, mouse:this.state.input.mouse.sub(this.pos)}); } } } GUI.prototype.childMouseUp = function(child, params){ if(child.onMouseUp != undefined){ if(child.bbox.checkPoint(params.mouse)){ //params.gui.focus = child; child.onMouseUp(); //child.focussed = true; //child.focus(); }else{ child.blur(); } } } GUI.prototype.onMouseMove = function(){ if(this.visible){ this.children.foreach(this.childMouseMove, {mouse:this.state.input.mouse.sub(this.pos)}); } } GUI.prototype.childMouseMove = function(child, params){ if(child.onMouseIn != undefined && child.onMouseOut != undefined){ if(child.bbox.checkPoint(params.mouse)){ child.onMouseIn(); }else{ child.onMouseOut(); } } } GUI.prototype.onKeyDown = function(key){ if(this.visible){ //this.children.foreach(this.childKeyDown, {mouse:this.state.input.mouse.sub(this.pos)}); //println(this.focus); if(this.focus != null && this.focus.onKeyDown){ this.focus.onKeyDown(key); } } } GUI.prototype.onKeyPress = function(key){ if(this.visible){ //this.children.foreach(this.childKeyDown, {mouse:this.state.input.mouse.sub(this.pos)}); //println(this.focus); if(this.focus != null && this.focus.onKeyPress){ this.focus.onKeyPress(key); } } } function GUIElement(){ } GUIElement.prototype = new Sprite(); GUIElement.prototype.color = "#000000"; GUIElement.prototype.drawColor = "#000000"; GUIElement.prototype.dropShadow = false; GUIElement.prototype.center = false; GUIElement.prototype.focussed = false; GUIElement.prototype.mouseOver = false; GUIElement.prototype.focus = function(){ this.focussed = true; } GUIElement.prototype.blur = function(){ this.focussed = false; } function TextBox(text){ this.init(); if(text != undefined){ this.text = text; } this.bufferColor = this.color; this.bbox = new BRect(0, 0, 1, 1); //Create second canvas to draw to improve text performance this.buffer = document.createElement("canvas"); this.bctx = this.buffer.getContext("2d"); } TextBox.prototype = new GUIElement(); TextBox.prototype.text = ""; TextBox.prototype.textBuffer = ""; TextBox.prototype.minWidth = 75; TextBox.prototype.fontSize = 16; TextBox.prototype.font = "Arial"; //TextBox.prototype.color = "#000000"; TextBox.prototype.bgColor = "#ffffff"; TextBox.prototype.bgDrawColor = "#ffffff"; TextBox.prototype.bgFocusColor = "#ccffcc"; TextBox.prototype.borderColor = "#000000"; TextBox.prototype.borderDrawColor = "#000000"; TextBox.prototype.borderFocusColor = "#ff0000"; TextBox.prototype.drawBG = false; TextBox.prototype.border = 0; //TextBox.prototype.dropShadow = false; //TextBox.prototype.center = false; TextBox.prototype.padTop = 2; TextBox.prototype.padLeft = 2; TextBox.prototype.padRight = 2; TextBox.prototype.padBottom = 2; TextBox.prototype.editable = false; TextBox.prototype.clearOnFocus = false; TextBox.prototype.oldText = ""; TextBox.prototype.getDims = function(){ /*var context = document.createElement("canvas").getContext("2d"); context.font = this.fontSize+"px "+this.font; context.textBaseline = "middle"; var textWidth = context.measureText(this.text).width; //return new Vector(textWidth+this.padLeft+this.padRight, this.padTop+this.padBottom+this.fontSize, 0); return new Vector(Math.max(this.minWidth, textWidth+this.padLeft+this.padRight), this.padTop+this.padBottom+this.fontSize, 0);*/ this.bctx.font = this.fontSize+"px "+this.font; this.bctx.textBaseline = "middle"; var textWidth = this.bctx.measureText(this.text).width; //return new Vector(textWidth+this.padLeft+this.padRight, this.padTop+this.padBottom+this.fontSize, 0); return new Vector(Math.max(this.minWidth, textWidth+this.padLeft+this.padRight), this.padTop+this.padBottom+this.fontSize, 0); } TextBox.prototype.onMouseDown = function(){ //this.drawColor = this.downColor; //println("textbox down"); } TextBox.prototype.onMouseUp = function(){ //println("textbox up"); } TextBox.prototype.onMouseIn = function(){ //this.mouseOver = true; //this.drawColor = this.upColor; } TextBox.prototype.onMouseOut = function(){ //this.mouseOver = false; //this.drawColor = this.color; } TextBox.prototype.onKeyDown = function(key){ if(key == 8){ this.text = this.text.substr(0, this.text.length-1); } } TextBox.prototype.onKeyPress = function(key){ var char = String.fromCharCode(key); //println(char); if(key != 8){ this.text += char; }else{ //this.text = this.text.substr(0, this.text.length-1); } } TextBox.prototype.focus = function(){ this.focussed = true; if(this.clearOnFocus){ this.minWidth = this.getDims().x; this.oldText = this.text; this.text = ""; } } TextBox.prototype.blur = function(){ this.focussed = false; if(this.clearOnFocus && this.text == ""){ this.text = this.oldText; } } TextBox.prototype.redraw = function(dims){ //var dims = this.getDims(); this.buffer.width = dims.x; this.buffer.height = dims.y; var bctx = this.bctx;//this.buffer.getContext("2d"); bctx.font = this.fontSize+"px "+this.font; //bctx.font = "16px 'Bangers'"; bctx.textBaseline = "middle"; var textWidth = bctx.measureText(this.text).width; this.width = dims.x; this.height = dims.y; var textXOff = 0; var xoff = 0; var yoff = 0; if(this.center){ textXOff = -(textWidth+this.padLeft+this.padRight)/2; xoff = -dims.x/2; //xoff = -(textWidth+this.padLeft+this.padRight)/2; yoff = -dims.y/2; //yoff = -this.fontSize/2; this.xoffset = -dims.x/2; this.yoffset = -dims.y/2; } if(this.editable && this.focussed){ this.bgDrawColor = this.bgFocusColor; this.borderDrawColor = this.borderFocusColor; }else{ this.bgDrawColor = this.bgColor; this.borderDrawColor = this.borderColor; } if(this.drawBG){ bctx.fillStyle = this.bgDrawColor; bctx.fillRect(0, 0, dims.x, dims.y); } if(this.border > 0){ bctx.lineWidth = this.border; bctx.strokeStyle = this.borderDrawColor; bctx.strokeRect(xoff, yoff, dims.x, dims.y); bctx.lineWidth = 1; } if(this.dropShadow){ bctx.shadowBlur = 3; bctx.shadowColor = "#000000"; } bctx.fillStyle = this.color; //bctx.fillText(this.text, this.padLeft, this.padTop-this.fontSize*(0.094-(this.fontSize/(this.fontSize*this.fontSize)))); bctx.fillText(this.text, this.padLeft, this.padTop+this.fontSize/2); bctx.shadowBlur = 0; this.image = this.buffer; createTexture(this.image); } TextBox.prototype.draw = function(context){ var dims = this.getDims(); var xoff = 0; var yoff = 0; if(this.center){ xoff = -dims.x/2; yoff = -dims.y/2; } this.bbox.pos.x = this.x+xoff; this.bbox.pos.y = this.y+yoff; this.bbox.dims.x = dims.x; this.bbox.dims.y = dims.y; if(this.text != this.textBuffer || dims.x != this.bufferDimX || this.color != this.bufferColor){ //println("redrawing text"); this.redraw(dims); this.textBuffer = this.text; this.bufferDimX = dims.x; this.bufferColor = this.color; } //this.image = this.buffer; //context.drawImage(this.buffer, xoff, yoff); //context.drawSprite(this); Sprite.prototype.draw.call(this, context); } function Button(func){ this.init(); this.func = func; this.bbox = new BRect(0, 0, 1, 1); this.color = "#ffffff"; this.upColor = "#ccffcc"; this.downColor = "#ccccff"; this.drawColor = this.color; this.drawBG = true; } Button.prototype = new GUIElement(); Button.prototype.onMouseDown = function(){ this.drawColor = this.downColor; } Button.prototype.onMouseUp = function(){ this.drawColor = this.upColor; if(this.focussed && this.func != undefined){ this.func(); } this.blur(); } Button.prototype.onMouseIn = function(){ this.mouseOver = true; if(!this.focussed){ this.drawColor = this.upColor; } } Button.prototype.onMouseOut = function(){ this.mouseOver = false; this.drawColor = this.color; } Button.prototype.update = function(delta){ /*this.bbox.x = this.x; this.bbox.y = this.y; this.bbox.width = this.width; this.bbox.height = this.height;*/ } Button.prototype.draw = function(context){ var xoff = 0; var yoff = 0; if(this.center){ xoff = -this.width/2; yoff = -this.height/2; //this.label.x = xoff; //this.label.y = yoff; //this.label.center = true; } this.bbox.pos.x = this.x+xoff; this.bbox.pos.y = this.y+yoff; this.bbox.dims.x = this.width; this.bbox.dims.y = this.height; if(this.dropShadow){ context.shadowBlur = 3; context.shadowColor = "#000000"; } context.fillStyle = this.drawColor; if(this.drawBG && (this.image.loaded == undefined || !this.image.loaded)){ //context.fillRect(xoff, yoff, this.width, this.height); } context.shadowBlur = 0; this.drawChildren(ctx); } function TextButton(label, func){ this.init(); this.label = new TextBox(label); this.label.minWidth = 0; this.addChild(this.label); this.width = this.label.getDims().x; this.height = this.label.getDims().y; this.bbox = new BRect(0, 0, this.width, this.height); this.func = func; this.labelColor = "#000000"; this.labelUpColor = "#000000"; this.labelDownColor = "#000000"; this.labelDrawColor = this.label.color; } TextButton.prototype = new Button(); TextButton.prototype.setLabelColors = function(normal, down, up){ this.labelColor = normal; this.labelUpColor = down; this.labelDownColor = up; this.labelDrawColor = normal; this.label.color = normal; } TextButton.prototype.onMouseDown = function(){ this.label.color = this.labelDownColor; Button.prototype.onMouseDown.call(this); } TextButton.prototype.onMouseUp = function(){ this.label.color = this.labelUpColor; Button.prototype.onMouseUp.call(this); } TextButton.prototype.onMouseIn = function(){ if(!this.focussed){ this.label.color = this.labelUpColor; } Button.prototype.onMouseIn.call(this); } TextButton.prototype.onMouseOut = function(){ this.label.color = this.labelColor; Button.prototype.onMouseOut.call(this); } TextButton.prototype.draw = function(context){ if(this.center){ this.label.center = true; } this.width = this.label.getDims().x; this.height = this.label.getDims().y; Button.prototype.draw.call(this, context); } var gameLoop; var oldTime; var MSPF = 17; var canvas; var aspectRatio; var ctx; var clearColor = [1,1,1,1]; var effects = new PostFXChain(); var log = new List(); var showConsole = false; var gInput = new Input(); var use2D = getCookie("use2D") ? getCookie("use2D") == "true" : false; var console; var useViewCulling = true; var allowContextMenu = true; var useStates = false; var world = new Sprite(); world.init = function(){}; var display; //Initializes the drawing context and input handlers function initGame(canvasId){ canvas = document.getElementById(canvasId); canvas.setAttribute("tabindex", "0"); canvas.radius = Math.sqrt(canvas.width*canvas.width+canvas.height*canvas.height)/2; canvas.pos = [canvas.width/2, canvas.height/2, 0]; aspectRatio = canvas.width/canvas.height; display = document.getElementById("display"); if(display != undefined){ display.style.width = canvas.width; display.style.height = canvas.height; display.style.overflow = "hidden"; display.style.position = "relative"; display.style.webkitTouchCallout = "none"; display.style.webkitUserSelect = "none"; display.style.khtmlUserSelect = "none"; display.style.MozUserSelect = "none"; display.style.msUserSelect = "none"; display.style.UserSelect = "none"; } console = document.getElementById("console"); //Attempts to create a 3D context falling back to 2D if 3D is unavailable if(canvas.getContext){ try{ if(!use2D){ ctx = canvas.getContext("experimental-webgl", {alpha: true}); } }catch(e){ } if(!ctx){ ctx = canvas.getContext("2d"); use2D = true; }else{ initGL(canvas); Textures.create(); } rewriteCTXFunctions(); if(typeof(states) != "undefined"){ useStates = true; } world.init(); //input.init(); gInput.addFunc(192, toggleConsole, false); gInput.addFunc(45, togglePrintKey); gameLoop = requestAnimationFrame(update); //New Method //gameLoop = setInterval(update, 30); //Old method } canvas.addEventListener("keydown",canvasHandleKeyDown,false); canvas.addEventListener("keyup",canvasHandleKeyUp,false); canvas.addEventListener("keypress",canvasHandleKeyPress,false); document.addEventListener('mousemove',canvasMouseMove,false); canvas.addEventListener('mousedown',canvasMouseDown,false); document.addEventListener('mouseup',canvasMouseUp,false); //document.onselectstart = function(){ return false;}; //Enable/disable the context menu on the canvas based on allowContextMenu if(!allowContextMenu){ canvas.oncontextmenu = function(){ return false; } } } function switchContext(){ if(use2D){ setCookie("use2D", false, 100); //window.location.reload(); }else{ setCookie("use2D", true, 100); //window.location.reload(); } } //Input handlers. Pass events to a global input object as well as the active state's input object function canvasMouseMove(e){ if(!e) e = window.event; if(useStates){ states.current().input.mouseMove(e); } gInput.mouseMove(e); } function canvasMouseDown(e){ if(!e) e = window.event; canvas.focus(); if(useStates){ states.current().input.mouseDown(e); } gInput.mouseDown(e); } function canvasMouseUp(e){ if(!e) e = window.event; if(useStates){ states.current().input.mouseUp(e); } gInput.mouseUp(e); } function canvasHandleKeyDown(e){ var key = e.keyCode; //println(key); if(useStates){ states.current().input.handleKeyDown(e); } gInput.handleKeyDown(e); } function canvasHandleKeyUp(e){ var key = e.keyCode; if(useStates){ states.current().input.handleKeyUp(e); } gInput.handleKeyUp(e); } function canvasHandleKeyPress(e){ var key = e.which; if(useStates){ states.current().input.handleKeyPress(e); } gInput.handleKeyPress(e); } //Blocks the context menu on the canvas function contextMenu(e){ println("context"); return false; } //Toggles printing pressed keys function togglePrintKey(){ if(gInput.printKey){ gInput.printKey = false; }else{ gInput.printKey = true; } } //Calls update on the state mananger and then calls draw function update(time){ if(!oldTime){ oldTime = time; } var delta = (time-oldTime)/MSPF; oldTime = time; println(delta); if(useStates){ states.update(delta); } world.update(delta); draw(); gameLoop = requestAnimationFrame(update); } //Clears the canvas, calls draw on the state manager, and then draws the console function draw(){ if(!use2D){ ctx.setBuffer(null); ctx.viewport(0, 0, ctx.viewportWidth, ctx.viewportHeight); var alpha = clearColor[3]; ctx.clearColor(clearColor[0]*alpha, clearColor[1]*alpha, clearColor[2]*alpha, alpha); ctx.clear(ctx.COLOR_BUFFER_BIT | ctx.DEPTH_BUFFER_BIT); ctx.setBuffer(colorBuffer); ctx.viewport(0, 0, ctx.viewportWidth, ctx.viewportHeight); //ctx.clearColor(clearColor[0]*alpha, clearColor[1]*alpha, clearColor[2]*alpha, alpha); ctx.clearColor(0,0,0,0); ctx.clear(ctx.COLOR_BUFFER_BIT); }else{ ctx.clearRect(0,0,canvas.width,canvas.height); ctx.fillStyle = rgb(clearColor); ctx.globalAlpha = clearColor[3]; ctx.fillRect(0,0,canvas.width,canvas.height); } mat4.ortho(-0, 1*aspectRatio, -1, 0, -1, 1, pMatrix); mat4.identity(mvMatrix); if(useStates){ states.draw(ctx); } //Draw the stateless world world.transform(ctx); world.draw(ctx); world.unTransform(ctx); if(!use2D){ ctx.clearColor(0, 0, 0, 0); effects.apply(ctx, colorBuffer); ctx.useProgram(shaderProgram); ctx.bindTexTo(colorBuffer.texture, shaderProgram.samplerUniform); ctx.uniform1f(shaderProgram.alpha, 1.0); ctx.setBuffer(null); ctx.drawScreenBuffer(shaderProgram); } if(showConsole){ if(!use2D){ console = document.getElementById("console"); if(console != undefined){ var text = ""; for(var node = log.head; node !== null; node = node.link){ text = node.item+"
"+text; } console.innerHTML = text; } console.style.visibility = "visible"; }else{ ctx.fillStyle = "#ffffff"; ctx.globalAlpha = 0.25; ctx.fillRect(0,0,canvas.width,canvas.height); ctx.globalAlpha = 1.0; ctx.fillStyle = "#000000"; //ctx.shadowBlur = 3; ctx.shadowColor = "#ffffff"; var lineHeight = 18; var lineNumber = 0; for(var node = log.head; node !== null; node = node.link){ var line = node.item; //ctx.font="16px Arial"; //ctx.strokeText(line, 5, canvas.height-(log.length-lineNumber)*12); ctx.font = lineHeight+"px Arial"; ctx.fillText(line, 5, canvas.height-(log.length-lineNumber)*lineHeight); lineNumber++; } ctx.shadowBlur = 0; } }else{ if(!use2D){ console.innerHTML = ""; console.style.visibility = "hidden"; } } } Textures.load("http://www.jar42.com/brine/engine/images/pixel.png", true); //Rewrites the default canvas context functions so that they work the same for 2D and 3D contexts function rewriteCTXFunctions(){ var ctxProto = ctx.__proto__; ctx.curDrawPos = vec3.create(); ctx.moveTo = function(x, y){ if(!use2D){ ctx.curDrawPos.x = x; ctx.curDrawPos.y = y; }else{ return ctxProto.moveTo.call(this, x, y); } } var lineSprite = new Sprite(); //lineSprite.image = Textures.load("../engine/images/pixel.png"); lineSprite.image = Textures.load("http://www.jar42.com/brine/engine/images/pixel.png", true); ctx.lineSprite = lineSprite; ctx.glLineWidth = 1; ctx.lineTo = function(x, y){ if(!use2D){ var xDis = x-this.curDrawPos.x; var yDis = y-this.curDrawPos.y; var length = Math.sqrt(xDis*xDis+yDis*yDis); var ang = Math.atan2(yDis, xDis); this.lineSprite.x = this.curDrawPos.x; this.lineSprite.y = this.curDrawPos.y; this.lineSprite.rotation = ang; this.lineSprite.width = length; this.lineSprite.height = this.glLineWidth; this.lineSprite.yoffset = -this.lineSprite.height/2; this.lineSprite.transform(this); this.lineSprite.draw(this); this.lineSprite.unTransform(this); this.curDrawPos.x = x; this.curDrawPos.y = y; }else{ return ctxProto.lineTo.call(this, x, y); } } ctx.getMatrix = function(){ return this.matrix; } ctx.scale = function(x, y){ x = x == 0 ? 0.0000001 : x; y = y == 0 ? 0.0000001 : y; mat4.scale(mvMatrix, [x, y, 1.0]); if(use2D){ return ctxProto.scale.call(this, x, y); } } ctx.rotate = function(angle){ mat4.rotateZ(mvMatrix, -angle); if(use2D){ return ctxProto.rotate.call(this, angle); } } ctx.translate = function(x, y){ mat4.translate(mvMatrix, [x*aspectRatio/canvas.width, -y/canvas.height, 0.0]); if(use2D){ return ctxProto.translate.call(this, x, y); } } //These 2 still need to be fixed ctx.transform = function(a, b, c, d, e, f){ if(use2D){ return ctxProto.transform.call(this, a, b, c, d, e, f); } } ctx.setTransform = function(a, b, c, d, e, f){ if(use2D){ return ctxProto.setTransform.call(this, a, b, c, d, e, f); } } if(use2D){ //Buffer for drawing scrolling sprite to ctx.spriteBuffer = document.createElement("canvas"); ctx.spriteBCTX = ctx.spriteBuffer.getContext("2d"); //document.body.appendChild(ctx.spriteBuffer); }else{ ctx.setBuffer = function(buffer){ this.bindFramebuffer(this.FRAMEBUFFER, buffer); } //Simplifies binding textures ctx.bindTexTo = function(texture, uniform, num){ num = num ? num : 0; this.activeTexture(this.TEXTURE0+num); this.bindTexture(this.TEXTURE_2D, texture); this.uniform1i(uniform, num); } ctx.drawScreenBuffer = function(shader, clearBuffer){ mat4.identity(mvMatrix); mat4.scale(mvMatrix, [aspectRatio, 1, 1.0]); this.viewport(0, 0, this.viewportWidth, this.viewportHeight); if(clearBuffer){ this.clear(this.COLOR_BUFFER_BIT); } this.blendFunc(this.ONE, this.ONE_MINUS_SRC_ALPHA); //This might need to be taken out if there is some buffer drawing issue down the line. this.bindBuffer(this.ARRAY_BUFFER, spriteVPB); this.vertexAttribPointer(shader.vertexPositionAttribute, spriteVPB.itemSize, this.FLOAT, false, 0, 0); this.bindBuffer(this.ARRAY_BUFFER, spriteVTB); this.vertexAttribPointer(shader.textureCoordAttribute, spriteVTB.itemSize, this.FLOAT, false, 0, 0); this.bindBuffer(this.ELEMENT_ARRAY_BUFFER, spriteVIB); setMatrixUniforms(shader); this.drawElements(this.TRIANGLES, spriteVIB.numItems, this.UNSIGNED_SHORT, 0); mat4.identity(mvMatrix); } } ctx.alpha = 1.0; var sPos = [0,0,0]; var verts = new Array(); verts.push([0,0,0]); verts.push([0,0,0]); verts.push([0,0,0]); verts.push([0,0,0]); ctx.drawSprite = function(sprite, frame){ var width = sprite.width; var height = sprite.height; var sWidth = width*sprite.xscale; var sHeight = height*sprite.yscale; var sRadius = Math.sqrt(sWidth*sWidth+sHeight*sHeight)/2; //var minDis = canvas.radius+sRadius; var minX = canvas.width/2+sRadius; var minY = canvas.height/2+sRadius; sPos[0] = 0; sPos[1] = 0; mat4.multiplyVec3(mvMatrix, sPos); vec3.multiply(sPos, [(1/aspectRatio)*canvas.width, -canvas.height, 1]); //var dis = vec3.dist(sPos, canvas.pos); var xDis = Math.abs(sPos[0]-canvas.pos[0]); var yDis = Math.abs(sPos[1]-canvas.pos[1]); //println("min: "+minDis+" dis: "+dis); //if(dis <= minDis){ if(!useViewCulling || (xDis <= minX && yDis <= minY)){ var x = sprite.xoffset; var y = sprite.yoffset; var image = sprite.image; frame = frame ? frame : 0; var frameWidth = sprite.frameWidth > 0 ? sprite.frameWidth : image.width; var frameHeight = sprite.frameHeight > 0 ? sprite.frameHeight : image.height; var multColor = sprite.multColor; //var alpha = sprite.alpha; var alpha = Math.max(0, ctx.alpha); var blendMode = sprite.blendMode; ctx.globalAlpha = alpha; ctx.globalCompositeOperation = blendMode; //If we are using webgl this sets a few uniforms and binds the sprite's texture if(sprite.image.texture != undefined){ y = -y; //ctx.blendFunc(ctx[sprite.blendFunction.a], ctx[sprite.blendFunction.b]); ctx.blendFuncSeparate(ctx[sprite.blendFunction.a], ctx[sprite.blendFunction.b], ctx.ONE, ctx.ONE_MINUS_SRC_ALPHA); mat4.translate(mvMatrix, [x*aspectRatio/canvas.width, y/canvas.height, 0.0]); //If the width or height is 0 the changes to the matrix can't be reversed width = Math.max(0.0000001, width); height = Math.max(0.0000001, height); mat4.scale(mvMatrix, [width*aspectRatio/canvas.width, height/canvas.height, 1.0]); ctx.useProgram(spriteShader); ctx.bindBuffer(ctx.ARRAY_BUFFER, spriteVPB); ctx.vertexAttribPointer(spriteShader.vertexPositionAttribute, spriteVPB.itemSize, ctx.FLOAT, false, 0, 0); ctx.bindBuffer(ctx.ARRAY_BUFFER, spriteVTB); ctx.vertexAttribPointer(spriteShader.textureCoordAttribute, spriteVTB.itemSize, ctx.FLOAT, false, 0, 0); ctx.activeTexture(ctx.TEXTURE0); ctx.bindTexture(ctx.TEXTURE_2D, sprite.image.texture); ctx.uniform1i(spriteShader.samplerUniform, 0); ctx.uniform3f(spriteShader.multColor, multColor.r, multColor.g, multColor.b); ctx.uniform1f(spriteShader.alpha, alpha); } var xtiles = sprite.xtiles; var ytiles = sprite.ytiles; var tileImage = (xtiles != undefined && ytiles != undefined); var xslice = Math.min(Math.max(0, sprite.xslice), frameWidth); var yslice = Math.min(Math.max(0, sprite.yslice), frameHeight); var sliceWidth = sprite.sliceWidth ? Math.max(0, sprite.sliceWidth) : sprite.sliceWidth; var sliceHeight = sprite.sliceHeight ? Math.max(0, sprite.sliceHeight) : sprite.sliceHeight; var xscroll = sprite.xscroll%(width/xtiles); var yscroll = sprite.yscroll%(height/ytiles); var scrollImage = (xscroll != undefined && yscroll != undefined && (xscroll != 0 || yscroll != 0)); //New consolidated drawing code var frameXOff = (frame%(image.width/frameWidth))*frameWidth; var frameYOff = Math.floor(frame/(image.width/frameWidth))*frameHeight; frameWidth = frameWidth-xslice; frameHeight = frameHeight-yslice; frameWidth = sliceWidth ? Math.min(frameWidth, sliceWidth) : frameWidth; frameHeight = sliceHeight ? Math.min(frameHeight, sliceHeight) : frameHeight; //Add Slice offsets frameXOff += xslice; frameYOff += yslice; //2D drawing if(use2D){ var xTileScale = 1/xtiles; var yTileScale = 1/ytiles; if(scrollImage){ xscroll /= xTileScale; yscroll /= yTileScale; xscroll = xscroll%width; yscroll = yscroll%height; //xscroll = -xscroll; yscroll = -yscroll; if(xscroll < 0){ xscroll = width+xscroll; } if(yscroll < 0){ yscroll = height+yscroll; } adXScroll = (xscroll/width)*frameWidth; adYScroll = (yscroll/height)*frameHeight; var q0Width = frameWidth-adXScroll; var q0Height = frameHeight-adYScroll; var q1Width = frameWidth-q0Width; var q1Height = q0Height; var q2Width = q1Width; var q2Height = frameHeight-q0Height; var q3Width = q0Width; var q3Height = q2Height; this.spriteBuffer.width = width; this.spriteBuffer.height = height; //Draw to this buffer so we can tile the sprite lots without having to draw it four times for each tile to get the scrolling effect this.spriteBCTX.drawImage(image, frameXOff+adXScroll, frameYOff+adYScroll, q0Width, q0Height, x, y, (q0Width/frameWidth)*width, (q0Height/frameHeight)*height); this.spriteBCTX.drawImage(image, frameXOff, frameYOff+adYScroll, q1Width, q1Height, (x+(width-xscroll)), y, (q1Width/frameWidth)*width, (q1Height/frameHeight)*height); this.spriteBCTX.drawImage(image, frameXOff, frameYOff, q2Width, q2Height, (x+(width-xscroll)), (y+(height-yscroll)), (q2Width/frameWidth)*width, (q2Height/frameHeight)*height); this.spriteBCTX.drawImage(image, frameXOff+adXScroll, frameYOff, q3Width, q3Height, x, (y+(height-yscroll)), (q3Width/frameWidth)*width, (q3Height/frameHeight)*height); //Set the current image (not the sprite's) to the buffer we just drew to image = this.spriteBuffer; //Reset everything to fit the buffer's dimensions frameXOff = 0; frameYOff = 0; frameWidth = width; frameHeight = height; } var xOff = 0; var yOff = 0; //Tile image (or don't) for(var i = 0; i < xtiles; i++){ for(var j = 0; j < ytiles; j++){ this.drawImage(image, frameXOff, frameYOff, frameWidth, frameHeight, x+xOff, y+yOff, width*xTileScale, height*yTileScale); yOff += height*yTileScale; } yOff = 0; xOff += width*xTileScale; } }else{ ctx.uniform2f(spriteShader.frameOffset, frameXOff/image.width, frameYOff/image.height); ctx.uniform2f(spriteShader.frameDims, frameWidth/image.width, frameHeight/image.height); } if(!use2D){ if(tileImage){ ctx.uniform2f(spriteShader.tiles, sprite.xtiles, sprite.ytiles); } if(scrollImage){ ctx.uniform2f(spriteShader.scroll, xscroll/width, yscroll/height); } } //WebGL drawing if(sprite.image.texture != undefined){ ctx.bindBuffer(ctx.ELEMENT_ARRAY_BUFFER, spriteVIB); setMatrixUniforms(spriteShader); ctx.drawElements(ctx.TRIANGLES, spriteVIB.numItems, ctx.UNSIGNED_SHORT, 0); mat4.scale(mvMatrix, [1/(width*aspectRatio/canvas.width), 1/(height/canvas.height), 1.0]); mat4.translate(mvMatrix, [-x*aspectRatio/canvas.width, -y/canvas.height, 0.0]); ctx.uniform2f(spriteShader.frameOffset, 0, 0); ctx.uniform2f(spriteShader.frameDims, 1, 1); ctx.uniform2f(spriteShader.tiles, 1, 1); ctx.uniform2f(spriteShader.scroll, 0, 0); } ctx.globalAlpha = 1.0; ctx.globalCompositeOperation = "source-over"; }else{ //println("Sprite failed broad sweep."); } } } function toggleConsole(){ if(showConsole){ showConsole = false; }else{ showConsole = true; } } function print(value){ log.push(value); if(log.length > 25){ log.remove(log.head.item); } } function println(value){ print(value+"\n"); } //Degree/Radian conversions function DTR(degrees){ return degrees*Math.PI/180; } function RTD(radians){ return radians*180/Math.PI; } //Convert RGB to hex string function rgb(color){ return "#"+(Math.round(color[0]*255)).toString(16)+(Math.round(color[1]*255)).toString(16)+(Math.round(color[2]*255)).toString(16); } function setCookie(name, value, days){ var date = new Date(); date.setDate(date.getDate() + days); var data = escape(value)+((days==null) ? "" : "; expires="+date.toUTCString()); document.cookie = name+"="+data; } function getCookie(name){ var strings = document.cookie.split("; "); //println(strings.length); for(var i=0; i < strings.length; i++){ var cookie = strings[i].split("="); //println(cookie[0]+": "+(cookie[0] == name)); if(cookie[0] == name){ return unescape(cookie[1]); } } return false; } function createGameCanvas(width, height, color){ var newCanvas = document.createElement("canvas"); newCanvas.width = width; newCanvas.height = height; //newCanvas.style.backgroundColor = color; newCanvas.innerHTML = "Your browser doesn't support HTML 5 Canvas.
You should probably switch to something a little more forward thinking.
"; return newCanvas; } // http://paulirish.com/2011/requestanimationframe-for-smart-animating/ // http://my.opera.com/emoller/blog/2011/12/20/requestanimationframe-for-smart-er-animating // requestAnimationFrame polyfill by Erik Möller // fixes from Paul Irish and Tino Zijdel (function() { var lastTime = 0; var vendors = ['ms', 'moz', 'webkit', 'o']; for(var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) { window.requestAnimationFrame = window[vendors[x]+'RequestAnimationFrame']; window.cancelAnimationFrame = window[vendors[x]+'CancelAnimationFrame'] || window[vendors[x]+'CancelRequestAnimationFrame']; } if (!window.requestAnimationFrame) window.requestAnimationFrame = function(callback, element) { var currTime = new Date().getTime(); var timeToCall = Math.max(0, 16 - (currTime - lastTime)); var id = window.setTimeout(function() { callback(currTime + timeToCall); }, timeToCall); lastTime = currTime + timeToCall; return id; }; if (!window.cancelAnimationFrame) window.cancelAnimationFrame = function(id) { clearTimeout(id); }; }());