/* GLGE WebGL Graphics Engine Copyright (c) 2010, Paul Brunt All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of GLGE nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL PAUL BRUNT BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /** * @fileOverview * @name GLGE_math.js */ if(typeof(GLGE) == "undefined"){ /** * @namespace Holds the functionality of the library */ GLGE = {}; } (function(GLGE){ var matrixCache=[]; //matrix reuse prevent so much GC GLGE.reuseMatrix4=function(mat4){ //if(mat4 && mat4.length==16 && matrixCache<10000) matrixCache.push(mat4); } GLGE.matrix4=function(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16){ if(matrixCache.length==0){ var mat=[a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16]; }else{ var mat=matrixCache.shift(); mat[0]=a1; mat[1]=a2; mat[2]=a3; mat[3]=a4; mat[4]=a5; mat[5]=a6; mat[6]=a7; mat[7]=a8; mat[8]=a9; mat[9]=a10; mat[10]=a11; mat[11]=a12; mat[12]=a13; mat[13]=a14; mat[14]=a15; mat[15]=a16; } return mat; } GLGE.Vec=function(array) { return array.slice(0); } /** * The Vec3 Class creates a vector * @param {Array} array An array of 3 floats */ GLGE.Vec3=function(x,y,z){ return [x,y,z]; } /** * The Vec4 Class creates a vector * @param {Array} array An array of 4 floats */ GLGE.Vec4=function(x,y,z,w){ return [x,y,z,w]; } /** * Gets the nth element (1 indexed) from the array * @param {Array} v A vector with 4 elements * @param {number} i The index from one */ GLGE.get1basedVec4=function(v,i){ return v[i-1]; }; /** * Gets the nth element (1 indexed) from the array * @param {Array} v A vector with 3 elements * @param {number} i The index from one */ GLGE.get1basedVec3=function(v,i){ return v[i-1]; }; /** * Gets the nth element (1 indexed) from the array * @param {Array} v A vector with 4 elements * @param {number} i The index from one */ GLGE.getVec4=function(v,i){ return v[i]; }; /** * Gets the nth element (1 indexed) from the array * @param {Array} v A vector with 3 elements * @param {number} i The index from one */ GLGE.getVec3=function(v,i){ return v[i]; }; /** * Adds a GLGE.Vec4 to this Vec4 * @param {Array} a The first value to add * * @param {Array} b The second value to add */ GLGE.addVec4=function(a,b) { return [a[0]+b[0],a[1]+b[1],a[2]+b[2],a[3]+b[3]]; } /** * Adds a GLGE.Vec3 to this GLGE.Vec3 * @param {Array} a The first value to add * @param {Array} b The second value to add */ GLGE.addVec3=function(a,b) { return [a[0]+b[0],a[1]+b[1],a[2]+b[2]]; } /** * Adds a GLGE.Vec4 to this Vec4 * @param {Array} a The first value * * @param {Array} b The second value to subtract from the first */ GLGE.subVec4=function(a,b) { return [a[0]-b[0],a[1]-b[1],a[2]-b[2],a[3]-b[3]]; } /** * Adds a GLGE.Vec3 to this GLGE.Vec3 * @param {Array} a The first value * @param {Array} b The second value to subtract from the first */ GLGE.subVec3=function(a,b) { return [a[0]-b[0],a[1]-b[1],a[2]-b[2]]; } /** * Gets the dot product between this and the input vector * @param {Array} a the first value to dot * @param {Array} b the second value to dot */ GLGE.dotVec3=function(a,b) { return a[0]*b[0]+a[1]*b[1]+a[2]*b[2]; } /** * Gets the dot product between this and the input vector * @param {Array} a the first value to dot * @param {Array} b the second value to dot */ GLGE.dotVec4=function(a,b) { return a[0]*b[0]+a[1]*b[1]+a[2]*b[2]+a[3]*b[3]; } /** * Gets the dot product between this and the input vector * @param {Array} a the vector to scale * @param {Number} b the scalar */ GLGE.scaleVec4=function(a,b) { return [a[0]*b,a[1]*b,a[2]*b,a[3]*b]; } /** * Gets the dot product between this and the input vector * @param {Array} a the vector to scale * @param {Number} b the scalar */ GLGE.scaleVec3=function(a,b) { return [a[0]*b,a[1]*b,a[2]*b]; } /** * Gets the cross product between this and the input vector * @param {Array} a the first value to dot * @param {Array} b the second value to dot */ GLGE.crossVec3=function(a,b) { return [a[1]*b[2]-a[2]*b[1], a[2]*b[0]-a[0]*b[2], a[0]*b[1]-a[1]*b[0]]; } /** * Returns a unitized version of the input vector3 * @param {Array} a the vector3 to be unitized */ GLGE.toUnitVec3=function(a) { var sq=a[0]*a[0]+a[1]*a[1]+a[2]*a[2]; var f=1.0; if (sq>0) { f=Math.pow(sq,0.5); } return [a[0]/f,a[1]/f,a[2]/f]; }; /** * Returns a unitized version of the input vector4 * @param {Array} a the vector4 to be unitized */ GLGE.toUnitVec4=function(a) { var sq=a[0]*a[0]+a[1]*a[1]+a[2]*a[2]+a[3]*a[3]; var f=1.0; if (sq>0) { f=Math.pow(sq,0.5); } return [a[0]/f,a[1]/f,a[2]/f,a[3]/f]; }; /** * Returns the length of a vector3 * @param {Array} a the vector to be measured */ GLGE.lengthVec3=function(a) { return Math.pow(a[0]*a[0]+a[1]*a[1]+a[2]*a[2],0.5); }; /** * Returns the distance between 2 vector3s * @param {Array} a the first vector * @param {Array} b the second vector */ GLGE.distanceVec3=function(a,b){ return GLGE.lengthVec3(GLGE.subVec3(a,b)); }; /** * Returns the length of a vector3 * @param {Array} a the vector to be measured */ GLGE.lengthVec4=function(a,b) { return Math.pow(a[0]*a[0]+a[1]*a[1]+a[2]*a[2]+a[3]*a[3],0.5); }; /** * Returns the distance between 2 vector4s * @param {Array} a the first vector * @param {Array} b the second vector */ GLGE.distanceVec4=function(a,b){ return GLGE.lengthVec4(GLGE.subVec4(a,b)); }; /** * Returns the angle between 2 vector3s in radians * @param {Array} a the first vector * @param {Array} b the second vector */ GLGE.angleVec3=function(a,b){ a=GLGE.toUnitVec3(a); b=GLGE.toUnitVec3(b); d=GLGE.dotVec3(a,b); if (d<-1) d=-1; if (d>1) d=1; return Math.acos(d); }; /** * Returns the angle between 2 vector4s in radians * @param {Array} a the first vector * @param {Array} b the second vector */ GLGE.angleVec4=function(a,b){ a=GLGE.toUnitVec4(a); b=GLGE.toUnitVec4(b); d=GLGE.dotVec4(a,b); if (d<-1) d=-1; if (d>1) d=1; return Math.acos(d); }; GLGE_math_use_webgl_float=false; /** * The Mat class creates a matrix from an array * @param {Array} array An array of 9 or 16 floats */ GLGE.Mat3=GLGE_math_use_webgl_float?function(array) { if (array.length==9) { return new Float32Array(array); }else if (array.length==16) { return new Float32Array([array[0],array[1],array[2],array[4],array[5],array[6],array[8],array[9],array[10]]); }else { throw "invalid matrix length"; } }:function(array) { var retval; if (array.length==9) { retval=array.slice(0); }else if (array.length==16) { retval=[array[0],array[1],array[2],array[4],array[5],array[6],array[8],array[9],array[10]]; }else { throw "invalid matrix length"; } retval.get=function(i){return this[i];}; return retval; }; GLGE.Mat=GLGE_math_use_webgl_float?function(array) { return new Float32Array(array); }:function(array){ var retval=array.slice(0); retval.get=function(i){return this[i];}; return retval; }; GLGE.Mat4=function(array) { var retval; if (array.length==9) { retval=[array[0],array[1],array[2],0,array[3],array[4],array[5],0,array[6],array[7],array[8],0,0,0,0,1]; }else if (array.length==16) { if(array.slice) retval=array.slice(0); else retval=array.subarray(0); }else { throw "invalid matrix length"; } retval.get=function(i){return this[i];}; return retval; }; /** * Finds the determinate of the matrix * @returns {number} the determinate */ GLGE.determinantMat4=function(m) { return m[12] * m[9] * m[6] * m[3] - m[8] * m[13] * m[6] * m[3] - m[12] * m[5] * m[10] * m[3] + m[4] * m[13] * m[10] * m[3] + m[8] * m[5] * m[14] * m[3] - m[4] * m[9] * m[14] * m[3] - m[12] * m[9] * m[2] * m[7] + m[8] * m[13] * m[2] * m[7] + m[12] * m[1] * m[10] * m[7] - m[0] * m[13] * m[10] * m[7] - m[8] * m[1] * m[14] * m[7] + m[0] * m[9] * m[14] * m[7] + m[12] * m[5] * m[2] * m[11] - m[4] * m[13] * m[2] * m[11] - m[12] * m[1] * m[6] * m[11] + m[0] * m[13] * m[6] * m[11] + m[4] * m[1] * m[14] * m[11] - m[0] * m[5] * m[14] * m[11] - m[8] * m[5] * m[2] * m[15] + m[4] * m[9] * m[2] * m[15] + m[8] * m[1] * m[6] * m[15] - m[0] * m[9] * m[6] * m[15] - m[4] * m[1] * m[10] * m[15] + m[0] * m[5] * m[10] * m[15]; }; /** * Finds the inverse of the matrix * @returns {GLGE.Mat} the inverse */ GLGE.inverseMat4=function(mat){ // Cache the matrix values (makes for huge speed increases!) var a00 = mat[0], a01 = mat[1], a02 = mat[2], a03 = mat[3]; var a10 = mat[4], a11 = mat[5], a12 = mat[6], a13 = mat[7]; var a20 = mat[8], a21 = mat[9], a22 = mat[10], a23 = mat[11]; var a30 = mat[12], a31 = mat[13], a32 = mat[14], a33 = mat[15]; var d = a30*a21*a12*a03 - a20*a31*a12*a03 - a30*a11*a22*a03 + a10*a31*a22*a03 + a20*a11*a32*a03 - a10*a21*a32*a03 - a30*a21*a02*a13 + a20*a31*a02*a13 + a30*a01*a22*a13 - a00*a31*a22*a13 - a20*a01*a32*a13 + a00*a21*a32*a13 + a30*a11*a02*a23 - a10*a31*a02*a23 - a30*a01*a12*a23 + a00*a31*a12*a23 + a10*a01*a32*a23 - a00*a11*a32*a23 - a20*a11*a02*a33 + a10*a21*a02*a33 + a20*a01*a12*a33 - a00*a21*a12*a33 - a10*a01*a22*a33 + a00*a11*a22*a33; return GLGE.matrix4((a21*a32*a13 - a31*a22*a13 + a31*a12*a23 - a11*a32*a23 - a21*a12*a33 + a11*a22*a33)/d, (a31*a22*a03 - a21*a32*a03 - a31*a02*a23 + a01*a32*a23 + a21*a02*a33 - a01*a22*a33)/d, (a11*a32*a03 - a31*a12*a03 + a31*a02*a13 - a01*a32*a13 - a11*a02*a33 + a01*a12*a33)/d, (a21*a12*a03 - a11*a22*a03 - a21*a02*a13 + a01*a22*a13 + a11*a02*a23 - a01*a12*a23)/d, (a30*a22*a13 - a20*a32*a13 - a30*a12*a23 + a10*a32*a23 + a20*a12*a33 - a10*a22*a33)/d, (a20*a32*a03 - a30*a22*a03 + a30*a02*a23 - a00*a32*a23 - a20*a02*a33 + a00*a22*a33)/d, (a30*a12*a03 - a10*a32*a03 - a30*a02*a13 + a00*a32*a13 + a10*a02*a33 - a00*a12*a33)/d, (a10*a22*a03 - a20*a12*a03 + a20*a02*a13 - a00*a22*a13 - a10*a02*a23 + a00*a12*a23)/d, (a20*a31*a13 - a30*a21*a13 + a30*a11*a23 - a10*a31*a23 - a20*a11*a33 + a10*a21*a33)/d, (a30*a21*a03 - a20*a31*a03 - a30*a01*a23 + a00*a31*a23 + a20*a01*a33 - a00*a21*a33)/d, (a10*a31*a03 - a30*a11*a03 + a30*a01*a13 - a00*a31*a13 - a10*a01*a33 + a00*a11*a33)/d, (a20*a11*a03 - a10*a21*a03 - a20*a01*a13 + a00*a21*a13 + a10*a01*a23 - a00*a11*a23)/d, (a30*a21*a12 - a20*a31*a12 - a30*a11*a22 + a10*a31*a22 + a20*a11*a32 - a10*a21*a32)/d, (a20*a31*a02 - a30*a21*a02 + a30*a01*a22 - a00*a31*a22 - a20*a01*a32 + a00*a21*a32)/d, (a30*a11*a02 - a10*a31*a02 - a30*a01*a12 + a00*a31*a12 + a10*a01*a32 - a00*a11*a32)/d, (a10*a21*a02 - a20*a11*a02 + a20*a01*a12 - a00*a21*a12 - a10*a01*a22 + a00*a11*a22)/d) }; /** * multiplies two mat4's * @returns {GLGE.Mat} the matrix multiplication of the matrices */ GLGE.mulMat4Vec3=function(mat1,vec2){ return GLGE.Vec3(mat1[0]*vec2[0]+mat1[1]*vec2[1]+mat1[2]*vec2[2]+mat1[3], mat1[4]*vec2[0]+mat1[5]*vec2[1]+mat1[6]*vec2[2]+mat1[7], mat1[8]*vec2[0]+mat1[9]*vec2[1]+mat1[10]*vec2[2]+mat1[11]); }; /** * multiplies two mat4's * @returns {GLGE.Mat} the matrix multiplication of the matrices */ GLGE.mulMat4Vec4=function(mat1,vec2){ return GLGE.Vec4(mat1[0]*vec2[0]+mat1[1]*vec2[1]+mat1[2]*vec2[2]+mat1[3]*vec2[3], mat1[4]*vec2[0]+mat1[5]*vec2[1]+mat1[6]*vec2[2]+mat1[7]*vec2[3], mat1[8]*vec2[0]+mat1[9]*vec2[1]+mat1[10]*vec2[2]+mat1[11]*vec2[3], mat1[12]*vec2[0]+mat1[13]*vec2[1]+mat1[14]*vec2[2]+mat1[15]*vec2[3]); }; /** * multiplies a Mat4 by a scalar value * @returns {GLGE.Mat} the matrix multiplication of the matrices */ GLGE.scaleMat4=function(m,value) { return GLGE.matrix4([m[0]*value,m[1]*value,m[2]*value,m[3]*value, m[4]*value,m[5]*value,m[6]*value,m[7]*value, m[8]*value,m[9]*value,m[10]*value,m[11]*value, m[12]*value,m[13]*value,m[14]*value,m[15]*value]); }; /** * multiplies a Mat4 by a scalar value in place without allocation * @returns {GLGE.Mat} the input matrix, modified */ GLGE.scaleInPlaceMat4=function(m,value) { m.set(0,m[0]*value); m.set(1,m[1]*value); m.set(2,m[2]*value); m.set(3,m[3]*value); m.set(4,m[4]*value); m.set(5,m[5]*value); m.set(6,m[6]*value); m.set(7,m[7]*value); m.set(8,m[8]*value); m.set(9,m[9]*value); m.set(10,m[10]*value); m.set(11,m[11]*value); m.set(12,m[12]*value); m.set(13,m[13]*value); m.set(14,m[14]*value); m.set(15,m[15]*value); return m; }; /** * adds a Mat4 to another Mat4 in place without allocation * @returns {GLGE.Mat} the first input matrix, modified to be added */ GLGE.addInPlaceMat4=function(m,value) { m.set(0,m[0]+value[0]); m.set(1,m[1]+value[1]); m.set(2,m[2]+value[2]); m.set(3,m[3]+value[3]); m.set(4,m[4]+value[4]); m.set(5,m[5]+value[5]); m.set(6,m[6]+value[6]); m.set(7,m[7]+value[7]); m.set(8,m[8]+value[8]); m.set(9,m[9]+value[9]); m.set(10,m[10]+value[10]); m.set(11,m[11]+value[11]); m.set(12,m[12]+value[12]); m.set(13,m[13]+value[13]); m.set(14,m[14]+value[14]); m.set(15,m[15]+value[15]); return m; }; /** * adds two Mat4 together * @returns {GLGE.Mat} a new, added Mat4 */ GLGE.addMat4=function(m,value) { return GLGE.Mat([m[0]+value[0], m[1]+value[1], m[2]+value[2], m[3]+value[3], m[4]+value[4], m[5]+value[5], m[6]+value[6], m[7]+value[7], m[8]+value[8], m[9]+value[9], m[10]+value[10], m[11]+value[11], m[12]+value[12], m[13]+value[13], m[14]+value[14], m[15]+value[15]]); return m; }; /** * subs a Mat4 from another Mat4 in place without allocation * @returns {GLGE.Mat} the first input matrix, modified to have the second subtacted */ GLGE.subInPlaceMat4=function(m,value) { m.set(0,m[0]-value[0]); m.set(1,m[1]-value[1]); m.set(2,m[2]-value[2]); m.set(3,m[3]-value[3]); m.set(4,m[4]-value[4]); m.set(5,m[5]-value[5]); m.set(6,m[6]-value[6]); m.set(7,m[7]-value[7]); m.set(8,m[8]-value[8]); m.set(9,m[9]-value[9]); m.set(10,m[10]-value[10]); m.set(11,m[11]-value[11]); m.set(12,m[12]-value[12]); m.set(13,m[13]-value[13]); m.set(14,m[14]-value[14]); m.set(15,m[15]-value[15]); return m; }; /** * subtracts the second matrix from the first * @returns {GLGE.Mat} a new, subed Mat4 */ GLGE.subMat4=function(m,value) { return GLGE.Mat([m[0]-value[0], m[1]-value[1], m[2]-value[2], m[3]-value[3], m[4]-value[4], m[5]-value[5], m[6]-value[6], m[7]-value[7], m[8]-value[8], m[9]-value[9], m[10]-value[10], m[11]-value[11], m[12]-value[12], m[13]-value[13], m[14]-value[14], m[15]-value[15]]); return m; }; /** * Finds the matrix multiplication with another GLGE.Mat or GLGE.vec or an Array of length 3-4 * @param {object} value An GLGE.Mat, GLGE.vec or Array * @returns {GLGE.Mat|GLGE.Vec} */ GLGE.mulMat4=function(mat2,mat1){ var a00 = mat1[0], a01 = mat1[1], a02 = mat1[2], a03 = mat1[3]; var a10 = mat1[4], a11 = mat1[5], a12 = mat1[6], a13 = mat1[7]; var a20 = mat1[8], a21 = mat1[9], a22 = mat1[10], a23 = mat1[11]; var a30 = mat1[12], a31 = mat1[13], a32 = mat1[14], a33 = mat1[15]; var b00 = mat2[0], b01 = mat2[1], b02 = mat2[2], b03 = mat2[3]; var b10 = mat2[4], b11 = mat2[5], b12 = mat2[6], b13 = mat2[7]; var b20 = mat2[8], b21 = mat2[9], b22 = mat2[10], b23 = mat2[11]; var b30 = mat2[12], b31 = mat2[13], b32 = mat2[14], b33 = mat2[15]; return GLGE.matrix4(b00 * a00 + b01 * a10 + b02 * a20 + b03 * a30, b00 * a01 + b01 * a11 + b02 * a21 + b03 * a31, b00 * a02 + b01 * a12 + b02 * a22 + b03 * a32, b00 * a03 + b01 * a13 + b02 * a23 + b03 * a33, b10 * a00 + b11 * a10 + b12 * a20 + b13 * a30, b10 * a01 + b11 * a11 + b12 * a21 + b13 * a31, b10 * a02 + b11 * a12 + b12 * a22 + b13 * a32, b10 * a03 + b11 * a13 + b12 * a23 + b13 * a33, b20 * a00 + b21 * a10 + b22 * a20 + b23 * a30, b20 * a01 + b21 * a11 + b22 * a21 + b23 * a31, b20 * a02 + b21 * a12 + b22 * a22 + b23 * a32, b20 * a03 + b21 * a13 + b22 * a23 + b23 * a33, b30 * a00 + b31 * a10 + b32 * a20 + b33 * a30, b30 * a01 + b31 * a11 + b32 * a21 + b33 * a31, b30 * a02 + b31 * a12 + b32 * a22 + b33 * a32, b30 * a03 + b31 * a13 + b32 * a23 + b33 * a33); }; GLGE.transposeInPlaceMat4=function(m) { var v=m[1]; m.set(1,m[4]); m.set(4,v); v=m[8]; m.set(8,m[2]); m.set(2,v); v=m[3]; m.set(3,m[12]); m.set(12,v); v=m[9]; m.set(9,m[6]); m.set(6,v); v=m[13]; m.set(13,m[7]); m.set(7,v); v=m[14]; m.set(14,m[11]); m.set(11,v); }; /** * Builds the transpose of the matrix * @returns {GLGE.Mat} the transposed matrix */ GLGE.transposeMat4=function(m) { return GLGE.matrix4(m[0],m[4],m[8],m[12], m[1],m[5],m[9],m[13], m[2],m[6],m[10],m[14], m[3],m[7],m[11],m[15]); }; /** * copys a js array into a webglarray * @param {array} mat the source array * @param {webglarray} glarray the destination array */ GLGE.mat4gl=function(mat,glarray){ glarray[0]=mat[0]; glarray[1]=mat[1]; glarray[2]=mat[2]; glarray[3]=mat[3]; glarray[4]=mat[4]; glarray[5]=mat[5]; glarray[6]=mat[6]; glarray[7]=mat[7]; glarray[8]=mat[8]; glarray[9]=mat[9]; glarray[10]=mat[10]; glarray[11]=mat[11]; glarray[12]=mat[12]; glarray[13]=mat[13]; glarray[14]=mat[14]; glarray[15]=mat[15]; }; /** * Sets the value at the specified index * @param {number} i the first index 1 offset * @param {number} j the second index 1 offset * @param {number} value the value to set */ GLGE.set1basedMat4=function(m,i,j,value){ m[(i-1)*4+(j-1)]=value; if(m.glData!==undefined){ delete m.glData; } }; /** * Sets the value at the specified index * @param {number} i the first index from zero * @param {number} j the second index from zero * @param {number} value the value to set */ GLGE.setMat4=function(m,i,j,value){ m[i*4+j]=value; if(m.glData!==undefined){ delete m.glData; } }; /** * Gets the value at the specified index * @param {number} i the first index from one * @param {number} j the second index from one * @returns {number} the value at the given index */ GLGE.get1basedMat4=function(m,i,j){ return m.get((i-1)*4+(j-1)); }; /** * Gets the value at the specified index * @param {number} i the first index from zero * @param {number} j the second index from zero * @returns {number} the value at the given index */ GLGE.getMat4=function(m,i,j){ return m[i*4+j]; }; /** * gets the a webgl float array for this Matrix, once generated it will cache it so it doesn't need to recreate everytime * @returns {Float32Array} the webgl array for this Matrix * @private */ GLGE.glDataMat4=function(m) { m.glArray=new Float32Array(m); return m.glArray; }; /** * Creates an identity matrix * @returns {GLGE.Mat} the identity matrix */ GLGE.identMatrix=function(){ return GLGE.matrix4(1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1); }; /** * Creates a translation matrix * @returns {Array} value an array GLGE.Vec or 3 paramters * @returns {GLGE.Mat} the translation matrix */ GLGE.translateMatrix=function(value){ var x; var y; var z; if(arguments.length==3){ x=arguments[0]; y=arguments[1]; z=arguments[2]; } else if(value.data){ x=value.data[0]; y=value.data[1]; z=value.data[2]; } else if(value instanceof Array){ x=value[0]; y=value[1]; z=value[2]; } return GLGE.matrix4( 1,0,0,x, 0,1,0,y, 0,0,1,z, 0,0,0,1 ); }; /** * Creates a scale matrix * @returns {Array} value an array GLGE.Vec or 3 paramters * @returns {GLGE.Mat} the scale matrix */ GLGE.scaleMatrix=function(value){ var x; var y; var z; if(arguments.length==3){ x=arguments[0]; y=arguments[1]; z=arguments[2]; } else if(value.data){ x=value.data[0]; y=value.data[1]; z=value.data[2]; } else if(value instanceof Array){ x=value[0]; y=value[1]; z=value[2]; } return GLGE.matrix4( x,0,0,0, 0,y,0,0, 0,0,z,0, 0,0,0,1 ); } /** * @constant * @description Enum for XYZ rotation order */ GLGE.ROT_XYZ=1; /** * @constant * @description Enum for XZY rotation order */ GLGE.ROT_XZY=2; /** * @constant * @description Enum for YXZ rotation order */ GLGE.ROT_YXZ=3; /** * @constant * @description Enum for YZX rotation order */ GLGE.ROT_YZX=4; /** * @constant * @description Enum for ZXY rotation order */ GLGE.ROT_ZXY=5; /** * @constant * @description Enum for ZYX rotation order */ GLGE.ROT_ZYX=6; /** * Creates a rotation matrix * @returns {Array} value an array GLGE.Vec or 3 paramters * @returns {GLGE.Mat} the rotation matrix */ GLGE.rotateMatrix=function(value,type) { var x; var y; var z; if(arguments.length>2){ x=arguments[0]; y=arguments[1]; z=arguments[2]; type=arguments[3]; } else if(value.data){ x=value.data[0]; y=value.data[1]; z=value.data[2]; } else if(value instanceof Array){ x=value[0]; y=value[1]; z=value[2]; } if(!type) type=GLGE.ROT_XYZ; var cosx=Math.cos(x); var sinx=Math.sin(x); var cosy=Math.cos(y); var siny=Math.sin(y); var cosz=Math.cos(z); var sinz=Math.sin(z); var rotx=GLGE.matrix4(1,0,0,0,0,cosx,-sinx,0,0,sinx,cosx,0,0,0,0,1); var roty=GLGE.matrix4(cosy,0,siny,0,0,1,0,0,-siny,0,cosy,0,0,0,0,1); var rotz=GLGE.matrix4(cosz,-sinz,0,0,sinz,cosz,0,0,0,0,1,0,0,0,0,1); switch(type){ case GLGE.ROT_XYZ: return GLGE.mulMat4(rotx,GLGE.mulMat4(roty,rotz)); break; case GLGE.ROT_XZY: return GLGE.mulMat4(rotx,GLGE.mulMat4(rotz,roty)); break; case GLGE.ROT_YXZ: return GLGE.mulMat4(roty,GLGE.mulMat4(rotx,rotz)); break; case GLGE.ROT_YZX: return GLGE.mulMat4(roty,GLGE.mulMat4(rotz,rotx)); break; case GLGE.ROT_ZXY: return GLGE.mulMat4(rotz,GLGE.mulMat4(rotx,roty)); break; case GLGE.ROT_ZYX: return GLGE.mulMat4(rotz,GLGE.mulMat4(roty,rotx)); break; } } GLGE.angleAxis=function(angle, axis) { var xmx,ymy,zmz,xmy,ymz,zmx,xms,yms,zms; axis=[axis[0],axis[1],axis[2],0]; var x = axis[0]; var y = axis[1]; var z = axis[2]; var cos = Math.cos(angle); var cosi = 1.0 - cos; var sin = Math.sin(angle); xms = x * sin;yms = y * sin;zms = z * sin; xmx = x * x;ymy = y * y;zmz = z * z; xmy = x * y;ymz = y * z;zmx = z * x; var matrix = GLGE.matrix4((cosi * xmx) + cos,(cosi * xmy) - zms,(cosi * zmx) + yms,0, (cosi * xmy) + zms,(cosi * ymy) + cos,(cosi * ymz) - xms,0, (cosi * zmx) - yms,(cosi * ymz) + xms,(cosi * zmz) + cos,0, 0,0,0,1); return GLGE.Mat(matrix); }; // JHD GLGE.quatFromAxisAngle = function(axis, angle) { var quaternion = []; var halfAngle = angle * 0.5; var sinus = Math.sin(halfAngle); var cosinus = Math.cos(halfAngle); quaternion[0] = axis[0] * sinus; quaternion[1] = axis[1] * sinus; quaternion[2] = axis[2] * sinus; quaternion[3] = cosinus; return quaternion; }; GLGE.mulQuat = function(quaternion1, quaternion2) { var quaternion = []; var x = quaternion1[0]; var y = quaternion1[1]; var z = quaternion1[2]; var w = quaternion1[3]; var x2 = quaternion2[0]; var y2 = quaternion2[1]; var z2 = quaternion2[2]; var w2 = quaternion2[3]; var a = (y * z2) - (z * y2); var b = (z * x2) - (x * z2); var c = (x * y2) - (y * x2); var d = ((x * x2) + (y * y2)) + (z * z2); quaternion[0] = ((x * w2) + (x2 * w)) + a; quaternion[1] = ((y * w2) + (y2 * w)) + b; quaternion[2] = ((z * w2) + (z2 * w)) + c; quaternion[3] = (w * w2) - d; return quaternion; }; GLGE.mat4FromQuat = function(quaternion) { // TODO: Optimize with storing the array-wise indexed values // in direct acessible variables? var x2 = quaternion[0] * quaternion[0]; var y2 = quaternion[1] * quaternion[1]; var z2 = quaternion[2] * quaternion[2]; var xy = quaternion[0] * quaternion[1]; var zw = quaternion[2] * quaternion[3]; var zx = quaternion[2] * quaternion[0]; var yw = quaternion[1] * quaternion[3]; var yz = quaternion[1] * quaternion[2]; var xw = quaternion[0] * quaternion[3]; var result = []; result[0] = 1 - (2 * (y2 + z2)); result[1] = 2 * (xy + zw); result[2] = 2 * (zx - yw); result[3] = 0; result[4] = 2 * (xy - zw); result[5] = 1 - (2 * (z2 + x2)); result[6] = 2 * (yz + xw); result[7] = 0; result[8] = 2 * (zx + yw); result[9] = 2 * (yz - xw); result[10] = 1 - (2 * (y2 + x2)); result[11] = 0; result[12] = 0; result[13] = 0; result[14] = 0; result[15] = 1; return result; }; // JHD - end GLGE.quatRotation=function(qx,qy,qz,qw){ return GLGE.matrix4( 1 - 2*qy*qy - 2*qz*qz,2*qx*qy - 2*qz*qw,2*qx*qz + 2*qy*qw,0, 2*qx*qy + 2*qz*qw,1 - 2*qx*qx - 2*qz*qz,2*qy*qz - 2*qx*qw,0, 2*qx*qz - 2*qy*qw,2*qy*qz + 2*qx*qw,1 - 2*qx*qx - 2*qy*qy,0, 0,0,0,1 ); }; GLGE.makeOrtho=function(left,right,bottom,top,near,far){ var x = -(right+left)/(right-left); var y = -(top+bottom)/(top-bottom); var z = -(far+near)/(far-near); return GLGE.matrix4(2/(right-left), 0, 0, x, 0, 2/(top-bottom), 0, y, 0, 0, -2/(far-near), z, 0, 0, 0, 1); }; GLGE.makeFrustum=function(left,right,bottom,top,near,far){ var x = 2*near/(right-left); var y = 2*near/(top-bottom); var a = (right+left)/(right-left); var b = (top+bottom)/(top-bottom); var c = -(far+near)/(far-near); var d = -2*far*near/(far-near); return GLGE.matrix4(x, 0, a, 0, 0, y, b, 0, 0, 0, c, d, 0, 0, -1, 0); }; GLGE.makePerspective=function(fovy, aspect, near, far){ var ymax = near * Math.tan(fovy * 0.00872664625972); var ymin = -ymax; var xmin = ymin * aspect; var xmax = ymax * aspect; return GLGE.makeFrustum(xmin, xmax, ymin, ymax, near, far); }; GLGE.makePerspectiveX=function(fovx, aspect, near, far){ var xmax = near * Math.tan(fovx * 0.00872664625972); var xmin = -xmax; var ymin = xmin / aspect; var ymax = xmax / aspect; return GLGE.makeFrustum(xmin, xmax, ymin, ymax, near, far); }; GLGE.matrix2Scale=function(m){ var m1=m[0]; var m2=m[1]; var m3=m[2]; var m4=m[4]; var m5=m[5]; var m6=m[6]; var m7=m[8]; var m8=m[9]; var m9=m[10]; var scaleX=Math.sqrt(m1*m1+m2*m2+m3*m3); var scaleY=Math.sqrt(m4*m4+m5*m5+m6*m6); var scaleZ=Math.sqrt(m7*m7+m8*m8+m9*m9); return [scaleX,scaleY,scaleZ] } GLGE.rotationMatrix2Quat=function(m){ var tr = m[0] + m[5] + m[10]+1.0; var S,x,y,z,w; if (tr > 0) { S = 0.5/Math.sqrt(tr); w = 0.25 / S; x = (m[9] - m[6]) * S; y = (m[2] - m[8]) * S; z = (m[4] - m[1]) * S; } else if ((m[0] > m[5])&&(m[0] > m[10])) { S = Math.sqrt(1.0 + m[0] - m[5] - m[10]) * 2; w = (m[9] - m[6]) / S; x = 0.25 / S; y = (m[1] + m[4]) / S; z = (m[2] + m[8]) / S; } else if (m[5] > m[10]) { S = Math.sqrt(1.0 + m[5] - m[0] - m[10]) * 2; w = (m[2] - m[8]) / S; x = (m[1] + m[4]) / S; y = 0.25 / S; z = (m[6] + m[9]) / S; } else { S = Math.sqrt(1.0 + m[10] - m[0] - m[5]) * 2; w = (m[4] - m[1]) / S; x = (m[2] + m[8]) / S; y = (m[6] + m[9]) / S; z = 0.25 / S; } var N=Math.sqrt(x*x+y*y+z*z+w*w) return [x/N,y/N,z/N,w/N]; } //returns plane as array [X,Y,Z,D] GLGE.rayToPlane=function(origin,dir){ var dirnorm=GLGE.toUnitVec3(dir); return [dirnorm[0],dirnorm[1],dirnorm[2],GLGE.dotVec3(origin,dirnorm)]; } GLGE.rayIntersectPlane=function(origin,dir,plane){ var planeN=[plane[0],plane[1],plane[2]]; var planeD=plane[3]; var vdir=GLGE.dotVec3(planeN,dir); if(vdir<=0){ //ray in wrong direction return false; } var vo=-(GLGE.dotVec3(planeN,origin)+planeD); var t=vo/vdir; if(t<=0){ return false; } return GLGE.addVec3(origin,GLGE.scaleVec3(dir,t)); } //assumes perspective projection GLGE.screenToDirection=function(x,y,width,height,proj){ xcoord = -( ( ( 2 * x ) / width ) - 1 ) / proj[0]; ycoord =( ( ( 2 * y ) / height ) - 1 ) / proj[5]; zcoord = 1; return GLGE.toUnitVec3([xcoord,ycoord,zcoord]); } GLGE.BoundingVolume=function(minX,maxX,minY,maxY,minZ,maxZ){ this.limits=[minX,maxX,minY,maxY,minZ,maxZ]; this.calcProps(); } GLGE.BoundingVolume.prototype.getCornerPoints=function(){ return this.points; } //returns the radius of a bounding sphere GLGE.BoundingVolume.prototype.getSphereRadius=function(){ return this.radius; } //returns the center of a bounding volume GLGE.BoundingVolume.prototype.getCenter=function(){ return this.center; } GLGE.BoundingVolume.prototype.isNull=function(){ return this.limits[0]==0&&this.limits[1]==0&&this.limits[2]==0&&this.limits[3]==0&&this.limits[4]==0&&this.limits[5]==0; } //adds an additional bounding volume to resize the current and returns the result GLGE.BoundingVolume.prototype.addBoundingVolume=function(vol){ if (this.isNull()) { this.limits[0]=vol.limits[0]; this.limits[1]=vol.limits[1]; this.limits[2]=vol.limits[2]; this.limits[3]=vol.limits[3]; this.limits[4]=vol.limits[4]; this.limits[5]=vol.limits[5]; } else if (!vol.isNull()) { this.limits[0]=Math.min(vol.limits[0],this.limits[0]); this.limits[2]=Math.min(vol.limits[2],this.limits[2]); this.limits[4]=Math.min(vol.limits[4],this.limits[4]); this.limits[1]=Math.max(vol.limits[1],this.limits[1]); this.limits[3]=Math.max(vol.limits[3],this.limits[3]); this.limits[5]=Math.max(vol.limits[5],this.limits[5]); } this.calcProps(); } //scales a volume based on a transform matrix GLGE.BoundingVolume.prototype.applyMatrix=function(matrix){ var coord0=GLGE.mulMat4Vec4(matrix,[this.limits[0],this.limits[2],this.limits[4],1]); var coord1=GLGE.mulMat4Vec4(matrix,[this.limits[1],this.limits[2],this.limits[4],1]); var coord2=GLGE.mulMat4Vec4(matrix,[this.limits[0],this.limits[3],this.limits[4],1]); var coord3=GLGE.mulMat4Vec4(matrix,[this.limits[1],this.limits[3],this.limits[4],1]); var coord4=GLGE.mulMat4Vec4(matrix,[this.limits[0],this.limits[2],this.limits[5],1]); var coord5=GLGE.mulMat4Vec4(matrix,[this.limits[1],this.limits[2],this.limits[5],1]); var coord6=GLGE.mulMat4Vec4(matrix,[this.limits[0],this.limits[3],this.limits[5],1]); var coord7=GLGE.mulMat4Vec4(matrix,[this.limits[1],this.limits[3],this.limits[5],1]); this.limits[0]=Math.min(coord0[0],coord1[0],coord2[0],coord3[0],coord4[0],coord5[0],coord6[0],coord7[0]); this.limits[1]=Math.max(coord0[0],coord1[0],coord2[0],coord3[0],coord4[0],coord5[0],coord6[0],coord7[0]); this.limits[2]=Math.min(coord0[1],coord1[1],coord2[1],coord3[1],coord4[1],coord5[1],coord6[1],coord7[1]); this.limits[3]=Math.max(coord0[1],coord1[1],coord2[1],coord3[1],coord4[1],coord5[1],coord6[1],coord7[1]); this.limits[4]=Math.min(coord0[2],coord1[2],coord2[2],coord3[2],coord4[2],coord5[2],coord6[2],coord7[2]); this.limits[5]=Math.max(coord0[2],coord1[2],coord2[2],coord3[2],coord4[2],coord5[2],coord6[2],coord7[2]); this.calcProps(); } GLGE.BoundingVolume.prototype.calcProps=function(){ var minX=this.limits[0]; var maxX=this.limits[1]; var minY=this.limits[2]; var maxY=this.limits[3]; var minZ=this.limits[4]; var maxZ=this.limits[5]; this.points=[ [minX,minY,minZ], [maxX,minY,minZ], [minX,maxY,minZ], [maxX,maxY,minZ], [minX,minY,maxZ], [maxX,minY,maxZ], [minX,maxY,maxZ], [maxX,maxY,maxZ] ]; this.center=[(this.limits[1]-this.limits[0])/2+this.limits[0],(this.limits[3]-this.limits[2])/2+this.limits[2],(this.limits[5]-this.limits[4])/2+this.limits[4]]; var dx=this.limits[0]-this.center[0]; var dy=this.limits[2]-this.center[1]; var dz=this.limits[4]-this.center[2]; this.radius=Math.sqrt(dx*dx+dy*dy+dz*dz); } GLGE.BoundingVolume.prototype.clone=function(){ return new GLGE.BoundingVolume(this.limits[0],this.limits[1],this.limits[2],this.limits[3],this.limits[4],this.limits[5]); } GLGE.BoundingVolume.prototype.toString=function(){ return this.limits.toString(); } //creates the bounding planes for the cameraViewProjectionMatrix GLGE.cameraViewProjectionToPlanes=function(cvp){ var cvpinv=GLGE.inverseMat4(cvp); var mulMat4Vec4=GLGE.mulMat4Vec4; var subVec3=GLGE.subVec3; var crossVec3=GLGE.crossVec3; var toUnitVec3=GLGE.toUnitVec3; var dotVec3=GLGE.dotVec3 var nbl=mulMat4Vec4(cvpinv,[-1,-1,-1,1]); var nbr=mulMat4Vec4(cvpinv,[1,-1,-1,1]); var fbl=mulMat4Vec4(cvpinv,[-1,-1,1,1]); var ntr=mulMat4Vec4(cvpinv,[1,1,-1,1]); var ftr=mulMat4Vec4(cvpinv,[1,1,1,1]); var ftl=mulMat4Vec4(cvpinv,[-1,1,1,1]); nbl=[nbl[0]/nbl[3],nbl[1]/nbl[3],nbl[2]/nbl[3]]; nbr=[nbr[0]/nbr[3],nbr[1]/nbr[3],nbr[2]/nbr[3]]; fbl=[fbl[0]/fbl[3],fbl[1]/fbl[3],fbl[2]/fbl[3]]; ntr=[ntr[0]/ntr[3],ntr[1]/ntr[3],ntr[2]/ntr[3]]; ftr=[ftr[0]/ftr[3],ftr[1]/ftr[3],ftr[2]/ftr[3]]; ftl=[ftl[0]/ftl[3],ftl[1]/ftl[3],ftl[2]/ftl[3]]; var nearnorm=toUnitVec3(crossVec3(subVec3(ntr,nbr),subVec3(nbl,nbr))); var farnorm=toUnitVec3(crossVec3(subVec3(ftl,fbl),subVec3(ftr,fbl))); var leftnorm=toUnitVec3(crossVec3(subVec3(nbl,fbl),subVec3(ftl,fbl))); var rightnorm=toUnitVec3(crossVec3(subVec3(ftr,ntr),subVec3(ntr,nbr))); var topnorm=toUnitVec3(crossVec3(subVec3(ftl,ntr),subVec3(ntr,ftr))); var bottomnorm=toUnitVec3(crossVec3(subVec3(nbl,nbr),subVec3(fbl,nbl))); nearnorm.push(dotVec3(nearnorm,nbl)); farnorm.push(dotVec3(farnorm,fbl)); leftnorm.push(dotVec3(leftnorm,nbl)); rightnorm.push(dotVec3(rightnorm,nbr)); topnorm.push(dotVec3(topnorm,ftr)); bottomnorm.push(dotVec3(bottomnorm,nbl)); //might be worth calulating the frustum sphere for optimization at this point! return [nearnorm,farnorm,leftnorm,rightnorm,topnorm,bottomnorm]; } //Checks if sphere is within frustum planes //sphere passed as [center.x,center.y,center.z,radius] GLGE.sphereInFrustumPlanes=function(sphere,planes){ var sphere0=sphere[0];var sphere1=sphere[1]; var sphere2=sphere[2];var sphere3=sphere[3]; var plane0=planes[0];var plane1=planes[1]; var plane2=planes[2];var plane3=planes[3]; var plane4=planes[4];var plane5=planes[5]; if(sphere0*plane0[0] + sphere1*plane0[1] + sphere2*plane0[2] - plane0[3] - sphere3 > 0 || sphere0*plane1[0] + sphere1*plane1[1] + sphere2*plane1[2] - plane1[3] - sphere3 > 0 || sphere0*plane2[0] + sphere1*plane2[1] + sphere2*plane2[2] - plane2[3] - sphere3 > 0 || sphere0*plane3[0] + sphere1*plane3[1] + sphere2*plane3[2] - plane3[3] - sphere3 > 0 || sphere0*plane4[0] + sphere1*plane4[1] + sphere2*plane4[2] - plane4[3] - sphere3 > 0 || sphere0*plane5[0] + sphere1*plane5[1] + sphere2*plane5[2] - plane5[3] - sphere3 > 0){ return false; }else{ return true; } } //checks if cube points are within the frustum planes GLGE.pointsInFrustumPlanes=function(points,planes){ var plane0=planes[0];var plane1=planes[1]; var plane2=planes[2];var plane3=planes[3]; var plane4=planes[4];var plane5=planes[5]; var x, y, z; for(var i=0; i 0 && x*plane1[0] + y*plane1[1] + z*plane1[2] - plane1[3] > 0 && x*plane2[0] + y*plane2[1] + z*plane2[2] - plane3[3] > 0 && x*plane3[0] + y*plane3[1] + z*plane3[2] - plane4[3] > 0 && x*plane4[0] + y*plane4[1] + z*plane4[2] - plane4[3] > 0 && x*plane5[0] + y*plane5[1] + z*plane5[2] - plane5[3] > 0){ return false; } } return true; } //get projection matrix for a directional light GLGE.getDirLightProjection=function(cvp,light,projectedDistance,distance){ var pointTransform=GLGE.mulMat4(light,GLGE.inverseMat4(cvp)); var min=[0,0,0]; var max=[0,0,0]; for(var x=0;x<2;x++){ for(var y=0;y<2;y++){ for(var z=0;z<2;z++){ var vec=GLGE.mulMat4Vec4(pointTransform,[x*2-1,y*2-1,z*projectedDistance,1]); vec[0]=vec[0]/vec[3];vec[1]=vec[1]/vec[3];vec[2]=vec[2]/vec[3]; min[0]=min[0] > vec[0] ? vec[0] : min[0]; min[1]=min[1] > vec[1] ? vec[1] : min[1]; max[0]=max[0] < vec[0] ? vec[0] : max[0]; max[1]=max[1] < vec[1] ? vec[1] : max[1]; max[2]=max[2] < vec[2] ? vec[2] : max[2]; } } } var mat=GLGE.makeOrtho(min[0],max[0],min[1],max[1],0.01,+distance); //mat[0]*=8; //mat[5]*=8; //var mat=GLGE.makeFrustum(min[0],max[0],min[1],max[1],500,0.01); //var mat=GLGE.makeOrtho(-30,30,-30,30,0.01,500); //alert(mat); return mat }; function GLGE_mathUnitTest() { var a=GLGE.Vec([1,2,3,4]); var b=GLGE.Vec4(GLGE.getVec4(a,3), GLGE.get1basedVec4(a,3), GLGE.getVec4(a,1), GLGE.getVec4(a,0)); var c=GLGE.identMatrix(); var d=GLGE.mulMat4Vec4(c,b); if (GLGE.getVec4(d,0)!=4|| GLGE.getVec4(d,1)!=3|| GLGE.getVec4(d,2)!=2|| GLGE.getVec4(d,3)!=1) { throw "Unit Test 1 failed MatVecMul "+d; } var m=GLGE.Mat4([3,4,5,0,.5,.75,0,0,.75,.5,0,0,.25,.25,1,1]); var m1=GLGE.Mat4([2,1,8,2,1,4,3,2,1,.5,6.5,2,8,3,1,.25]); var mm1=GLGE.mulMat4(m,m1); var am1=GLGE.Mat4([15,21.5,68.5,24, 1.75,3.5,6.25,2.5, 2,2.75,7.5,2.5, 9.75,4.75,10.25,3.25]); for (var i=0;i<4;++i) { for (var j=0;j<4;++j) { var diff=GLGE.getMat4(mm1,i,j)-GLGE.getMat4(am1,i,j); if (diff<.000001&&diff>-.000001) { }else { throw "Unit Test 1 failed Multiplication "+GLGE.getMat4(mm1,i,j)+" != "+GLGE.getMat4(am1,i,j); } } } var inv = GLGE.inverseMat4(m); var k = GLGE.mulMat4(m,inv); var l = GLGE.mulMat4(inv,m); for (var i=0;i<4;++i) { for (var j=0;j<4;++j) { var diff=GLGE.getMat4(k,i,j)-GLGE.getMat4(c,i,j); if (diff<.0001&&diff>-.0001) { }else { throw "Unit Test 1 failed Inverse "+GLGE.getMat4(k,i,j)+" != "+GLGE.getMat4(c,i,j); } } } } GLGE_mathUnitTest() ; })(GLGE); /* GLGE WebGL Graphics Engine Copyright (c) 2010, Paul Brunt All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of GLGE nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL PAUL BRUNT BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /** * @fileOverview * @name glge.js * @author me@paulbrunt.co.uk */ if(typeof(GLGE) == "undefined"){ /** * @namespace Holds the functionality of the library */ GLGE = {}; } (function(GLGE){ //speed ups parsing a float that is already a float is expensive! var parseFloat2=function(val){ if(typeof val!="number") return parseFloat(val); else return val; } /** * Function to augment one object with another * @param {object} obj1 Source Object * @param {object} obj2 Destination Object */ GLGE.augment=function(obj1,obj2){ obj2.prototype.baseclass = obj1; for(var proto in obj1.prototype){ if(!obj2.prototype[proto]) // do not overwrite functions of the derived objects obj2.prototype[proto]=obj1.prototype[proto]; else // Attach those to the baseclass instead. Use 'call(this)' to call baseclass methods obj2.prototype.baseclass[proto]=obj1.prototype[proto]; } } /** * Moves all GLGE function to global **/ GLGE.makeGlobal=function(){ for(var key in GLGE){ window[key]=GLGE[key]; } } GLGE.New=function(createclass){ if(GLGE[createclass].prototype.className!=""){ return new GLGE[createclass](); }else{ return false; } } GLGE.now = function(){ return parseInt(new Date().getTime()); }; /** * @constant * @description Enumeration for TRUE */ GLGE.TRUE=1; /** * @constant * @description Enumeration for FALSE */ GLGE.FALSE=0; /** * @constant * @description Enumeration for global refrance frame */ GLGE.GLOBAL=0; /** * @constant * @description Enumeration for local refrance frame */ GLGE.LOCAL=1; /** * @constant * @description Enumeration for tri rendering */ GLGE.DRAW_TRIS=1; /** * @constant * @description Enumeration for line rendering */ GLGE.DRAW_LINES=2; /** * @constant * @description Enumeration for line loop rendering */ GLGE.DRAW_LINELOOPS=3; /** * @constant * @description Enumeration for line loop rendering */ GLGE.DRAW_LINESTRIPS=4; /** * @constant * @description Enumeration for point rendering */ GLGE.DRAW_POINTS=5; /** * @constant * @description Enumeration for point rendering */ GLGE.DRAW_TRIANGLESTRIP=6; /** * @constant * @description Enumeration for rendering using default shader */ GLGE.RENDER_DEFAULT=0; /** * @constant * @description Enumeration for rendering using shadow shader */ GLGE.RENDER_SHADOW=1; /** * @constant * @description Enumeration for rendering using pick shader */ GLGE.RENDER_PICK=2; /** * @constant * @description Enumeration for rendering using normal shader */ GLGE.RENDER_NORMAL=3; /** * @constant * @description Enumeration for emit rendering */ GLGE.RENDER_EMIT=4; /** * @constant * @description Enumeration for depth rendering */ GLGE.RENDER_DEPTH=5; /** * @constant * @description Enumeration for no rendering */ GLGE.RENDER_NULL=6; /** * @constant * @description Enumeration for box bound text picking */ GLGE.TEXT_BOXPICK=1; /** * @constant * @description Enumeration for text bound text picking */ GLGE.TEXT_TEXTPICK=2; /** * @constant * @description Enumeration for euler rotaions mode */ GLGE.P_EULER=1; /** * @constant * @description Enumeration for quaternions mode */ GLGE.P_QUAT=2; /** * @constant * @description Enumeration for matrix rotation mode */ GLGE.P_MATRIX=3; /** * @constant * @description Enumeration for no value */ GLGE.NONE=0; /** * @constant * @description Enumeration for X-Axis */ GLGE.XAXIS=1; /** * @constant * @description Enumeration for Y-Axis */ GLGE.YAXIS=2; /** * @constant * @description Enumeration for Z-Axis */ GLGE.ZAXIS=3; /** * @constant * @description Enumeration for +X-Axis */ GLGE.POS_XAXIS=1; /** * @constant * @description Enumeration for -X-Axis */ GLGE.NEG_XAXIS=2; /** * @constant * @description Enumeration for +Y-Axis */ GLGE.POS_YAXIS=3; /** * @constant * @description Enumeration for -Y-Axis */ GLGE.NEG_YAXIS=4; /** * @constant * @description Enumeration for +Z-Axis */ GLGE.POS_ZAXIS=5; /** * @constant * @description Enumeration for -Z-Axis */ GLGE.NEG_ZAXIS=6; GLGE.ZERO="ZERO"; GLGE.ONE="ONE"; GLGE.SRC_COLOR="SRC_COLOR"; GLGE.ONE_MINUS_SRC_COLOR="ONE_MINUS_SRC_COLOR"; GLGE.SRC_ALPHA="SRC_ALPHA"; GLGE.ONE_MINUS_SRC_ALPHA="ONE_MINUS_SRC_ALPHA"; GLGE.DST_ALPHA="DST_ALPHA"; GLGE.ONE_MINUS_DST_ALPHA="ONE_MINUS_DST_ALPHA"; /** * @constant * @description Linear blending function */ GLGE.LINEAR_BLEND=function(value){ return value; } /** * @constant * @description Quadratic blending function */ GLGE.QUAD_BLEND=function(value){ return value*value; } /** * @constant * @description Special blending function */ GLGE.SPECIAL_BLEND=function(value){ value=value*(2-value); return value*value; } GLGE.error=function(error){ if (console&&console.log) console.log("GLGE error: "+error); //do not use a modal dialog to indicate this users can override GLGE.error if they desire }; GLGE.warning=function(warning){ if (console&&console.log) console.log("GLGE warning: "+warning); //do not use a modal dialog to indicate this users can override GLGE.warning if they desire }; /** * @namespace Holds the global asset store */ GLGE.Assets={}; GLGE.Assets.assets={}; //don't need to register assets unless we are using network or webworkers GLGE.REGISTER_ASSETS=true; GLGE.Assets.createUUID=function(){ var data=["0","1","2","3","4","5","6","7","8","9","A","B","C","D","E","F"]; var data2=["8","9","A","B"]; uuid=""; for(var i=0;i<38;i++){ switch(i){ case 8:uuid=uuid+"-";break; case 13:uuid=uuid+"-";break; case 18:uuid=uuid+"-";break; case 14:uuid=uuid+"4";break; case 19:uuid=uuid+data2[Math.round(Math.random()*3)];break; default:uuid=uuid+data[Math.round(Math.random()*15)];break; } } return uuid; } /** * @function registers a new asset */ GLGE.Assets.registerAsset=function(obj,uid){ if(typeof uid=="object"){ if(obj._) obj._(uid); uid=uid.uid; } if(!uid){ uid=GLGE.Assets.createUUID(); }; obj.uid=uid; if(GLGE.REGISTER_ASSETS){ GLGE.Assets.assets[uid]=obj; } } /** * @function removes an asset */ GLGE.Assets.unregisterAsset=function(uid){ delete GLGE.Assets.assets[uid]; } /** * @function finds an asset by uid */ GLGE.Assets.get=function(uid){ var value=GLGE.Assets.assets[uid]; if(value){ return value; }else{ return false; } } /** * @function hashing function * @private */ GLGE.DJBHash=function(str){ var hash = 5381; for(var i = 0; i < str.length; i++){ hash = ((hash << 5) + hash) + str.charCodeAt(i); } return hash; } /** * @function check if shader is already created if not then create it * @private */ GLGE.getGLShader=function(gl,type,str){ var hash=GLGE.DJBHash(str); if(!gl.shaderCache) gl.shaderCache={}; if(!gl.shaderCache[hash]){ var shader=gl.createShader(type); gl.shaderSource(shader, str); gl.compileShader(shader); if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) { try { GLGE.error(gl.getShaderInfoLog(shader)); return; } catch (e) { /* Firefox hack: Assume no error if there was no shader log. */ } } gl.shaderCache[hash]=shader; } return gl.shaderCache[hash]; } var progIdx=0; /** * @function tries to re use programs * @private */ GLGE.getGLProgram=function(gl,vShader,fShader){ if(!gl.programCache) gl.programCache=[]; var programCache=gl.programCache; for(var i=0; i1){ if(this.loop){ frame=((parseFloat(now)-parseFloat(this.animationStart))/1000*this.frameRate)%(this.animFrames-1)+1+this.startFrame; }else{ frame=((parseFloat(now)-parseFloat(this.animationStart))/1000*this.frameRate)+1+this.startFrame; if(frame>=(this.animFrames+this.startFrame)){ frame=this.animFrames; } } }else{ frame=1; } return parseInt(frame); } /** * Sets the start frame for the animation overriding the animation default * @param {number} startFrame the start frame */ GLGE.Animatable.prototype.setStartFrame=function(startFrame,blendTime,loop){ this.loop=loop; var starttime=GLGE.now(); if(!blendTime) blendTime=0; if(blendTime>0){ if(this.animation){ this.blendInitValues=this.getInitialValues(this.animation,starttime); this.blendTime=blendTime; } } this.animationStart=starttime; this.pauseTime=starttime; this.lastFrame=null; this.animFinished=false; this.startFrame=startFrame; if(this.children){ for(var i=0;i0){ this.blendInitValues=this.getInitialValues(animationVector,starttime); this.blendTime=blendDuration; } this.animFrames=null; this.startFrame=null; this.animationStart=starttime; this.pauseTime=starttime; this.lastFrame=null; this.animation=animationVector; this.animFinished=false; return this; } /** * Gets the animation vector of this object * @returns {AnimationVector} */ GLGE.Animatable.prototype.getAnimation=function(){ return this.animation; } /** * Sets the frame rate of the animation * @param {number} value the frame rate to set */ GLGE.Animatable.prototype.setFrameRate=function(value){ this.frameRate=value; if (this.children) { for (var i = 0; i < this.children.length; i++) { if (this.children[i].setFrameRate) { this.children[i].setFrameRate(value); } } } return this; } /** * Gets the frame rate of the animation * @return {number} the current frame rate */ GLGE.Animatable.prototype.getFrameRate=function(){ return this.frameRate; } /** * Sets the loop flag to GLGE.TRUE or GLGE.FALSE * @param {boolean} value */ GLGE.Animatable.prototype.setLoop=function(value){ this.loop=value; return this; } /** * Gets the loop flag * @return {boolean} */ GLGE.Animatable.prototype.getLoop=function(){ return this.loop; } /** * @function is looping? @see GLGE.Animatable#getLoop */ GLGE.Animatable.prototype.isLooping=GLGE.Animatable.prototype.getLoop; /** * Sets the paused flag to GLGE.TRUE or GLGE.FALSE * @param {boolean} value */ GLGE.Animatable.prototype.setPaused=function(value){ if(value && !this.paused) this.pauseTime=GLGE.now(); else if(!value && this.paused) this.animationStart=this.animationStart+(GLGE.now()-this.pauseTime); this.paused=value; return this; } /** * Gets the paused flag * @return {boolean} */ GLGE.Animatable.prototype.getPaused=function(){ return this.paused; } /** * Toggles the paused flag * @return {boolean} returns the resulting flag state */ GLGE.Animatable.prototype.togglePaused=function(){ this.setPaused(!this.getPaused()); return this.paused; } })(GLGE); /* GLGE WebGL Graphics Engine Copyright (c) 2010, Paul Brunt All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of GLGE nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL PAUL BRUNT BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /** * @fileOverview * @name glge_document.js * @author me@paulbrunt.co.uk */ (function(GLGE){ /** * @class Document class to load scene, object, mesh etc from an external XML file * @param {string} url URL of the resource to load */ GLGE.Document=function(){ this.listeners=[]; this.documents=[]; } GLGE.Document.prototype.listeners=null; GLGE.Document.prototype.documents=null; GLGE.Document.prototype.rootURL=null; GLGE.Document.prototype.loadCount=0; GLGE.Document.prototype.version=0; GLGE.Document.prototype.preloader=null; /** * This is just a fix for a bug in webkit * @param {string} id the id name to get * @returns {object} node with teh specified id * @private */ GLGE.Document.prototype.getElementById=function(id){ var tags=this.getElementsByTagName("*"); for(var i=0; i0) return this.getDefault(ele); //as of GLGE XML 1.0 the mesh is nothing special! if(!ele.object){ ele.object=new GLGE.Mesh(); this.setProperties(ele); var child=ele.firstChild; while(child){ switch(child.tagName){ case "positions": ele.object.setPositions(this.parseArray(child)); break; case "normals": ele.object.setNormals(this.parseArray(child)); break; case "uv1": ele.object.setUV(this.parseArray(child)); break; case "uv2": ele.object.setUV2(this.parseArray(child)); break; case "faces": ele.object.setFaces(this.parseArray(child)); break; case "color": ele.object.setVertexColors(this.parseArray(child)); break; case "joint_names": var names=this.parseArray(child); var jointObjects=[]; for(var i=0;i0) || object.className=="Light"){ var root=object; while(root.parent) root=root.parent; root.updateAllPrograms(); } if(object.addEventListener){ object.addEventListener("shaderupdate",function(){ var root=this; while(root.parent) root=root.parent; root.updateAllPrograms(); }); object.addEventListener("downloadComplete",this.downloadComplete); } this.fireEvent("childAdded",{obj:object}); if(object.fireEvent) object.fireEvent("appened",{obj:this}); this.fireEvent("childAdded",{obj:object}); //fire child added event for all parents as well var o=this; while(o=o.parent) o.fireEvent("childAdded",{obj:object,target:this}); return this; } GLGE.Group.prototype.addObject=GLGE.Group.prototype.addChild; GLGE.Group.prototype.addObjectInstance=GLGE.Group.prototype.addChild; GLGE.Group.prototype.addGroup=GLGE.Group.prototype.addChild; GLGE.Group.prototype.addLight=GLGE.Group.prototype.addChild; GLGE.Group.prototype.addText=GLGE.Group.prototype.addChild; GLGE.Group.prototype.addSkeleton=GLGE.Group.prototype.addChild; GLGE.Group.prototype.addCamera=GLGE.Group.prototype.addChild; GLGE.Group.prototype.addWavefront=GLGE.Group.prototype.addChild; /** * Removes an object or sub group from this group * @param {object} object the item to remove */ GLGE.Group.prototype.removeChild=function(object){ for(var i=0;i0) GLGE.Message.loadMessages(); } })(GLGE);/* GLGE WebGL Graphics Engine Copyright (c) 2010, Paul Brunt All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of GLGE nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL PAUL BRUNT BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /** * @fileOverview * @name glge_action.js * @author me@paulbrunt.co.uk */ (function(GLGE){ /** * @class Class to describe and action on a skeleton * @param {string} uid a unique reference string for this object * @augments GLGE.QuickNotation * @augments GLGE.JSONLoader */ GLGE.Action=function(uid){ this.channels=[]; GLGE.Assets.registerAsset(this,uid); }; GLGE.augment(GLGE.QuickNotation,GLGE.Action); GLGE.augment(GLGE.JSONLoader,GLGE.Action); /** * @name Action#animFinished * @event * @param {object} data */ GLGE.augment(GLGE.Events,GLGE.Action); /** * Starts playing the action */ GLGE.Action.prototype.start=function(blendTime,loop,names){ if(!loop) loop=false; if(!blendTime) blendTime=0; var channels=this.channels; var start=GLGE.now(); this.animFinished=false; for(var i=0;ithis.keyFrames[startKey].x)){ preStartKey=startKey; startKey=i; }else if(this.keyFrames[i].x<=frame && (preStartKey==undefined || this.keyFrames[i].x>this.keyFrames[preStartKey].x)){ preStartKey=i; } if(this.keyFrames[i].x>frame && (endKey==undefined || this.keyFrames[i].x<=this.keyFrames[endKey].x)){ preEndKey=endKey; endKey=i; }else if(this.keyFrames[i].x>frame && (preEndKey==undefined || this.keyFrames[i].x<=this.keyFrames[preEndKey].x)){ preEndKey=i; } } if(startKey==undefined){ startKey=endKey; endKey=preEndKey; } if(endKey==undefined){ endKey=startKey; startKey=preStartKey; } if(this.keyFrames[startKey] instanceof GLGE.BezTriple && this.keyFrames[endKey] instanceof GLGE.BezTriple){ var C1=this.coord(this.keyFrames[startKey].x,this.keyFrames[startKey].y); var C2=this.coord(this.keyFrames[startKey].x3,this.keyFrames[startKey].y3); var C3=this.coord(this.keyFrames[endKey].x1,this.keyFrames[endKey].y1); var C4=this.coord(this.keyFrames[endKey].x,this.keyFrames[endKey].y); return this.atX(frame,C1,C2,C3,C4).y; } if(this.keyFrames[startKey] instanceof GLGE.LinearPoint && this.keyFrames[endKey] instanceof GLGE.BezTriple){ var C1=this.coord(this.keyFrames[startKey].x,this.keyFrames[startKey].y); var C2=this.coord(this.keyFrames[endKey].x1,this.keyFrames[endKey].y1); var C3=this.coord(this.keyFrames[endKey].x1,this.keyFrames[endKey].y1); var C4=this.coord(this.keyFrames[endKey].x,this.keyFrames[endKey].y); return this.atX(frame,C1,C2,C3,C4).y; } if(this.keyFrames[startKey] instanceof GLGE.BezTriple && this.keyFrames[endKey] instanceof GLGE.LinearPoint){ var C1=this.coord(this.keyFrames[startKey].x,this.keyFrames[startKey].y); var C2=this.coord(this.keyFrames[startKey].x3,this.keyFrames[startKey].y3); var C3=this.coord(this.keyFrames[startKey].x3,this.keyFrames[startKey].y3); var C4=this.coord(this.keyFrames[endKey].x,this.keyFrames[endKey].y); return this.atX(frame,C1,C2,C3,C4).y; } if(this.keyFrames[startKey] instanceof GLGE.LinearPoint && this.keyFrames[endKey] instanceof GLGE.LinearPoint){ var value=(frame-this.keyFrames[startKey].x)*(this.keyFrames[endKey].y-this.keyFrames[startKey].y)/(this.keyFrames[endKey].x-this.keyFrames[startKey].x)+this.keyFrames[startKey].y; return value; } if(this.keyFrames[startKey] instanceof GLGE.StepPoint){ return this.keyFrames[startKey].y } if(!this.keyFrames.preStartKey) this.keyFrames.preStartKey=this.keyFrames[0].y; this.caches[frame]=this.keyFrames.preStartKey; return this.caches[frame]; }; /** * Function used to calculate bezier curve * @private */ GLGE.AnimationCurve.prototype.B1=function(t) { return t*t*t }; /** * Function used to calculate bezier curve * @private */ GLGE.AnimationCurve.prototype.B2=function(t) { return 3*t*t*(1-t) }; /** * Function used to calculate bezier curve * @private */ GLGE.AnimationCurve.prototype.B3=function(t) { return 3*t*(1-t)*(1-t) }; /** * Function used to calculate bezier curve * @private */ GLGE.AnimationCurve.prototype.B4=function(t) { return (1-t)*(1-t)*(1-t) }; /** * Gets the value of a bezier curve at a given point * @private */ GLGE.AnimationCurve.prototype.getBezier=function(t,C1,C2,C3,C4) { var pos = {}; pos.x = C1.x*this.B1(t) + C2.x*this.B2(t) + C3.x*this.B3(t) + C4.x*this.B4(t); pos.y = C1.y*this.B1(t) + C2.y*this.B2(t) + C3.y*this.B3(t) + C4.y*this.B4(t); return pos; }; /** * Solves cubic equation to get the parametic value of the curve at a specified point * @private */ GLGE.AnimationCurve.prototype.Quad3Solve=function(a,b,c,d){ ref=a+"-"+b+"-"+"-"+c+"-"+d; if(this.solutions[ref]){ return this.solutions[ref]; } else { b /= a;c /= a;d /= a; var q, r, d1, s, t, t1, r13; q = (3.0*c - (b*b))/9.0; r = -(27.0*d) + b*(9.0*c - 2.0*(b*b)); r /= 54.0; t1 = (b/3.0); discrim = q*q*q + r*r; result=[]; if (discrim > 0) { // one real, two complex s = r + Math.sqrt(discrim); s = ((s < 0) ? -Math.pow(-s, (1.0/3.0)) : Math.pow(s, (1.0/3.0))); t = r - Math.sqrt(discrim); t = ((t < 0) ? -Math.pow(-t, (1.0/3.0)) : Math.pow(t, (1.0/3.0))); result[0] = -t1 + s + t; t1 = t1 + (s + t)/2.0; result[1] = result[2] = -t1; t1 = Math.sqrt(3.0)*(-t + s)/2; } else if (discrim == 0){ // All roots real r13 = ((r < 0) ? -Math.pow(-r,(1.0/3.0)) : Math.pow(r,(1.0/3.0))); result[1] = -t1 + 2.0*r13; result[1] = result[2] = -(r13 + t1); } else { q = -q; d1 = q*q*q; d1 = Math.acos(r/Math.sqrt(1)); r13 = 2.0*Math.sqrt(q); result[0] = -t1 + r13*Math.cos(d1/3.0); result[1] = -t1 + r13*Math.cos((d1 + 2.0*Math.PI)/3.0); result[2] = -t1 + r13*Math.cos((d1 + 4.0*Math.PI)/3.0); } var toreturn=false; //determine which is the correct result if(result[0]>=0 && result[0]<=1) toreturn=result[0]; if(!toreturn && result[1]>=0 && result[1]<=1) toreturn=result[1]; if(!toreturn && result[2]>=0 && result[2]<=1) toreturn=result[2]; //cache result for next time this.solutions[ref]=toreturn; return toreturn; } }; /** * Get the value of the a single bezier curve * @param {Number} x xcoord of point to get * @param {Number} C1 First bezier control point * @param {Number} C2 Second bezier control point * @param {Number} C3 Third bezier control point * @param {Number} C4 Forth bezier control point * @returns {Number} The value of the curve at the given x */ GLGE.AnimationCurve.prototype.atX=function(x,C1,C2,C3,C4){ a=C1.x-C2.x*3+C3.x*3-C4.x; b=C2.x*3-C3.x*6+C4.x*3; c=C3.x*3-C4.x*3; d=C4.x-x; return this.getBezier(this.Quad3Solve(a,b,c,d),C1,C2,C3,C4); }; })(GLGE); /* GLGE WebGL Graphics Engine Copyright (c) 2010, Paul Brunt All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of GLGE nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL PAUL BRUNT BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /** * @fileOverview * @name glge_animationvector.js * @author me@paulbrunt.co.uk */ (function(GLGE){ /** * @class The AnimationVectors class allows you to specify the 2D Animation curves that define specific channels of animation within the engine. * @augments GLGE.QuickNotation * @augments GLGE.JSONLoader */ GLGE.AnimationVector=function(uid){ this.curves={}; GLGE.Assets.registerAsset(this,uid); } GLGE.augment(GLGE.QuickNotation,GLGE.AnimationVector); GLGE.augment(GLGE.JSONLoader,GLGE.AnimationVector); GLGE.AnimationVector.prototype.curves={}; GLGE.AnimationVector.prototype.frames=250; GLGE.AnimationVector.prototype.startFrame=0; /** * Adds an Animation Curve to a channel * @param {String} channel The name of the curve to be added * @param {GLGE.AnimationCurve} curve The animation curve to add */ GLGE.AnimationVector.prototype.addAnimationCurve=function(curve){ this.curves[curve.channel]=curve; return this; } /** * Removes an Animation Curve form a channel * @param {String} channel The name of the curve to be removed */ GLGE.AnimationVector.prototype.removeAnimationCurve=function(name){ delete(this.curves[name]); } /** * Sets the number of frames in the animation * @param {number} value The number of frames in the animation */ GLGE.AnimationVector.prototype.setFrames=function(value){ this.frames=value; return this; } /** * Sets the number of frames in the animation * @returns {number} The number of frames in the animation */ GLGE.AnimationVector.prototype.getFrames=function(){ return this.frames; } /** * Sets the start frame * @param {number} value The starting frame for the animation */ GLGE.AnimationVector.prototype.setStartFrame=function(value){ this.startFrame=value; return this; } /** * Gets the start fames * @returns {number} The starting frame for the animation */ GLGE.AnimationVector.prototype.getStartFrame=function(){ return this.startFrame; } })(GLGE); /* GLGE WebGL Graphics Engine Copyright (c) 2010, Paul Brunt All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of GLGE nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL PAUL BRUNT BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /** * @fileOverview * @name glge_animationpoints.js * @author me@paulbrunt.co.uk */ (function(GLGE){ /** * @class A bezier class to add points to the Animation Curve * @param {string} uid a unique string to identify this object * @augments GLGE.QuickNotation * @augments GLGE.JSONLoader */ GLGE.BezTriple=function(uid){ GLGE.Assets.registerAsset(this,uid); }; GLGE.augment(GLGE.QuickNotation,GLGE.BezTriple); GLGE.augment(GLGE.JSONLoader,GLGE.BezTriple); GLGE.BezTriple.prototype.className="BezTriple"; /** * set the x1-coord * @param {number} x x1-coord control point */ GLGE.BezTriple.prototype.setX1=function(x){ this.x1=parseFloat(x); return this; }; /** * set the y1-coord * @param {number} y y1-coord control point */ GLGE.BezTriple.prototype.setY1=function(y){ this.y1=parseFloat(y); return this; }; /** * set the x2-coord * @param {number} x x2-coord control point */ GLGE.BezTriple.prototype.setX2=function(x){ this.x=parseFloat(x); return this; }; /** * set the y2-coord * @param {number} y y2-coord control point */ GLGE.BezTriple.prototype.setY2=function(y){ this.y=parseFloat(y); return this; }; /** * set the x3-coord * @param {number} x x3-coord control point */ GLGE.BezTriple.prototype.setX3=function(x){ this.x3=parseFloat(x); return this; }; /** * set the y3-coord * @param {number} y y3-coord control point */ GLGE.BezTriple.prototype.setY3=function(y){ this.y3=parseFloat(y); return this; }; /** * @class A LinearPoint class to add points to the Animation Curve * @param {string} uid unique string for this class * @augments GLGE.QuickNotation * @augments GLGE.JSONLoader */ GLGE.LinearPoint=function(uid){ //GLGE.Assets.registerAsset(this,uid); }; GLGE.augment(GLGE.QuickNotation,GLGE.LinearPoint); GLGE.augment(GLGE.JSONLoader,GLGE.LinearPoint); GLGE.LinearPoint.prototype.className="LinearPoint"; GLGE.LinearPoint.prototype.x=0; GLGE.LinearPoint.prototype.y=0; /** * set the x-coord * @param {number} x x-coord control point */ GLGE.LinearPoint.prototype.setX=function(x){ this.x=parseFloat(x); return this; }; /** * set the y-coord * @param {number} y y-coord control point */ GLGE.LinearPoint.prototype.setY=function(y){ this.y=parseFloat(y); return this; }; /** * @class A StepPoint class to add points to the Animation Curve * @param {number} x x-coord control point * @param {object} value value of control point */ GLGE.StepPoint=function(x,value){ this.x=parseFloat(x); this.y=value; }; })(GLGE); /* GLGE WebGL Graphics Engine Copyright (c) 2010, Paul Brunt All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of GLGE nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL PAUL BRUNT BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /** * @fileOverview * @name glge_mesh.js * @author me@paulbrunt.co.uk */ (function(GLGE){ var meshIndx = 0; /** * @class Creates a new mesh * @see GLGE.Object * @augments GLGE.QuickNotation * @augments GLGE.JSONLoader * @augments GLGE.Events */ GLGE.Mesh=function(uid,windingOrder){ this.GLbuffers=[]; this.buffers=[]; this.framePositions=[]; this.frameNormals=[]; this.frameTangents=[]; this.UV=[]; this.boneWeights=[]; this.setBuffers=[]; this.faces={}; this.name = "mesh"+ (++meshIndx); if (windingOrder!==undefined) this.windingOrder=windingOrder; else this.windingOrder=GLGE.Mesh.WINDING_ORDER_UNKNOWN; GLGE.Assets.registerAsset(this,uid); }; GLGE.Mesh.WINDING_ORDER_UNKNOWN=2; GLGE.Mesh.WINDING_ORDER_CLOCKWISE=1; GLGE.Mesh.WINDING_ORDER_COUNTER=0; GLGE.augment(GLGE.QuickNotation,GLGE.Mesh); GLGE.augment(GLGE.JSONLoader,GLGE.Mesh); GLGE.augment(GLGE.Events,GLGE.Mesh); GLGE.Mesh.prototype.gl=null; GLGE.Mesh.prototype.className="Mesh"; GLGE.Mesh.prototype.GLbuffers=null; GLGE.Mesh.prototype.buffers=null; GLGE.Mesh.prototype.setBuffers=null; GLGE.Mesh.prototype.GLfaces=null; GLGE.Mesh.prototype.faces=null; GLGE.Mesh.prototype.UV=null; GLGE.Mesh.prototype.joints=null; GLGE.Mesh.prototype.invBind=null; GLGE.Mesh.prototype.loaded=false; /** * @name GLGE.Mesh#shaderupdate * @event fired when the shader needs updating * @param {object} data */ /** * Gets the bounding volume for the mesh * @returns {GLGE.BoundingVolume} */ GLGE.Mesh.prototype.getBoundingVolume=function(){ if(!this.positions) return new GLGE.BoundingVolume(0,0,0,0,0,0); if(!this.boundingVolume){ var minX,maxX,minY,maxY,minZ,maxZ; var positions=this.positions; for(var i=0;i0){ t=scaleVec3(t,-1); b=scaleVec3(b,-1); } return [t,b]; } /** * Sets the faces for this mesh * @param {Number[]} jsArray The 1 dimentional array of normals */ GLGE.Mesh.prototype.setFaces=function(jsArray){ this.faces={data:jsArray,GL:false}; //if at this point calculate normals if we haven't got them yet if(!this.normals) this.calcNormals(); if(!this.tangents && this.UV.length>0) this.calcTangents(); return this; } /** * Calculates the tangents for this mesh - this is messy FIX ME! * @private */ GLGE.Mesh.prototype.calcTangents=function(){ for(var j=0;j0){ tangentsTemp.push(tangents[faces[i]*3]); tangentsTemp.push(tangents[faces[i]*3+1]); tangentsTemp.push(tangents[faces[i]*3+2]); } if(uv1){ uv1Temp.push(uv1[faces[i]*2]); uv1Temp.push(uv1[faces[i]*2+1]); } if(uv2){ uv2Temp.push(uv2[faces[i]*2]); uv2Temp.push(uv2[faces[i]*2+1]); } } }else{ vertsTemp=verts; normalsTemp=normals; tangentsTemp=tangents; uv1Temp=uv1; uv2Temp=uv2; } var newVerts=[]; var newNormals=[]; var newFaces=[]; var newUV1s=[]; var newUV2s=[]; var newTangents=[]; var stack=[]; for(var i=0;i0){ newTangents.push(tangentsTemp[i]); newTangents.push(tangentsTemp[i+1]); newTangents.push(tangentsTemp[i+2]); } if(uv1){ newUV1s.push(uv1Temp[i/3*2]); newUV1s.push(uv1Temp[i/3*2+1]); } if(uv2){ newUV2s.push(uv2Temp[i/3*2]); newUV2s.push(uv2Temp[i/3*2+1]); } } newFaces.push(vertIdx); } this.setPositions(newVerts).setNormals(newNormals).setFaces(newFaces).setUV(newUV1s).setUV2(newUV2s).setTangents(newTangents); } /** * Sets the Attributes for this mesh * @param {WebGLContext} gl The context being drawn on * @private */ GLGE.Mesh.prototype.GLAttributes=function(gl,shaderProgram,frame1, frame2){ this.gl=gl; if(!frame1) frame1=0; //if at this point we have no normals set then calculate them if(!this.normals) this.calcNormals(); //disable all the attribute initially arrays - do I really need this? for(var i=0; i<8; i++) gl.disableVertexAttribArray(i); //check if the faces have been updated if(!this.faces.GL && this.faces.data && this.faces.data.length>0){ this.GLSetFaceBuffer(gl); this.faces.GL=true; } //loop though the buffers for(i=0; i-1){ gl.bindBuffer(gl.ARRAY_BUFFER, this.GLbuffers[this.buffers[i].name]); gl.enableVertexAttribArray(attribslot); gl.vertexAttribPointer(attribslot, this.GLbuffers[this.buffers[i].name].itemSize, gl.FLOAT, false, 0, 0); } } //do the position normal and if we have tangent then tangent var positionSlot=GLGE.getAttribLocation(gl,shaderProgram, "position"); if(positionSlot>-1){ gl.bindBuffer(gl.ARRAY_BUFFER, this.GLbuffers["position"+frame1]); gl.enableVertexAttribArray(positionSlot); gl.vertexAttribPointer(positionSlot, this.GLbuffers["position"+frame1].itemSize, gl.FLOAT, false, 0, 0); } var normalSlot=GLGE.getAttribLocation(gl,shaderProgram, "normal"); if(normalSlot>-1){ gl.bindBuffer(gl.ARRAY_BUFFER, this.GLbuffers["normal"+frame1]); gl.enableVertexAttribArray(normalSlot); gl.vertexAttribPointer(normalSlot, this.GLbuffers["normal"+frame1].itemSize, gl.FLOAT, false, 0, 0); } var tangentSlot=GLGE.getAttribLocation(gl,shaderProgram, "tangent"); if(tangentSlot>-1){ gl.bindBuffer(gl.ARRAY_BUFFER, this.GLbuffers["tangent"+frame1]); gl.enableVertexAttribArray(tangentSlot); gl.vertexAttribPointer(tangentSlot, this.GLbuffers["tangent"+frame1].itemSize, gl.FLOAT, false, 0, 0); } if(frame2!=undefined){ var positionSlot2=GLGE.getAttribLocation(gl,shaderProgram, "position2"); if(positionSlot2>-1){ gl.bindBuffer(gl.ARRAY_BUFFER, this.GLbuffers["position"+frame2]); gl.enableVertexAttribArray(positionSlot2); gl.vertexAttribPointer(positionSlot2, this.GLbuffers["position"+frame2].itemSize, gl.FLOAT, false, 0, 0); } var normalSlot2=GLGE.getAttribLocation(gl,shaderProgram, "normal2"); if(normalSlot2>-1){ gl.bindBuffer(gl.ARRAY_BUFFER, this.GLbuffers["normal"+frame2]); gl.enableVertexAttribArray(normalSlot2); gl.vertexAttribPointer(normalSlot2, this.GLbuffers["normal"+frame2].itemSize, gl.FLOAT, false, 0, 0); } var tangentSlot2=GLGE.getAttribLocation(gl,shaderProgram, "tangent2"); if(tangentSlot2>-1){ gl.bindBuffer(gl.ARRAY_BUFFER, this.GLbuffers["tangent"+frame2]); gl.enableVertexAttribArray(tangentSlot2); gl.vertexAttribPointer(tangentSlot2, this.GLbuffers["tangent"+frame2].itemSize, gl.FLOAT, false, 0, 0); } } } })(GLGE);/* GLGE WebGL Graphics Engine Copyright (c) 2011, Paul Brunt All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of GLGE nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL PAUL BRUNT BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /** * @fileOverview * @name glge_sphere.js * @author me@paulbrunt.co.uk */ (function(GLGE){ /** * @class Used to generate a basic sphere mesh * @augments GLGE.Mesh */ GLGE.Sphere=function(uid){ this.vertical=10; this.horizontal=10; this.radius=1; this.dirtySphere=false; GLGE.Mesh.apply(this,arguments); this.generateMeshData(); } GLGE.augment(GLGE.Mesh,GLGE.Sphere); /** * @private */ GLGE.Sphere.prototype.generateMeshData=function(){ var vertical=this.vertical; var horizontal=this.horizontal; var radius=this.radius; var t1,y,r1,i,j,x,y,t2; var verts=[]; var normals=[]; var faces=[]; for(i=0;i<=vertical;i++){ t1=i/vertical*Math.PI; y=Math.cos(t1)*radius; r1=Math.sin(t1)*radius; for(j=0;j0){ for(j=0;j0) color={r:color,g:color,b:color}; if(!color.r){ color=GLGE.colorParse(color); } this.emit={r:parseFloat(color.r),g:parseFloat(color.g),b:parseFloat(color.b)}; this.fireEvent("shaderupdate",{}); return this; }; /** * Sets how much the Red material should emit * @param {Number} value what Red to emit */ GLGE.Material.prototype.setEmitR=function(value){ this.emit.r=parseFloat(value); return this; }; /** * Sets how much the green material should emit * @param {Number} value what green to emit */ GLGE.Material.prototype.setEmitG=function(value){ this.emit.g=parseFloat(value); return this; }; /** * Sets how much the blue material should emit * @param {Number} value what blue to emit */ GLGE.Material.prototype.setEmitB=function(value){ this.emit.b=parseFloat(value); return this; }; /** * Sets how much the Red material should emit * @returns Red to emit */ GLGE.Material.prototype.getEmitR=function(value){ return this.emit.r; }; /** * Sets how much the green material should emit * @returns green to emit */ GLGE.Material.prototype.getEmitG=function(value){ return this.emit.g; }; /** * Sets how much the blue material should emit * @returns blue to emit */ GLGE.Material.prototype.getEmitB=function(value){ return this.emit.b; }; /** * Gets the amount this material emits * @return {Number} The emit value for the material */ GLGE.Material.prototype.getEmit=function(){ return this.emit; }; /** * Sets reflectivity of the material * @param {Number} value how much to reflect (0-1) */ GLGE.Material.prototype.setReflectivity=function(value){ this.reflect=value; this.fireEvent("shaderupdate",{}); return this; }; /** * Gets the materials reflectivity * @return {Number} The reflectivity of the material */ GLGE.Material.prototype.getReflectivity=function(){ return this.reflect; }; /** * Sets the material to output with 0 alpha or 1 alpha * @param {boolean} value binary alpha flag */ GLGE.Material.prototype.setBinaryAlpha=function(value){ this.binaryAlpha=value; this.fireEvent("shaderupdate",{}); return this; }; /** * Gets the binary alpha flag * @return {boolean} The binary alpha flag */ GLGE.Material.prototype.getBinaryAlpha=function(){ return this.binaryAlpha; }; /** * Add a new layer to the material * @param {MaterialLayer} layer The material layer to add to the material */ GLGE.Material.prototype.addMaterialLayer=function(layer){ if(typeof layer=="string") layer=GLGE.Assets.get(layer); this.layers.push(layer); var material=this; var listener=function(event){ material.fireEvent("shaderupdate",{}); }; this.layerlisteners.push(listener); layer.addEventListener("shaderupdate",listener); this.fireEvent("shaderupdate",{}); return this; }; /** * Removes a layer from the material * @param {MaterialLayer} layer The material layer to remove */ GLGE.Material.prototype.removeMaterialLayer=function(layer){ var idx=this.layers.indexOf(layer); if(idx>=0){ this.layers.splice(idx,1); layer.removeEventListener("shaderupdate",this.layerlisteners[idx]); this.layerlisteners.splice(idx,1); this.fireEvent("shaderupdate",{}); } return this; }; /** * Gets all the materials layers * @returns {GLGE.MaterialLayer[]} all of the layers contained within this material */ GLGE.Material.prototype.getLayers=function(){ return this.layers; }; /** * Generate the code required to calculate the texture coords for each layer * @private */ GLGE.Material.prototype.getLayerCoords=function(shaderInjection){ var shader=[]; shader.push("vec4 texturePos;\n"); for(var i=0; ineye.z*steepdisplace"+i+"){"; shader=shader+"textureHeight=vec3(vec2(neye.x,neye.y)*steepdisplace"+i+",0.0);"; shader=shader+"}else{"; shader=shader+"steepdisplace"+i+"-=steepstep"+i+";"; shader=shader+"steepstep"+i+"*=0.5;"; shader=shader+"}"; shader=shader+"steepdisplace"+i+"+=steepstep"+i+";"; shader=shader+"}"; } if((this.layers[i].mapto & GLGE.M_SPECCOLOR) == GLGE.M_SPECCOLOR){ shader=shader+"specC = specC*(1.0-mask) + texture"+sampletype+"(TEXTURE"+this.layers[i].texture.idx+", textureCoords."+txcoord+").rgb*mask;\n"; } if((this.layers[i].mapto & GLGE.M_MSKR) == GLGE.M_MSKR){ shader=shader+"mask = texture"+sampletype+"(TEXTURE"+this.layers[i].texture.idx+", textureCoords."+txcoord+").r;\n"; } if((this.layers[i].mapto & GLGE.M_MSKG) == GLGE.M_MSKG){ shader=shader+"mask = texture"+sampletype+"(TEXTURE"+this.layers[i].texture.idx+", textureCoords."+txcoord+").g;\n"; } if((this.layers[i].mapto & GLGE.M_MSKB) == GLGE.M_MSKB){ shader=shader+"mask = texture"+sampletype+"(TEXTURE"+this.layers[i].texture.idx+", textureCoords."+txcoord+").b;\n"; } if((this.layers[i].mapto & GLGE.M_MSKA) == GLGE.M_MSKA){ shader=shader+"mask = texture"+sampletype+"(TEXTURE"+this.layers[i].texture.idx+", textureCoords."+txcoord+").a;\n"; } if((this.layers[i].mapto & GLGE.M_SPECULAR) == GLGE.M_SPECULAR){ shader=shader+"spec = spec*(1.0-mask) + texture"+sampletype+"(TEXTURE"+this.layers[i].texture.idx+", textureCoords."+txcoord+").r*mask;\n"; } if((this.layers[i].mapto & GLGE.M_REFLECT) == GLGE.M_REFLECT){ shader=shader+"ref = ref*(1.0-mask) + texture"+sampletype+"(TEXTURE"+this.layers[i].texture.idx+", textureCoords."+txcoord+").g*mask;\n"; } if((this.layers[i].mapto & GLGE.M_SHINE) == GLGE.M_SHINE){ shader=shader+"sh = sh*(1.0-mask) + texture"+sampletype+"(TEXTURE"+this.layers[i].texture.idx+", textureCoords."+txcoord+").b*mask*255.0;\n"; } if((this.layers[i].mapto & GLGE.M_EMIT) == GLGE.M_EMIT){ shader=shader+"em = em*(1.0-mask) + texture"+sampletype+"(TEXTURE"+this.layers[i].texture.idx+", textureCoords."+txcoord+").rgb*mask;\n"; } if((this.layers[i].mapto & GLGE.M_NOR) == GLGE.M_NOR){ shader=shader+"normalmap = normalmap*(1.0-mask) + texture"+sampletype+"(TEXTURE"+this.layers[i].texture.idx+", textureCoords."+txcoord+")*mask;\n"; shader=shader+"normal = normalmap.rgb;\n"; shader=shader+"normal = 2.0*(vec3(normal.r, -normal.g, normal.b) - vec3(0.5, -0.5, 0.5));"; shader=shader+"b=normalize(cross(t.xyz,n));\n"; shader=shader+"normal = normal.x*t + normal.y*b + normal.z*n;"; shader=shader+"normal = normalize(normal);"; } if((this.layers[i].mapto & GLGE.M_ALPHA) == GLGE.M_ALPHA){ anyAlpha=true; shader=shader+"al = al*(1.0-mask) + texture"+sampletype+"(TEXTURE"+this.layers[i].texture.idx+", textureCoords."+txcoord+").a*mask;\n"; } if((this.layers[i].mapto & GLGE.M_AMBIENT) == GLGE.M_AMBIENT){ shader=shader+"amblight = amblight*(1.0-mask) + texture"+sampletype+"(TEXTURE"+this.layers[i].texture.idx+", textureCoords."+txcoord+").rgb*mask;\n"; } } shader=shader+"amblight *= amb;\n"; if (!anyAlpha && this.layers.length) { if(this.layers[diffuseLayer].getTexture().className=="Texture" || this.layers[diffuseLayer].getTexture().className=="TextureCanvas" || this.layers[diffuseLayer].getTexture().className=="TextureVideo" ) { var txcoord="xy"; var sampletype="2D"; }else{ var txcoord="xyz"; var sampletype="Cube"; } shader=shader+"al = al*(1.0-mask) + texture"+sampletype+"(TEXTURE"+this.layers[diffuseLayer].texture.idx+", textureCoords."+txcoord+").a*al*mask;\n"; } if(colors && this.vertexColorMode==GLGE.VC_MUL){ shader=shader+"color *= vcolor;"; } if(this.binaryAlpha) { shader=shader+"if(al<0.5) discard;\n"; shader=shader+"al=1.0;\n"; }else{ shader=shader+"if(al==0.0) discard;\n"; } shader=shader+"vec3 lightvalue=amblight;\n"; if(colors && this.vertexColorMode==GLGE.VC_AMB){ shader=shader+"lightvalue = vcolor.rgb;"; } if(colors && this.vertexColorMode==GLGE.VC_AMBMUL){ shader=shader+"lightvalue *= vcolor.rgb;"; } shader=shader+"float dotN,spotEffect;"; shader=shader+"vec3 lightvec=vec3(0.0,0.0,0.0);"; shader=shader+"vec3 viewvec=vec3(0.0,0.0,0.0);"; shader=shader+"vec3 specvalue=vec3(0.0,0.0,0.0);"; shader=shader+"vec2 scoord=vec2(0.0,0.0);"; shader=shader+"float sDepth=0.0;"; shader=shader+"float spotmul=0.0;"; shader=shader+"float rnd=0.0;"; shader=shader+"float spotsampleX=0.0;"; shader=shader+"float spotsampleY=0.0;"; shader=shader+"float totalweight=0.0;"; shader=shader+"int cnt=0;"; shader=shader+"float specularSmoothStepValue=.125;\n"; shader=shader+"vec2 spotoffset=vec2(0.0,0.0);"; shader=shader+"float dp=0.0;"; shader=shader+"vec4 dist;float depth,m1,m2,prob,variance;\n"; shader=shader+"if (normal.z<0.0) {normal.z=0.0;}\n"; shader=shader+"float fogfact=1.0;"; shader=shader+"if(fogtype=="+GLGE.FOG_QUADRATIC+" || fogtype=="+GLGE.FOG_SKYQUADRATIC+") fogfact=clamp(pow(max((fogfar - length(eyevec)) / (fogfar - fognear),0.0),2.0),0.0,1.0);\n"; shader=shader+"if(fogtype=="+GLGE.FOG_LINEAR+" || fogtype=="+GLGE.FOG_SKYLINEAR+") fogfact=clamp((fogfar - length(eyevec)) / (fogfar - fognear),0.0,1.0);\n"; shader=shader+"if (emitpass) {gl_FragColor=vec4(em,1.0);} else if (shadeless) {\n"; shader=shader+"gl_FragColor=vec4(color.rgb,al);\n"; shader=shader+"} else {\n"; for(var i=0; i0.0){\n"; if(lights[i].diffuse){ shader=shader+"lightvalue += att * dotN * lightcolor"+i+";\n"; } shader=shader+"}\n"; if(lights[i].specular){ shader=shader+"specvalue += smoothstep(-specularSmoothStepValue,specularSmoothStepValue,dotN)*att * specC * lightcolor"+i+" * spec * pow(max(dot(reflect(normalize(lightvec), normal),normalize(viewvec)),0.0), 0.3*sh);\n"; } } shader=shader+"spotEffect = 0.0;\n"; if(lights[i].type==GLGE.L_SPOT){ shader=shader+"spotEffect = dot(normalize(lightdir"+i+"), normalize(-lightvec"+i+"));"; shader=shader+"if (spotEffect > spotCosCutOff"+i+""+(!this.spotCutOff ? " || spotEffect>0.0" : "")+") {\n"; shader=shader+"spotEffect = pow(spotEffect, spotExp"+i+");"; //spot shadow stuff if(lights[i].getCastShadows() && this.shadow){ shader=shader+"scoord=(((spotcoord"+i+".xy)/spotcoord"+i+".w)+1.0)/2.0;\n"; shader=shader+"if(scoord.x>0.0 && scoord.x<1.0 && scoord.y>0.0 && scoord.y<1.0){\n"; shader=shader+"dist=texture2D(TEXTURE"+(shadowlights[i])+", scoord);\n"; if(lights[i].spotSoftness==0){ shader=shader+"depth = dot(dist, vec4(0.000000059604644775390625,0.0000152587890625,0.00390625,1.0))*"+lights[i].distance+".0;\n"; shader=shader+"if(depth0.0){\n"; if(lights[i].diffuse){ shader=shader+"lightvalue -= (1.0-spotEffect) / (lightAttenuation"+i+"[0] + lightAttenuation"+i+"[1] * lightdist"+i+" + lightAttenuation"+i+"[2] * lightdist"+i+" * lightdist"+i+");\n"; } shader=shader+"}\n"; }else{ shader=shader+"att = spotEffect / (lightAttenuation"+i+"[0] + lightdist"+i+"*(lightAttenuation"+i+"[1] + lightAttenuation"+i+"[2] * lightdist"+i+"));\n"; shader=shader+"if(dotN>0.0){\n"; if(lights[i].diffuse){ shader=shader+"lightvalue += att * dotN * lightcolor"+i+";\n"; } shader=shader+"}\n"; if(lights[i].specular){ shader=shader+"specvalue += smoothstep(-specularSmoothStepValue,specularSmoothStepValue,dotN) * att * specC * lightcolor"+i+" * spec * pow(max(dot(reflect(normalize(lightvec), normal),normalize(viewvec)),0.0), 0.3 * sh);\n"; } } shader=shader+"}\n"; } if(lights[i].type==GLGE.L_DIR){ shader=shader+"dotN=max(dot(normal,-normalize(lightvec)),0.0);\n"; if(lights[i].getCastShadows() && this.shadow){ shader=shader+"float shadowfact"+i+" = 0.0;\n"; shader=shader+"float level"+i+" = 1.0;\n"; shader=shader+"scoord=((spotcoord"+i+".xy)+1.0)/2.0;\n"; var levels=lights[i].getCascadeLevels(); for(var l=1;l1.0 || scoord.y<0.0 || scoord.y>1.0) {scoord=((spotcoord"+i+".xy-shadowoffset"+i+")*"+Math.pow(0.5,l).toFixed(5)+"+shadowoffset"+i+"+1.0)/2.0;level"+i+"="+(l+1).toFixed(2)+";};\n"; } shader=shader+"scoord.y=scoord.y/"+levels.toFixed(2)+"+1.0-"+((1/levels).toFixed(5))+"*level"+i+";\n"; if(lights[i].samples==0){ shader=shader+"dist=texture2D(TEXTURE"+shadowlights[i]+", scoord);\n"; shader=shader+"depth = dot(dist, vec4(0.000000059604644775390625,0.0000152587890625,0.00390625,1.0))*"+((+lights[i].distance).toFixed(2))+";\n"; shader=shader+"sDepth = ((spotcoord"+i+".z)/spotcoord"+i+".w+1.0)/2.0;\n"; shader=shader+"if(scoord.x>0.0 && scoord.x<1.0 && scoord.y>0.0 && scoord.y<1.0 && sDepth-shadowbias"+i+"-depth>0.0) {\n"; shader=shader+"shadowfact"+i+"=pow(clamp(2.0*length(eyevec)/"+((+lights[i].distance).toFixed(2))+",0.0,1.0),1.2);\n"; shader=shader+"}else{shadowfact"+i+"=1.0;}\n"; }else{ shader=shader+"rnd=(fract(sin(dot(scoord,vec2(12.9898,78.233))) * 43758.5453)-0.5)*0.5;\n"; //generate random number for(var x=-lights[i].samples;x<=lights[i].samples;x++){ for(var y=-lights[i].samples;y<=lights[i].samples;y++){ shader=shader+"dist=texture2D(TEXTURE"+shadowlights[i]+", scoord+vec2("+(x/lights[i].bufferWidth).toFixed(4)+","+(y/lights[i].bufferHeight).toFixed(4)+")*shadowsoftness"+i+"*100.0/level"+i+"+vec2("+(1.0/lights[i].bufferWidth).toFixed(4)+","+(1.0/lights[i].bufferHeight).toFixed(4)+")*rnd);\n"; shader=shader+"depth = dot(dist, vec4(0.000000059604644775390625,0.0000152587890625,0.00390625,1.0))*"+((+lights[i].distance).toFixed(2))+";\n"; shader=shader+"sDepth = ((spotcoord"+i+".z)/spotcoord"+i+".w+1.0)/2.0;\n"; shader=shader+"if(scoord.x>0.0 && scoord.x<1.0 && scoord.y>0.0 && scoord.y<1.0 && sDepth-shadowbias"+i+"-depth>0.0) {\n"; shader=shader+"shadowfact"+i+"+=pow(clamp(2.0*length(eyevec)/"+((+lights[i].distance).toFixed(2))+",0.0,1.0),2.0);\n"; shader=shader+"}else{shadowfact"+i+"+=1.0;}\n"; } } shader=shader+"shadowfact"+i+"/="+((lights[i].samples*2+1)*(lights[i].samples*2+1)).toFixed(1)+";\n"; } }else{ shader=shader+"float shadowfact"+i+" = 1.0;\n"; } if(lights[i].diffuse){ if(lights[i].negativeShadow){ shader=shader+"lightvalue -= lightcolor"+i+"-(dotN * lightcolor"+i+" * shadowfact"+i+");\n"; }else{ shader=shader+"lightvalue += dotN * lightcolor"+i+" * shadowfact"+i+";\n"; } } if(lights[i].specular){ shader=shader+"specvalue += smoothstep(-specularSmoothStepValue,specularSmoothStepValue,dotN) * specC * lightcolor"+i+" * spec * pow(max(dot(reflect(normalize(lightvec), normal),normalize(viewvec)),0.0), 0.3 * sh);\n"; } } } shader=shader+"lightvalue = (lightvalue)*ref;\n"; shader=shader+"vec3 fc=fogcolor.rgb;\n"; shader=shader+"if(fogtype=="+GLGE.FOG_SKYLINEAR+" || fogtype=="+GLGE.FOG_SKYQUADRATIC+"){"; shader=shader+"vec4 view=projection * vec4(-eyevec,1.0);\n"; shader=shader+"vec2 fogCoords=view.xy/view.w*0.5+0.5;\n"; shader=shader+"fc=texture2D(sky,fogCoords.xy).rgb;\n"; //shader=shader+"fogfact=1.0-(1.0-fogfact)*min(length(fc)/1.73,1.0);\n"; shader=shader+"}\n"; shader=shader+"vec4 finalColor =vec4(specvalue.rgb+color.rgb*lightvalue.rgb+em.rgb,al)*fogfact+vec4(fc,al)*(1.0-fogfact);\n"; if(shaderInjection && ~shaderInjection.indexOf("GLGE_FragColor")){ shader=shader+"finalColor=GLGE_FragColor(finalColor);\n"; } shader=shader+"gl_FragColor = finalColor;"; if(GLGE.DEBUGNORMALS) shader=shader+"gl_FragColor = vec4(normal.rgb,1.0);"; if(GLGE.DEBUGCOORD0) shader=shader+"gl_FragColor = vec4(textureCoords0.rg,0.0,1.0);"; shader=shader+"}\n"; //end emit pass test shader=shader+"}\n"; return shader; }; /** * Set the uniforms needed to render this material * @private */ GLGE.Material.prototype.textureUniforms=function(gl,shaderProgram,lights,object){ if(this.animation) this.animate(); var pc=shaderProgram.caches; if(!pc.baseColor || pc.baseColor.r!=this.color.r || pc.baseColor.g!=this.color.g || pc.baseColor.b!=this.color.b || pc.baseColor.a!=this.color.a){ if(!this.ccache || this.ccache.r!=this.color.r || this.ccache.g!=this.color.g || this.ccache.b!=this.color.b || this.ccache.a!=this.color.a){ this.ccache=this.color; this.glColor=new Float32Array([this.color.r,this.color.g,this.color.b,this.color.a]); } gl.uniform4fv(GLGE.getUniformLocation(gl,shaderProgram, "baseColor"), this.glColor); pc.baseColor=this.color; } if(pc.specColor!=this.specColor){ if(this.sccache!=this.specColor){ this.sccache=this.specColor; this.glspecColor=new Float32Array([this.specColor.r,this.specColor.g,this.specColor.b]); } gl.uniform3fv(GLGE.getUniformLocation(gl,shaderProgram, "specColor"), this.glspecColor); pc.specColor=this.specColor; } if(pc.emit!=this.emit){ gl.uniform3f(GLGE.getUniformLocation(gl,shaderProgram, "emit"), this.emit.r,this.emit.g,this.emit.b); pc.emit=this.emit; } if(pc.specular!=this.specular){ GLGE.setUniform(gl,"1f",GLGE.getUniformLocation(gl,shaderProgram, "specular"), this.specular); pc.specular=this.specular; } if(pc.shine!=this.shine){ GLGE.setUniform(gl,"1f",GLGE.getUniformLocation(gl,shaderProgram, "shine"), this.shine); pc.shine=this.shine; } if(pc.reflect!=this.reflect){ GLGE.setUniform(gl,"1f",GLGE.getUniformLocation(gl,shaderProgram, "reflective"), this.reflect); pc.reflect=this.reflect; } if(pc.alpha!=this.alpha){ GLGE.setUniform(gl,"1f",GLGE.getUniformLocation(gl,shaderProgram, "alpha"), this.alpha); pc.alpha=this.alpha; } if(pc.shadeless==undefined || pc.shadeless!=this.shadeless){ GLGE.setUniform(gl,"1i",GLGE.getUniformLocation(gl,shaderProgram, "shadeless"), this.shadeless); pc.shadeless=this.shadeless; } if(gl.scene.skyTexture){ gl.activeTexture(gl["TEXTURE0"]); gl.bindTexture(gl.TEXTURE_2D, gl.scene.skyTexture); 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); GLGE.setUniform(gl,"1i",GLGE.getUniformLocation(gl,shaderProgram, "sky"), 0); } /* if(this.ambient && pc.ambient!=this.ambient){ gl.uniform3fv(GLGE.getUniformLocation(gl,shaderProgram, "amb"), new Float32Array([this.ambient.r,this.ambient.g,this.ambient.b])); pc.ambient=this.ambient; } */ var cnt=1; var num=0; if(!pc["lightcolor"]){ pc["lightcolor"]=[]; pc["lightAttenuation"]=[]; pc["spotCosCutOff"]=[]; pc["spotExponent"]=[]; pc["shadowbias"]=[]; pc["castshadows"]=[]; pc["shadowsamples"]=[]; pc["shadowsoftness"]=[]; } for(var i=0; i1){ for(var i=1; icurrentSize && size0; } })(GLGE);/* GLGE WebGL Graphics Engine Copyright (c) 2010, Paul Brunt All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of GLGE nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL PAUL BRUNT BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /** * @fileOverview * @name glge_texturecamera.js * @author me@paulbrunt.co.uk */ (function(GLGE){ /** * @class A reflection texture will reflect in a plane for a specified transform * @param {string} uid the unique id for this texture * @see GLGE.Material * @augments GLGE.QuickNotation * @augments GLGE.JSONLoader */ GLGE.TextureCamera=function(uid){ GLGE.Assets.registerAsset(this,uid); } GLGE.augment(GLGE.QuickNotation,GLGE.TextureCamera); GLGE.augment(GLGE.JSONLoader,GLGE.TextureCamera); GLGE.augment(GLGE.Events,GLGE.TextureCamera); GLGE.TextureCamera.prototype.className="Texture"; GLGE.TextureCamera.prototype.texture=null; GLGE.TextureCamera.prototype.glTexture=null; GLGE.TextureCamera.prototype.object=null; GLGE.TextureCamera.prototype.camera=null; GLGE.TextureCamera.prototype.bufferHeight=0; GLGE.TextureCamera.prototype.bufferWidth=0; GLGE.TextureCamera.prototype.planeOffset=0; GLGE.TextureCamera.prototype.mirrorAxis=GLGE.NONE; GLGE.TextureCamera.prototype.clipAxis=GLGE.NONE; /** * sets the RTT render clipping plane offset * @param {number} buffer width **/ GLGE.TextureCamera.prototype.setPlaneOffset=function(planeoffset){ this.planeOffset=planeoffset; return this; } /** * gets the RTT render clipping plane offset * @returns the width **/ GLGE.TextureCamera.prototype.getPlaneOffset=function(){ return this.planeOffset; } /** * sets the RTT render buffer width * @param {number} buffer width **/ GLGE.TextureCamera.prototype.setBufferWidth=function(width){ this.bufferWidth=width; this.update=true; return this; } /** * gets the RTT render buffer width * @returns the width **/ GLGE.TextureCamera.prototype.getBufferWidth=function(){ return this.bufferWidth; } /** * sets the RTT render buffer height * @param {number} buffer height **/ GLGE.TextureCamera.prototype.setBufferHeight=function(height){ this.bufferHeight=height; this.update=true; return this; } /** * gets the RTT render buffer height * @returns the height **/ GLGE.TextureCamera.prototype.getBufferHeight=function(){ return this.bufferHeight; } /** * sets the RTT clip axis * @param {number} the axis **/ GLGE.TextureCamera.prototype.setClipAxis=function(camera){ this.clipAxis=camera; return this; } /** * gets the RTT clip axis * @returns the axis **/ GLGE.TextureCamera.prototype.getClipAxis=function(){ return this.clipAxis; } /** * sets the RTT mirror axis * @param {number} the axis **/ GLGE.TextureCamera.prototype.setMirrorAxis=function(camera){ this.mirrorAxis=camera; return this; } /** * gets the RTT mirror axis * @returns the axis **/ GLGE.TextureCamera.prototype.getMirrorAxis=function(){ return this.mirrorAxis; } /** * sets the RTT camera to use * @param {GLGE.Camera} the source camera **/ GLGE.TextureCamera.prototype.setCamera=function(camera){ this.camera=camera; return this; } /** * gets the RTT source camera * @returns {GLGE.Camera} the source camera **/ GLGE.TextureCamera.prototype.getCamera=function(){ return this.camera; } /** * does what is needed to get the texture * @private **/ GLGE.TextureCamera.prototype.doTexture=function(gl,object){ if(this.camera){ this.gl=gl; var modelmatrix=object.getModelMatrix(); var pmatrix=gl.scene.camera.getProjectionMatrix(); var cameramatrix=this.camera.getViewMatrix(); var matrix; if(this.mirrorAxis){ switch(this.mirrorAxis){ case GLGE.XAXIS: matrix=GLGE.mulMat4(GLGE.mulMat4(GLGE.mulMat4(cameramatrix,modelmatrix),GLGE.scaleMatrix(-1,1,1)),GLGE.inverseMat4(modelmatrix)); break; case GLGE.YAXIS: matrix=GLGE.mulMat4(GLGE.mulMat4(GLGE.mulMat4(cameramatrix,modelmatrix),GLGE.scaleMatrix(1,-1,1)),GLGE.inverseMat4(modelmatrix)); break; case GLGE.ZAXIS: matrix=GLGE.mulMat4(GLGE.mulMat4(GLGE.mulMat4(cameramatrix,modelmatrix),GLGE.scaleMatrix(1,1,-1)),GLGE.inverseMat4(modelmatrix)); break; } }else{ matrix=cameramatrix; } if(this.clipAxis){ var clipplane switch(this.clipAxis){ case GLGE.NEG_XAXIS: var dirnorm=GLGE.toUnitVec3([-modelmatrix[0],-modelmatrix[4],-modelmatrix[8]]); clipplane=[dirnorm[0],dirnorm[1],dirnorm[2],-GLGE.dotVec3([modelmatrix[3],modelmatrix[7],modelmatrix[11]],dirnorm)-this.planeOffset]; break; case GLGE.POS_XAXIS: var dirnorm=GLGE.toUnitVec3([modelmatrix[0],modelmatrix[4],modelmatrix[8]]); clipplane=[dirnorm[0],dirnorm[1],dirnorm[2],-GLGE.dotVec3([modelmatrix[3],modelmatrix[7],modelmatrix[11]],dirnorm)-this.planeOffset]; break; case GLGE.NEG_YAXIS: var dirnorm=GLGE.toUnitVec3([-modelmatrix[1],-modelmatrix[5],-modelmatrix[9]]); clipplane=[dirnorm[0],dirnorm[1],dirnorm[2],-GLGE.dotVec3([modelmatrix[3],modelmatrix[7],modelmatrix[11]],dirnorm)-this.planeOffset]; break; case GLGE.POS_YAXIS: var dirnorm=GLGE.toUnitVec3([modelmatrix[1],modelmatrix[5],modelmatrix[9]]); clipplane=[dirnorm[0],dirnorm[1],dirnorm[2],-GLGE.dotVec3([modelmatrix[3],modelmatrix[7],modelmatrix[11]],dirnorm)-this.planeOffset]; break; case GLGE.NEG_ZAXIS: var dirnorm=GLGE.toUnitVec3([-modelmatrix[2],-modelmatrix[6],-modelmatrix[10]]); clipplane=[dirnorm[0],dirnorm[1],dirnorm[2],-GLGE.dotVec3([modelmatrix[3],modelmatrix[7],modelmatrix[11]],dirnorm)-this.planeOffset]; break; case GLGE.POS_ZAXIS: var dirnorm=GLGE.toUnitVec3([modelmatrix[2],modelmatrix[6],modelmatrix[10]]); clipplane=[dirnorm[0],dirnorm[1],dirnorm[2],-GLGE.dotVec3([modelmatrix[3],modelmatrix[7],modelmatrix[11]],dirnorm)-this.planeOffset]; break; } var itmvp=GLGE.transposeMat4(GLGE.inverseMat4(GLGE.mulMat4(pmatrix,matrix))); clipplane=GLGE.mulMat4Vec4(itmvp,clipplane); clipplane=GLGE.scaleVec4(clipplane,pmatrix[10]); clipplane[3] -= 1; if(clipplane[2]<0) GLGE.scaleVec4(clipplane,-1); var suffix=[ 1,0,0,0, 0,1,0,0, clipplane[0],clipplane[1],clipplane[2],clipplane[3], 0,0,0,1]; pmatrix=GLGE.mulMat4(suffix,pmatrix); } var height=(!this.bufferHeight ? gl.scene.renderer.canvas.height : this.bufferHeight); var width=(!this.bufferWidth ? gl.scene.renderer.canvas.width : this.bufferWidth); //create the texture if it's not already created if(!this.glTexture || this.update){ this.createFrameBuffer(gl); gl.scene.addRenderPass(this.frameBuffer,matrix, gl.scene.camera.getProjectionMatrix(),width,height,object); gl.bindTexture(gl.TEXTURE_2D, this.glTexture); this.update=false; return false; }else{ gl.bindTexture(gl.TEXTURE_2D, this.glTexture); 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.scene.addRenderPass(this.frameBuffer,matrix, pmatrix,width,height,object); return true; } }else{ return false; } } GLGE.TextureCamera.prototype.registerPasses=GLGE.TextureCamera.prototype.doTexture; /** * Creates the frame buffer for our texture * @private */ GLGE.TextureCamera.prototype.createFrameBuffer=function(gl){ var height=(!this.bufferHeight ? gl.scene.renderer.canvas.height : this.bufferHeight); var width=(!this.bufferWidth ? gl.scene.renderer.canvas.width : this.bufferWidth); if(!this.frameBuffer) this.frameBuffer = gl.createFramebuffer(); if(!this.renderBuffer) this.renderBuffer = gl.createRenderbuffer(); if(!this.glTexture) this.glTexture=gl.createTexture(); gl.bindTexture(gl.TEXTURE_2D, this.glTexture); var tex = new Uint8Array(width*height*4); gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, width,height, 0, gl.RGBA, gl.UNSIGNED_BYTE, tex); gl.bindFramebuffer(gl.FRAMEBUFFER, this.frameBuffer); gl.bindRenderbuffer(gl.RENDERBUFFER, this.renderBuffer); //dpeth stencil doesn't seem to work in either webkit or mozilla so don't use for now - reflected particles will be messed up! //gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_STENCIL,width, height); //gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.RENDERBUFFER, this.renderBuffer); gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_COMPONENT16,width, height); gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER, this.renderBuffer); gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, this.glTexture, 0); gl.bindRenderbuffer(gl.RENDERBUFFER, null); gl.bindFramebuffer(gl.FRAMEBUFFER, null); gl.bindTexture(gl.TEXTURE_2D, null); } })(GLGE);/* GLGE WebGL Graphics Engine Copyright (c) 2010, Paul Brunt All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of GLGE nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL PAUL BRUNT BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /** * @fileOverview * @name glge_texturecanvas.js * @author me@paulbrunt.co.uk */ (function(GLGE){ /** * @class A canvase texture to be included in a material * @param {string} uid the unique id for this texture * @see GLGE.Material * @augments GLGE.QuickNotation * @augments GLGE.JSONLoader */ GLGE.TextureCanvas=function( uid, width, height, ID, canvas ){ if ( canvas === undefined ) { this.canvas=document.createElement("canvas"); } else { this.canvas = canvas; } //temp canvas to force chrome to update FIX ME when bug sorted! this.t=document.createElement("canvas"); this.t.width=1; this.t.height=1; GLGE.Assets.registerAsset(this,uid); this.canvas.style.display="none"; if ( ID !== undefined ) { this.canvas.setAttribute("id",ID); } this.canvas.setAttribute("width", width ? width : "256" ); this.canvas.setAttribute("height", height ? height : "256" ); document.getElementsByTagName("body")[0].appendChild(this.canvas); } GLGE.augment(GLGE.QuickNotation,GLGE.TextureCanvas); GLGE.augment(GLGE.JSONLoader,GLGE.TextureCanvas); GLGE.augment(GLGE.Events,GLGE.TextureCanvas); GLGE.TextureCanvas.prototype.className="TextureCanvas"; GLGE.TextureCanvas.prototype.glTexture=null; GLGE.TextureCanvas.prototype.autoUpdate=true; /** * Gets the auto update flag * @return {boolean} The auto update flag */ GLGE.TextureCanvas.prototype.getAutoUpdate=function(){ return this.autoUpdate; }; /** * Sets the auto update flag * @param {boolean} value The auto update flag */ GLGE.TextureCanvas.prototype.setAutoUpdate=function(value){ this.autoUpdate=value; return this; }; /** * Gets the canvas used by the texture * @return {canvas} The textures image url */ GLGE.TextureCanvas.prototype.getCanvas=function(){ return this.canvas; }; /** * Sets the canvas used by the texture * @param {canvas} canvas The canvas to use */ GLGE.TextureCanvas.prototype.setCanvas=function(canvas){ this.canvas=canvas; return this; }; /** * Sets the canvas height * @param {number} value The canvas height */ GLGE.TextureCanvas.prototype.setHeight=function(value){ this.canvas.height=value; return this; }; /** * Sets the canvas width * @param {number} value The canvas width */ GLGE.TextureCanvas.prototype.setWidth=function(value){ this.canvas.width=value; return this; }; /** * gets the canvas height * @returns {number} The canvas height */ GLGE.TextureCanvas.prototype.getHeight=function(){ return this.canvas.height; }; /** * gets the canvas width * @returns {number} The canvas width */ GLGE.TextureCanvas.prototype.getWidth=function(){ return this.canvas.width; }; /** * does the canvas texture GL stuff * @private **/ GLGE.TextureCanvas.prototype.doTexture=function(gl){ this.gl=gl; //create the texture if it's not already created if(!this.glTexture){ this.glTexture=gl.createTexture(); gl.bindTexture(gl.TEXTURE_2D, this.glTexture); this.updateCanvas(gl); }else{ gl.bindTexture(gl.TEXTURE_2D, this.glTexture); if(this.autoUpdate || this.doUpdate) this.updateCanvas(gl); } this.doUpdate=false; return true; } /** * Manually updates the canvas Texture */ GLGE.TextureCanvas.prototype.update=function(){ this.doUpdate=true; } /** * Updates the canvas texture * @private */ GLGE.TextureCanvas.prototype.updateCanvas=function(gl){ var canvas = this.canvas; gl.bindTexture(gl.TEXTURE_2D, this.glTexture); gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, this.t); //force chrome to update remove when chrome bug fixed gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, canvas); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR); gl.generateMipmap(gl.TEXTURE_2D); } })(GLGE);/* GLGE WebGL Graphics Engine Copyright (c) 2010, Paul Brunt All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of GLGE nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL PAUL BRUNT BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /** * @fileOverview * @name glge_texturecube.js * @author me@paulbrunt.co.uk */ (function(GLGE){ /** * @class A texture to be included in a material * @param {string} uid the unique id for this texture * @see GLGE.Material * @augments GLGE.QuickNotation * @augments GLGE.JSONLoader */ GLGE.TextureCube=function(uid){ GLGE.Assets.registerAsset(this,uid); } GLGE.augment(GLGE.QuickNotation,GLGE.TextureCube); GLGE.augment(GLGE.JSONLoader,GLGE.TextureCube); GLGE.augment(GLGE.Events,GLGE.TextureCube); GLGE.TextureCube.prototype.className="TextureCube"; GLGE.TextureCube.prototype.posX=null; GLGE.TextureCube.prototype.negX=null; GLGE.TextureCube.prototype.posY=null; GLGE.TextureCube.prototype.negY=null; GLGE.TextureCube.prototype.posZ=null; GLGE.TextureCube.prototype.negZ=null; GLGE.TextureCube.prototype.texture=null; GLGE.TextureCube.prototype.glTexture=null; GLGE.TextureCube.prototype.loadState=0; /** * Sets the url for a given image * @param {string} url the texture image url * @param {string} image the image element to load */ GLGE.TextureCube.prototype.setSrc=function(url,image,mask){ this.url=url; this.state=0; this[image]=new Image(); var texture=this; this[image].onload = function(){ texture.loadState+=mask; } this[image].src=url; if(this.glTexture && this.gl) { this.gl.deleteTexture(this.glTexture); this.glTexture=null; } return this; } /** * Sets the positive X cube image * @param {string} url the texture image url */ GLGE.TextureCube.prototype.setSrcPosX=function(url){ this.setSrc(url,"posX",1); return this; }; /** * Sets the negative X cube image * @param {string} url the texture image url */ GLGE.TextureCube.prototype.setSrcNegX=function(url){ this.setSrc(url,"negX",2); return this; }; /** * Sets the positive Y cube image * @param {string} url the texture image url */ GLGE.TextureCube.prototype.setSrcPosY=function(url){ this.setSrc(url,"posY",4); return this; }; /** * Sets the negative Y cube image * @param {string} url the texture image url */ GLGE.TextureCube.prototype.setSrcNegY=function(url){ if(typeof url!="string"){ this.negY=url; this.loadState+=8; }else{ this.setSrc(url,"negY",8); } return this; }; /** * Sets the positive Z cube image * @param {string} url the texture image url */ GLGE.TextureCube.prototype.setSrcPosZ=function(url){ this.setSrc(url,"posZ",16); return this; }; /** * Sets the negative Z cube image * @param {string} url the texture image url */ GLGE.TextureCube.prototype.setSrcNegZ=function(url){ this.setSrc(url,"negZ",32); return this; }; /** * Sets the textures image location * @private **/ GLGE.TextureCube.prototype.doTexture=function(gl,object){ this.gl=gl; //create the texture if it's not already created if(!this.glTexture) this.glTexture=gl.createTexture(); //if the image is loaded then set in the texture data gl.bindTexture(gl.TEXTURE_CUBE_MAP, this.glTexture); if(this.loadState==63 && this.state==0){ gl.texImage2D(gl.TEXTURE_CUBE_MAP_POSITIVE_X, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, this.posX); gl.texImage2D(gl.TEXTURE_CUBE_MAP_NEGATIVE_X, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, this.negX); gl.texImage2D(gl.TEXTURE_CUBE_MAP_POSITIVE_Y, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, this.posY); gl.texImage2D(gl.TEXTURE_CUBE_MAP_NEGATIVE_Y, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, this.negY); gl.texImage2D(gl.TEXTURE_CUBE_MAP_POSITIVE_Z, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, this.posZ); gl.texImage2D(gl.TEXTURE_CUBE_MAP_NEGATIVE_Z, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, this.negZ); gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_MAG_FILTER, gl.LINEAR); gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_LINEAR); gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); gl.generateMipmap(gl.TEXTURE_CUBE_MAP); gl.bindTexture(gl.TEXTURE_CUBE_MAP, null); this.state=1; } gl.bindTexture(gl.TEXTURE_CUBE_MAP, this.glTexture); if(this.state==1) return true; else return false; } })(GLGE);/* GLGE WebGL Graphics Engine Copyright (c) 2010, Paul Brunt All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of GLGE nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL PAUL BRUNT BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /** * @fileOverview * @name glge_texturevideo.js * @author me@paulbrunt.co.uk */ (function(GLGE){ /** * @class A video texture to be included in a material * @param {string} uid the unique id for this texture * @see GLGE.Material * @augments GLGE.QuickNotation * @augments GLGE.JSONLoader */ GLGE.TextureVideo=function( uid, width, height, ID, video ){ if ( video === undefined ) { this.video=document.createElement("video"); } else { this.video = video; } this.video.style.display="none"; this.video.setAttribute("loop","loop"); if ( ID !== undefined ) { this.video.setAttribute("id",ID); } this.video.setAttribute("width", width ? width : "256" ); this.video.setAttribute("height", height ? height : "256" ); this.video.autoplay=true; //looping isn't working in firefox so quick fix! this.video.addEventListener("ended", function() { this.play(); }, true); //video needs to be part of page to work for some reason :-s document.getElementsByTagName("body")[0].appendChild(this.video); //used to get webkit working this.canvas=document.createElement("canvas"); this.ctx=this.canvas.getContext("2d"); GLGE.Assets.registerAsset(this,uid); } GLGE.augment(GLGE.QuickNotation,GLGE.TextureVideo); GLGE.augment(GLGE.JSONLoader,GLGE.TextureVideo); GLGE.augment(GLGE.Events,GLGE.TextureVideo); GLGE.TextureVideo.prototype.className="TextureVideo"; GLGE.TextureVideo.prototype.glTexture=null; /** * Gets the canvas used by the texture * @return {video} The textures image url */ GLGE.TextureVideo.prototype.getVideo=function(){ return this.video; }; /** * Sets the video used by the texture * @param {video} canvas The canvas to use */ GLGE.TextureVideo.prototype.setVideo=function(video){ this.video=video; return this; }; /** * Sets the source used for the video * @param {string} src The URL of the video */ GLGE.TextureVideo.prototype.setSrc=function(src){ this.video.src=src; return this; }; /** * gets the source used for the video * @returns {string} The URL of the video */ GLGE.TextureVideo.prototype.getSrc=function(src){ return this.video.src; }; /** * does the canvas texture GL stuff * @private **/ GLGE.TextureVideo.prototype.doTexture=function(gl){ this.gl=gl; //create the texture if it's not already created if(!this.glTexture){ this.glTexture=gl.createTexture(); gl.bindTexture(gl.TEXTURE_2D, this.glTexture); this.updateTexture(gl); }else{ gl.bindTexture(gl.TEXTURE_2D, this.glTexture); this.updateTexture(gl); } return true; } /** * Updates the canvas texture * @private */ GLGE.TextureVideo.prototype.updateTexture=function(gl){ var video = this.video; gl.bindTexture(gl.TEXTURE_2D, this.glTexture); //TODO: fix this when minefield is upto spec if(video.readyState>0){ if(video.height<=0){ video.style.display=""; video.height=video.offsetHeight; video.width=video.offsetWidth; video.style.display="none"; } this.canvas.height=video.height; this.canvas.width=video.width; this.ctx.drawImage(video, 0, 0); try{gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, this.canvas);} catch(e){gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, this.canvas,null);} gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR); gl.generateMipmap(gl.TEXTURE_2D); /* use when video is working in webkit try{gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, video);} catch(e){gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, video,null);} gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR); gl.generateMipmap(gl.TEXTURE_2D); */ } } })(GLGE);/* GLGE WebGL Graphics Engine Copyright (c) 2010, Paul Brunt All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of GLGE nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL PAUL BRUNT BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /** * @fileOverview * @name glge_lod.js * @author me@paulbrunt.co.uk */ (function(GLGE){ /** * @name GLGE.ObjectLod#downloadComplete * @event fires when all the assets for this LOD have finished loading * @param {object} data */ /** * @class Creates a new load for a multimaterial * @augments GLGE.QuickNotation * @augments GLGE.JSONLoader * @augments GLGE.Events */ GLGE.ObjectLod=function(uid){ this.setMaterial(GLGE.DEFAULT_MATERIAL); GLGE.Assets.registerAsset(this,uid); } GLGE.augment(GLGE.QuickNotation,GLGE.ObjectLod); GLGE.augment(GLGE.JSONLoader,GLGE.ObjectLod); GLGE.augment(GLGE.Events,GLGE.ObjectLod); GLGE.ObjectLod.prototype.mesh=null; GLGE.ObjectLod.prototype.className="ObjectLod"; GLGE.ObjectLod.prototype.material=null; GLGE.ObjectLod.prototype.program=null; GLGE.ObjectLod.prototype.GLShaderProgramPick=null; GLGE.ObjectLod.prototype.GLShaderProgramShadow=null; GLGE.ObjectLod.prototype.GLShaderProgram=null; GLGE.ObjectLod.prototype.pixelSize=0; /** * sets the mesh * @param {GLGE.Mesh} mesh */ GLGE.ObjectLod.prototype.setMesh=function(mesh){ if(typeof mesh=="string") mesh=GLGE.Assets.get(mesh); //remove event listener from current material if(this.mesh){ this.mesh.removeEventListener("shaderupdate",this.meshupdated); this.mesh.removeEventListener("boundupdate",this.boundupdated); } var multiMaterial=this; this.meshupdated=function(event){ multiMaterial.GLShaderProgram=null; }; this.boundupdated=function(event){ multiMaterial.fireEvent("boundupdate",{}); }; //set event listener for new material mesh.addEventListener("shaderupdate",this.meshupdated); mesh.addEventListener("boundupdate",this.boundupdated); this.GLShaderProgram=null; this.mesh=mesh; return this; } /** * Checks if resources have finished downloading * @returns {boolean} */ GLGE.ObjectLod.prototype.isComplete=function(){ return this.material.isComplete(); } /** * gets the mesh * @returns {GLGE.Mesh} */ GLGE.ObjectLod.prototype.getMesh=function(){ return this.mesh; } /** * sets the material * @param {GLGE.Material} material */ GLGE.ObjectLod.prototype.setMaterial=function(material){ if(typeof material=="string") material=GLGE.Assets.get(material); //remove event listener from current material if(this.material){ this.material.removeEventListener("shaderupdate",this.materialupdated); this.material.removeEventListener("downloadComplete",this.downloadComplete); } var ObjectLOD=this; this.materialupdated=function(event){ ObjectLOD.GLShaderProgram=null; }; //set event listener for new material material.addEventListener("shaderupdate",this.materialupdated); this.downloadComplete=function(){ ObjectLOD.fireEvent("downloadComplete"); }; material.addEventListener("downloadComplete",this.downloadComplete); this.GLShaderProgram=null; this.material=material; return this; } /** * gets the material * @returns {GLGE.Material} */ GLGE.ObjectLod.prototype.getMaterial=function(){ return this.material; } /** * gets the pixelsize limit for this lod * @returns {number} */ GLGE.ObjectLod.prototype.getPixelSize=function(){ return this.pixelSize; } /** * sets the pixelsize limit for this lod * @returns {number} */ GLGE.ObjectLod.prototype.setPixelSize=function(value){ this.pixelSize=parseFloat(value); } })(GLGE);/* GLGE WebGL Graphics Engine Copyright (c) 2010, Paul Brunt All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of GLGE nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL PAUL BRUNT BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /** * @fileOverview * @name glge_object.js * @author me@paulbrunt.co.uk */ (function(GLGE){ /** * @name GLGE.Object#downloadComplete * @event fires when all the assets for this class have finished loading * @param {object} data */ /** * @name GLGE.Object#willRender * @event fires when all the assets will be rendered * @param {object} data */ /** * @name GLGE.Object#willRender * @event fires when all the assets will culled * @param {object} data */ /** * @class An object that can be rendered in a scene * @augments GLGE.Animatable * @augments GLGE.Placeable * @augments GLGE.QuickNotation * @augments GLGE.JSONLoader */ GLGE.Object=function(uid){ this.multimaterials=[]; this.renderCaches=[]; var that=this; this.downloadComplete=function(){ if(that.isComplete()) that.fireEvent("downloadComplete"); } GLGE.Assets.registerAsset(this,uid); } GLGE.augment(GLGE.Placeable,GLGE.Object); GLGE.augment(GLGE.Animatable,GLGE.Object); GLGE.augment(GLGE.QuickNotation,GLGE.Object); GLGE.augment(GLGE.JSONLoader,GLGE.Object); GLGE.Object.prototype.className="Object"; GLGE.Object.prototype.mesh=null; GLGE.Object.prototype.skeleton=null; GLGE.Object.prototype.scene=null; GLGE.Object.prototype.transformMatrix=GLGE.identMatrix(); GLGE.Object.prototype.material=null; GLGE.Object.prototype.gl=null; GLGE.Object.prototype.multimaterials=null; GLGE.Object.prototype.zTrans=false; GLGE.Object.prototype.renderCaches=null; GLGE.Object.prototype.id=""; GLGE.Object.prototype.pickable=true; GLGE.Object.prototype.drawType=GLGE.DRAW_TRIS; GLGE.Object.prototype.pointSize=1; GLGE.Object.prototype.lineWidth=1; GLGE.Object.prototype.cull=true; GLGE.Object.prototype.culled=true; GLGE.Object.prototype.visible=true; GLGE.Object.prototype.depthTest=true; GLGE.Object.prototype.meshFrame1=0; GLGE.Object.prototype.meshFrame2=0; GLGE.Object.prototype.meshBlendFactor=0; GLGE.Object.prototype.noCastShadows=null; //shadow fragment var shfragStr=[]; shfragStr.push("#ifdef GL_ES\nprecision highp float;\n#endif\n"); shfragStr.push("uniform float distance;\n"); shfragStr.push("uniform bool shadowtype;\n"); shfragStr.push("varying vec3 eyevec;\n"); shfragStr.push("void main(void)\n "); shfragStr.push("{\n"); shfragStr.push("float depth = gl_FragCoord.z / gl_FragCoord.w;\n"); shfragStr.push("if(shadowtype) depth=length(eyevec);\n"); shfragStr.push("vec4 rgba=fract(depth/distance * vec4(16777216.0, 65536.0, 256.0, 1.0));\n"); shfragStr.push("gl_FragColor=rgba-rgba.rrgb*vec4(0.0,0.00390625,0.00390625,0.00390625);\n"); shfragStr.push("}\n"); GLGE.Object.prototype.shfragStr=shfragStr.join(""); //normal fragment var nfragStr=[]; nfragStr.push("#ifdef GL_ES\nprecision highp float;\n#endif\n"); nfragStr.push("varying vec3 n;\n"); nfragStr.push("void main(void)\n"); nfragStr.push("{\n"); nfragStr.push("float depth = gl_FragCoord.z / gl_FragCoord.w;\n"); nfragStr.push("gl_FragColor=vec4(normalize(n)/2.0+0.5,depth/1000.0);\n"); nfragStr.push("}\n"); GLGE.Object.prototype.nfragStr=nfragStr.join(""); //picking fragment var pkfragStr=[]; pkfragStr.push("#ifdef GL_ES\nprecision highp float;\n#endif\n"); pkfragStr.push("uniform float far;\n"); pkfragStr.push("uniform vec3 pickcolor;\n"); pkfragStr.push("varying vec3 n;\n"); pkfragStr.push("varying vec4 UVCoord;\n"); pkfragStr.push("void main(void)\n"); pkfragStr.push("{\n"); pkfragStr.push("float Xcoord = gl_FragCoord.x+0.5;\n"); pkfragStr.push("if(Xcoord>0.0) gl_FragColor = vec4(pickcolor,1.0);\n"); pkfragStr.push("if(Xcoord>1.0) gl_FragColor = vec4(n,1.0);\n"); pkfragStr.push("if(Xcoord>2.0){"); pkfragStr.push("vec3 rgb=fract((gl_FragCoord.z/gl_FragCoord.w) * vec3(65536.0, 256.0, 1.0));\n"); pkfragStr.push("gl_FragColor=vec4(rgb-rgb.rrg*vec3(0.0,0.00390625,0.00390625),1.0);\n"); pkfragStr.push("}"); //x tex coord pkfragStr.push("if(Xcoord>3.0){"); pkfragStr.push("vec3 rgb=fract(UVCoord.x * vec3(65536.0, 256.0, 1.0));\n"); pkfragStr.push("gl_FragColor=vec4(rgb-rgb.rrg*vec3(0.0,0.00390625,0.00390625),1.0);\n"); pkfragStr.push("}"); //y tex coord pkfragStr.push("if(Xcoord>4.0){"); pkfragStr.push("vec3 rgb=fract(UVCoord.y * vec3(65536.0, 256.0, 1.0));\n"); pkfragStr.push("gl_FragColor=vec4(rgb-rgb.rrg*vec3(0.0,0.00390625,0.00390625),1.0);\n"); pkfragStr.push("}"); pkfragStr.push("}\n"); GLGE.Object.prototype.pkfragStr=pkfragStr.join(""); /** * Sets the object visibility * @param {boolean} visable flag to indicate the objects visibility */ GLGE.Object.prototype.setVisible=function(visible){ this.visible=visible; return this; } /** * Gets the object visibility * @returns flag to indicate the objects visibility */ GLGE.Object.prototype.getVisible=function(){ return this.visible; } /** * Sets the first mesh frame to use when using an animated mesh * @param {boolean} frame the inital frame */ GLGE.Object.prototype.setMeshFrame1=function(frame){ this.meshFrame1=frame; return this; } /** * Sets the second mesh frame to use when using an animated mesh * @param {boolean} frame the final frame */ GLGE.Object.prototype.setMeshFrame2=function(frame){ this.meshFrame2=frame; return this; } /** * blending between frames * @param {boolean} frame value 0-1 morth between frame1 and frame2 */ GLGE.Object.prototype.setMeshBlendFactor=function(factor){ this.meshBlendFactor=factor; return this; } /** * Gets blending between frames * @returns blender factor */ GLGE.Object.prototype.getMeshBlendFactor=function(){ return this.meshBlendFactor; } /** * Gets the pickable flag for the object */ GLGE.Object.prototype.getPickable=function(){ return this.pickable; } /** * Sets the pickable flag for the object * @param {boolean} value the culling flag */ GLGE.Object.prototype.setPickable=function(pickable){ this.pickable=pickable; return this; } /** * Gets the depth test flag for the object */ GLGE.Object.prototype.getDepthTest=function(){ return this.depthTest; } /** * Sets the depth test flag for the object * @param {boolean} value the culling flag */ GLGE.Object.prototype.setDepthTest=function(test){ this.depthTest=test; return this; } /** * Gets the culling flag for the object */ GLGE.Object.prototype.getCull=function(){ return this.cull; } /** * Sets the culling flag for the object * @param {boolean} value the culling flag */ GLGE.Object.prototype.setCull=function(cull){ this.cull=cull; return this; } /** * Gets the objects draw type */ GLGE.Object.prototype.getDrawType=function(){ return this.drawType; } /** * Sets the objects draw type * @param {GLGE.number} value the draw type of this object */ GLGE.Object.prototype.setDrawType=function(value){ this.drawType=value; return this; } /** * Gets the objects draw point size */ GLGE.Object.prototype.getPointSize=function(){ return this.pointSize; } /** * Sets the objects draw points size * @param {GLGE.number} value the point size to render */ GLGE.Object.prototype.setPointSize=function(value){ this.pointSize=parseFloat(value); return this; } /** * Gets the objects line width */ GLGE.Object.prototype.getLineWidth=function(){ return this.lineWidth; } /** * Sets the objects line width * @param {GLGE.number} value the line width */ GLGE.Object.prototype.setLineWidth=function(value){ this.lineWidth=parseFloat(value); return this; } /** * Sets a custom usinform on this object * @param {string} type the uniform type eg 1i, 3fv, Matrix4fv, etc * @param {string} name the uniform name * @param {array} value the value of the uniform */ GLGE.Object.prototype.setUniform=function(type,name,value){ if(!this.uniforms) this.uniforms={}; this.uniforms[name]={type:type,value:value}; } /** * Gets the value of a custom uniform * @param {string} name the name of the uniform to return * @returns {number} the value of the uniform */ GLGE.Object.prototype.getUniform=function(name){ if(!this.uniforms) this.uniforms={}; return this.uniforms[name].value } /** * Gets the type of a custom uniform * @param {string} name the name of the uniform to return * @returns {number} the type of the uniform */ GLGE.Object.prototype.getUniformType=function(name){ if(!this.uniforms) this.uniforms={}; return this.uniforms[name].type; } /** * Sets the code to inject into the vertex shader * @param {string} shader the glsl code to inject into the vertex shader of this object GLGE will call the function GLGE_Position(vec4 position) to modify the position */ GLGE.Object.prototype.setVertexShaderInjection=function(shader){ this.shaderVertexInjection=shader; this.updateProgram(); return this; } /** * Gets the glsl code injected into the vertex shader of this object * @returns {string} shader the glsl code injected into the vertex shader of this object */ GLGE.Object.prototype.getVertexShaderInjection=function(shader){ return this.shaderVertexInjection; } /** * Gets the objects skeleton * @returns GLGE.Group */ GLGE.Object.prototype.getSkeleton=function(){ return this.skeleton; } /** * Sets the objects skeleton * @param {GLGE.Group} value the skeleton group to set */ GLGE.Object.prototype.setSkeleton=function(value){ this.skeleton=value; this.bones=null; return this; } GLGE.Object.prototype.getBoundingVolume=function(local){ if(!local) local=0; if(!this.boundingVolume) this.boundingVolume=[]; if(!this.boundmatrix) this.boundmatrix=[]; var matrix=this.getModelMatrix(); if(matrix!=this.boundmatrix[local] || !this.boundingVolume[local]){ var multimaterials=this.multimaterials; var boundingVolume; for(var i=0;i1){ vertexStr.push("attribute vec"+this.mesh.buffers[i].size+" "+this.mesh.buffers[i].name+";\n"); }else{ vertexStr.push("attribute float "+this.mesh.buffers[i].name+";\n"); } if(this.mesh.buffers[i].name=="UV") UV=true; if(this.mesh.buffers[i].name=="color") colors=true; if(this.mesh.buffers[i].name=="joints1") joints1=this.mesh.buffers[i]; if(this.mesh.buffers[i].name=="joints2") joints2=this.mesh.buffers[i]; } if(this.mesh.framePositions.length>1){ var morph=true; vertexStr.push("attribute vec3 position2;\n"); vertexStr.push("attribute vec3 normal2;\n"); vertexStr.push("uniform float framesBlend;\n"); if(tangent) vertexStr.push("attribute vec3 tangent2;\n"); } if(tangent) vertexStr.push("attribute vec3 tangent;\n"); vertexStr.push("uniform mat4 worldView;\n"); vertexStr.push("uniform mat4 projection;\n"); vertexStr.push("uniform mat4 worldInverseTranspose;\n"); vertexStr.push("uniform mat4 envMat;\n"); //vertexStr.push("uniform vec3 cameraPos;\n"); vertexStr.push("uniform float cascadeLevel;\n"); for(var i=0; i0){ vertexStr.push("uniform vec4 jointMat["+(3*this.mesh.joints.length)+"];\n"); } if(this.material) vertexStr.push(this.material.getVertexVarying(vertexStr)); vertexStr.push("varying vec3 n;\n"); vertexStr.push("varying vec3 t;\n"); if(colors) vertexStr.push("varying vec4 vcolor;\n"); vertexStr.push("varying vec4 UVCoord;\n"); vertexStr.push("varying vec3 OBJCoord;\n"); if(this.shaderVertexInjection){ vertexStr.push(this.shaderVertexInjection); } vertexStr.push("void main(void)\n"); vertexStr.push("{\n"); if(colors) vertexStr.push("vcolor=color;\n"); if(UV) vertexStr.push("UVCoord=UV;\n"); else vertexStr.push("UVCoord=vec4(0.0,0.0,0.0,0.0);\n"); vertexStr.push("OBJCoord = position;\n"); vertexStr.push("vec3 tang;\n"); vertexStr.push("vec4 pos = vec4(0.0, 0.0, 0.0, 1.0);\n"); vertexStr.push("vec4 norm = vec4(0.0, 0.0, 0.0, 1.0);\n"); if(tangent) vertexStr.push("vec4 tang4 = vec4(0.0, 0.0, 0.0, 1.0);\n"); if(joints1){ if(joints1.size==1){ vertexStr.push("pos += vec4(dot(jointMat[int(3.0*joints1)],vec4(position,1.0)),\n"+ " dot(jointMat[int(3.0*joints1+1.0)],vec4(position,1.0)),\n"+ " dot(jointMat[int(3.0*joints1+2.0)],vec4(position,1.0)),1.0)*weights1;\n"); vertexStr.push("norm += vec4(dot(jointMat[int(3.0*joints1)].xyz,normal),\n"+ " dot(jointMat[int(3.0*joints1+1.0)].xyz,normal),\n"+ " dot(jointMat[int(3.0*joints1+2.0)].xyz,normal),1.0)*weights1;\n"); if (tangent) vertexStr.push("tang4 += vec4(dot(jointMat[int(3.0*joints1)].xyz,tangent),\n"+ " dot(jointMat[int(3.0*joints1+1.0)].xyz,tangent),\n"+ " dot(jointMat[int(3.0*joints1+2.0)].xyz,tangent),1.0)*weights1;\n"); }else{ for(var i=0;i-1){ vertexStr.push("pos=GLGE_Position(vec4(pos.xyz, 1.0));\n"); } vertexStr.push("pos = worldView * vec4(pos.xyz, 1.0);\n"); vertexStr.push("norm = worldInverseTranspose * vec4(norm.xyz, 1.0);\n"); if(tangent) vertexStr.push("tang = (worldInverseTranspose*vec4(tang4.xyz,1.0)).xyz;\n"); }else{ if(morph){ vertexStr.push("vec4 pos4=vec4(mix(position,position2,framesBlend),1.0);\n"); }else{ vertexStr.push("vec4 pos4=vec4(position,1.0);\n"); } if(this.shaderVertexInjection && this.shaderVertexInjection.indexOf("GLGE_Position")>-1){ vertexStr.push("pos4=GLGE_Position(pos4);\n"); } //vertexStr.push("pos4.xyz = (pos4.xyz-cameraPos.xyz)/(pow(length(pos4.xyz-cameraPos.xyz),0.5))+cameraPos.xyz;\n"); for(var i=0; i> 16 & 0xFF; var g = pickindex >> 8 & 0xFF; var r = pickindex & 0xFF; GLGE.setUniform3(gl,"3f",GLGE.getUniformLocation(gl,program, "pickcolor"), r/255,g/255,b/255); break; } //set the line width gl.lineWidth(this.lineWidth); //set custom uinforms for(var key in this.uniforms){ var uniform=this.uniforms[key]; if(uniform.type=="Matrix4fv"){ GLGE.setUniformMatrix(gl,"Matrix4fv",GLGE.getUniformLocation(gl,program, key),false,uniform.value); }else{ GLGE.setUniform(gl,uniform.type,GLGE.getUniformLocation(gl,program, key),uniform.value); } } if(!program.caches) program.caches={}; if(!program.glarrays) program.glarrays={}; var pc=program.caches; var pgl=program.glarrays; var scene=gl.scene; var camera=scene.camera; if(pc.far!=camera.far){ GLGE.setUniform(gl,"1i",GLGE.getUniformLocation(gl,program, "far"), camera.far); pc.far=camera.far; } if(renderType==GLGE.RENDER_DEFAULT || renderType==GLGE.RENDER_EMIT){ if(pc.ambientColor!=scene.ambientColor){ var ambientColor=scene.ambientColor; GLGE.setUniform3(gl,"3f",GLGE.getUniformLocation(gl,program, "amb"), ambientColor.r,ambientColor.g,ambientColor.b); pc.ambientColor=ambientColor; } if(pc.fogFar!=scene.fogFar){ GLGE.setUniform(gl,"1f",GLGE.getUniformLocation(gl,program, "fogfar"), scene.fogFar); pc.fogFar=scene.fogFar; } if(pc.fogNear!=scene.fogNear){ GLGE.setUniform(gl,"1f",GLGE.getUniformLocation(gl,program, "fognear"), scene.fogNear); pc.fogNear=scene.fogNear; } if(pc.fogType!=scene.fogType){ GLGE.setUniform(gl,"1i",GLGE.getUniformLocation(gl,program, "fogtype"), scene.fogType); pc.fogType=scene.fogType; } if(pc.fogType!=scene.fogcolor){ GLGE.setUniform3(gl,"3f",GLGE.getUniformLocation(gl,program, "fogcolor"), scene.fogColor.r,scene.fogColor.g,scene.fogColor.b); pc.fogcolor=scene.fogcolor; } } if(pc.meshBlendFactor!=this.meshBlendFactor){ GLGE.setUniform(gl,"1f",GLGE.getUniformLocation(gl,program, "framesBlend"), this.meshBlendFactor); pc.meshBlendFactor=this.meshBlendFactor; } var cameraMatrix=camera.getViewMatrix(); var objMatrix=modelMatrix=this.getModelMatrix(); if(!pc.mvMatrix) pc.mvMatrix={cameraMatrix:null,modelMatrix:null}; var mvCache=pc.mvMatrix; if(mvCache.cameraMatrix!=cameraMatrix || mvCache.modelMatrix!=modelMatrix){ //generate and set the modelView matrix if(!this.caches.mvMatrix) this.caches.mvMatrix=GLGE.mulMat4(cameraMatrix,modelMatrix); mvMatrix=this.caches.mvMatrix; if(this.mesh.joints){ mvMatrix=cameraMatrix; } //GLGE.setUniform3(gl,"3f",GLGE.getUniformLocation(gl,program, "cameraPos"),camera.location[0],camera.location[1],camera.location[2]); var mvUniform = GLGE.getUniformLocation(gl,program, "worldView"); var M1=GLGE.transposeMat4(mvMatrix); if(!pgl.mvMatrix){ pgl.mvMatrixT=new Float32Array(M1); }else{ GLGE.mat4gl(M1,pgl.mvMatrixT); } //GLGE.reuseMatrix4(M1); pgl.mvMatrix=mvMatrix; GLGE.setUniformMatrix(gl,"Matrix4fv",mvUniform, false, program.glarrays.mvMatrixT); //invCamera matrix var icUniform = GLGE.getUniformLocation(gl,program, "envMat"); if(icUniform){ if(!this.caches.envMat){ var envMat = GLGE.inverseMat4(mvMatrix); envMat[3]=0; envMat[7]=0; envMat[11]=0; this.caches.envMat = envMat; } envMat=this.caches.envMat; M1=GLGE.transposeMat4(envMat); if(!program.glarrays.envMat){ pgl.envMatT=new Float32Array(M1); }else{ GLGE.mat4gl(M1,pgl.envMatT); } //GLGE.reuseMatrix4(M1); pgl.envMat=envMat; GLGE.setUniformMatrix(gl,"Matrix4fv",icUniform, false, pgl.envMatT); } //normalising matrix if(!this.caches.normalMatrix){ var normalMatrix = GLGE.inverseMat4(mvMatrix); this.caches.normalMatrix = normalMatrix; } normalMatrix=this.caches.normalMatrix; var nUniform = GLGE.getUniformLocation(gl,program, "worldInverseTranspose"); if(!pgl.normalMatrix) pgl.normalMatrix=new Float32Array(normalMatrix); else GLGE.mat4gl(normalMatrix,pgl.normalMatrix); GLGE.setUniformMatrix(gl,"Matrix4fv",nUniform, false, pgl.normalMatrix); var cUniform = GLGE.getUniformLocation(gl,program, "view"); M1=GLGE.transposeMat4(cameraMatrix); if(!pgl.cameraMatrix){ pgl.cameraMatrixT=new Float32Array(M1); }else{ GLGE.mat4gl(M1,pgl.cameraMatrixT); } //GLGE.reuseMatrix4(M1); pgl.cameraMatrix=cameraMatrix; GLGE.setUniformMatrix(gl,"Matrix4fv",cUniform, false, pgl.cameraMatrixT); mvCache.cameraMatrix=cameraMatrix; mvCache.modelMatrix=modelMatrix; } var pUniform = GLGE.getUniformLocation(gl,program, "projection"); M1=GLGE.transposeMat4(camera.getProjectionMatrix()); if(!pgl.pMatrix){ pgl.pMatrixT=new Float32Array(M1); }else{ GLGE.mat4gl(M1,pgl.pMatrixT); } //GLGE.reuseMatrix4(M1); pgl.pMatrix=camera.getProjectionMatrix(); GLGE.setUniformMatrix(gl,"Matrix4fv",pUniform, false, pgl.pMatrixT); //light //dont' need lighting for picking if(renderType==GLGE.RENDER_DEFAULT || renderType==GLGE.RENDER_SHADOW || renderType==GLGE.RENDER_DEPTH || renderType==GLGE.RENDER_EMIT){ var pos,lpos; var lights=gl.lights if(!pc.lights) pc.lights=[]; if(!pgl.lights) pgl.lights=[]; if(!this.caches.lights) this.caches.lights=[]; var lightCache=pc.lights; for(var i=0; i1 && !pixelsize){ var camerapos=gl.scene.camera.getPosition(); var modelpos=this.getPosition(); var dist=GLGE.lengthVec3([camerapos.x-modelpos.x,camerapos.y-modelpos.y,camerapos.z-modelpos.z]); dist=GLGE.mulMat4Vec4(gl.scene.camera.getProjectionMatrix(),[this.getBoundingVolume().getSphereRadius(),0,-dist,1]); pixelsize=dist[0]/dist[3]*gl.scene.renderer.canvas.width; } var lod=this.multimaterials[i].getLOD(pixelsize); if(lod.mesh && lod.mesh.loaded){ if(renderType==GLGE.RENDER_NULL){ if(lod.material) lod.material.registerPasses(gl,this); break; } if(!lod.GLShaderProgram){ this.createShaders(lod); }else{ this.GLShaderProgramPick=lod.GLShaderProgramPick; this.GLShaderProgramShadow=lod.GLShaderProgramShadow; this.GLShaderProgram=lod.GLShaderProgram; } this.mesh=lod.mesh; this.material=lod.material; var drawType; switch(this.drawType){ case GLGE.DRAW_LINES: drawType=gl.LINES; break; case GLGE.DRAW_POINTS: drawType=gl.POINTS; break; case GLGE.DRAW_LINELOOPS: drawType=gl.LINE_LOOP; break; case GLGE.DRAW_LINESTRIPS: drawType=gl.LINE_STRIP; break; case GLGE.DRAW_TRIANGLESTRIP: drawType=gl.TRIANGLE_STRIP; break; default: drawType=gl.TRIANGLES; break; } switch(renderType){ case GLGE.RENDER_DEFAULT: case GLGE.RENDER_EMIT: if(gl.program!=this.GLShaderProgram){ gl.useProgram(this.GLShaderProgram); gl.program=this.GLShaderProgram; } this.mesh.GLAttributes(gl,this.GLShaderProgram,this.meshFrame1,this.meshFrame2); break; case GLGE.RENDER_SHADOW: case GLGE.RENDER_DEPTH: if(gl.program!=this.GLShaderProgramShadow){ gl.useProgram(this.GLShaderProgramShadow,this.meshFrame1,this.meshFrame2); gl.program=this.GLShaderProgramShadow; } if(!distance) distance=gl.scene.camera.getFar(); GLGE.setUniform(gl,"1f",GLGE.getUniformLocation(gl,this.GLShaderProgramShadow, "distance"), distance); this.mesh.GLAttributes(gl,this.GLShaderProgramShadow,this.meshFrame1,this.meshFrame2); break; case GLGE.RENDER_NORMAL: if(gl.program!=this.GLShaderProgramNormal){ gl.useProgram(this.GLShaderProgramNormal); gl.program=this.GLShaderProgramNormal; } this.mesh.GLAttributes(gl,this.GLShaderProgramNormal,this.meshFrame1,this.meshFrame2); break; case GLGE.RENDER_PICK: if(gl.program!=this.GLShaderProgramPick){ gl.useProgram(this.GLShaderProgramPick); gl.program=this.GLShaderProgramPick; } this.mesh.GLAttributes(gl,this.GLShaderProgramPick,this.meshFrame1,this.meshFrame2); drawType=gl.TRIANGLES; break; } //render the object this.GLUniforms(gl,renderType,pickindex); switch (this.mesh.windingOrder) { case GLGE.Mesh.WINDING_ORDER_UNKNOWN: if (gl.scene.renderer.cullFaces) gl.enable(gl.CULL_FACE); else gl.disable(gl.CULL_FACE); break; case GLGE.Mesh.WINDING_ORDER_CLOCKWISE: gl.enable(gl.CULL_FACE); break; case GLGE.Mesh.WINDING_ORDER_COUNTER: gl.cullFace(gl.FRONT); gl.enable(gl.CULL_FACE); default: break; } if(this.noDepthMask) gl.depthMask(false); if(this.mesh.GLfaces){ gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.mesh.GLfaces); gl.drawElements(drawType, this.mesh.GLfaces.numItems, gl.UNSIGNED_SHORT, 0); }else{ gl.drawArrays(drawType, 0, this.mesh.positions.length/3); } gl.depthMask(true); switch (this.mesh.windingOrder) { case GLGE.Mesh.WINDING_ORDER_UNKNOWN: if (gl.scene.renderer.cullFaces) gl.enable(gl.CULL_FACE); break; case GLGE.Mesh.WINDING_ORDER_COUNTER: gl.cullFace(gl.BACK); default: break; } var matrix=this.matrix; var caches=this.caches; this.matrix=matrix; this.caches=caches; } } } })(GLGE);/* GLGE WebGL Graphics Engine Copyright (c) 2010, Paul Brunt All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of GLGE nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL PAUL BRUNT BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /** * @fileOverview * @name glge_text.js * @author me@paulbrunt.co.uk */ (function(GLGE){ /** * @class Text that can be rendered in a scene * @augments GLGE.Animatable * @augments GLGE.Placeable * @augments GLGE.QuickNotation * @augments GLGE.JSONLoader */ GLGE.Text=function(uid){ this.canvas=document.createElement("canvas"); this.scaleCanvas=document.createElement("canvas"); this.color={r:1.0,g:1.0,b:1.0}; GLGE.Assets.registerAsset(this,uid); } GLGE.augment(GLGE.Placeable,GLGE.Text); GLGE.augment(GLGE.Animatable,GLGE.Text); GLGE.augment(GLGE.QuickNotation,GLGE.Text); GLGE.augment(GLGE.JSONLoader,GLGE.Text); GLGE.Text.prototype.className="Text"; GLGE.Text.prototype.zTrans=true; GLGE.Text.prototype.canvas=null; GLGE.Text.prototype.aspect=1.0; GLGE.Text.prototype.color=null; GLGE.Text.prototype.text=""; GLGE.Text.prototype.font="Times"; GLGE.Text.prototype.size=100; GLGE.Text.prototype.pickType=GLGE.TEXT_TEXTPICK; GLGE.Text.prototype.pickable=true; GLGE.Text.prototype.alpha=1; GLGE.Text.prototype.dirty=true; /** * Gets the pick type for this text * @returns {string} the pick type */ GLGE.Text.prototype.getPickType=function(){ return this.pickType; }; /** * Sets the pick type GLGE.TEXT_BOXPICK for picking based on bound box or GLGE.TEXT_TEXTPICK for pixel perfect text picking * @param {Number} value the picking type */ GLGE.Text.prototype.setPickType=function(value){ this.pickType=value; return this; }; /** * Gets the aspect of the text * @returns {Number} the aspect of the text */ GLGE.Text.prototype.getAspect=function(){ return this.aspect; }; /** * Sets the aspect of the text * @param {Number} value the aspect of the text */ GLGE.Text.prototype.setAspect=function(value){ this.aspect=value; this.dirty=true; return this; }; /** * Gets the font of the text * @returns {string} the font of the text */ GLGE.Text.prototype.getFont=function(){ return this.size; }; /** * Sets the font of the text * @param {string} value the font of the text */ GLGE.Text.prototype.setFont=function(value){ this.font=value; this.dirty=true; return this; }; /** * Gets the size of the text * @returns {string} the size of the text */ GLGE.Text.prototype.getSize=function(){ return this.size; }; /** * Sets the size of the text * @param {Number} value the size of the text */ GLGE.Text.prototype.setSize=function(value){ this.size=value; this.dirty=true; return this; }; /** * Gets the rendered text * @returns {string} the text rendered */ GLGE.Text.prototype.getText=function(){ return this.text; }; /** * Sets the text to be rendered * @param {Number} value the text to render */ GLGE.Text.prototype.setText=function(value){ this.text=value; this.dirty=true; return this; }; /** * Sets the base colour of the text * @param {string} color The colour of the material */ GLGE.Text.prototype.setColor=function(color){ color=GLGE.colorParse(color); this.color={r:color.r,g:color.g,b:color.b}; return this; }; /** * Sets the red base colour of the text * @param {Number} r The new red level 0-1 */ GLGE.Text.prototype.setColorR=function(value){ this.color.r=value; return this; }; /** * Sets the green base colour of the text * @param {Number} g The new green level 0-1 */ GLGE.Text.prototype.setColorG=function(value){ this.color.g=value; return this; }; /** * Sets the blue base colour of the text * @param {Number} b The new blue level 0-1 */ GLGE.Text.prototype.setColorB=function(value){ this.color.b=value; return this; }; /** * Gets the current base color of the text * @return {[r,g,b]} The current base color */ GLGE.Text.prototype.getColor=function(){ return this.color; return this; }; /** * Sets the alpha * @param {Number} b The new alpha level 0-1 */ GLGE.Text.prototype.setAlpha=function(value){ this.alpha=value; return this; }; /** * Gets the alpha * @returns The alpha level */ GLGE.Text.prototype.getAlpha=function(){ return this.alpha; }; /** * Sets the Z Transparency of this text * @param {boolean} value Does this object need blending? */ GLGE.Text.prototype.setZtransparent=function(value){ this.zTrans=value; return this; } /** * Gets the z transparency * @returns boolean */ GLGE.Text.prototype.isZtransparent=function(){ return this.zTrans; } /** * Creates the shader program for the object * @private */ GLGE.Text.prototype.GLGenerateShader=function(gl){ if(this.GLShaderProgram) gl.deleteProgram(this.GLShaderProgram); //Vertex Shader var vertexStr=""; vertexStr+="attribute vec3 position;\n"; vertexStr+="attribute vec2 uvcoord;\n"; vertexStr+="varying vec2 texcoord;\n"; vertexStr+="uniform mat4 Matrix;\n"; vertexStr+="uniform mat4 PMatrix;\n"; vertexStr+="varying vec4 pos;\n"; vertexStr+="void main(void){\n"; vertexStr+="texcoord=uvcoord;\n"; vertexStr+="pos = Matrix * vec4(position,1.0);\n"; vertexStr+="gl_Position = PMatrix * pos;\n"; vertexStr+="}\n"; //Fragment Shader var fragStr="#ifdef GL_ES\nprecision highp float;\n#endif\n"; fragStr=fragStr+"uniform sampler2D TEXTURE;\n"; fragStr=fragStr+"varying vec2 texcoord;\n"; fragStr=fragStr+"uniform mat4 Matrix;\n"; fragStr=fragStr+"varying vec4 pos;\n"; fragStr=fragStr+"uniform float far;\n"; fragStr=fragStr+"uniform bool depthrender;\n"; fragStr=fragStr+"uniform float distance;\n"; fragStr=fragStr+"uniform int picktype;\n"; fragStr=fragStr+"uniform vec3 pickcolor;\n"; fragStr=fragStr+"uniform vec3 color;\n"; fragStr=fragStr+"uniform float alpha;\n"; fragStr=fragStr+"void main(void){\n"; fragStr=fragStr+"float ob=pow(min(1.0,abs(dot(normalize(Matrix[2].rgb),vec3(0.0,0.0,1.0)))*2.0),1.5);\n"; fragStr=fragStr+"float a=texture2D(TEXTURE,texcoord).a*alpha*ob;\n"; fragStr=fragStr+"if(picktype=="+GLGE.TEXT_BOXPICK+"){gl_FragColor = vec4(pickcolor,1.0);}" fragStr=fragStr+"else if(picktype=="+GLGE.TEXT_TEXTPICK+"){if(alpha<1.0) discard; gl_FragColor = vec4(pickcolor,alpha);}" fragStr=fragStr+"else{gl_FragColor = vec4(color.rgb,a);};\n"; fragStr=fragStr+"if (depthrender) { if(a<0.5) discard; float depth = gl_FragCoord.z / gl_FragCoord.w;\n"; fragStr=fragStr+"vec4 rgba=fract(depth/distance * vec4(16777216.0, 65536.0, 256.0, 1.0));\n"; fragStr=fragStr+"gl_FragColor=rgba-rgba.rrgb*vec4(0.0,0.00390625,0.00390625,0.00390625);}\n"; fragStr=fragStr+"}\n"; this.GLFragmentShader=gl.createShader(gl.FRAGMENT_SHADER); this.GLVertexShader=gl.createShader(gl.VERTEX_SHADER); gl.shaderSource(this.GLFragmentShader, fragStr); gl.compileShader(this.GLFragmentShader); if (!gl.getShaderParameter(this.GLFragmentShader, gl.COMPILE_STATUS)) { GLGE.error(gl.getShaderInfoLog(this.GLFragmentShader)); return; } //set and compile the vertex shader //need to set str gl.shaderSource(this.GLVertexShader, vertexStr); gl.compileShader(this.GLVertexShader); if (!gl.getShaderParameter(this.GLVertexShader, gl.COMPILE_STATUS)) { GLGE.error(gl.getShaderInfoLog(this.GLVertexShader)); return; } this.GLShaderProgram = gl.createProgram(); gl.attachShader(this.GLShaderProgram, this.GLVertexShader); gl.attachShader(this.GLShaderProgram, this.GLFragmentShader); gl.linkProgram(this.GLShaderProgram); } /** * Initiallize all the GL stuff needed to render to screen * @private */ GLGE.Text.prototype.GLInit=function(gl){ this.gl=gl; this.createPlane(gl); this.GLGenerateShader(gl); this.glTexture=gl.createTexture(); this.dirty=true; } /** * Updates the canvas texture * @private */ GLGE.Text.prototype.updateCanvas=function(gl){ var canvas = this.canvas; canvas.width=1; canvas.height=this.size*1.2; var ctx = canvas.getContext("2d"); ctx.font = this.size+"px "+this.font; canvas.width= ctx.measureText(this.text).width || 80; canvas.height=this.size*1.2; ctx = canvas.getContext("2d"); ctx.textBaseline="top"; ctx.font = (this.extra||"") + " " + this.size+"px "+this.font; this.aspect=canvas.width/canvas.height; ctx.fillText(this.text, 0, 0); var height=Math.pow(2,Math.ceil(Math.log(canvas.height))/(Math.log(2))); var width=Math.pow(2,Math.ceil(Math.log(canvas.width))/(Math.log(2))); this.scaleCanvas.height=height; this.scaleCanvas.width=width; this.scaleContext=this.scaleCanvas.getContext("2d"); this.scaleContext.clearRect(0,0,width,height); this.scaleContext.drawImage(canvas, 0, 0, width, height); gl.bindTexture(gl.TEXTURE_2D, this.glTexture); //TODO: fix this when minefield is upto spec try{gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, this.scaleCanvas);} catch(e){gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, this.scaleCanvas,null);} 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.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR_MIPMAP_LINEAR); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR); gl.generateMipmap(gl.TEXTURE_2D); gl.bindTexture(gl.TEXTURE_2D, null); this.dirty=false; } /** * Renders the text to the render buffer * @private */ GLGE.Text.prototype.GLRender=function(gl,renderType,pickindex){ if(!this.gl){ this.GLInit(gl); } if(this.dirty) this.updateCanvas(gl); if(renderType==GLGE.RENDER_DEFAULT || renderType==GLGE.RENDER_PICK || renderType==GLGE.RENDER_SHADOW){ //if look at is set then look if(this.lookAt) this.Lookat(this.lookAt); if(gl.program!=this.GLShaderProgram){ gl.useProgram(this.GLShaderProgram); gl.program=this.GLShaderProgram; } var attribslot; //disable all the attribute initially arrays - do I really need this? for(var i=0; i<8; i++) gl.disableVertexAttribArray(i); attribslot=GLGE.getAttribLocation(gl,this.GLShaderProgram, "position"); gl.bindBuffer(gl.ARRAY_BUFFER, this.posBuffer); gl.enableVertexAttribArray(attribslot); gl.vertexAttribPointer(attribslot, this.posBuffer.itemSize, gl.FLOAT, false, 0, 0); attribslot=GLGE.getAttribLocation(gl,this.GLShaderProgram, "uvcoord"); gl.bindBuffer(gl.ARRAY_BUFFER, this.uvBuffer); gl.enableVertexAttribArray(attribslot); gl.vertexAttribPointer(attribslot, this.uvBuffer.itemSize, gl.FLOAT, false, 0, 0); gl.activeTexture(gl["TEXTURE0"]); gl.bindTexture(gl.TEXTURE_2D, this.glTexture); GLGE.setUniform(gl,"1i",GLGE.getUniformLocation(gl,this.GLShaderProgram, "TEXTURE"),0); if(!pickindex) pickindex=0; var b = pickindex >> 16 & 0xFF; var g = pickindex >> 8 & 0xFF; var r = pickindex & 0xFF; GLGE.setUniform3(gl,"3f",GLGE.getUniformLocation(gl,this.GLShaderProgram, "pickcolor"),r/255,g/255,b/255); if(renderType==GLGE.RENDER_PICK){ GLGE.setUniform(gl,"1i",GLGE.getUniformLocation(gl,this.GLShaderProgram, "picktype"), this.pickType); }else{ GLGE.setUniform(gl,"1i",GLGE.getUniformLocation(gl,this.GLShaderProgram, "picktype"), 0); } var distance=gl.scene.camera.getFar(); GLGE.setUniform(gl,"1f",GLGE.getUniformLocation(gl,this.GLShaderProgram, "distance"), distance); if(renderType==GLGE.RENDER_SHADOW){ GLGE.setUniform(gl,"1i",GLGE.getUniformLocation(gl,this.GLShaderProgram, "depthrender"), 1); }else{ GLGE.setUniform(gl,"1i",GLGE.getUniformLocation(gl,this.GLShaderProgram, "depthrender"), 0); } if(!this.GLShaderProgram.glarrays) this.GLShaderProgram.glarrays={}; //generate and set the modelView matrix var scalefactor=this.size/100; var mMatrix=GLGE.mulMat4(gl.scene.camera.getViewMatrix(),GLGE.mulMat4(this.getModelMatrix(),GLGE.scaleMatrix(this.aspect*scalefactor,scalefactor,scalefactor))); var mUniform = GLGE.getUniformLocation(gl,this.GLShaderProgram, "Matrix"); if(!this.GLShaderProgram.glarrays.mMatrix) this.GLShaderProgram.glarrays.mMatrix=new Float32Array(mMatrix); else GLGE.mat4gl(mMatrix,this.GLShaderProgram.glarrays.mMatrix); GLGE.setUniformMatrix(gl,"Matrix4fv",mUniform, true, this.GLShaderProgram.glarrays.mMatrix); var mUniform = GLGE.getUniformLocation(gl,this.GLShaderProgram, "PMatrix"); if(!this.GLShaderProgram.glarrays.pMatrix) this.GLShaderProgram.glarrays.pMatrix=new Float32Array(gl.scene.camera.getProjectionMatrix()); else GLGE.mat4gl(gl.scene.camera.getProjectionMatrix(),this.GLShaderProgram.glarrays.pMatrix); GLGE.setUniformMatrix(gl,"Matrix4fv",mUniform, true, this.GLShaderProgram.glarrays.pMatrix); var farUniform = GLGE.getUniformLocation(gl,this.GLShaderProgram, "far"); GLGE.setUniform(gl,"1f",farUniform, gl.scene.camera.getFar()); var alphaUniform = GLGE.getUniformLocation(gl,this.GLShaderProgram, "alpha"); GLGE.setUniform(gl,"1f",alphaUniform, this.alpha); //set the color GLGE.setUniform3(gl,"3f",GLGE.getUniformLocation(gl,this.GLShaderProgram, "color"), this.color.r,this.color.g,this.color.b); gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.GLfaces); gl.drawElements(gl.TRIANGLES, this.GLfaces.numItems, gl.UNSIGNED_SHORT, 0); gl.scene.lastMaterial=null; } } /** * creates the plane mesh to draw * @private */ GLGE.Text.prototype.createPlane=function(gl){ //create the vertex positions if(!this.posBuffer) this.posBuffer = gl.createBuffer(); gl.bindBuffer(gl.ARRAY_BUFFER, this.posBuffer); gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([1,1,0,-1,1,0,-1,-1,0,1,-1,0]), gl.STATIC_DRAW); this.posBuffer.itemSize = 3; this.posBuffer.numItems = 4; //create the vertex uv coords if(!this.uvBuffer) this.uvBuffer = gl.createBuffer(); gl.bindBuffer(gl.ARRAY_BUFFER, this.uvBuffer); gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([0,0,1,0,1,1,0,1]), gl.STATIC_DRAW); this.uvBuffer.itemSize = 2; this.uvBuffer.numItems = 4; //create the faces if(!this.GLfaces) this.GLfaces = gl.createBuffer(); gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.GLfaces); gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array([2,1,0,0,3,2]), gl.STATIC_DRAW); this.GLfaces.itemSize = 1; this.GLfaces.numItems = 6; } })(GLGE);/* GLGE WebGL Graphics Engine Copyright (c) 2010, Paul Brunt All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of GLGE nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL PAUL BRUNT BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /** * @fileOverview * @name glge_renderer.js * @author me@paulbrunt.co.uk */ (function(GLGE){ /** * @class Sets the scene to render * @param {object} canvas The canvas element to render to * @augments GLGE.QuickNotation */ GLGE.Renderer=function(canvas,error,props){ this.viewport=[]; this.canvas=canvas; if(!props) props={alpha:true,depth:true,stencil:true,antialias:true,premultipliedAlpha:true}; try { this.gl = canvas.getContext("experimental-webgl",props); } catch(e) {} try { if(!this.gl) this.gl = canvas.getContext("webgl",props); } catch(e) {} if(!this.gl) { console.log("GLGE err:", typeof(globalNoWebGLError)=="undefined") if( (!error) && (typeof(globalNoWebGLError)=="undefined")){ var div=document.createElement("div"); div.setAttribute("style","position: absolute; top: 10px; left: 10px; font-family: sans-serif; font-size: 14px; padding: 10px;background-color: #fcffcb;color: #800; width: 200px; border:2px solid #f00"); div.innerHTML="WebGL compatible Browser Required(Firefox 4 or Chrome 9 and up) or you may need to update your graphics card driver."; document.getElementsByTagName("body")[0].appendChild(div); throw "cannot create webgl context"; }else{ error(); throw "cannot create webgl context"; } } //firefox is doing something here? try{ this.gl.canvas=canvas; }catch(e){}; //this.gl = WebGLDebugUtils.makeDebugContext(this.gl); //this.gl.setTracing(true); //chome compatibility //TODO: Remove this when chome is right if (!this.gl.getProgramParameter) { this.gl.getProgramParameter = this.gl.getProgrami } if (!this.gl.getShaderParameter) { this.gl.getShaderParameter = this.gl.getShaderi } // End of Chrome compatibility code this.gl.uniformMatrix4fvX=this.gl.uniformMatrix4fv this.gl.uniformMatrix4fv=function(uniform,transpose,array){ if(!transpose){ this.uniformMatrix4fvX(uniform,false,array); }else{ GLGE.mat4gl(GLGE.transposeMat4(array),array); this.uniformMatrix4fvX(uniform,false,array); } } var gl=this.gl; /*this.gl.texImage2Dx=this.gl.texImage2D; this.gl.texImage2D=function(){ if(arguments.length==9){ gl.texImage2Dx(arguments[0], arguments[1], arguments[2],arguments[3],arguments[4],arguments[5],arguments[6],arguments[7],arguments[8]); }else{ gl.texImage2Dx(arguments[0], arguments[1], arguments[5],false,false); } }*/ //set up defaults this.gl.clearDepth(1.0); this.gl.clearStencil(0); this.gl.enable(this.gl.DEPTH_TEST); this.gl.depthFunc(this.gl.LEQUAL); this.gl.blendFuncSeparate(this.gl.SRC_ALPHA,this.gl.ONE_MINUS_SRC_ALPHA,this.gl.ZERO,this.gl.ONE); }; GLGE.augment(GLGE.QuickNotation,GLGE.Renderer); GLGE.Renderer.prototype.gl=null; GLGE.Renderer.prototype.scene=null; GLGE.C_STENCIL=1; GLGE.C_DEPTH=2; GLGE.C_COLOR=4; GLGE.C_ALL=7; GLGE.Renderer.prototype.clearType=GLGE.C_ALL; /** * Sets the width of the viewport to render * @param width the width of the viewport to render */ GLGE.Renderer.prototype.setViewportWidth=function(width){ this.viewport[0]=width; return this; }; /** * Sets the height of the viewport to render * @param height the height of the viewport to render */ GLGE.Renderer.prototype.setViewportHeight=function(height){ this.viewport[1]=height; return this; }; /** * Sets the left offset of the viewport to render * @param left the left offset of the viewport to render */ GLGE.Renderer.prototype.setViewportOffsetX=function(left){ this.viewport[2]=left; return this; }; /** * Sets the top offset of the viewport to render * @param top the top offset of the viewport to render */ GLGE.Renderer.prototype.setViewportOffsetY=function(top){ this.viewport[3]=top; return this; }; /** * Clears all viewport data and defaults back to canvas size */ GLGE.Renderer.prototype.clearViewport=function(){ this.viewport=[]; }; /** * Gets the width of the viewport to render * @returns the viewport width */ GLGE.Renderer.prototype.getViewportWidth=function(){ if(this.viewport.length>0){ return this.viewport[0]; }else{ return this.canvas.width; } }; /** * Gets the height of the viewport to render * @returns the viewport height */ GLGE.Renderer.prototype.getViewportHeight=function(){ if(this.viewport.length>0){ return this.viewport[1]; }else{ return this.canvas.height; } }; /** * Gets the left offset of the viewport to render * @returns the left viewport offset */ GLGE.Renderer.prototype.getViewportOffsetX=function(){ if(this.viewport.length>0){ return this.viewport[2]; }else{ return 0; } }; /** * Gets the top offset of the viewport to render * @returns the top viewport offset */ GLGE.Renderer.prototype.getViewportOffsetY=function(){ if(this.viewport.length>0){ return this.viewport[3]; }else{ return 0; } }; /** * Sets the clear type for rendering GLGE.C_ALL, GLGE.C_STENCIL, GLGE.C_DEPTH, GLGE.C_COLOR * @param type how to clear the viewport for the next render */ GLGE.Renderer.prototype.setClearType=function(type){ this.clearType=type; return this; }; /** * Gets the clear type for rendering GLGE.C_ALL, GLGE.C_STENCIL, GLGE.C_DEPTH, GLGE.C_COLOR * @returns how to clear the viewport for the next render */ GLGE.Renderer.prototype.getClearType=function(){ return this.clearType; }; /** * Clears the viewport * @private */ GLGE.Renderer.prototype.GLClear=function(){ var gl=this.gl; var clearType=this.clearType; var clear=0; if((clearType & GLGE.C_COLOR) == GLGE.C_COLOR){ clear=clear | gl.COLOR_BUFFER_BIT; } if((clearType & GLGE.C_DEPTH) == GLGE.C_DEPTH){ clear=clear | gl.DEPTH_BUFFER_BIT; } if((clearType & GLGE.C_STENCIL) == GLGE.C_STENCIL){ clear=clear | gl.STENCIL_BUFFER_BIT; } gl.clear(clear); }; /** * Gets the scene which is set to be rendered * @returns the current render scene */ GLGE.Renderer.prototype.getScene=function(){ return this.scene; }; /** * Sets the scene to render * @param {GLGE.Scene} scene The scene to be rendered */ GLGE.Renderer.prototype.setScene=function(scene){ scene.renderer=this; this.scene=scene; if(!scene.gl) scene.GLInit(this.gl); //this.render(); scene.camera.updateMatrix(); //reset camera matrix to force cache update return this; }; /** * Renders the current scene to the canvas */ GLGE.Renderer.prototype.render=function(){ if(this.transitonFilter){ var now=+new Date; if(nowbidx){ return 1; }else if(aidxbidx){ return 1; }else if(aidxbidx){ return 1; }else if(aidx0){ var pass=this.passes.pop(); gl.bindFramebuffer(gl.FRAMEBUFFER, pass.frameBuffer); this.camera.matrix=pass.cameraMatrix; this.camera.setProjectionMatrix(pass.projectionMatrix); this.renderPass(gl,renderObjects,0,0,pass.width,pass.height,GLGE.RENDER_DEFAULT,pass.self); } this.camera.matrix=cameraMatrix; this.camera.setProjectionMatrix(cameraPMatrix); gl.bindFramebuffer(gl.FRAMEBUFFER, this.filter ? this.framebuffer : this.transbuffer); this.renderPass(gl,renderObjects,this.renderer.getViewportOffsetX(),this.renderer.getViewportOffsetY(),this.renderer.getViewportWidth(),this.renderer.getViewportHeight()); this.applyFilter(gl,renderObjects, this.transbuffer); this.allowPasses=true; } /** * gets the passes needed to render this scene * @private */ GLGE.Scene.prototype.getPasses=function(gl,renderObjects){ for(var i=0; isizeTimeLife[2] && (time-sizeTimeLife[2])-1){ gl.bindBuffer(gl.ARRAY_BUFFER, this.attribute.initPosGL); gl.enableVertexAttribArray(attrib); gl.vertexAttribPointer(attrib, 3, gl.FLOAT, false, 0, 0); } var attrib=GLGE.getAttribLocation(gl,this.program, "initAcc"); if(attrib>-1){ gl.bindBuffer(gl.ARRAY_BUFFER, this.attribute.initAccGL); gl.enableVertexAttribArray(attrib); gl.vertexAttribPointer(attrib, 3, gl.FLOAT, false, 0, 0); } var attrib=GLGE.getAttribLocation(gl,this.program, "endAcc"); if(attrib>-1){ gl.bindBuffer(gl.ARRAY_BUFFER, this.attribute.endAccGL); gl.enableVertexAttribArray(attrib); gl.vertexAttribPointer(attrib, 3, gl.FLOAT, false, 0, 0); } var attrib=GLGE.getAttribLocation(gl,this.program, "initColor"); if(attrib>-1){ gl.bindBuffer(gl.ARRAY_BUFFER, this.attribute.initColorGL); gl.enableVertexAttribArray(attrib); gl.vertexAttribPointer(attrib, 4, gl.FLOAT, false, 0, 0); } var attrib=GLGE.getAttribLocation(gl,this.program, "endColor"); if(attrib>-1){ gl.bindBuffer(gl.ARRAY_BUFFER, this.attribute.endColorGL); gl.enableVertexAttribArray(attrib); gl.vertexAttribPointer(attrib, 4, gl.FLOAT, false, 0, 0); } var attrib=GLGE.getAttribLocation(gl,this.program, "sizeTimeLife"); if(attrib>-1){ gl.bindBuffer(gl.ARRAY_BUFFER, this.attribute.sizeAndOffsetGL); gl.enableVertexAttribArray(attrib); gl.vertexAttribPointer(attrib, 4, gl.FLOAT, false, 0, 0); } var attrib=GLGE.getAttribLocation(gl,this.program, "initVel"); if(attrib>-1){ gl.bindBuffer(gl.ARRAY_BUFFER, this.attribute.initVelGL); gl.enableVertexAttribArray(attrib); gl.vertexAttribPointer(attrib, 3, gl.FLOAT, false, 0, 0); } } /** * Renders the particle system * @private */ GLGE.ParticleSystem.prototype.GLRender=function(gl){ if(!this.attribute) this.generateParticles(gl); if(!this.program) this.generateProgram(gl); gl.useProgram(this.program); this.setAttributes(gl); this.setUniforms(gl); gl.colorMask(0,0,0,0); gl.disable(gl.BLEND); gl.enable(gl.STENCIL_TEST); gl.stencilFunc(gl.ALWAYS, 1, 1); gl.stencilOp(gl.KEEP, gl.KEEP, gl.REPLACE); gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.facesGL); gl.drawElements(gl.TRIANGLES,this.facesGL.num, gl.UNSIGNED_SHORT, 0); gl.stencilFunc(gl.EQUAL, 1, 1); gl.stencilOp(gl.KEEP, gl.KEEP, gl.KEEP); gl.colorMask(1,1,1,1); gl.disable(gl.DEPTH_TEST); gl.enable(gl.BLEND); gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.facesGL); gl.drawElements(gl.TRIANGLES,this.facesGL.num, gl.UNSIGNED_SHORT, 0); gl.stencilOp(gl.REPLACE, gl.REPLACE, gl.REPLACE); gl.stencilFunc(gl.ALWAYS, 0, 0); gl.enable(gl.DEPTH_TEST); gl.scene.lastMaterial=null; } /** * @function Adds a particle system to the scene * @param {GLGE.ParticleSystem} the particle system to add */ GLGE.Scene.prototype.addParticleSystem=GLGE.Scene.prototype.addGroup; /** * @function Adds a particle system to the group * @param {GLGE.ParticleSystem} the particle system to add */ GLGE.Group.prototype.addParticleSystem=GLGE.Group.prototype.addGroup; })(GLGE);/* GLGE WebGL Graphics Engine Copyright (c) 2010, Paul Brunt All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of GLGE nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL PAUL BRUNT BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /** * @fileOverview * @name glge_md2.js * @author me@paulbrunt.co.uk */ (function(GLGE){ /** * @name GLGE.MD2#md2AnimFinished * @event fired when the the animation has finished * @param {object} data */ /** * @class A quake MD2 model class * @augments GLGE.Object */ GLGE.MD2=function(uid){ this.MD2Started=+new Date; this.setAnimation(new GLGE.AnimationVector); GLGE.Object.call(this,uid); } GLGE.augment(GLGE.Object,GLGE.MD2); GLGE.MD2.prototype.loadingCache={}; GLGE.MD2.prototype.headersCache={}; GLGE.MD2.prototype.meshCache={}; GLGE.MD2.prototype.MD2Animations={}; GLGE.MD2.prototype.MD2StartFrame=0; GLGE.MD2.prototype.MD2EndFrame=0; GLGE.MD2.prototype.MD2Loop=true; GLGE.MD2.prototype.MD2AnimFinished=false; GLGE.MD2.prototype.headerNames=[ "ident", "version", "skinwidth", "skinheight", "framesize", "num_skins", "num_xyz", "num_st", "num_tris", "num_glcmds", "num_frames", "ofs_skins", "ofs_st", "ofs_tris", "ofs_frames", "ofs_glcmds", "ofs_end"]; GLGE.MD2.prototype.preNormals = [ [-0.525731, 0.000000, 0.850651], [-0.442863, 0.238856, 0.864188], [-0.295242, 0.000000, 0.955423], [-0.309017, 0.500000, 0.809017], [-0.162460, 0.262866, 0.951056], [ 0.000000, 0.000000, 1.000000], [ 0.000000, 0.850651, 0.525731], [-0.147621, 0.716567, 0.681718], [ 0.147621, 0.716567, 0.681718], [ 0.000000, 0.525731, 0.850651], [ 0.309017, 0.500000, 0.809017], [ 0.525731, 0.000000, 0.850651], [ 0.295242, 0.000000, 0.955423], [ 0.442863, 0.238856, 0.864188], [ 0.162460, 0.262866, 0.951056], [-0.681718, 0.147621, 0.716567], [-0.809017, 0.309017, 0.500000], [-0.587785, 0.425325, 0.688191], [-0.850651, 0.525731, 0.000000], [-0.864188, 0.442863, 0.238856], [-0.716567, 0.681718, 0.147621], [-0.688191, 0.587785, 0.425325], [-0.500000, 0.809017, 0.309017], [-0.238856, 0.864188, 0.442863], [-0.425325, 0.688191, 0.587785], [-0.716567, 0.681718, -0.147621], [-0.500000, 0.809017, -0.309017], [-0.525731, 0.850651, 0.000000], [ 0.000000, 0.850651, -0.525731], [-0.238856, 0.864188, -0.442863], [ 0.000000, 0.955423, -0.295242], [-0.262866, 0.951056, -0.162460], [ 0.000000, 1.000000, 0.000000], [ 0.000000, 0.955423, 0.295242], [-0.262866, 0.951056, 0.162460], [ 0.238856, 0.864188, 0.442863], [ 0.262866, 0.951056, 0.162460], [ 0.500000, 0.809017, 0.309017], [ 0.238856, 0.864188, -0.442863], [ 0.262866, 0.951056, -0.162460], [ 0.500000, 0.809017, -0.309017], [ 0.850651, 0.525731, 0.000000], [ 0.716567, 0.681718, 0.147621], [ 0.716567, 0.681718, -0.147621], [ 0.525731, 0.850651, 0.000000], [ 0.425325, 0.688191, 0.587785], [ 0.864188, 0.442863, 0.238856], [ 0.688191, 0.587785, 0.425325], [ 0.809017, 0.309017, 0.500000], [ 0.681718, 0.147621, 0.716567], [ 0.587785, 0.425325, 0.688191], [ 0.955423, 0.295242, 0.000000], [ 1.000000, 0.000000, 0.000000], [ 0.951056, 0.162460, 0.262866], [ 0.850651, -0.525731, 0.000000], [ 0.955423, -0.295242, 0.000000], [ 0.864188, -0.442863, 0.238856], [ 0.951056, -0.162460, 0.262866], [ 0.809017, -0.309017, 0.500000], [ 0.681718, -0.147621, 0.716567], [ 0.850651, 0.000000, 0.525731], [ 0.864188, 0.442863, -0.238856], [ 0.809017, 0.309017, -0.500000], [ 0.951056, 0.162460, -0.262866], [ 0.525731, 0.000000, -0.850651], [ 0.681718, 0.147621, -0.716567], [ 0.681718, -0.147621, -0.716567], [ 0.850651, 0.000000, -0.525731], [ 0.809017, -0.309017, -0.500000], [ 0.864188, -0.442863, -0.238856], [ 0.951056, -0.162460, -0.262866], [ 0.147621, 0.716567, -0.681718], [ 0.309017, 0.500000, -0.809017], [ 0.425325, 0.688191, -0.587785], [ 0.442863, 0.238856, -0.864188], [ 0.587785, 0.425325, -0.688191], [ 0.688191, 0.587785, -0.425325], [-0.147621, 0.716567, -0.681718], [-0.309017, 0.500000, -0.809017], [ 0.000000, 0.525731, -0.850651], [-0.525731, 0.000000, -0.850651], [-0.442863, 0.238856, -0.864188], [-0.295242, 0.000000, -0.955423], [-0.162460, 0.262866, -0.951056], [ 0.000000, 0.000000, -1.000000], [ 0.295242, 0.000000, -0.955423], [ 0.162460, 0.262866, -0.951056], [-0.442863, -0.238856, -0.864188], [-0.309017, -0.500000, -0.809017], [-0.162460, -0.262866, -0.951056], [ 0.000000, -0.850651, -0.525731], [-0.147621, -0.716567, -0.681718], [ 0.147621, -0.716567, -0.681718], [ 0.000000, -0.525731, -0.850651], [ 0.309017, -0.500000, -0.809017], [ 0.442863, -0.238856, -0.864188], [ 0.162460, -0.262866, -0.951056], [ 0.238856, -0.864188, -0.442863], [ 0.500000, -0.809017, -0.309017], [ 0.425325, -0.688191, -0.587785], [ 0.716567, -0.681718, -0.147621], [ 0.688191, -0.587785, -0.425325], [ 0.587785, -0.425325, -0.688191], [ 0.000000, -0.955423, -0.295242], [ 0.000000, -1.000000, 0.000000], [ 0.262866, -0.951056, -0.162460], [ 0.000000, -0.850651, 0.525731], [ 0.000000, -0.955423, 0.295242], [ 0.238856, -0.864188, 0.442863], [ 0.262866, -0.951056, 0.162460], [ 0.500000, -0.809017, 0.309017], [ 0.716567, -0.681718, 0.147621], [ 0.525731, -0.850651, 0.000000], [-0.238856, -0.864188, -0.442863], [-0.500000, -0.809017, -0.309017], [-0.262866, -0.951056, -0.162460], [-0.850651, -0.525731, 0.000000], [-0.716567, -0.681718, -0.147621], [-0.716567, -0.681718, 0.147621], [-0.525731, -0.850651, 0.000000], [-0.500000, -0.809017, 0.309017], [-0.238856, -0.864188, 0.442863], [-0.262866, -0.951056, 0.162460], [-0.864188, -0.442863, 0.238856], [-0.809017, -0.309017, 0.500000], [-0.688191, -0.587785, 0.425325], [-0.681718, -0.147621, 0.716567], [-0.442863, -0.238856, 0.864188], [-0.587785, -0.425325, 0.688191], [-0.309017, -0.500000, 0.809017], [-0.147621, -0.716567, 0.681718], [-0.425325, -0.688191, 0.587785], [-0.162460, -0.262866, 0.951056], [ 0.442863, -0.238856, 0.864188], [ 0.162460, -0.262866, 0.951056], [ 0.309017, -0.500000, 0.809017], [ 0.147621, -0.716567, 0.681718], [ 0.000000, -0.525731, 0.850651], [ 0.425325, -0.688191, 0.587785], [ 0.587785, -0.425325, 0.688191], [ 0.688191, -0.587785, 0.425325], [-0.955423, 0.295242, 0.000000], [-0.951056, 0.162460, 0.262866], [-1.000000, 0.000000, 0.000000], [-0.850651, 0.000000, 0.525731], [-0.955423, -0.295242, 0.000000], [-0.951056, -0.162460, 0.262866], [-0.864188, 0.442863, -0.238856], [-0.951056, 0.162460, -0.262866], [-0.809017, 0.309017, -0.500000], [-0.864188, -0.442863, -0.238856], [-0.951056, -0.162460, -0.262866], [-0.809017, -0.309017, -0.500000], [-0.681718, 0.147621, -0.716567], [-0.681718, -0.147621, -0.716567], [-0.850651, 0.000000, -0.525731], [-0.688191, 0.587785, -0.425325], [-0.587785, 0.425325, -0.688191], [-0.425325, 0.688191, -0.587785], [-0.425325, -0.688191, -0.587785], [-0.587785, -0.425325, -0.688191], [-0.688191, -0.587785, -0.425325] ]; GLGE.MD2.prototype.MD2FrameRate=6; /** * Gets the absolute path given an import path and the path it's relative to * @param {string} path the path to get the absolute path for * @param {string} relativeto the path the supplied path is relativeto * @returns {string} absolute path * @private */ GLGE.MD2.prototype.getAbsolutePath=function(path,relativeto){ if(path.substr(0,7)=="http://" || path.substr(0,7)=="file://" || path.substr(0,7)=="https://"){ return path; } else { if(!relativeto){ relativeto=window.location.href; } if (relativeto.indexOf("://")==-1){ return relativeto.slice(0,relativeto.lastIndexOf("/"))+"/"+path; } //find the path compoents var bits=relativeto.split("/"); var domain=bits[2]; var proto=bits[0]; var initpath=[]; for(var i=3;i> 7)), exponent = (((b0 << 1) & 0xff) | (b1 >> 7)) - 127, mantissa = ((b1 & 0x7f) << 16) | (b2 << 8) | b3; if (mantissa == 0 && exponent == -127) { return 0.0; } if (exponent == -127) { // Denormalized return sign * mantissa * Math.pow(2, -126 - 23); } return sign * (1 + mantissa * Math.pow(2, -23)) * Math.pow(2, exponent); } /** * process the frame data * @private */ GLGE.MD2.prototype.parseFrames=function(){ var vertsArray = this.byteArray; var startFrame=0; var MD2Animations={}; for(var j=0;j0) this.addMD3Childred(); this.loaded=true; this.fireEvent("loaded",{url:this.url}); } /** * Adds the child md3 object * @private */ GLGE.MD3.prototype.addMD3Childred=function(){ for(var i=0; i0x8000) value=value-0x10000; return value; } /** * get 32 bit signed int at location * @private */ GLGE.MD3.prototype.getSint32At=function(index){ var value=this.byteArray[index]|(this.byteArray[index+1]<<8)|(this.byteArray[index+2]<<16)|(this.byteArray[index+3]<<24); if(value>0x80000000) value=value-0x100000000; return value; } /** * Get 32 bit float at location * @private */ GLGE.MD3.prototype.getFloat32At=function(index){ var b3=this.byteArray[index]; var b2=this.byteArray[index+1]; var b1=this.byteArray[index+2]; var b0=this.byteArray[index+3]; sign = 1 - (2 * (b0 >> 7)), exponent = (((b0 << 1) & 0xff) | (b1 >> 7)) - 127, mantissa = ((b1 & 0x7f) << 16) | (b2 << 8) | b3; if (mantissa == 0 && exponent == -127) { return 0.0; } if (exponent == -127) { // Denormalized return sign * mantissa * Math.pow(2, -126 - 23); } return sign * (1 + mantissa * Math.pow(2, -23)) * Math.pow(2, exponent); } /** * Get 32 bit float at location * @private */ GLGE.MD3.prototype.getStringAt=function(index,size){ var name=""; for(var i=index;i-1) this.textures.splice(idx,1); } GLGE.Filter2d.prototype.createBuffer=function(gl,width,height){ if(!width) width=gl.canvas.width; if(!height) height=gl.canvas.height; var frameBuffer = gl.createFramebuffer(); var renderBuffer = gl.createRenderbuffer(); var texture = gl.createTexture(); gl.bindTexture(gl.TEXTURE_2D, texture); var tex = new Uint8Array(width*height*4); gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, width, height, 0, gl.RGBA, gl.UNSIGNED_BYTE, tex); gl.bindFramebuffer(gl.FRAMEBUFFER, frameBuffer); gl.bindRenderbuffer(gl.RENDERBUFFER, renderBuffer); gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_COMPONENT16, width, height); gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER, renderBuffer); gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, texture, 0); gl.bindRenderbuffer(gl.RENDERBUFFER, null); gl.bindFramebuffer(gl.FRAMEBUFFER, null); gl.bindTexture(gl.TEXTURE_2D, null); return [frameBuffer,renderBuffer,texture]; } GLGE.Filter2d.prototype.getFrameBuffer=function(gl){ if(!this.passes) return null; if(!this.gl) this.gl=gl; if(!this.buffers){ this.buffers=this.createBuffer(gl); } return this.buffers[0]; } GLGE.Filter2d.prototype.getEmitBuffer=function(gl){ if(!this.passes) return null; if(!this.gl) this.gl=gl; if(!this.emitBuffers){ this.emitBuffers=this.createBuffer(gl,this.getEmitBufferWidth(),this.getEmitBufferHeight()); } return this.emitBuffers[0]; } GLGE.Filter2d.prototype.setEmitBufferWidth=function(value){ this.emitBufferWidth=value; this.emitBuffers=null; } GLGE.Filter2d.prototype.getEmitBufferWidth=function(){ return (this.emitBufferWidth ? this.emitBufferWidth : this.gl.canvas.width); } GLGE.Filter2d.prototype.setEmitBufferHeight=function(value){ this.emitBufferHeight=value; this.emitBuffers=null; } GLGE.Filter2d.prototype.getEmitBufferHeight=function(){ return (this.emitBufferHeight ? this.emitBufferHeight : this.gl.canvas.height); } GLGE.Filter2d.prototype.getDepthBuffer=function(gl){ if(!this.passes) return null; if(!this.gl) this.gl=gl; if(!this.depthBuffers){ this.depthBuffers=this.createBuffer(gl,this.getDepthBufferWidth(),this.getDepthBufferHeight()); } return this.depthBuffers[0]; } GLGE.Filter2d.prototype.setDepthBufferWidth=function(value){ this.depthBufferWidth=value; this.depthBuffers=null; } GLGE.Filter2d.prototype.getDepthBufferWidth=function(){ return (this.depthBufferWidth ? this.depthBufferWidth : this.gl.canvas.width); } GLGE.Filter2d.prototype.setDepthBufferHeight=function(value){ this.depthBufferHeight=value; this.depthBuffers=null; } GLGE.Filter2d.prototype.getDepthBufferHeight=function(){ return (this.depthBufferHeight ? this.depthBufferHeight : this.gl.canvas.height); } GLGE.Filter2d.prototype.setNormalBufferWidth=function(value){ this.normalBufferWidth=value; this.normalBuffers=null; } GLGE.Filter2d.prototype.getNormalBufferWidth=function(){ return (this.normalBufferWidth ? this.normalBufferWidth : this.gl.canvas.width); } GLGE.Filter2d.prototype.setNormalBufferHeight=function(value){ this.normalBufferHeight=value; this.normalBuffers=null; } GLGE.Filter2d.prototype.getNormalBufferHeight=function(){ return (this.normalBufferHeight ? this.normalBufferHeight : this.gl.canvas.height); } GLGE.Filter2d.prototype.getNormalBuffer=function(gl){ if(!this.gl) this.gl=gl; if(!this.normalBuffers){ this.normalBuffers=this.createBuffer(gl,this.getNormalBufferWidth(),this.getNormalBufferHeight()); } return this.normalBuffers[0]; } GLGE.Filter2d.prototype.setUniform=function(type,name,value){ if(!this.uniforms) this.uniforms={}; this.uniforms[name]={type:type,value:value}; } GLGE.Filter2d.prototype.getUniform=function(name){ if(!this.uniforms) this.uniforms={}; return this.uniforms[name].value } GLGE.Filter2d.prototype.getUniformType=function(name){ if(!this.uniforms) this.uniforms={}; return this.uniforms[name].type; } GLGE.Filter2d.prototype.addPassFile=function(url){ var req = new XMLHttpRequest(); var filter=this; if(req) { req.open("GET", url, false); req.send(""); filter.addPass(req.responseText); } } GLGE.Filter2d.prototype.addPass=function(GLSL,width,height){ if(!this.passes) this.passes=[]; this.passes.push({GLSL:GLSL,height:height,width:width}); } /** * Creates the preserve texture * @private */ GLGE.Filter2d.prototype.createPersistTexture=function(gl){ this.persistTexture = gl.createTexture(); gl.bindTexture(gl.TEXTURE_2D, this.persistTexture); gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.canvas.width,gl.canvas.height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null); } //does all passes and renders result to screen GLGE.Filter2d.prototype.GLRender=function(gl,buffer){ gl.disable(gl.BLEND); if(!buffer) buffer=null; if(this.passes){ for(var i=0;i lumaMax)) gl_FragColor = vec4(rgbA,1.0);"); pass3.push(" else gl_FragColor = vec4(rgbB,1.0);"); pass3.push(" if(length(rgbM)>"+this.fxaacutoff.toFixed(2)+") gl_FragColor = vec4(rgbM,1.0);"); pass3.push(" if(length(rgbM)<"+this.fxaastartintensity.toFixed(2)+") gl_FragColor = vec4(rgbM,1.0);"); pass3.push("}"); this.addPass(pass3.join("\n")); } } })(GLGE);/* GLGE WebGL Graphics Engine Copyright (c) 2010, Paul Brunt All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of GLGE nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL PAUL BRUNT BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /** * @fileOverview * @name glge_filter_ao.js * @author me@paulbrunt.co.uk */ (function(GLGE){ /** * @class Postprocessing Ambient Occlusion filter * @augments GLGE.Filter2d */ GLGE.FilterAO=function(){ this.setUniform("1f","cavitygamma",1/3); this.setUniform("1f","whiteMul",2); this.setUniform("1f","aogamma",1/3); this.setUniform("1f","maxDist",0.025); this.passes=[]; }; GLGE.augment(GLGE.Filter2d,GLGE.FilterAO); GLGE.FilterAO.prototype.renderNormal=true; GLGE.FilterAO.prototype.quality=1; GLGE.FilterAO.prototype.range=80; GLGE.FilterAO.prototype.samples=16; GLGE.FilterAO.prototype.useRender=true; GLGE.FilterAO.prototype.getNormalBufferHeight=function(){ return (this.normalBufferHeight ? this.normalBufferHeight : (this.gl.canvas.height*this.quality|0)); } GLGE.FilterAO.prototype.getNormalBufferWidth=function(){ return (this.normalBufferWidth ? this.normalBufferWidth : (this.gl.canvas.width*this.quality|0)); } GLGE.FilterAO.prototype.setUseRender=function(value){ this.useRender=value; this.normalBuffers=null; this.passes=[]; return this; } GLGE.FilterAO.prototype.setSamples=function(value){ this.samples=value; this.normalBuffers=null; this.passes=[]; return this; } GLGE.FilterAO.prototype.setQuality=function(value){ this.quality=value; this.normalBuffers=null; this.passes=[]; return this; } GLGE.FilterAO.prototype.setRange=function(value){ this.range=value; if(this.gl){ this.setUniform("1f","blurX",this.range/this.getNormalBufferWidth()*this.quality/this.samples); this.setUniform("1f","blurY",this.range/this.getNormalBufferHeight()/this.samples); } return this; } GLGE.FilterAO.prototype.setCavityGamma=function(value){ this.setUniform("1f","cavitygamma",1/value); return this; } GLGE.FilterAO.prototype.setAmbientMultiplier=function(value){ this.setUniform("1f","whiteMul",value); return this; } GLGE.FilterAO.prototype.setAmbientGamma=function(value){ this.setUniform("1f","aogamma",1/value); return this; } GLGE.FilterAO.prototype.setMaximumDistance=function(value){ this.setUniform("1f","maxDist",value); return this; } GLGE.FilterAO.prototype.GLRender=function(gl,buffer){ this.gl=gl; if(this.passes.length==0){ this.createPasses(); } return GLGE.Filter2d.prototype.GLRender.call(this,gl,buffer) } GLGE.FilterAO.prototype.createPasses=function(){ if(!this.gl) return; var width=this.getNormalBufferWidth(); var height=this.getNormalBufferHeight(); var size=(this.samples/4)|0; var weights=[]; for(var i=-size,cnt=0; i<=size;i++,cnt++){ var n=size-Math.abs(i)+1; weights[cnt]=n/(size*size+size); } weights[size]=0; this.setUniform("1f","blurX",this.range/width*this.quality/this.samples); this.setUniform("1f","blurY",this.range/height/this.samples); var pass1=[]; pass1.push("precision highp float;"); pass1.push("uniform sampler2D GLGE_NORMAL;"); pass1.push("uniform float maxDist;"); pass1.push("varying vec2 texCoord;"); pass1.push("uniform float blurX;"); pass1.push("float rand(vec2 co){"); pass1.push("return (fract(sin(dot(co.xy ,vec2(12.9898,78.233))) * 43758.5453)-0.5)*2.0;"); pass1.push("}"); pass1.push("void main(void){"); pass1.push("vec4 n=texture2D(GLGE_NORMAL,texCoord.xy).rgba;"); pass1.push("vec4 color=vec4(0.0,0.0,0.0,n.a);"); pass1.push("float blurSize=blurX/(n.a*n.a+1.0);"); pass1.push("float offset=rand(texCoord.xy)*blurSize+texCoord.x;"); pass1.push("vec3 samp;"); pass1.push("float delta;"); for(var i=-size,cnt=0;i<=size;i++,cnt++){ if(i==0) continue; pass1.push("samp = texture2D(GLGE_NORMAL, vec2("+i+".0*blurSize+offset, texCoord.y)).rga;"); pass1.push("delta=abs(n.a-samp.b);"); pass1.push("if(delta lumaMax)) gl_FragColor = vec4(rgbA,1.0);"); pass3.push(" else gl_FragColor = vec4(rgbB,1.0);"); pass3.push(" if(length(rgbM)>10.0) gl_FragColor = vec4(rgbM,1.0);"); pass3.push("}"); this.passes=[]; this.addPass(pass1.join(""),width,height); this.addPass(pass2.join("")); this.addPass(pass3.join("\n")); } })(GLGE);/* GLGE WebGL Graphics Engine Copyright (c) 2010, Paul Brunt All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of GLGE nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL PAUL BRUNT BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /** * @fileOverview * @name glge_collada.js * @author me@paulbrunt.co.uk */ if(typeof(GLGE) == "undefined"){ /** * @namespace Holds the functionality of the library */ GLGE = {}; } (function(GLGE){ GLGE.ColladaDocuments=[]; /** * @class Class to represent a collada object * @augments GLGE.Group */ GLGE.Collada=function(uid){ GLGE.Group.call(this); this.children=[]; this.actions={}; this.boneIdx=0; this.objIdx=0; this.actionsIdx=0; GLGE.Assets.registerAsset(this,uid); }; GLGE.augment(GLGE.Group,GLGE.Collada); GLGE.Collada.prototype.type=GLGE.G_NODE; GLGE.Collada.prototype.useLights=false; GLGE.Collada.prototype.useCamera=false GLGE.Collada.prototype.useBinaryAlpha=false; /** * Gets the absolute path given an import path and the path it's relative to * @param {string} path the path to get the absolute path for * @param {string} relativeto the path the supplied path is relativeto * @returns {string} absolute path * @private */ GLGE.Collada.prototype.getAbsolutePath=function(path,relativeto){ if(path.substr(0,7)=="http://" || path.substr(0,7)=="file://" || path.substr(0,7)=="https://"){ return path; } else { if(!relativeto){ relativeto=window.location.href; } if (relativeto.indexOf("://")==-1){ return relativeto.slice(0,relativeto.lastIndexOf("/"))+"/"+path; } //find the path compoents var bits=relativeto.split("/"); var domain=bits[2]; var proto=bits[0]; var initpath=[]; for(var i=3;i0) polygons[i].getElementsByTagName("p")[0].data=tris; } //create a mesh for each set of faces var triangles=[]; var tris=meshNode.getElementsByTagName("triangles"); for(i=0;i0) triangles.push(polygons[i])}; for(i=0;ib?b:a); } var MAXVERTS=21843; MAXVERTS*=3;//always must be a multiple of 3 (3 vertices) var nummesh=((faces.length-faces.length%MAXVERTS)/MAXVERTS)+(faces.length%MAXVERTS?1:0); var trimesh=[]; var vstride=3; var nstride=3; var tstride=2; for (var index=0;index8){ var newjoints=[]; var newweights=[]; for(var j=0;j * * The material getter below borked if there is e.g. a scene node with the same name as the material. * This is used to fix that by only looking for materials in the library_materials element. */ function getChildElementById( dNode, id ) { var dResult = null; if ( dNode.getAttribute('id') == id ) return dNode; for ( var i = 0; i < dNode.childNodes.length; i++ ) { if ( dNode.childNodes[i].nodeType == 1 ) { dResult = getChildElementById( dNode.childNodes[i], id ); //note: 1-level deep would suffice here, doesn't need to recurse into further childs. but this works. if ( dResult != null ) break; } } return dResult; } var MaterialCache={}; /** * Gets the sampler for a texture * @param {string} id the id or the material element * @private */ GLGE.Collada.prototype.getMaterial=function(id,bvi){ // JHD: Added "else" and enclosing brackets if (!MaterialCache[this.url]) { MaterialCache[this.url] = {}; } else if (MaterialCache[this.url][id]) { return MaterialCache[this.url][id]; } var materialLib=this.xml.getElementsByTagName("library_materials")[0]; var materialNode=getChildElementById(materialLib, id); //this.xml.getElementById(id); if (!materialNode) { var returnMaterial=new GLGE.Material(); MaterialCache[this.url][id]=returnMaterial; return returnMaterial; } var effectid=materialNode.getElementsByTagName("instance_effect")[0].getAttribute("url").substr(1); var effect=this.xml.getElementById(effectid); var common=effect.getElementsByTagName("profile_COMMON")[0]; //glge only supports one technique currently so try and match as best we can var technique=common.getElementsByTagName("technique")[0]; var returnMaterial=new GLGE.Material(); returnMaterial.setBinaryAlpha(this.useBinaryAlpha); returnMaterial.setSpecular(0); MaterialCache[this.url][id]=returnMaterial; var child; var color; //do ambient lighting var ambient=technique.getElementsByTagName("ambient"); if(ambient.length>0){ child=ambient[0].firstChild; do{ switch(child.tagName){ case "color": color=child.firstChild.nodeValue.replace(/\s+/g,' ').split(" "); returnMaterial.setAmbient({r:color[0],g:color[1],b:color[2]}); break; case "param": color=this.getFloat4(common,child.getAttribute("ref")).replace(/\s+/g,' ').split(" "); returnMaterial.setAmbient({r:color[0],g:color[1],b:color[2]}); break; case "texture": this.createMaterialLayer(child,returnMaterial,common,GLGE.M_AMBIENT,bvi); break; } }while(child=child.nextSibling); } //do diffuse color var diffuse=technique.getElementsByTagName("diffuse"); if(diffuse.length>0){ child=diffuse[0].firstChild; do{ switch(child.tagName){ case "color": color=child.firstChild.nodeValue.replace(/\s+/g,' ').split(" "); returnMaterial.setColor({r:color[0],g:color[1],b:color[2]}); break; case "param": color=this.getFloat4(common,child.getAttribute("ref")).replace(/\s+/g,' ').split(" "); returnMaterial.setColor({r:color[0],g:color[1],b:color[2]}); break; case "texture": this.createMaterialLayer(child,returnMaterial,common,GLGE.M_COLOR,bvi); break; } }while(child=child.nextSibling); } var bump=technique.getElementsByTagName("bump"); if(bump.length>0){ child=bump[0].firstChild; do{ switch(child.tagName){ case "texture": this.createMaterialLayer(child,returnMaterial,common,GLGE.M_NOR,bvi); break; } }while(child=child.nextSibling); } //do shininess var shininess=technique.getElementsByTagName("shininess"); if(shininess.length>0){ returnMaterial.setSpecular(1); child=technique.getElementsByTagName("shininess")[0].firstChild; do{ switch(child.tagName){ case "float": if(parseFloat(child.firstChild.nodeValue)>1) returnMaterial.setShininess(parseFloat(child.firstChild.nodeValue)); else returnMaterial.setShininess(parseFloat(child.firstChild.nodeValue)*128); break; case "param": var value=parseFloat(this.getFloat(common,child.getAttribute("ref"))); if(value>1) returnMaterial.setShininess(value); else returnMaterial.setShininess(value*128); break; // MCB: texture is invalid here. should remove this case. case "texture": this.createMaterialLayer(child,returnMaterial,common,GLGE.M_SHINE,bvi); break; } }while(child=child.nextSibling); } //do specular color var specular=technique.getElementsByTagName("specular"); if(specular.length>0){ returnMaterial.setSpecular(1); child=specular[0].firstChild; do{ switch(child.tagName){ case "color": color=child.firstChild.nodeValue.replace(/\s+/g,' ').split(" "); returnMaterial.setSpecularColor({r:color[0],g:color[1],b:color[2]}); break; case "param": color=this.getFloat4(common,child.getAttribute("ref")).replace(/\s+/g,' ').split(" "); returnMaterial.setSpecularColor({r:color[0],g:color[1],b:color[2]}); break; case "texture": this.createMaterialLayer(child,returnMaterial,common,GLGE.M_SPECCOLOR,bvi); break; } }while(child=child.nextSibling); } //do reflectivity /* var reflectivity=technique.getElementsByTagName("reflectivity"); if(reflectivity.length>0){ child=reflectivity[0].firstChild; do{ switch(child.tagName){ case "float": //returnMaterial.setReflectivity(parseFloat(child.firstChild.nodeValue)) break; case "param": //returnMaterial.setReflectivity(parseFloat(this.getFloat(common,child.getAttribute("ref")))); break; // MCB: texture is invalid here. should remove this case. case "texture": var imageid=this.getSurface(common,this.getSampler(common,child.getAttribute("texture"))); textureImage=this.getImage(imageid); var texture=new GLGE.Texture(textureImage); returnMaterial.addTexture(texture); returnMaterial.addMaterialLayer(new GLGE.MaterialLayer(texture,GLGE.M_REFLECT,GLGE.UV1)); break; } }while(child=child.nextSibling); }*/ //do emission color var emission=technique.getElementsByTagName("emission"); if(emission.length>0){ child=emission[0].firstChild; do{ switch(child.tagName){ case "color": color=child.firstChild.nodeValue.split(" "); returnMaterial.setEmit({r:color[0],g:color[1],b:color[2]}); break; case "param": color=this.getFloat4(common,child.getAttribute("ref")).split(" "); returnMaterial.setEmit(color[0]); break; case "texture": this.createMaterialLayer(child,returnMaterial,common,GLGE.M_EMIT,bvi); break; } }while(child=child.nextSibling); } //do reflective color var reflective=technique.getElementsByTagName("reflective"); if(reflective.length>0){ child=reflective[0].firstChild; do{ switch(child.tagName){ case "color": color=child.firstChild.nodeValue.replace(/\s+/g,' ').split(" "); //TODO returnMaterial.setReflectiveColor({r:color[0],g:color[1],b:color[2]}); break; case "param": color=this.getFloat4(common,child.getAttribute("ref")).replace(/\s+/g,' ').split(" "); //TODO returnMaterial.setReflectiveColor({r:color[0],g:color[1],b:color[2]}); break; case "texture": this.createMaterialLayer(child,returnMaterial,common,GLGE.M_REFLECT,bvi); break; } }while(child=child.nextSibling); } //do transparency var transparency=technique.getElementsByTagName("transparency"); if(transparency.length>0){ child=transparency[0].firstChild; do{ switch(child.tagName){ case "float": //TODO returnMaterial.setTransparency(parseFloat(child.firstChild.nodeValue)) //Causing issues with a couple of models //returnMaterial.setAlpha(parseFloat(child.firstChild.nodeValue)); //returnMaterial.trans=true; break; case "param": //TODO returnMaterial.setTransparency(parseFloat(this.getFloat(common,child.getAttribute("ref")))); break; } }while(child=child.nextSibling); } //do transparent color var transparent=technique.getElementsByTagName("transparent"); if(transparent.length>0){ var opaque=transparent[0].getAttribute("opaque"); if(!opaque) opaque="A_ONE"; // schema default child=transparent[0].firstChild; do{ switch(child.tagName){ // MCB: float is invalid here. should remove this case. case "float": var alpha=parseFloat(child.firstChild.nodeValue); if(alpha<1){ returnMaterial.setAlpha(parseFloat(child.firstChild.nodeValue)); returnMaterial.trans=true; } break; case "color": color=child.firstChild.nodeValue.replace(/\s+/g,' ').split(" "); var alpha=this.getMaterialAlpha(color,opaque,1); //TODO var alpha=this.getMaterialAlpha(color,opaque,returnMaterial.getTransparency()); if(alpha<1){ returnMaterial.setAlpha(alpha); returnMaterial.trans=true; } break; case "param": color=this.getFloat4(common,child.getAttribute("ref")).replace(/\s+/g,' ').split(" "); var alpha=this.getMaterialAlpha(color,opaque,1); //TODO var alpha=this.getMaterialAlpha(color,opaque,returnMaterial.getTransparency()); if(alpha<1){ returnMaterial.setAlpha(alpha); returnMaterial.trans=true; } break; // MCB: this case assumes opaque="A_ONE" and transparency="1.0" case "texture": this.createMaterialLayer(child,returnMaterial,common,GLGE.M_ALPHA,bvi); returnMaterial.trans=true; break; } }while(child=child.nextSibling); } return returnMaterial; }; /** * gets the material alpha from the transparent color * @param {color} the transparent color * @param {opaque} the transparent color opaque attribute value * @param {transparency} the transparency value * @private */ GLGE.Collada.prototype.getMaterialAlpha=function(color,opaque,transparency){ var returnAlpha; switch(opaque){ case "A_ONE": returnAlpha=parseFloat(color[3])*transparency; break; case "A_ZERO": returnAlpha=1-parseFloat(color[3])*transparency; break; case "RGB_ONE": var luminance=parseFloat(color[0])*0.212671 +parseFloat(color[1])*0.715160 +parseFloat(color[2])*0.072169; returnAlpha=luminance*transparency; break; case "RGB_ZERO": var luminance=parseFloat(color[0])*0.212671 +parseFloat(color[1])*0.715160 +parseFloat(color[2])*0.072169; returnAlpha=1-luminance*transparency; break; } return returnAlpha; }; GLGE.Collada.prototype.setMaterialOntoMesh=function(meshes,node) { var materials=node.getElementsByTagName("instance_material"); var objMaterials={}; for(var i=0; i=0;--i) if (str[i]>="0"&&str[i]<="9") retval=str[i]+retval; if (retval.length==0) return "0"; return retval; } bvi[bvis[j].getAttribute("semantic")]=getLastNumber(bvis[j].getAttribute("semantic")); } } mat=this.getMaterial(materials[i].getAttribute("target").substr(1),bvi); objMaterials[materials[i].getAttribute("symbol")]=mat; } //create GLGE object var obj=new GLGE.Object(); if ( !obj.name || obj.name == "" ) { obj.name = "glgeObj" + ( ++this.objIdx ); } for(i=0; i1) idx=parseInt(idx[0])+4*parseInt(idx[1]); else idx=parseInt(idx[0]); sids[sidtarget].animations[idx]=animcurves[0]; }else{ //do all for(var j=0;j0){ bindShapeMatrix=this.parseArray(controller.getElementsByTagName("bind_shape_matrix")[0]); }else{ //assume identity bindShapeMatrix=GLGE.identMatrix(); } var inverseBindMatrix=[bindShapeMatrix]; var base=this.newGroup( undefined ); this.addGroup(base); var joints=[base]; var mat; for(var i=0; i0){ var colors=color[0].firstChild.nodeValue.split(" "); var c="rgb("+((colors[0]*255)|0)+","+((colors[1]*255)|0)+","+((colors[2]*255)|0)+")"; light.setColor(c); } switch (type.tagName) { // JHD case "point": light.setType(GLGE.L_POINT); case "spot": // JHD - End var ca = type.getElementsByTagName("constant_attenuation"); if (ca.length > 0) light.setAttenuationConstant(parseFloat(ca[0].firstChild.nodeValue)); var la = type.getElementsByTagName("linear_attenuation"); if (la.length > 0) light.setAttenuationLinear(parseFloat(la[0].firstChild.nodeValue)); var qa = type.getElementsByTagName("quadratic_attenuation"); if (qa.length > 0) light.setAttenuationQuadratic(parseFloat(qa[0].firstChild.nodeValue)); // JHD if (type.tagName == "spot") { light.setType(GLGE.L_SPOT); } else { break; } // case "spot": // JHD - End var se = type.getElementsByTagName("falloff_exponent"); if (se.length > 0) { var exp = parseFloat(se[0].firstChild.nodeValue); if (exp < 1.0001) exp *= 128; // if less then one then assume they // are using 0-1 so convert to 0-128 light.setSpotExponent(exp); } var fa = type.getElementsByTagName("falloff_angle"); if (fa.length > 0) light.setSpotCosCutOff(Math.cos(parseFloat(fa[0].firstChild.nodeValue) / 180 * Math.PI)); break; } return light; } GLGE.Collada.prototype.newGroup=function( node ){ var newGroup = new GLGE.Group(); var name="bone"+(++this.boneIdx); newGroup.setName(name); if ( node ) { newGroup.colladaId = node.getAttribute( "id" ); newGroup.colladaName = node.getAttribute( "name" ); } return newGroup; } // JHD /** * Creates a new group and parses it's children * @param {DOM Element} node the element to parse * @param {boolean} ref should this just get a reference for later addition * @private */ GLGE.Collada.prototype.addColladaCamera = function(object) { object.matrix = null; // Clear any cache object.parent = this; this.children.push(object); this.hasCamera = true; return this; } // JHD - End /** * Creates a new group and parses it's children * @param {DOM Element} node the element to parse * @param {boolean} ref should this just get a reference for later addition * @private */ GLGE.Collada.prototype.getNode=function(node,ref){ //if a reference has previously been created then add it now if(!ref && node.GLGEObject){ newGroup=node.GLGEObject; delete(this.GLGEObject); return newGroup; } //if a reference is requested a the node previously created then return here if(ref && node && node.GLGEObjects){ return node.GLGEObjects[0]; } var newGroup = this.newGroup( node ); var name="bone"+(++this.boneIdx); newGroup.setName(name); if (!node) { return newGroup; } if(!node.GLGEObjects) node.GLGEObjects=[]; node.GLGEObjects.push(newGroup); //map Collada DOM to GLGE var child=node.firstChild; var matrix=GLGE.identMatrix(); var data; if(child) do{ switch(child.tagName){ case "node": newGroup.addGroup(this.getNode(child)); break; case "instance_node": newGroup.addGroup(this.getNode(this.xml.getElementById(child.getAttribute("url").substr(1)))); break; case "instance_visual_scene": newGroup.addGroup(this.getNode(this.xml.getElementById(child.getAttribute("url").substr(1)))); break; case "instance_light": if(this.useLights) newGroup.addLight(this.getInstanceLight(this.xml.getElementById(child.getAttribute("url").substr(1)))); break; case "instance_geometry": newGroup.addObject(this.getInstanceGeometry(child)); break; case "instance_controller": newGroup.addObject(this.getInstanceController(child)); break; // JHD case "instance_camera": if(!this.useCamera) break; newGroup.addColladaCamera(this.getNode(this.xml.getElementById(child.getAttribute("url").substr(1)))); break; case "optics": if(!this.useCamera) break; var opticChild = child.getElementsByTagName("technique_common"); if (opticChild && opticChild.length > 0) { opticChild = opticChild[0].getElementsByTagName("perspective"); if (opticChild && opticChild.length > 0) { var yFov = opticChild[0].getElementsByTagName("yfov"); if (yFov && yFov.length > 0) { newGroup.yFov = parseFloat(yFov[0].textContent); } var zNear = opticChild[0].getElementsByTagName("znear"); if (zNear && zNear.length > 0) { newGroup.zNear = parseFloat(zNear[0].textContent); } var zFar = opticChild[0].getElementsByTagName("zfar"); if (zFar && zFar.length > 0) { newGroup.zFar = parseFloat(zFar[0].textContent); } } } break; // JHD - End case "matrix": matrix=this.parseArray(child); break; case "translate": data=this.parseArray(child); matrix=GLGE.mulMat4(matrix,GLGE.translateMatrix(data[0],data[1],data[2])); break; case "rotate": data=this.parseArray(child); matrix=GLGE.mulMat4(matrix,GLGE.angleAxis(data[3]*0.017453278,[data[0],data[1],data[2]])); break; case "scale": data=this.parseArray(child); matrix=GLGE.mulMat4(matrix,GLGE.scaleMatrix(data[0],data[1],data[2])); break; } }while(child=child.nextSibling); newGroup.setLoc(matrix[3],matrix[7],matrix[11]); var mat=GLGE.Mat4([matrix[0], matrix[1], matrix[2], 0, matrix[4], matrix[5], matrix[6], 0, matrix[8], matrix[9], matrix[10], 0, 0, 0, 0, 1]); newGroup.setRotMatrix(mat); if(ref) node.GLGEObject=newGroup; return newGroup; }; /** * Initializes the Object/Scene when the collada document has been loaded * @private */ GLGE.Collada.prototype.initVisualScene=function(){ var metadata=this.xml.getElementsByTagName("asset"); var up_axis="Z_UP"; var app_up_axis = "Z_UP"; if(metadata.length) { var up_axis_node=metadata[0].getElementsByTagName("up_axis"); if (up_axis_node.length) { up_axis_node=up_axis_node[0]; var cur_axis=up_axis_node.firstChild.nodeValue; if (cur_axis.length) up_axis=cur_axis; } } var transformRoot=this; if ( app_up_axis == "Z_UP" ) { switch ( up_axis[0] ) { case "Z": case "z": // do nothing break; case "Y": case "y": transformRoot = this.newGroup( undefined ); this.addChild( transformRoot ); transformRoot.setRotMatrix( GLGE.Mat4( [1, 0, 0, 0, 0, 0, -1, 0, 0, 1, 0, 0, 0, 0, 0, 1] )); break; case "X": case "x": break; } //{1,0,0,0, //0,0,-1,0, //0,1,0,"11":0,"12":0, //"13":0,"14":0,"15":1,"length":16,"buffer":{"byteLength":64},"byteLength":64,"byteOffset":0} } else { if (up_axis[0]!="Y"&&up_axis[0]!="y") { transformRoot = this.newGroup( undefined ); this.addChild(transformRoot); if (up_axis[0]!="Z"&&up_axis[0]!="z") { transformRoot.setRotMatrix(GLGE.Mat4([0, -1 , 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1])); }else { transformRoot.setRotMatrix(GLGE.Mat4([1, 0 , 0, 0, 0, 0, 1, 0, 0, -1, 0, 0, 0, 0, 0, 1])); } } } if(!this.rootId){ var scene=this.xml.getElementsByTagName("scene"); if(scene.length>0){ transformRoot.addGroup(this.getNode(scene[0])); }else{ GLGE.error("Please indicate the asset to render in Collada Document"+this.url); } }else{ var root=this.xml.getElementById(this.rootId); if(root){ transformRoot.addGroup(this.getNode(root)); }else{ GLGE.error("Asset "+this.rootId+" not found in document"+this.url); } } if(this.useCamera){ // JHD var tempCamera; var findChild = function(root) { if (root.hasCamera) { tempCamera = root; return; } if (!root.children) { return; } for ( var i = 0; i < root.children.length && !tempCamera; i++) { findChild(root.children[i]); } }; findChild(transformRoot); if (tempCamera) { pp = transformRoot.parent.parent; pp.camera.locX = tempCamera.locX; pp.camera.locY = tempCamera.locY; pp.camera.locZ = tempCamera.locZ; if (tempCamera.children && tempCamera.children.length > 0) { var child = tempCamera.children[0]; if (child.yFov) { pp.camera.fovy = child.yFov; pp.camera.pMatrix = null; } // TODO: Does this really get applied into WebGL states? if (child.zNear) { pp.camera.near = child.zNear; } if (child.zFar) { pp.camera.far = child.zFar; } } // Clear camera cache - The camera has, at this point, already been // calculated! pp.camera.matrix = null; pp.camera.rotmatrix = tempCamera.rotmatrix; pp.camera.lookAt = null; } // JHD - End } }; /** * Exceptions for the bad exports out there, I'm sure there will be many more :-( */ var exceptions={ "default":{}, "COLLADA Mixamo exporter":{badAccessor:true}, "FBX COLLADA exporter":{badAccessor:true}, "Blender2.5":{flipangle:true,negjoints:true} } GLGE.Collada.prototype.getExceptions=function(){ if(this.xml.getElementsByTagName("authoring_tool").length>0 && this.xml.getElementsByTagName("authoring_tool")[0].firstChild.nodeValue=="COLLADA Mixamo exporter"){ return exceptions["COLLADA Mixamo exporter"]; } if(this.xml.getElementsByTagName("authoring_tool").length>0 && this.xml.getElementsByTagName("authoring_tool")[0].firstChild.nodeValue=="FBX COLLADA exporter"){ return exceptions["FBX COLLADA exporter"]; } if(this.xml.getElementsByTagName("authoring_tool").length>0 && /Blender 2.5/.test(this.xml.getElementsByTagName("authoring_tool")[0].firstChild.nodeValue)){ return exceptions["Blender2.5"]; } } /** * Called when a collada document has is loaded * @param {string} url the url of the loaded document * @param {DOM Document} xml the xml document * @private */ GLGE.Collada.prototype.loaded=function(url,xml){ this.xml=xml; if(xml.getElementsByTagName("authoring_tool").length>0) this.exceptions=exceptions[xml.getElementsByTagName("authoring_tool")[0].firstChild.nodeValue]; this.exceptions=this.getExceptions(); if(!this.exceptions) this.exceptions=exceptions['default']; /// FIXME -- I used to have some try/catches going on here to avoid silent fails this.initVisualScene(); this.getAnimations(); if (this.loadedCallback) { this.loadedCallback(this); } //WTF firefox gets here too soon???? var collada=this; setTimeout(function(){ collada.fireEvent("loaded",{url:this.url}); if(collada.isComplete()) collada.fireEvent("downloadComplete",{}); },1); }; GLGE.Scene.prototype.addCollada=GLGE.Scene.prototype.addGroup; GLGE.Group.prototype.addCollada=GLGE.Group.prototype.addGroup; if(GLGE.Document){ /** * Parses the dom element and creates a collada object * @param {domelement} ele the element to create the objects from * @private */ GLGE.Document.prototype.getCollada=function(ele){ if(!ele.object){ ele.object=new GLGE[this.classString(ele.tagName)](); ele.object.setDocument(ele.getAttribute("document"),this.getAbsolutePath(this.rootURL,null)); ele.removeAttribute("document"); this.setProperties(ele); } return ele.object; } } })(GLGE); /* GLGE WebGL Graphics Engine Copyright (c) 2010, Paul Brunt All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of GLGE nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL PAUL BRUNT BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /** * @fileOverview * @name glge_input.js * @author me@paulbrunt.co.uk */ if(!GLGE){ /** * @namespace Holds the functionality of the library */ var GLGE={}; } (function(GLGE){ /** * @class Creates a heightmap for a region of the world based on an image. Originally created as a quick and easy collision detection. At least until we have a better physics implementation. * @deprecated not intended as a permanent addition * @param {string} imageURL The url of the image to generate the hightmap for * @param {number} imageWidth The width of the image * @param {number} imageHeight The height of the image * @param {number} x1 The lower X bound of the height map in world coords * @param {number} x2 The upper X bound of the height map in world coords * @param {number} y1 The lower Y bound of the height map in world coords * @param {number} y2 The upper Y bound of the height map in world coords * @param {number} z1 The lower Z bound of the height map in world coords * @param {number} z2 The upper Z bound of the height map in world coords */ GLGE.HeightMap = function(imageURL, imageWidth, imageHeight, x1, x2, y1, y2, z1, z2){ this.canvas = document.createElement("canvas"); this.context = this.canvas.getContext('2d'); this.canvas.width = imageWidth; this.canvas.height = imageHeight; this.minX = x1; this.maxX = x2; this.minY = y1; this.maxY = y2; this.minZ = z1; this.maxZ = z2; var image = new Image(); image.heightmap = this; image.onload = function(e){ this.heightmap.context.drawImage(this, 0, 0); this.heightmap.data = this.heightmap.context.getImageData(0, 0, this.heightmap.canvas.width, this.heightmap.canvas.height).data; this.heightmap.minImgValue = this.heightmap.data[0]; this.heightmap.maxImgValue = this.heightmap.data[0]; for (i = 0; i < this.heightmap.data.length; i += 4) { if (this.heightmap.data[i] < this.heightmap.minImgValue) { this.heightmap.minImgValue = this.heightmap.data[i]; } if (this.heightmap.data[i] > this.heightmap.maxImgValue) { this.heightmap.maxImgValue = this.heightmap.data[i]; } } }; image.src = imageURL; } GLGE.HeightMap.prototype.canvas = null; GLGE.HeightMap.prototype.context = null; GLGE.HeightMap.prototype.minZ = null; GLGE.HeightMap.prototype.maxZ = null; GLGE.HeightMap.prototype.minY = null; GLGE.HeightMap.prototype.maxY = null; GLGE.HeightMap.prototype.minX = null; GLGE.HeightMap.prototype.maxX = null; GLGE.HeightMap.prototype.data = null; /** * Gets the pixel height at the specified image coords * @param {number} x the x image coord * @param {number} y the y image coord * @private */ GLGE.HeightMap.prototype.getPixelAt = function(x, y){ if (this.data) { return (((this.data[(this.canvas.width * y + x) * 4]) - this.minImgValue) / (this.maxImgValue - this.minImgValue)) * (this.maxZ - this.minZ) + this.minZ; } else { return 0; } } /** * Function to get he height as specified x, y world coords * @param {number} x the x world coord * @param {number} y the y world coord * @returns {number} the height of the level in world units */ GLGE.HeightMap.prototype.getHeightAt = function(x, y){ var retValue; if (this.lastx != undefined && x == this.lastx && y == this.lasty) { retValue = this.lastValue; } else { var imgX = Math.round((x - this.minX) / (this.maxX - this.minX) * this.canvas.width); var imgY = Math.round((y - this.minY) / (this.maxY - this.minY) * this.canvas.height); retValue = this.getPixelAt(imgX, imgY); this.lastValue = retValue; } this.lastx = x; this.lasty = y; return retValue; } /** * @class Monitors keyboard input for use in render loops */ GLGE.KeyInput=function(){ if(!document.keyStates) document.keyStates=[]; document.addEventListener("keydown",this.onKeyDown,false); document.addEventListener("keyup",this.onKeyUp,false); } /** * Tests if a key is pressed * @param {number} the keycode to check * @returns {boolean} key returns true if the key is being pressed */ GLGE.KeyInput.prototype.isKeyPressed=function(key){ if(document.keyStates[key]) return true; else return false; }; var skiptimmer=null; /** * document keydown event used to monitor the key states * @param {event} e the event being fired * @private */ GLGE.KeyInput.prototype.onKeyDown=function(e){ document.keyStates[e.keyCode]=true; }; /** * Document keyup event used to monitor the key states * @param {event} e the event being fired * @private */ GLGE.KeyInput.prototype.onKeyUp=function(e){ document.keyStates[e.keyCode]=false; }; /** * @class Monitors mouse input for use in render loops */ GLGE.MouseInput=function(element){ this.element=element; this.element.mouseX=0; this.element.mouseY=0; if(!this.element.buttonState) this.element.buttonState=[]; element.addEventListener("mousemove",this.onMouseMove,false); element.addEventListener("mousedown",this.onMouseDown,false); element.addEventListener("mouseup",this.onMouseUp,false); } GLGE.MouseInput.prototype.element=null; /** * Elements mousemove event used to monitor the mouse states * @param {event} e the event being fired * @private */ GLGE.MouseInput.prototype.onMouseMove=function(e){ this.mouseX=e.clientX; this.mouseY=e.clientY; } /** * Elements mousedown event used to monitor the mouse states * @param {event} e the event being fired * @private */ GLGE.MouseInput.prototype.onMouseDown=function(e){ this.buttonState[e.button]=true; } /** * Elements mouseup event used to monitor the mouse states * @param {event} e the event being fired * @private */ GLGE.MouseInput.prototype.onMouseUp=function(e){ this.buttonState[e.button]=false; } /** * Tests if a mouse button is pressed * @param {number} button the button to check * @returns {boolean} returns true if the button is being pressed */ GLGE.MouseInput.prototype.isButtonDown=function(button){ if(this.element.buttonState[button]) return true; else return false; } /** * Gets the mouse coords * @returns {object} the current mouse coors */ GLGE.MouseInput.prototype.getMousePosition=function(){ return {x:this.element.mouseX,y:this.element.mouseY} } /** * @constant * @description Enumeration for the left mouse button */ GLGE.MI_LEFT=0; /** * @constant * @description Enumeration for the middle mouse button */ GLGE.MI_MIDDLE=1; /** * @constant * @description Enumeration for the right mouse button */ GLGE.MI_RIGHT=2; /** * @constant * @description Enumeration for the backspace key */ GLGE.KI_BACKSPACE=8; /** * @constant * @description Enumeration for the tab key */ GLGE.KI_TAB=9; /** * @constant * @description Enumeration for the enter key */ GLGE.KI_ENTER=13; /** * @constant * @description Enumeration for the shift key */ GLGE.KI_SHIFT=16; /** * @constant * @description Enumeration for the ctrl key */ GLGE.KI_CTRL=17; /** * @constant * @description Enumeration for the alt key */ GLGE.KI_ALT=18; /** * @constant * @description Enumeration for the pause/break key */ GLGE.KI_PAUSE_BREAK=19; /** * @constant * @description Enumeration for the caps lock key */ GLGE.KI_CAPS_LOCK=20; /** * @constant * @description Enumeration for the escape key */ GLGE.KI_ESCAPE=27; /** * @constant * @description Enumeration for the page up key */ GLGE.KI_PAGE_UP=33; /** * @constant * @description Enumeration for the page down key */ GLGE.KI_PAGE_DOWN=34; /** * @constant * @description Enumeration for the end key */ GLGE.KI_END=35; /** * @constant * @description Enumeration for the home key */ GLGE.KI_HOME=36; /** * @constant * @description Enumeration for the left arrow key */ GLGE.KI_LEFT_ARROW=37; /** * @constant * @description Enumeration for the up arrow key */ GLGE.KI_UP_ARROW=38; /** * @constant * @description Enumeration for the right arrow key */ GLGE.KI_RIGHT_ARROW=39; /** * @constant * @description Enumeration for the down arrow key */ GLGE.KI_DOWN_ARROW=40; /** * @constant * @description Enumeration for the insert key */ GLGE.KI_INSERT=45; /** * @constant * @description Enumeration for the delete key */ GLGE.KI_DELETE=46; /** * @constant * @description Enumeration for the 0 key */ GLGE.KI_0=48; /** * @constant * @description Enumeration for the 1 key */ GLGE.KI_1=49; /** * @constant * @description Enumeration for the 2 key */ GLGE.KI_2=50; /** * @constant * @description Enumeration for the 3 key */ GLGE.KI_3=51; /** * @constant * @description Enumeration for the 4 key */ GLGE.KI_4=52; /** * @constant * @description Enumeration for the 5 key */ GLGE.KI_5=53; /** * @constant * @description Enumeration for the 6 key */ GLGE.KI_6=54; /** * @constant * @description Enumeration for the 7 key */ GLGE.KI_7=55; /** * @constant * @description Enumeration for the 8 key */ GLGE.KI_8=56; /** * @constant * @description Enumeration for the 9 key */ GLGE.KI_9=57; /** * @constant * @description Enumeration for the a key */ GLGE.KI_A=65; /** * @constant * @description Enumeration for the b key */ GLGE.KI_B=66; /** * @constant * @description Enumeration for the c key */ GLGE.KI_C=67; /** * @constant * @description Enumeration for the d key */ GLGE.KI_D=68; /** * @constant * @description Enumeration for the e key */ GLGE.KI_E=69; /** * @constant * @description Enumeration for the f key */ GLGE.KI_F=70; /** * @constant * @description Enumeration for the g key */ GLGE.KI_G=71; /** * @constant * @description Enumeration for the h key */ GLGE.KI_H=72; /** * @constant * @description Enumeration for the i key */ GLGE.KI_I=73; /** * @constant * @description Enumeration for the j key */ GLGE.KI_J=74; /** * @constant * @description Enumeration for the k key */ GLGE.KI_K=75; /** * @constant * @description Enumeration for the l key */ GLGE.KI_L=76; /** * @constant * @description Enumeration for the m key */ GLGE.KI_M=77; /** * @constant * @description Enumeration for the n key */ GLGE.KI_N=78; /** * @constant * @description Enumeration for the o key */ GLGE.KI_O=79; /** * @constant * @description Enumeration for the p key */ GLGE.KI_P=80; /** * @constant * @description Enumeration for the q key */ GLGE.KI_Q=81; /** * @constant * @description Enumeration for the r key */ GLGE.KI_R=82; /** * @constant * @description Enumeration for the s key */ GLGE.KI_S=83; /** * @constant * @description Enumeration for the t key */ GLGE.KI_T=84; /** * @constant * @description Enumeration for the u key */ GLGE.KI_U=85; /** * @constant * @description Enumeration for the v key */ GLGE.KI_V=86; /** * @constant * @description Enumeration for the w key */ GLGE.KI_W=87; /** * @constant * @description Enumeration for the x key */ GLGE.KI_X=88; /** * @constant * @description Enumeration for the y key */ GLGE.KI_Y=89; /** * @constant * @description Enumeration for the z key */ GLGE.KI_Z=90; /** * @constant * @description Enumeration for the left window key key */ GLGE.KI_LEFT_WINDOW_KEY=91; /** * @constant * @description Enumeration for the right window key key */ GLGE.KI_RIGHT_WINDOW_KEY=92; /** * @constant * @description Enumeration for the select key key */ GLGE.KI_SELECT_KEY=93; /** * @constant * @description Enumeration for the numpad 0 key */ GLGE.KI_NUMPAD_0=96; /** * @constant * @description Enumeration for the numpad 1 key */ GLGE.KI_NUMPAD_1=97; /** * @constant * @description Enumeration for the numpad 2 key */ GLGE.KI_NUMPAD_2=98; /** * @constant * @description Enumeration for the numpad 3 key */ GLGE.KI_NUMPAD_3=99; /** * @constant * @description Enumeration for the numpad 4 key */ GLGE.KI_NUMPAD_4=100; /** * @constant * @description Enumeration for the numpad 5 key */ GLGE.KI_NUMPAD_5=101; /** * @constant * @description Enumeration for the numpad 6 key */ GLGE.KI_NUMPAD_6=102; /** * @constant * @description Enumeration for the numpad 7 key */ GLGE.KI_NUMPAD_7=103; /** * @constant * @description Enumeration for the numpad 8 key */ GLGE.KI_NUMPAD_8=104; /** * @constant * @description Enumeration for the numpad 9 key */ GLGE.KI_NUMPAD_9=105; /** * @constant * @description Enumeration for the multiply key */ GLGE.KI_MULTIPLY=106; /** * @constant * @description Enumeration for the add key */ GLGE.KI_ADD=107; /** * @constant * @description Enumeration for the subtract key */ GLGE.KI_SUBTRACT=109; /** * @constant * @description Enumeration for the decimal point key */ GLGE.KI_DECIMAL_POINT=110; /** * @constant * @description Enumeration for the divide key */ GLGE.KI_DIVIDE=111; /** * @constant * @description Enumeration for the f1 key */ GLGE.KI_F1=112; /** * @constant * @description Enumeration for the f2 key */ GLGE.KI_F2=113; /** * @constant * @description Enumeration for the f3 key */ GLGE.KI_F3=114; /** * @constant * @description Enumeration for the f4 key */ GLGE.KI_F4=115; /** * @constant * @description Enumeration for the f5 key */ GLGE.KI_F5=116; /** * @constant * @description Enumeration for the f6 key */ GLGE.KI_F6=117; /** * @constant * @description Enumeration for the f7 key */ GLGE.KI_F7=118; /** * @constant * @description Enumeration for the f8 key */ GLGE.KI_F8=119; /** * @constant * @description Enumeration for the f9 key */ GLGE.KI_F9=120; /** * @constant * @description Enumeration for the f10 key */ GLGE.KI_F10=121; /** * @constant * @description Enumeration for the f11 key */ GLGE.KI_F11=122; /** * @constant * @description Enumeration for the f12 key */ GLGE.KI_F12=123; /** * @constant * @description Enumeration for the num lock key */ GLGE.KI_NUM_LOCK=144; /** * @constant * @description Enumeration for the scroll lock key */ GLGE.KI_SCROLL_LOCK=145; /** * @constant * @description Enumeration for the semi-colon key */ GLGE.KI_SEMI_COLON=186; /** * @constant * @description Enumeration for the equal sign key */ GLGE.KI_EQUAL_SIGN=187; /** * @constant * @description Enumeration for the comma key */ GLGE.KI_COMMA=188; /** * @constant * @description Enumeration for the dash key */ GLGE.KI_DASH=189; /** * @constant * @description Enumeration for the period key */ GLGE.KI_PERIOD=190; /** * @constant * @description Enumeration for the forward slash key */ GLGE.KI_FORWARD_SLASH=191; /** * @constant * @description Enumeration for the grave accent key */ GLGE.KI_GRAVE_ACCENT=192; /** * @constant * @description Enumeration for the open bracket key */ GLGE.KI_OPEN_BRACKET=219; /** * @constant * @description Enumeration for the back slash key */ GLGE.KI_BACK_SLASH=220; /** * @constant * @description Enumeration for the close braket key */ GLGE.KI_CLOSE_BRAKET=221; /** * @constant * @description Enumeration for the single quote key */ GLGE.KI_SINGLE_QUOTE=222; /** * @constant * @description Enumeration for the space key */ GLGE.KI_SPACE=32; //code by @paul_irish if ( !window.requestAnimationFrame ) { window.requestAnimationFrame = ( function() { return window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame || function( /* function FrameRequestCallback */ callback, /* DOMElement Element */ element ) { window.setTimeout( callback, 1000 / 60 ); }; } )(); } })(GLGE); /* GLGE WebGL Graphics Engine Copyright (c) 2010, Paul Brunt All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of GLGE nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL PAUL BRUNT BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /** * @fileOverview * @name glge_wavefront.js * @author me@paulbrunt.co.uk */ (function(GLGE){ /** * @class parses and displays a warefront object file with mtl material * @param {string} uid the unique id for this object * @augments GLGE.Object */ GLGE.Wavefront=function(uid){ this.multimaterials=[]; this.materials={}; this.instances=[]; this.queue=[]; this.idMaterials = [];//storaged name of material (string) GLGE.Object.call(this,uid); GLGE.Assets.registerAsset(this,uid); } GLGE.augment(GLGE.Object,GLGE.Wavefront); /** * Gets the absolute path given an import path and the path it's relative to * @param {string} path the path to get the absolute path for * @param {string} relativeto the path the supplied path is relativeto * @returns {string} absolute path * @private */ GLGE.Wavefront.prototype.getAbsolutePath=function(path,relativeto){ if(path.substr(0,7)=="http://" || path.substr(0,7)=="file://" || path.substr(0,7)=="https://"){ return path; } else { if(!relativeto){ relativeto=window.location.href; } if(relativeto.indexOf("?")>0){ relativeto=relativeto.substr(0,relativeto.indexOf("?")); } //find the path compoents var bits=relativeto.split("/"); var domain=bits[2]; var proto=bits[0]; var initpath=[]; for(var i=3;i0){ var matUrl=this.queue.pop(); this.loadMaterials(matUrl,this.src); }else{ this.parseMesh(); this.fireEvent("loaded",{}); } }); }else{ this.queue.push(url); } }; /** * creates the GLGE materials from a mtl file * @param {string} file the file to parse * @private */ GLGE.Wavefront.prototype.parseMaterials=function(file){ //loop though all lines and look for matlibs var j = 0; var i = 0; var index = 0; var idNameMaterial; while(i1) { switch(data[0]){ case "Kd": material.setColorR(parseFloat(data[1])); material.setColorG(parseFloat(data[2])); material.setColorB(parseFloat(data[3])); break; case "Ks": material.setSpecularColor({r:parseFloat(data[1]),g:parseFloat(data[2]),b:parseFloat(data[3])}); break; case "Ns": material.setShininess(parseFloat(data[1])); break; case "d": this.setZtransparent(true); material.setAlpha(parseFloat(data[1])); break; case "map_Kd": var ml=new GLGE.MaterialLayer; ml.setMapto(GLGE.M_COLOR); ml.setMapinput(GLGE.UV1); var tex=new GLGE.Texture(); var k=1; while(data[k][0]=="-") k=k+2; tex.setSrc(this.getAbsolutePath(data[k],this.relativeTo)); material.addTexture(tex); ml.setTexture(tex); material.addMaterialLayer(ml); break; case "map_Ks": case "map_spec": var ml=new GLGE.MaterialLayer; ml.setMapto(GLGE.M_SPECULAR); ml.setMapinput(GLGE.UV1); var tex=new GLGE.Texture(); var k=1; while(data[k][0]=="-") k=k+2; tex.setSrc(this.getAbsolutePath(data[k],this.relativeTo)); material.addTexture(tex); ml.setTexture(tex); material.addMaterialLayer(ml); break; case "bump": case "map_bump": var ml=new GLGE.MaterialLayer; ml.setMapto(GLGE.M_NOR); ml.setMapinput(GLGE.UV1); var tex=new GLGE.Texture(); var k=1; while(data[k][0]=="-") k=k+2; tex.setSrc(this.getAbsolutePath(data[k],this.relativeTo)); material.addTexture(tex); ml.setTexture(tex); material.addMaterialLayer(ml); break; } } j++; if(j>=file.length) break; } i=j-1; this.materials[index]=material; this.idMaterials.push(idNameMaterial); index++; } i++; } }; /** * loads a resource from a url * @param {string} url the url of the resource to load * @param {string} relativeTo the url to load relative to * @param {function} callback thefunction to call once the file is loaded * @private */ GLGE.Wavefront.prototype.loadFile=function(url,relativeTo,callback){ this.loading=true; if(!callback) callback=this.loaded; if(!relativeTo && this.relativeTo) relativeTo=this.relativeTo; url=this.getAbsolutePath(url,relativeTo); if(!this.relativeTo) this.relativeTo=url; var req = new XMLHttpRequest(); var that=this; if(req) { req.overrideMimeType("text/plain") req.onreadystatechange = function() { if(this.readyState == 4) { if(this.status == 200 || this.status==0){ that.loading=false; callback.call(that,url,this.responseText); }else{ GLGE.error("Error loading Document: "+url+" status "+this.status); } } }; req.open("GET", url, true); req.send(""); } } /** * loads a wavefront ojvect from a given url * @param {DOM Element} url the url to retrieve * @param {string} relativeTo optional the path the url is relative to */ GLGE.Wavefront.prototype.setSrc=function(url,relativeTo){ this.src=this.getAbsolutePath(url,relativeTo); this.loadFile(this.src,relativeTo); }; /** * loads a resource from a url * @param {string} url the url of the resource loaded * @param {string} objfile the loaded file * @private */ GLGE.Wavefront.prototype.loaded=function(url,objfile){ this.file=objArray=objfile.split("\n"); var hasMaterial=false; //loop through the file and load the Materials for(var i=0;i1){ if(data[0]=="mtllib"){ hasMaterial=true; this.loadMaterials(data[1]); } } } if(!hasMaterial){ this.parseMesh(); this.fireEvent("loaded",{}); } }; /** * creates a new multimaterial * @private */ GLGE.Wavefront.prototype.createMultiMaterial=function(idxDataOrig,verts,norms,texCoords,faces,material,smooth){ //loop though the indexes to produce streams var positions=[]; var normals=[]; var uv=[]; var newfaces=[]; var idxData=[]; for(var i=0;i0) var vertData=idxData[i].split("/"); else var vertData=[idxData[i]]; if(!verts[vertData[0]-1]) GLGE.error(vertData[0]); positions.push(verts[vertData[0]-1][1]); positions.push(verts[vertData[0]-1][2]); positions.push(verts[vertData[0]-1][3]); if(vertData[1]){ uv.push(texCoords[vertData[1]-1][1]); uv.push(texCoords[vertData[1]-1][2]); } if(vertData[2]){ normals.push(norms[vertData[2]-1][1]); normals.push(norms[vertData[2]-1][2]); normals.push(norms[vertData[2]-1][3]); } } var multiMat=new GLGE.MultiMaterial; var mesh=new GLGE.Mesh; mesh.setPositions(positions); if(uv.length>0) mesh.setUV(uv); if(normals.length>0) mesh.setNormals(normals); mesh.setFaces(faces); multiMat.setMesh(mesh); multiMat.setMaterial(material); this.addMultiMaterial(multiMat); } /** * Parses the mesh * @private */ GLGE.Wavefront.prototype.parseMesh=function(){ objArray=this.file; var texCoords=[]; var verts=[]; var norms=[]; var faces=[]; var idxData=[]; var vertoffset=0; var smooth=true; var material=new GLGE.Material; for(var i=0;i0){ switch(data[0]){ case "s": if(data[1]=="1") smooth=true; else smooth=false; case "o": if(faces.length>0){ this.createMultiMaterial(idxData,verts,norms,texCoords,faces,material,smooth); faces=[]; material=new GLGE.Material; } break; case "usemtl": if(faces.length>0){ this.createMultiMaterial(idxData,verts,norms,texCoords,faces,material,smooth); faces=[]; } if(this.idMaterials.indexOf(data[1]) == -1)//Material no name material=this.materials[0];//default else material=this.materials[this.idMaterials.indexOf(data[1])];//get Idname material break; case "v": verts.push(data); break; case "vt": texCoords.push(data); break; case "vn": norms.push(data); break; case "f": var tmpface=[]; for(var j=1;j-1){ this.constraints.push(constraint); if(this.physicsSystem) this.physicsSystem.removeConstraint(constraint.constraint); } return this; } })(GLGE);/* GLGE WebGL Graphics Engine Copyright (c) 2010, Paul Brunt All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of GLGE nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL PAUL BRUNT BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /** * @fileOverview * @name glge_physicscar.js * @author me@paulbrunt.co.uk */ (function(GLGE){ /** * @class Physics Car class * @augments GLGE.PhysicsBox * @see GLGE.PhysicsWheel */ GLGE.PhysicsCar=function(uid){ GLGE.PhysicsBox.call(this,uid); this.wheels=[]; this.setRotationalVelocityDamping([0.1,0.6,0.1]); this.setLinearVelocityDamping([0.996,0.92,0.996]); return this; } GLGE.augment(GLGE.PhysicsBox,GLGE.PhysicsCar); GLGE.PhysicsCar.prototype.className="PhysicsCar"; GLGE.Group.prototype.addPhysicsCar=GLGE.Group.prototype.addChild; GLGE.Scene.prototype.addPhysicsCar=GLGE.Group.prototype.addChild; /** * Applies a driving force to the car * @param {number} force the item driving force to apply to each powered wheel */ GLGE.PhysicsCar.prototype.drive=function(force){ for(var i=0;i-1) this.wheels.splice(idx,1); return GLGE.PhsyicsBox.prototype.addChild.call(this,wheel); } /** * does the physics stuff * @private */ GLGE.PhysicsCar.prototype.getScene=function(){ var child=this; while(child.parent) child=child.parent; return child; } /** * does the physics stuff * @private */ GLGE.PhysicsCar.prototype.preProcess=function(dt){ var scene=this.getScene(); var velocity=this.getVelocity(); var carMass=this.getMass(); var wheels=this.wheels for(var i=0;imaxdw) dw=maxdw; } if(wheel.driveForce){ var drive=wheel.driveForce*(1-wheel.braking); if(drive<-maxForwardForce) drive=maxForwardForce; if(drive>maxForwardForce) drive=maxForwardForce; this.addWorldForce(GLGE.scaleVec3(forward,drive),position); dw+=(wheel.driveForce/carMass*dt)/wheelRadius; } if(wheel.braking){ var frontVel=GLGE.dotVec3(velocity,forward); var braking=-wheel.braking*frontVel/dt if(braking<-maxForwardForce) braking=-maxForwardForce; if(braking>maxForwardForce) braking=maxForwardForce; this.addWorldForce(GLGE.scaleVec3(forward,braking),position); } wheel.angVel+=dw; if(wheel.brake) wheel.angVel*=(1-wheel.braking); wheel.innerGroup.setRotZ(wheel.innerGroup.getRotZ()-wheel.angVel*dt); wheel.angVel*=0.995; wheel.oldPos=position; } GLGE.PhysicsBox.prototype.preProcess.call(this,dt); } /** * @class physics wheel class used with PhysicsCar class * @augments GLGE.Group * @see GLGE.PhysicsBox */ GLGE.PhysicsWheel=function(uid){ GLGE.Group.call(this,uid); this.innerGroup=new GLGE.Group; GLGE.Group.prototype.addChild.call(this,this.innerGroup); return this; } GLGE.augment(GLGE.Group,GLGE.PhysicsWheel); GLGE.PhysicsWheel.prototype.radius=1; GLGE.PhysicsWheel.prototype.travel=0.75; GLGE.PhysicsWheel.prototype.angVel=0; GLGE.PhysicsWheel.prototype.spring=90; GLGE.PhysicsWheel.prototype.braking=0; GLGE.PhysicsWheel.prototype.driveForce=0; GLGE.PhysicsWheel.prototype.powered=false; GLGE.PhysicsWheel.prototype.sideFriction=3; //sideways friction co-efficient GLGE.PhysicsWheel.prototype.frontFriction=3; //front friction force GLGE.PhysicsWheel.prototype.className="PhysicsWheel"; /** * Adds a child to the wheel container * @param {object} child a GLGE object to represent the wheel */ GLGE.PhysicsWheel.prototype.addChild=function(child){ return this.innerGroup.addChild(child); } /** * Removes a child to the wheel container * @param {object} child a GLGE object to represent the wheel */ GLGE.PhysicsWheel.prototype.removeChild=function(child){ return this.innerGroup.removeChild(child); } GLGE.PhysicsWheel.prototype.addGroup=GLGE.PhysicsWheel.prototype.addChild; GLGE.PhysicsWheel.prototype.addCollada=GLGE.PhysicsWheel.prototype.addChild; GLGE.PhysicsWheel.prototype.addObject=GLGE.PhysicsWheel.prototype.addChild; GLGE.PhysicsWheel.prototype.addMD2=GLGE.PhysicsWheel.prototype.addChild; GLGE.PhysicsWheel.prototype.addMD3=GLGE.PhysicsWheel.prototype.addChild; GLGE.PhysicsWheel.prototype.addWavefront=GLGE.PhysicsWheel.prototype.addChild; /** * Sets the wheel to be a powered wheel * @param {boolean} powered flag indicateding if wheel is powered */ GLGE.PhysicsWheel.prototype.setPowered=function(powered){ this.powered=powered; return this; } /** * Sets the wheel Radius * @param {number} radius the wheel radius */ GLGE.PhysicsWheel.prototype.setRadius=function(radius){ this.radius=radius; return this; } /** * Sets the suspension spring distance * @param {number} radius the wheel radius */ GLGE.PhysicsWheel.prototype.setSpring=function(spring){ this.spring=spring; return this; } /** * Sets the suspension travel distance * @param {number} travel the suspension travel */ GLGE.PhysicsWheel.prototype.setTravel=function(travel){ this.travel=travel; return this; } /** * Sets the front friction coefficient * @param {number} friction the front fricition coefficient */ GLGE.PhysicsWheel.prototype.setFrontFriction=function(friction){ this.frontFriction=friction; return this; } /** * Sets the side friction coefficient * @param {number} friction the side fricition coefficient */ GLGE.PhysicsWheel.prototype.setSideFriction=function(friction){ this.sideFriction=friction; return this; } /** * Sets the wheel Rotation * @param {number} rotation the rotation of the wheel */ GLGE.PhysicsWheel.prototype.setWheelRotation=function(rotation){ this.setRotY(rotation); return this; } /** * Gets the wheel Rotation * @returns the wheel roation in radians */ GLGE.PhysicsWheel.prototype.getWheelRotation=function(rotation){ return this.getRotY(); } /** * Gets the wheel Radius * @returns the wheel radius */ GLGE.PhysicsWheel.prototype.getRadius=function(){ return this.radius; } /** * Gets the suspension spring * @returns the wheel radius */ GLGE.PhysicsWheel.prototype.getSpring=function(){ return this.spring; } /** * Gets the suspension travel distance * @returns the suspension travel */ GLGE.PhysicsWheel.prototype.getTravel=function(){ return this.travel; } /** * Gets the front friction coefficient * @returns the front fricition coefficient */ GLGE.PhysicsWheel.prototype.getFrontFriction=function(){ return this.frontFriction; } /** * Gets the side friction coefficient * @returns the side fricition coefficient */ GLGE.PhysicsWheel.prototype.getSideFriction=function(){ return this.sideFriction; } /** * Sets a driving force for the wheel * @param {number} force the driving force in N */ GLGE.PhysicsWheel.prototype.drive=function(force){ this.driveForce=force; return this; } /** * Sets the braking level * @param {number} brake 0-1 value indicating the level of braking */ GLGE.PhysicsWheel.prototype.brake=function(brake){ this.braking=brake; return this; } })(GLGE);/* Copyright (c) 2011 Martin Ruenz Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /** * @fileOverview Base class for preloaders. Enables the handling of multiple files. * @name glge_filepreloader.js * @author seamonkey@uni-koblenz.de */ (function(GLGE){ /** * @class FilePreloader class * @augments GLGE.Events */ GLGE.FilePreloader=function(){ this.files=[]; } GLGE.augment(GLGE.Events,GLGE.FilePreloader); GLGE.FilePreloader.prototype.loadedBytes=0; GLGE.FilePreloader.prototype.totalBytes=0; GLGE.FilePreloader.prototype.numLoadedFiles=0; GLGE.FilePreloader.prototype.numTotalFiles=0; GLGE.FilePreloader.prototype.sizesCount=0; /** @description Specifies how many file sizes has been collected */ GLGE.FilePreloader.prototype.progress=0; /** @description 0 - 100 */ GLGE.FilePreloader.prototype.files=null; /** @description List of files. file: { "url":url,"loaded":fileloaded,"size":filesize,"bytesLoaded":loadedSize, "type":'xml'/'image',"callback":called when loaded,"content":content, "preloader":GLGE.FilePreloader} */ /** * Add a file which has to be loaded * @param {string} url The url of the file. * @param {string} type Defines the type of the requested file. "image" or "xml" * @param {function} [callback] Call this function when the file is loaded and pass the loaded content. * @public */ GLGE.FilePreloader.prototype.addFile=function(url, type, callback){ //if(this.files.indexOf(url) != -1) return; this.files.push({"url":url,"loaded":false,"size":-1,"bytesLoaded":0,"type":type,"callback":callback,"content":null,"preloader":this}); this.numTotalFiles++; } /** * Same as addFile. But instead of creating a new file object use an existing one. * @param {object} file The file to add. * @public */ GLGE.FilePreloader.prototype.addFileRef=function(file){ //if(this.files.indexOf(url) != -1) return; this.files.push(file); this.numTotalFiles++; } /** * This function accumulates the size of all files. When done it triggers loadFiles(). It has to be called for each file. * @param {object} file Current file. * @private */ GLGE.FilePreloader.prototype.accumulateFileSize=function(file) { var req = new XMLHttpRequest(); req.preloader = this; req.active = true; req.file = file; req.overrideMimeType("text/xml"); req.onreadystatechange = function() { if(this.readyState > 1 && req.active) { this.active = false; this.file.size = parseFloat(this.getResponseHeader('Content-length')); this.preloader.totalBytes += this.file.size; if(++this.preloader.sizesCount >= this.preloader.files.length) // are all file sizes collected? this.preloader.loadFiles(); this.abort(); this.onreadystatechange = null; } }; req.open("GET", file.url, true); req.send(""); } /** * Start loading * @public */ GLGE.FilePreloader.prototype.start=function(){ for(i in this.files) this.accumulateFileSize(this.files[i]); } /** * Load files. Assumes that the file sizes have been accumulated. * @private */ GLGE.FilePreloader.prototype.loadFiles=function(){ for(i in this.files){ var file = this.files[i]; if(file.type == "image") { // only update the preloader, when the file is completely loaded (no ajax) var image = new Image(); file.content = image; var that = this; image.file = file; image.onload = function(){ that.fileLoaded(this.file, this.file.size); } image.src=file.url; }else{ // update the preloader each 0.1 seconds (ajax) var req = new XMLHttpRequest(); req.overrideMimeType("text/xml"); req.preloader = this; req.file = file; var updateTrigger = setInterval (function () { if (req.readyState == 3) { // TODO: Check if the file reference is always correct var stepBytes = req.responseText.length - file.bytesLoaded; file.bytesLoaded = req.responseText.length; req.preloader.update(stepBytes); } }, 100); req.onreadystatechange = function() { if(this.readyState >= 4) { clearInterval(updateTrigger); this.file.content = this.responseXML; var stepBytes = this.responseText.length - this.file.bytesLoaded; this.preloader.update(stepBytes); this.preloader.fileLoaded(this.file, stepBytes); } }; req.open("GET", file.url, true); req.send(); } } } /** * This functions updates the progress. * @param {number} stepBytes Amount of bytes that have been loaded since the last call. * @private */ GLGE.FilePreloader.prototype.update=function(stepBytes){ this.loadedBytes += stepBytes; this.progress = (100.0 * this.loadedBytes) / this.totalBytes; this.fireEvent("progress", {"progress":this.progress, "stepBytes":stepBytes, "loadedBytes":this.loadedBytes, "totalBytes":this.totalBytes, "loadedFiles": this.numLoadedFiles, "totalFiles": this.numTotalFiles}); } /** * Called when a file has been loaded. This function triggers an event and updates the state. * @param {object} file The file that has been loaded. * @param {number} stepBytes Amount of bytes that have been loaded since the last call. * @private */ GLGE.FilePreloader.prototype.fileLoaded=function(file, stepBytes){ this.numLoadedFiles++; // update file file.loaded = true; file.bytesLoaded = file.size; // update progress if(this.numLoadedFiles >= this.files.length){ this.progress = 100; this.fireEvent("downloadComplete", {"file":file,"stepBytes":stepBytes}); }else{ this.update(stepBytes); } // events this.fireEvent("fileLoaded", {"file":file,"stepBytes":stepBytes}); if(file.callback) file.callback(file); } /** * This function returns a list (an array) of all loaded files. * @public */ GLGE.FilePreloader.prototype.getLoadedFiles=function(){ var result = []; for(i in this.files) if(this.files[i].loaded) result.push(this.files[i]); return result; } /** * This function returns information about one file. * @param {string} url The url of the file. * @public */ GLGE.FilePreloader.prototype.getFile=function(url){ for(i in this.files) if(this.files[i].url==url) return this.files[i]; return -1; } })(GLGE); /* Copyright (c) 2011 Martin Ruenz Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /** * @fileOverview * @name glge_documentpreloader.js * @author seamonkey@uni-koblenz.de */ (function(GLGE){ /** * @class Document preloader class * @augments GLGE.Events */ GLGE.DocumentPreloader=function(doc, args){ // create image preloader this.imagePreloader = new GLGE.FilePreloader(); this.document = doc; if(args.XMLQuota) this.XMLQuota = args.XMLQuota; else this.XMLQuota = 0.2; // 20% XML, 80% images this.imageQuota = 1-this.XMLQuota; // Passing the size of all xml files will improve the accuracy of the preloader. Alternative: Pass the number of xml files (approximation) if(args.XMLBytes) this.XMLBytes = args.XMLBytes; else if(args.numXMLFiles) this.numXMLFiles = args.numXMLFiles; else this.numXMLFiles = 3; //TODO necessary? } GLGE.augment(GLGE.Events,GLGE.DocumentPreloader); GLGE.DocumentPreloader.prototype.progress = 0; GLGE.DocumentPreloader.prototype.imageQuota = 0; // size quota of images (Textures) [0..1] GLGE.DocumentPreloader.prototype.XMLQuota = 0; // size quota XML (Documents) [0..1] GLGE.DocumentPreloader.prototype.XMLBytes = -1; // XML size in bytes (for higher accuracy) GLGE.DocumentPreloader.prototype.totalBytes = -1; // XML size in bytes (highest accuracy) GLGE.DocumentPreloader.prototype.loadedBytes=0; GLGE.DocumentPreloader.prototype.numXMLFiles = 3; // default value GLGE.DocumentPreloader.prototype.state = 0; // 0: not yet started, 1: loading XML, 2: loading images, 3: completed GLGE.DocumentPreloader.prototype.imagePreloader = null; // GLGE.Peloader GLGE.DocumentPreloader.prototype.document = null; // GLGE.Document /** * Add an image, which should be loaded by the preloader. * @param {string} url Url of the image. */ GLGE.DocumentPreloader.prototype.addImage=function(url){ this.imagePreloader.addFile(url, "image"); } /** * Start loading all images in all xml files. Assumes that XML-files have finished loading. */ GLGE.DocumentPreloader.prototype.loadImages=function(){ this.changeState(2); if(this.progress < this.XMLQuota * 100.0) this.progress = this.XMLQuota * 100.0; // correct progress. var that = this; this.imagePreloader.addEventListener("progress", function(args){that.updateProgress.call(that, args);}); this.imagePreloader.addEventListener("downloadComplete", function(args){that.finish.call(that, args);}); this.imagePreloader.addEventListener("fileLoaded", function(args){that.fireEvent("fileLoaded", args.file);}); this.imagePreloader.start(); } /** * Update preloader progress. * @param {object} args Progress information. *
args.stepBytes describes how many bytes have been loaded since the last update. */ GLGE.DocumentPreloader.prototype.updateProgress=function(args){ if(this.state < 2){ // loading xml if(this.XMLBytes > 0){ // high accuracy //if(!args.stepBytes) args.stepBytes = 0; this.loadedBytes += args.stepBytes; this.progress = this.XMLQuota * 100.0 * this.loadedBytes / this.XMLBytes; } else{ // low accuracy this.progress += this.XMLQuota * 100.0 / this.numXMLFiles; if(this.progress > this.XMLQuota * 100) this.progress = this.XMLQuota * 100; } } else{ // loading images this.progress = this.XMLQuota * 100 + this.imageQuota * this.imagePreloader.progress; } this.fireEvent("progress", {"progress":this.progress, "stepBytes":args.stepBytes, "loadedBytes":args.loadedBytes, "totalBytes":args.totalBytes, "loadedFiles": args.loadedFiles, "totalFiles": args.totalFiles}); } /** * This function loads a XML-file. Assumes that loading images hasn't yet begun. * @param {string} url Url of the XML-file. */ GLGE.DocumentPreloader.prototype.loadXMLFile=function(url){ this.changeState(1); var xmlPreloader = new GLGE.FilePreloader(); xmlPreloader.addFile(url, "xml"); var that = this; if(this.XMLBytes > 0) xmlPreloader.addEventListener("progress", function(arg){that.updateProgress.call(that, arg);}); // high accuracy else xmlPreloader.addEventListener("downloadComplete", function(arg){that.updateProgress.call(that, arg);}); // low accuracy var doc = this.document; xmlPreloader.addEventListener("fileLoaded", function(args){ args.file.content.getElementById=doc.getElementById; doc.loaded(args.file.url,args.file.content); that.fireEvent("fileLoaded", args.file); }); xmlPreloader.start(); } /** * Sets the state of the document preloader. * @param {number} newState New state */ GLGE.DocumentPreloader.prototype.changeState = function(newState) { //if(this.state > newState) GLGE.warning("GLGE.DocumentPreloader.prototype.changeState: The new state is lower than the old."); this.state = newState; this.fireEvent("stateChange", newState); } /** * Called when the document preloader loaded all files. * @param {object} event Event parameter. Not used at all. */ GLGE.DocumentPreloader.prototype.finish=function(event){ this.changeState(3); this.progress = 100; this.fireEvent("downloadComplete"); } })(GLGE); /* Copyright (c) 2011 Martin Ruenz Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /** * @fileOverview * @name widget.js * @author seamonkey@uni-koblenz.de */ (function(GLGE){ if(typeof(GLGE.GUI) == "undefined"){ /** * @namespace Holds the functionality of the GUI */ GLGE.GUI = {}; } (function(GUI){ /** * Replace as much gui-objects as possible, with those provided by the library */ GUI.useLibrary = function(library){ if((library == "jQuery") && jQuery) { // progressbar GUI.Progressbar.prototype.setValue = function(value){$(this.domRoot).progressbar({'value': value });} GUI.Progressbar.prototype.init = function(){ $(this.domRoot).progressbar({value: 0 }); } } // TODO: Support for more libraries and widgets } /** * @class Widget Widgets are gui objects like progressbars or sliders */ GUI.Widget = function(){ this.domRoot = document.createElement('div'); this.domRoot.setAttribute('class','glge-gui-widget-root'); this.init(); } GUI.Widget.prototype.domRoot = null; GUI.Widget.prototype.init = function(){}; /** * @class Progressbar A progressbar widget */ GUI.Progressbar = function(){ // call super constructor this.baseclass.call(this); this.domRoot.className += ' glge-gui-progressbar'; } GUI.Progressbar.prototype.value = 0; /** * Set the progress value * @param {number} value progress value */ GUI.Progressbar.prototype.setValue = function(value){ this.value = value; } GLGE.augment(GUI.Widget,GUI.Progressbar); })(GLGE.GUI);})(GLGE); /* Copyright (c) 2011 Martin Ruenz Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /** * @fileOverview * @name gadget.js * @author seamonkey@uni-koblenz.de */ (function(GLGE){ if(typeof(GLGE.GUI) == "undefined"){ /** * @namespace Holds the functionality of the GUI */ GLGE.GUI = {}; } (function(GUI){ /** * @class Gadget Gadgets are more complex widgets. One could think of them as windows. They may contain widgets. */ GUI.Gadget=function(){ // setup new DOM-Object // root this.domGadgetRoot = document.createElement('div'); this.domGadgetRoot.setAttribute('class','glge-gui-gadget-root'); this.domGadgetRoot.style.position = 'absolute'; this.domGadgetRoot.style.top = '0px'; // Outer Wrapper this.domGadgetOuterWrapper = document.createElement('div'); this.domGadgetOuterWrapper.setAttribute('class','glge-gui-gadget-OuterWrapper'); this.domGadgetOuterWrapper.style.position = 'relative'; this.domGadgetRoot.appendChild(this.domGadgetOuterWrapper); // Inner Wrapper this.domGadgetInnerWrapper = document.createElement('div'); this.domGadgetInnerWrapper.setAttribute('class','glge-gui-gadget-InnerWrapper'); this.domGadgetInnerWrapper.style.position = 'relative'; this.domGadgetOuterWrapper.appendChild(this.domGadgetInnerWrapper); // object this.domGadgetObject = document.createElement('div'); this.domGadgetObject.setAttribute('class','glge-gui-gadget'); this.domGadgetObject.style.position = 'relative'; this.domGadgetInnerWrapper.appendChild(this.domGadgetObject); // footer this.domGadgetFooter = document.createElement('div'); this.domGadgetFooter.setAttribute('class','glge-gui-gadget-footer'); this.domGadgetFooter.style.clear = 'both'; this.domGadgetRoot.appendChild(this.domGadgetFooter); // variables this.position = {}; this.position.x = 'middle'; this.position.y = 'middle'; this.updatePosition(); } GUI.Gadget.prototype.domGadgetRoot = null; // div: attached to dom GUI.Gadget.prototype.domGadgetOuterWrapper = null; // div: wrapper for css (vertical align) GUI.Gadget.prototype.domGadgetInnerWrapper = null; // div: wrapper for css (horizontal align) GUI.Gadget.prototype.domGadgetObject = null; // div: actual gadget GUI.Gadget.prototype.domGadgetFooter = null; // div: footer GUI.Gadget.prototype.domGadgetParent = null; // parent object, already in dom GUI.Gadget.prototype.position = null; // position.x, position.y /** * This function sets the position of the gadget * @param {object} position position.x, possible values: "left", "middle", "right", number
* position.y, possible values: "top", "middle", "bottom", number */ GUI.Gadget.prototype.setPosition = function(position){ if(position){ if(position.x) this.position.x = position.x; if(position.y) this.position.y = position.y; } this.updatePosition(); } /** * This function changes css attributes in order to position the gadget * @param {object} position position.x, possible values: "left", "middle", "right"
* position.y, possible values: "top", "middle", "bottom" */ // TODO: Possibility to set the position absolute (e.g. x= 15, y=20) GUI.Gadget.prototype.updatePosition = function(){ if(!this.domGadgetParent) return; var parentPosition = ''; if(document.defaultView && document.defaultView.getComputedStyle) parentPosition = document.defaultView.getComputedStyle(this.domGadgetParent,null).getPropertyValue('position'); else if (this.domGadgetParent.currentStyle) parentPosition = this.domGadgetParent.currentStyle['position']; if(parentPosition == 'absolute'){ this.domGadgetRoot.style.width = '100%'; this.domGadgetRoot.style.height = '100%'; this.domGadgetRoot.style.display = 'table'; this.domGadgetOuterWrapper.style.display = 'table-cell'; if(this.position.y == "top"){ this.domGadgetOuterWrapper.style.verticalAlign = 'top'; } else if(this.position.y == "middle"){ this.domGadgetOuterWrapper.style.verticalAlign = 'middle'; } else if(this.position.y == "bottom"){ this.domGadgetOuterWrapper.style.verticalAlign = 'bottom'; } if(this.position.x == "left"){ this.domGadgetInnerWrapper.style.cssFloat = 'left'; this.domGadgetInnerWrapper.style.left = '0px'; this.domGadgetObject.style.cssFloat = 'left'; this.domGadgetObject.style.left = '0px'; } else if(this.position.x == "middle"){ this.domGadgetInnerWrapper.style.cssFloat = 'right'; this.domGadgetInnerWrapper.style.right = '50%'; this.domGadgetObject.style.cssFloat = 'left'; this.domGadgetObject.style.right = '-50%'; } else if(this.position.x == "right"){ this.domGadgetInnerWrapper.style.cssFloat = 'right'; this.domGadgetInnerWrapper.style.right = '0px'; this.domGadgetObject.style.cssFloat = 'right'; this.domGadgetObject.style.right = '0px'; } }else{ // TODO: css would be much better! if(this.position.y == "top"){ this.domGadgetRoot.style.top = this.domGadgetParent.offsetTop; } else if(this.position.y == "middle"){ this.domGadgetRoot.style.top = this.domGadgetParent.offsetTop + this.domGadgetParent.offsetHeight / 2 - this.domGadgetRoot.offsetHeight / 2; } else if(this.position.y == "bottom"){ this.domGadgetRoot.style.top = this.domGadgetParent.offsetTop + this.domGadgetParent.offsetHeight - this.domGadgetRoot.offsetHeight; } if(this.position.x == "left"){ this.domGadgetRoot.style.left = this.domGadgetParent.offsetLeft; } else if(this.position.x == "middle"){ this.domGadgetRoot.style.left = this.domGadgetParent.offsetLeft + this.domGadgetParent.offsetWidth / 2 - this.domGadgetRoot.offsetWidth / 2; } else if(this.position.x == "right"){ this.domGadgetRoot.style.left = this.domGadgetParent.offsetLeft + this.domGadgetParent.offsetWidth - this.domGadgetRoot.offsetWidth; } } } /** * Add Gadget to DOM * @param {object} element Parent element of the gadget * @param {object} [position] position.x, possible values: "left", "middle", "right"
* position.y, possible values: "top", "middle", "bottom" */ GUI.Gadget.prototype.addToDOM = function(element, position){ this.domGadgetParent = element; // add gadget to the document this.domGadgetParent.appendChild(this.domGadgetRoot); this.setPosition(position); } })(GLGE.GUI);})(GLGE); /* Copyright (c) 2011 Martin Ruenz Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /** * @fileOverview * @name preloader_gadget.js * @author seamonkey@uni-koblenz.de */ (function(GLGE){ (function(GUI){ /** * @class Preloader gadget * @augments GLGE.GUI.Gadget */ GUI.Preloader=function(){ // call super constructor this.baseclass.call(this); this.domGadgetObject.innerHTML = "

Loading

"; this.domGadgetObject.className += ' glge-gui-gadget-preloader'; // progress bar this.progressBar = new GUI.Progressbar(); this.domGadgetObject.appendChild(this.progressBar.domRoot); this.domPercentageLabel = document.createElement('div'); this.domPercentageLabel.setAttribute('class','glge-gui-gadget-preloader-percentage'); this.domPercentageLabel.innerHTML = "
0%
100%
"; this.domGadgetObject.appendChild(this.domPercentageLabel); // information box this.domInfoBox = document.createElement('div'); this.domInfoBox.setAttribute('class','glge-gui-gadget-preloader-info'); this.domInfoBox.setAttribute('style','clear:both;'); this.domGadgetObject.appendChild(this.domInfoBox); // state label this.domStateLabel = document.createElement('div'); this.domInfoBox.appendChild(this.domStateLabel); // bytes label this.domBytesLabel = document.createElement('div'); this.domInfoBox.appendChild(this.domBytesLabel); // files label this.domFilesLabel = document.createElement('div'); this.domInfoBox.appendChild(this.domFilesLabel); // last file label this.domLastFileLabel = document.createElement('div'); this.domInfoBox.appendChild(this.domLastFileLabel); } GUI.Preloader.prototype.progressBar = null; GUI.Preloader.prototype.documentLoader = null; GUI.Preloader.prototype.domInfoBox = null; GUI.Preloader.prototype.domStateLabel = null; GUI.Preloader.prototype.domBytesLabel = null; GUI.Preloader.prototype.domFilesLabel = null; GUI.Preloader.prototype.domLastFileLabel = null; GUI.Preloader.prototype.domPercentageLabel = null; /** * Combine the preloader gadget with an actual preloader * @param {GLGE.DocumentPreloader} docLoader preloader */ GUI.Preloader.prototype.setDocumentLoader = function(docLoader){ this.documentLoader = docLoader; // add listeners var that = this; this.documentLoader.addEventListener("downloadComplete", function(args){that.complete(args);}); this.documentLoader.addEventListener("progress", function(args){that.progress(args);}); this.documentLoader.addEventListener("stateChange", function(args){that.stateChange(args);}); this.documentLoader.addEventListener("fileLoaded", function(args){that.fileLoaded(args);}); } /** * Add preloader-gadget to DOM. Creates the content of the DOM-object (domGadgetObject). * @param {object} element Parent element of the gadget * @param {string|object} [position] Gadget position */ GUI.Preloader.prototype.addToDOM = function(element, position){ // update labels this.stateChange(this.documentLoader.state); this.progress({progress:0, loadedBytes:0, loadedFiles:0, totalFiles:0, totalBytes: 0}); this.fileLoaded({}); this.baseclass.addToDOM.call(this, element, position) } /** * Called on progress */ GUI.Preloader.prototype.progress = function(args){ //this.domProgressBar.progressbar({value: args.progress }); this.progressBar.setValue(args.progress); this.domBytesLabel.innerHTML = args.loadedBytes + " of " + args.totalBytes + " Bytes loaded"; this.domFilesLabel.innerHTML = args.loadedFiles + " of " + args.totalFiles + " Files loaded"; } /** * Called when the preloader finished loading */ GUI.Preloader.prototype.complete = function(args){ //this.domProgressBar.progressbar({value: 100 }); this.progressBar.setValue(100); var that = this; setTimeout ( function(){that.domGadgetRoot.parentNode.removeChild(that.domGadgetRoot)}, 300); } /** * Called when the preloader changed it's state */ GUI.Preloader.prototype.stateChange = function(args){ switch(args) { case 0: case 1: this.domStateLabel.innerHTML = "Step 1 of 2: Loading XML"; break; case 2: case 3: this.domStateLabel.innerHTML = "Step 2 of 2: Loading Textures"; break; } } /** * Called when a file has been loaded */ GUI.Preloader.prototype.fileLoaded = function(args){ if(args.url){ var path = args.url; // use only 40 letters if(path.length > 40){ path = path.slice(-37); path = "..." + path; } this.domLastFileLabel.innerHTML = "Last file loaded: \"" + path + "\""; } else if(this.domLastFileLabel.innerHTML == "") this.domLastFileLabel.innerHTML = "Last file loaded: none"; } GLGE.augment(GUI.Gadget,GUI.Preloader); })(GLGE.GUI);})(GLGE);