/* 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 */ // Start of compatibility code try { WebGLFloatArray; } catch (e) { try { WebGLFloatArray = CanvasFloatArray; WebGLUnsignedShortArray = CanvasUnsignedShortArray; } catch (e) { alert("Could not find any WebGL array types."); } } // End of compatibility code if(!GLGE){ /** * @namespace Holds the functionality of the library */ var GLGE={}; } (function(GLGE){ /** * @constant * @description Enumeration for TRUE */ GLGE.TRUE=1; /** * @constant * @description Enumeration for FALSE */ GLGE.FALSE=0; /** * @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 box bound text picking */ GLGE.TEXT_BOXPICK=1; /** * @constant * @description Enumeration for text bound text picking */ GLGE.TEXT_TEXTPICK=1; /** * @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; /** * function to cache the uniform locations * @param {glcontext} the gl context of the program * @param {program} the shader program * @param {string} the uniform name * @private */ GLGE.getUniformLocation=function(gl,program, uniform){ if(!program.uniformCache) program.uniformCache={}; if(!program.uniformCache[uniform]){ program.uniformCache[uniform]=gl.getUniformLocation(program, uniform); } return program.uniformCache[uniform]; }; /** * function to cache the attribute locations * @param {glcontext} the gl context of the program * @param {program} the shader program * @param {string} the attribe name * @private */ GLGE.getAttribLocation=function(gl,program, attrib){ if(!program.attribCache) program.attribCache={}; if(!program.attribCache[attrib]){ program.attribCache[attrib]=gl.getAttribLocation(program, attrib); } return program.attribCache[attrib]; } /** * function to parse a colour input into RGB eg #ff00ff, red, rgb(100,100,100) * @param {string} color the color to parse */ GLGE.colorParse=function(color){ var red,green,blue; //defines the color names var color_names = { aliceblue: 'f0f8ff', antiquewhite: 'faebd7', aqua: '00ffff', aquamarine: '7fffd4', azure: 'f0ffff', beige: 'f5f5dc', bisque: 'ffe4c4', black: '000000', blanchedalmond: 'ffebcd', blue: '0000ff', blueviolet: '8a2be2', brown: 'a52a2a', burlywood: 'deb887', cadetblue: '5f9ea0', chartreuse: '7fff00', chocolate: 'd2691e', coral: 'ff7f50', cornflowerblue: '6495ed', cornsilk: 'fff8dc', crimson: 'dc143c', cyan: '00ffff', darkblue: '00008b', darkcyan: '008b8b', darkgoldenrod: 'b8860b', darkgray: 'a9a9a9', darkgreen: '006400', darkkhaki: 'bdb76b', darkmagenta: '8b008b', darkolivegreen: '556b2f', darkorange: 'ff8c00', darkorchid: '9932cc', darkred: '8b0000', darksalmon: 'e9967a', darkseagreen: '8fbc8f', darkslateblue: '483d8b', darkslategray: '2f4f4f', darkturquoise: '00ced1', darkviolet: '9400d3', deeppink: 'ff1493', deepskyblue: '00bfff', dimgray: '696969', dodgerblue: '1e90ff', feldspar: 'd19275', firebrick: 'b22222', floralwhite: 'fffaf0', forestgreen: '228b22', fuchsia: 'ff00ff', gainsboro: 'dcdcdc', ghostwhite: 'f8f8ff', gold: 'ffd700', goldenrod: 'daa520', gray: '808080', green: '008000', greenyellow: 'adff2f', honeydew: 'f0fff0', hotpink: 'ff69b4', indianred : 'cd5c5c', indigo : '4b0082', ivory: 'fffff0', khaki: 'f0e68c', lavender: 'e6e6fa', lavenderblush: 'fff0f5', lawngreen: '7cfc00', lemonchiffon: 'fffacd', lightblue: 'add8e6', lightcoral: 'f08080', lightcyan: 'e0ffff', lightgoldenrodyellow: 'fafad2', lightgrey: 'd3d3d3', lightgreen: '90ee90', lightpink: 'ffb6c1', lightsalmon: 'ffa07a', lightseagreen: '20b2aa', lightskyblue: '87cefa', lightslateblue: '8470ff', lightslategray: '778899', lightsteelblue: 'b0c4de', lightyellow: 'ffffe0', lime: '00ff00', limegreen: '32cd32', linen: 'faf0e6', magenta: 'ff00ff', maroon: '800000', mediumaquamarine: '66cdaa', mediumblue: '0000cd', mediumorchid: 'ba55d3', mediumpurple: '9370d8', mediumseagreen: '3cb371', mediumslateblue: '7b68ee', mediumspringgreen: '00fa9a', mediumturquoise: '48d1cc', mediumvioletred: 'c71585', midnightblue: '191970', mintcream: 'f5fffa', mistyrose: 'ffe4e1', moccasin: 'ffe4b5', navajowhite: 'ffdead', navy: '000080', oldlace: 'fdf5e6', olive: '808000', olivedrab: '6b8e23', orange: 'ffa500', orangered: 'ff4500', orchid: 'da70d6', palegoldenrod: 'eee8aa', palegreen: '98fb98', paleturquoise: 'afeeee', palevioletred: 'd87093', papayawhip: 'ffefd5', peachpuff: 'ffdab9', peru: 'cd853f', pink: 'ffc0cb', plum: 'dda0dd', powderblue: 'b0e0e6', purple: '800080', red: 'ff0000', rosybrown: 'bc8f8f', royalblue: '4169e1', saddlebrown: '8b4513', salmon: 'fa8072', sandybrown: 'f4a460', seagreen: '2e8b57', seashell: 'fff5ee', sienna: 'a0522d', silver: 'c0c0c0', skyblue: '87ceeb', slateblue: '6a5acd', slategray: '708090', snow: 'fffafa', springgreen: '00ff7f', steelblue: '4682b4', tan: 'd2b48c', teal: '008080', thistle: 'd8bfd8', tomato: 'ff6347', turquoise: '40e0d0', violet: 'ee82ee', violetred: 'd02090', wheat: 'f5deb3', white: 'ffffff', whitesmoke: 'f5f5f5', yellow: 'ffff00', yellowgreen: '9acd32' }; if(color_names[color]) color="#"+color_names[color]; if(color.substr && color.substr(0,1)=="#"){ color=color.substr(1); if(color.length==6){ red=parseInt("0x"+color.substr(0,2))/255; green=parseInt("0x"+color.substr(2,2))/255; blue=parseInt("0x"+color.substr(4,2))/255; } else if(color.length==3){ red=parseInt("0x"+color.substr(0,1))/15; green=parseInt("0x"+color.substr(1,1))/15; blue=parseInt("0x"+color.substr(2,1))/15; } }else if(color.substr && color.substr(0,4)=="rgb("){ var colors=color.substr(4).split(","); red=parseInt(colors[0])/255; green=parseInt(colors[1])/255; blue=parseInt(colors[2])/255; } else { red=0; green=0; blue=0; } return {r:red,g:green,b:blue}; } /** * @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; /** * 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; i1){ if(this.loop){ frame=((parseFloat(now)-parseFloat(this.animationStart))/1000*this.frameRate)%(this.animation.frames-1)+1; }else{ frame=((parseFloat(now)-parseFloat(this.animationStart))/1000*this.frameRate)+1; if(frame>this.animation.frames) frame=this.animation.frames; } }else{ frame=1; } if(frame!=this.lastFrame){ this.lastFrame=frame; for(property in this.animation.curves){ if(this["set"+property]) this["set"+property](this.animation.curves[property].getValue(parseFloat(frame))); } } } } /** * Sets the animation vector of this object * @param {GLGE.AnimationVector} animationVector the animation to apply to this object */ GLGE.Animatable.prototype.setAnimation=function(animationVector){ this.animationStart=parseInt(new Date().getTime()); this.animation=animationVector; } /** * 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; } /** * 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; } /** * 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.pauseTime=parseInt(new Date().getTime()); else this.animationStart=this.animationStart+(parseInt(new Date().getTime())-this.pauseTime); this.paused=value; } /** * 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; } /** * @class A bezier class to add points to the Animation Curve * @param {number} x1 x-coord of the first control point * @param {number} y1 y-coord of the first control point * @param {number} x2 x-coord of the second control point * @param {number} y2 y-coord of the second control point * @param {number} x3 x-coord of the third control point * @param {number} y3 y-coord of the third control point */ GLGE.BezTriple=function(x1,y1,x2,y2,x3,y3){ this.x1=parseFloat(x1); this.y1=parseFloat(y1); this.x=parseFloat(x2); this.y=parseFloat(y2); this.x3=parseFloat(x3); this.y3=parseFloat(y3); }; /** * @class A LinearPoint class to add points to the Animation Curve * @param {number} x x-coord control point * @param {number} y y-coord control point */ GLGE.LinearPoint=function(x,y){ this.x=parseFloat(x); this.y=parseFloat(y); }; /** * @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; }; /** * @class A curve which interpolates between control points */ GLGE.AnimationCurve=function(){ this.keyFrames=[]; this.solutions={}; }; GLGE.AnimationCurve.prototype.keyFrames=null; /** * Adds a point to the curve * @param {object} point The point to add * @returns {Number} Index of the newly added point */ GLGE.AnimationCurve.prototype.addPoint=function(point){ this.keyFrames.push(point); return this.keyFrames.length-1; }; /** * Get the value of the curve at any point * @param {Number} frame The frame(x-coord) to return the value for * @returns {Number} The value of the curve at the given point */ GLGE.AnimationCurve.prototype.coord=function(x,y){ return {x:x,y:y} } GLGE.AnimationCurve.prototype.getValue=function(frame){ var startKey; var endKey; var preStartKey; var preEndKey; 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].xframe && (preEndKey==undefined || this.keyFrames[i].x 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); }; /** * @class The AnimationVectors class allows you to specify the 2D Animation curves that define specific channels of animation within the engine. */ GLGE.AnimationVector=function(){ this.curves=[]; } GLGE.AnimationVector.prototype.curves=[]; GLGE.AnimationVector.prototype.frames=250; /** * 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.addCurve=function(name,curve){ this.curves[name]=curve; } /** * Removes an Animation Curve form a channel * @param {String} channel The name of the curve to be removed */ GLGE.AnimationVector.prototype.removeCurve=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; } /** * 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; } /** * Function to augment one object with another * @param {object} obj1 Source Object * @param {object} obj2 Destination Object */ GLGE.augment=function(obj1,obj2){ for(proto in obj1.prototype){ obj2.prototype[proto]=obj1.prototype[proto]; } } /** * @class Class defining a bones name and position in a skeleton * @param {string} name the name of the bone * @param {number} x the x co-ordinate of the bone * @param {number} y the y co-ordinate of the bone * @param {number} z the z co-ordinate of the bone */ GLGE.Bone=function(name,x,y,z){ this.name=name; this.x=x; this.y=y; this.z=z; } GLGE.error=function(message){ alert(message) } /** * @class Class specifing bones,locations and relationships */ GLGE.Skeleton=function(){ this.bones=[]; }; GLGE.Skeleton.prototype.bones=[]; /** * Adds a bone to the skeleton * @param {GLGE.Bone} bone the bone to add * NOTE why don't I just add the parent into the bone object???? */ GLGE.Skeleton.prototype.addBone=function(bone,parent){ if(parent) bone.parent=parent; this.bones.push(bone); } /** * Gets the transform of a bone for a given action at a specified frame * @param {string} bone the bone to get the matrix for * @param {GLGE.SkeletalAction} action the action to the the matrix for * @param {number} frame The frame number to get the matrix for * @returns Matrix */ GLGE.Skeleton.prototype.getBoneTransforms=function(bone,action,frame){ var TRANS1=GLGE.translateMatrix(bone.x*-1,bone.y*-1,bone.z*-1); var TRANS2=GLGE.translateMatrix(bone.x,bone.y,bone.z); var result=GLGE.identMatrix(); if(action && action.cache[frame][bone.name]) result=TRANS2.x(action.cache[frame][bone.name]).x(TRANS1); return result; } /** * Gets the bone object from it's name * @param {string} name the name of the bone to get * @returns GLGE.Bone */ GLGE.Skeleton.prototype.boneFromName=function(name){ for(var i=0; i0.0) gl_FragDepth=-pos.z/far; else gl_FragDepth=1.0;}" fragStr=fragStr+"else { gl_FragColor = vec4(color.rgb*alpha,alpha); if(alpha>0.0) gl_FragDepth=-pos.z/far; else gl_FragDepth=1.0;}\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.updateCanvas(gl); } /** * 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; canvas.height=this.size*1.2; ctx = canvas.getContext("2d"); ctx.textBaseline="top"; ctx.font = this.size+"px "+this.font; this.aspect=canvas.width/canvas.height; ctx.fillText(this.text, 0, 0); gl.bindTexture(gl.TEXTURE_2D, this.glTexture); //TODO: fix this when minefield is upto spec try{gl.texImage2D(gl.TEXTURE_2D, 0, canvas,false,true);} catch(e){gl.texImage2D(gl.TEXTURE_2D, 0, canvas,null);} gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_LINEAR); gl.generateMipmap(gl.TEXTURE_2D); gl.bindTexture(gl.TEXTURE_2D, null); } /** * Renders the text to the render buffer * @private */ GLGE.Text.prototype.GLRender=function(gl,renderType){ if(renderType==GLGE.RENDER_DEFAULT || renderType==GLGE.RENDER_PICK){ //if look at is set then look if(this.lookAt) this.Lookat(this.lookAt); //animate this object if(this.animation) this.animate(); gl.useProgram(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); gl.uniform1i(GLGE.getUniformLocation(gl,this.GLShaderProgram, "TEXTURE"), 0); if(renderType==GLGE.RENDER_PICK){ gl.uniform1i(GLGE.getUniformLocation(gl,this.GLShaderProgram, "picktype"), this.pickType); }else{ gl.uniform1i(GLGE.getUniformLocation(gl,this.GLShaderProgram, "picktype"), 0); } //generate and set the modelView matrix var scalefactor=this.size/100; var mMatrix=this.scene.camera.getViewMatrix().x(this.getModelMatrix().x(GLGE.scaleMatrix(this.aspect*scalefactor,scalefactor,scalefactor))); var mUniform = GLGE.getUniformLocation(gl,this.GLShaderProgram, "Matrix"); gl.uniformMatrix4fv(mUniform, false, mMatrix.glData()); var mUniform = GLGE.getUniformLocation(gl,this.GLShaderProgram, "PMatrix"); gl.uniformMatrix4fv(mUniform, false, this.scene.camera.getProjectionMatrix().glData()); var farUniform = GLGE.getUniformLocation(gl,this.GLShaderProgram, "far"); gl.uniform1f(farUniform, this.scene.camera.getFar()); //set the color gl.uniform3f(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); } } /** * 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 WebGLFloatArray([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 WebGLFloatArray([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 WebGLUnsignedShortArray([0,1,2,2,3,0]), gl.STATIC_DRAW); this.GLfaces.itemSize = 1; this.GLfaces.numItems = 6; } /** * sets the scene this text is in * @param {GLGE.Scene} scene the scene * @private */ GLGE.Text.prototype.setScene=function(scene){ this.scene=scene; } /** * sets the scene this text is in * @returns {GLGE.Scene} * @private */ GLGE.Text.prototype.getScene=function(){ return this.scene; } /** * @class Creates a new mesh/material to add to an object * @param {GLGE.Mesh} mesh optional mesh * @param {GLGE.Material} material optional material */ GLGE.MultiMaterial=function(mesh,material){ if(mesh) this.mesh=mesh; if(material) this.material=material; } GLGE.MultiMaterial.prototype.mesh=null; GLGE.MultiMaterial.prototype.material=null; GLGE.MultiMaterial.prototype.program=null; GLGE.MultiMaterial.prototype.GLShaderProgramPick=null; GLGE.MultiMaterial.prototype.GLShaderProgramShadow=null; GLGE.MultiMaterial.prototype.GLShaderProgram=null; /** * sets the mesh * @param {GLGE.Mesh} mesh */ GLGE.MultiMaterial.prototype.setMesh=function(mesh){ this.GLShaderProgram=null; this.mesh=mesh; } /** * gets the mesh * @returns {GLGE.Mesh} */ GLGE.MultiMaterial.prototype.getMesh=function(){ return this.mesh; } /** * sets the material * @param {GLGE.Material} material */ GLGE.MultiMaterial.prototype.setMaterial=function(material){ this.GLShaderProgram=null; this.material=material; } /** * gets the material * @returns {GLGE.Material} */ GLGE.MultiMaterial.prototype.getMaterial=function(){ return this.material; } /** * @class An object that can be rendered in a scene * @augments GLGE.Animatable * @augments GLGE.Placeable */ GLGE.Object=function(){ this.multimaterials=[]; } GLGE.augment(GLGE.Placeable,GLGE.Object); GLGE.augment(GLGE.Animatable,GLGE.Object); GLGE.Object.prototype.action=null; 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.actionStart=null; GLGE.Object.prototype.blendState=null; GLGE.Object.prototype.actionCache=null; GLGE.Object.prototype.multimaterials=null; GLGE.Object.prototype.zTrans=false; GLGE.Object.prototype.id=""; /** * Sets the objects id string * @param {string} id The id string of this object */ GLGE.Object.prototype.setId=function(id){ this.id=id; } /** * Gets the id string of this object * @returns {string} */ GLGE.Object.prototype.getId=function(){ return this.id } /** * Blend from current skeletal action to another * @param {GLGE.SkeletalAction} action The action to be blended to * @param {Number} duration Number of millisecons the blend should last for */ GLGE.Object.prototype.blendAction=function(action,duration){ this.blendState=this.getBoneTransforms(); this.setAction(action); this.blendDuration=duration; this.actionCache=[]; } /** * Sets the skeletal action of this object * @param {GLGE.SkeletalAction} action The action to be blended to */ GLGE.Object.prototype.setAction=function(action){ this.action=action; this.actionCache=[]; if(!this.action.cache) this.action.cacheTransforms(); this.actionStart=parseInt(new Date().getTime()); } /** * Gets the current skeletal action of this object * @returns GLGE.SkeletalAction */ GLGE.Object.prototype.getAction=function(){ return this.action } /** * Gets the current transfroms for each of the bones * @returns Matrix[] * @private */ GLGE.Object.prototype.getBoneTransforms=function(){ var now=parseInt(new Date().getTime()); var frame; if(this.action.frames>1){ frame=((now-this.actionStart)/1000*this.action.frameRate)%(this.action.frames-1)+1; }else{ frame=1; } frame=Math.round(frame); if(this.actionCache[frame]){ var transforms=this.actionCache[frame]; } else { var transforms=this.skeleton.getTransforms(this.action,frame); if(this.blendState){ var blendframe; var blendpoint=(now-this.actionStart)/this.blendDuration; if(blendpoint>=1){ this.blendState=null; this.actionCache=[]; } else { //combine the two sets of transforms var newtransforms={}; for(bone in transforms){ if(transforms[bone].matrix){ newtransforms[bone]={matrix:this.blendState[bone].matrix.x(1-blendpoint).add(transforms[bone].matrix.x(blendpoint))}; } } transforms=newtransforms; } } else { this.actionCache[frame]=transforms; } } return transforms; } /** * Sets the Z Transparency of this object * @param {boolean} value Does this object need blending? */ GLGE.Object.prototype.setZtransparent=function(value){ this.zTrans=value; } /** * Gets the z transparency * @returns boolean */ GLGE.Object.prototype.isZtransparent=function(){ return this.zTrans; } /** * Sets the skeletal action of this object * @param {GLGE.SkeletalAction} action The action to be blended to */ GLGE.Object.prototype.setSkeleton=function(skeleton){ this.skeleton=skeleton; } /** * Gets the current skeletal action of this object * @returns GLGE.SkeletalAction */ GLGE.Object.prototype.getSkeleton=function(){ return this.skeleton; } /** * Sets the material associated with the object * @param GLGE.Material */ GLGE.Object.prototype.setMaterial=function(material,idx){ if(!idx) idx=0; if(!this.multimaterials[idx]) this.multimaterials[idx]=new GLGE.MultiMaterial(); if(this.multimaterials[idx].getMaterial()!=material){ this.multimaterials[idx].setMaterial(material); this.updateProgram(); } } /** * Gets the material associated with the object * @returns GLGE.Material */ GLGE.Object.prototype.getMaterial=function(idx){ if(!idx) idx=0; if(this.multimaterials[idx]) { return this.multimaterials[idx].getMaterial(); }else{ return false; } } GLGE.Object.prototype.setScene=function(scene){ this.scene=scene; } GLGE.Object.prototype.getScene=function(){ return this.scene; } /** * Sets the mesh associated with the object * @param GLGE.Mesh */ GLGE.Object.prototype.setMesh=function(mesh,idx){ if(!idx) idx=0; if(!this.multimaterials[idx]) this.multimaterials.push(new GLGE.MultiMaterial()); this.multimaterials[idx].setMesh(mesh); } /** * Gets the mesh associated with the object * @returns GLGE.Mesh */ GLGE.Object.prototype.getMesh=function(idx){ if(!idx) idx=0; if(this.multimaterials[idx]) { this.multimaterials[idx].getMesh(); }else{ return false; } } /** * Initiallize all the GL stuff needed to render to screen * @private */ GLGE.Object.prototype.GLInit=function(gl){ this.gl=gl; } /** * Cleans up all the GL stuff we sets * @private */ GLGE.Object.prototype.GLDestory=function(gl){ } /** * Updates the GL shader program for the object * @private */ GLGE.Object.prototype.updateProgram=function(){ for(var i=0; i1) vertexStr=vertexStr+"attribute vec"+this.mesh.buffers[i].size+" "+this.mesh.buffers[i].name+";\n"; else vertexStr=vertexStr+"attribute float "+this.mesh.buffers[i].name+";\n"; if(this.mesh.buffers[i].name=="UV") UV=true; } vertexStr=vertexStr+"uniform mat4 MVMatrix;\n"; vertexStr=vertexStr+"uniform mat4 PMatrix;\n"; //normals needed for lighting vertexStr=vertexStr+"uniform mat4 uNMatrix;\n"; for(var i=0; i0.0){\n"; cnt=0; for(var 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); } } } /** * updates the programs for the objects when buffers are added/removed * @private */ GLGE.Mesh.prototype.updatePrograms=function(){ for(var i=0;i0){ return this.objects[index-1]; }else{ return false; } }else{ return false; } } /** * @class Sets the scene to render * @param {GLGE.Scene} scene The scene to be rendered */ GLGE.Renderer=function(canvas){ this.canvas=canvas; try { this.gl = canvas.getContext("experimental-webgl",{alpha:false,depth:true,stencil:true,antialias:true,premultipliedAlpha:false}); } catch(e) {} if (!this.gl) { alert("What, What Whaaat? No WebGL!"); throw "cannot create webgl context"; } //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 //set up defaults this.gl.clearDepth(1.0); this.gl.enable(this.gl.DEPTH_TEST); //this.gl.enable(this.gl.SAMPLE_ALPHA_TO_COVERAGE); 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); //this.gl.enable(this.gl.CULL_FACE); }; GLGE.Renderer.prototype.gl=null; GLGE.Renderer.prototype.scene=null; /** * Gets the scene which is set to be rendered * @returns the current render scene */ GLGE.Renderer.prototype.getScene=function(gcene){ 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; scene.init(); }; /** * Renders the current scene to the canvas */ GLGE.Renderer.prototype.render=function(){ this.scene.render(this.gl); }; /** * @class A texture to be included in a material * @param {string} url the url of the image to use as the texture * @see GLGE.Material */ GLGE.Texture=function(url){ this.image=new Image(); this.image.texture=this; this.image.onload = function(){ this.texture.state=1; } this.image.src=url; this.state=0; this.glTexture=null; } GLGE.Texture.prototype.image=null; GLGE.Texture.prototype.texture=null; GLGE.Texture.prototype.glTexture=null; /** * @class The material layer describes how to apply this layer to the material * @param {number} texture the texture index to apply to the layer * @param {number} mapto how to map this layer on to the material see M_XXXXX constants * @param {number} mapinput the UV layer to map to, UV1 or UV2 * @param {Object} scale how much scaling the texture eg {x: 10, y:10, z:1} * @param {Object} offset how much to offset the texture eg {x: 10, y:10, z:1} * @see GLGE.Material * @augments GLGE.Animatable */ GLGE.MaterialLayer=function(texture,mapto,mapinput,scale,offset){ this.texture=texture; this.mapinput=mapinput; this.uv=mapinput; this.blendeMode=GLGE.BL_MIX; this.mapto=mapto; if(scale){ this.setScaleX(scale.x); this.setScaleY(scale.y); this.setScaleZ(scale.z); } if(offset){ this.setOffsetX(offset.x); this.setOffsetY(offset.y); this.setOffsetZ(offset.z); } this.scale=scale; this.offset=offset; }; GLGE.augment(GLGE.Animatable,GLGE.MaterialLayer); GLGE.MaterialLayer.prototype.texture=null; GLGE.MaterialLayer.prototype.blendMode=null; GLGE.MaterialLayer.prototype.mapto=GLGE.M_COLOR; GLGE.MaterialLayer.prototype.mapinput=GLGE.UV1; GLGE.MaterialLayer.prototype.scaleX=1; GLGE.MaterialLayer.prototype.offsetX=0; GLGE.MaterialLayer.prototype.rotX=0; GLGE.MaterialLayer.prototype.scaleY=1; GLGE.MaterialLayer.prototype.offsetY=0; GLGE.MaterialLayer.prototype.rotY=0; GLGE.MaterialLayer.prototype.scaleZ=1; GLGE.MaterialLayer.prototype.offsetZ=0; GLGE.MaterialLayer.prototype.rotZ=0; GLGE.MaterialLayer.prototype.dScaleX=0; GLGE.MaterialLayer.prototype.dOffsetX=0; GLGE.MaterialLayer.prototype.dRotX=0; GLGE.MaterialLayer.prototype.dScaleY=0; GLGE.MaterialLayer.prototype.dOffsetY=0; GLGE.MaterialLayer.prototype.dRotY=0; GLGE.MaterialLayer.prototype.dScaleZ=0; GLGE.MaterialLayer.prototype.dOffsetZ=0; GLGE.MaterialLayer.prototype.dRotZ=0; GLGE.MaterialLayer.prototype.matrix=null; /** * Gets the textures used by the layer * @return {GLGE.Texture} The current shininess of the material */ GLGE.MaterialLayer.prototype.getMatrix=function(){ if(!this.matrix){ var offset=this.getOffset(); var scale=this.getScale(); var rotation=this.getRotation(); this.matrix=GLGE.translateMatrix(offset.x,offset.y,offset.z).x(GLGE.scaleMatrix(scale.x,scale.y,scale.z).x(GLGE.rotateMatrix(rotation.x,rotation.y,rotation.z))); } return this.matrix; }; /** * Sets the textures used by the layer * @param {GLGE.Texture} value the teture to associate with this layer */ GLGE.MaterialLayer.prototype.setTexture=function(value){ this.texture=value; }; /** * Gets the textures used by the layer * @return {GLGE.Texture} The current shininess of the material */ GLGE.MaterialLayer.prototype.getTexture=function(){ return this.texture; }; /** * Sets the flag for how this layer maps to the material * @param {Number} value the flags to set for this layer */ GLGE.MaterialLayer.prototype.setMapto=function(value){ this.mapto=value; }; /** * Gets the flag representing the way the layer maps to the material * @return {Number} The flags currently set for this layer */ GLGE.MaterialLayer.prototype.getMapto=function(){ return this.mapto; }; /** * Sets the texture coordinate system * @param {Number} value the mapping to use */ GLGE.MaterialLayer.prototype.setMapinput=function(value){ this.mapinput=value; }; /** * Gets the texture coordinate system * @return {Number} The current mapping */ GLGE.MaterialLayer.prototype.getMapinput=function(){ return this.mapinput; }; /** * Gets the layers texture offset * @return {object} the current offset */ GLGE.MaterialLayer.prototype.getOffset=function(){ var offset={}; offset.x=parseFloat(this.getOffsetX())+parseFloat(this.getDOffsetX()); offset.y=parseFloat(this.getOffsetY())+parseFloat(this.getDOffsetY()); offset.z=parseFloat(this.getOffsetZ())+parseFloat(this.getDOffsetZ()); return offset; }; /** * Gets the layers texture rotation * @return {object} the current rotation */ GLGE.MaterialLayer.prototype.getRotation=function(){ var rotation={}; rotation.x=parseFloat(this.getRotX())+parseFloat(this.getDRotX()); rotation.y=parseFloat(this.getRotY())+parseFloat(this.getDRotY()); rotation.z=parseFloat(this.getRotZ())+parseFloat(this.getDRotZ()); return rotation; }; /** * Gets the layers texture scale * @return {object} the current scale */ GLGE.MaterialLayer.prototype.getScale=function(){ var scale={}; scale.x=parseFloat(this.getScaleX())+parseFloat(this.getDScaleX()); scale.y=parseFloat(this.getScaleY())+parseFloat(this.getDScaleY()); scale.z=parseFloat(this.getScaleZ())+parseFloat(this.getDScaleZ()); return scale; }; /** * Sets the layers texture X offset * @param {Number} value the amount to offset the texture */ GLGE.MaterialLayer.prototype.setOffsetX=function(value){ this.matrix=null; this.offsetX=value; }; /** * Gets the layers texture X offset * @return {Number} the current offset */ GLGE.MaterialLayer.prototype.getOffsetX=function(){ return this.offsetX; }; /** * Sets the layers texture Y offset * @param {Number} value the amount to offset the texture */ GLGE.MaterialLayer.prototype.setOffsetY=function(value){ this.matrix=null; this.offsetY=value; }; /** * Gets the layers texture Y offset * @return {Number} the current offset */ GLGE.MaterialLayer.prototype.getOffsetY=function(){ return this.offsetY; }; /** * Sets the layers texture Z offset * @param {Number} value the amount to offset the texture */ GLGE.MaterialLayer.prototype.setOffsetZ=function(value){ this.matrix=null; this.offsetZ=value; }; /** * Gets the layers texture Z offset * @return {Number} the current offset */ GLGE.MaterialLayer.prototype.getOffsetZ=function(){ return this.offsetZ; }; /** * Sets the layers texture X displacment offset, useful for animation * @param {Number} value the amount to offset the texture */ GLGE.MaterialLayer.prototype.setDOffsetX=function(value){ this.matrix=null; this.dOffsetX=value; }; /** * Gets the layers texture X displacment offset, useful for animation * @return {Number} the current offset */ GLGE.MaterialLayer.prototype.getDOffsetX=function(){ return this.dOffsetX; }; /** * Sets the layers texture Y displacment offset, useful for animation * @param {Number} value the amount to offset the texture */ GLGE.MaterialLayer.prototype.setDOffsetY=function(value){ this.matrix=null; this.dOffsetY=value; }; /** * Gets the layers texture Y displacment offset, useful for animation * @return {Number} the current offset */ GLGE.MaterialLayer.prototype.getDOffsetY=function(){ return this.dOffsetY; }; /** * Sets the layers texture Z displacment offset, useful for animation * @param {Number} value the amount to offset the texture */ GLGE.MaterialLayer.prototype.setDOffsetZ=function(value){ this.matrix=null; this.dOffsetZ=value; }; /** * Gets the layers texture X displacment offset, useful for animation * @return {Number} the current offset */ GLGE.MaterialLayer.prototype.getDOffsetZ=function(){ return this.dOffsetZ; }; /** * Sets the layers texture X scale * @param {Number} value the amount to scale the texture */ GLGE.MaterialLayer.prototype.setScaleX=function(value){ this.matrix=null; this.scaleX=value; }; /** * Gets the layers texture X scale * @return {Number} the current scale */ GLGE.MaterialLayer.prototype.getScaleX=function(){ return this.scaleX; }; /** * Sets the layers texture Y scale * @param {Number} value the amount to scale the texture */ GLGE.MaterialLayer.prototype.setScaleY=function(value){ this.matrix=null; this.scaleY=value; }; /** * Gets the layers texture Y scale * @return {Number} the current scale */ GLGE.MaterialLayer.prototype.getScaleY=function(){ return this.scaleY; }; /** * Sets the layers texture Z scale * @param {Number} value the amount to scale the texture */ GLGE.MaterialLayer.prototype.setScaleZ=function(value){ this.matrix=null; this.scaleZ=value; }; /** * Gets the layers texture Z offset * @return {Number} the current offset */ GLGE.MaterialLayer.prototype.getScaleZ=function(){ return this.scaleZ; }; /** * Sets the layers texture X displacment scale, useful for animation * @param {Number} value the amount to scale the texture */ GLGE.MaterialLayer.prototype.setDScaleX=function(value){ this.matrix=null; this.dScaleX=value; }; /** * Gets the layers texture X displacment scale, useful for animation * @return {Number} the current scale */ GLGE.MaterialLayer.prototype.getDScaleX=function(){ return this.dScaleX; }; /** * Sets the layers texture Y displacment scale, useful for animation * @param {Number} value the amount to scale the texture */ GLGE.MaterialLayer.prototype.setDScaleY=function(value){ this.matrix=null; this.dScaleY=value; }; /** * Gets the layers texture Y displacment scale, useful for animation * @return {Number} the current scale */ GLGE.MaterialLayer.prototype.getDScaleY=function(){ return this.dScaleY; }; /** * Sets the layers texture Z displacment scale, useful for animation * @param {Number} value the amount to scale the texture */ GLGE.MaterialLayer.prototype.setDScaleZ=function(value){ this.matrix=null; this.dScaleZ=value; }; /** * Gets the layers texture X displacment scale, useful for animation * @return {Number} the current scale */ GLGE.MaterialLayer.prototype.getDScaleZ=function(){ return this.dScaleZ; }; /** * Sets the layers texture X Rotation * @param {Number} value the amount to roate the texture */ GLGE.MaterialLayer.prototype.setRotX=function(value){ this.matrix=null; this.rotX=value; }; /** * Gets the layers texture X rotate * @return {Number} the current rotate */ GLGE.MaterialLayer.prototype.getRotX=function(){ return this.rotX; }; /** * Sets the layers texture Y rotate * @param {Number} value the amount to rotate the texture */ GLGE.MaterialLayer.prototype.setRotY=function(value){ this.matrix=null; this.rotY=value; }; /** * Gets the layers texture Y rotate * @return {Number} the current rotate */ GLGE.MaterialLayer.prototype.getRotY=function(){ return this.rotY; }; /** * Sets the layers texture Z rotate * @param {Number} value the amount to rotate the texture */ GLGE.MaterialLayer.prototype.setRotZ=function(value){ this.matrix=null; this.rotZ=value; }; /** * Gets the layers texture Z rotate * @return {Number} the current rotate */ GLGE.MaterialLayer.prototype.getRotZ=function(){ return this.rotZ; }; /** * Sets the layers texture X displacment rotation, useful for animation * @param {Number} value the amount to rotation the texture */ GLGE.MaterialLayer.prototype.setDRotX=function(value){ this.matrix=null; this.dRotX=value; }; /** * Gets the layers texture X displacment rotation, useful for animation * @return {Number} the current rotation */ GLGE.MaterialLayer.prototype.getDRotX=function(){ return this.dRotX; }; /** * Sets the layers texture Y displacment rotation, useful for animation * @param {Number} value the amount to rotaion the texture */ GLGE.MaterialLayer.prototype.setDRotY=function(value){ this.matrix=null; this.dRotY=value; }; /** * Gets the layers texture Y displacment rotation, useful for animation * @return {Number} the current rotation */ GLGE.MaterialLayer.prototype.getDRotY=function(){ return this.dRotY; }; /** * Sets the layers texture Z displacment rotation, useful for animation * @param {Number} value the amount to rotation the texture */ GLGE.MaterialLayer.prototype.setDRotZ=function(value){ this.matrix=null; this.dRotZ=value; }; /** * Gets the layers texture X displacment rotation, useful for animation * @return {Number} the current rotation */ GLGE.MaterialLayer.prototype.getDRotZ=function(){ return this.dRotZ; }; /** * Sets the layers blending mode * @param {Number} value the blend mode for the layer */ GLGE.MaterialLayer.prototype.setBlendMode=function(value){ this.blendMode=value; }; /** * Gets the layers tblending mode * @return {Number} the blend mode for the layer */ GLGE.MaterialLayer.prototype.getBlendMode=function(){ return this.blendMode; }; /** * @class The Material class creates materials to be applied to objects in the graphics engine * @see GLGE.Object * @augments GLGE.Animatable */ GLGE.Material=function(){ this.layers=[]; this.textures=[]; this.lights=[]; this.color={r:1,g:1,b:1,a:1}; this.specColor={r:1,g:1,b:1}; this.reflect=0.8; this.shine=50; this.specular=1; this.emit=0; this.alpha=1; }; GLGE.augment(GLGE.Animatable,GLGE.Material); /** * @constant * @description Flag for material colour */ GLGE.M_COLOR=1; /** * @constant * @description Flag for material normal */ GLGE.M_NOR=2; /** * @constant * @description Flag for material alpha */ GLGE.M_ALPHA=4; /** * @constant * @description Flag for material specular color */ GLGE.M_SPECCOLOR=8; /** * @constant * @description Flag for material specular cvalue */ GLGE.M_SPECULAR=16; /** * @constant * @description Flag for material shineiness */ GLGE.M_SHINE=32; /** * @constant * @description Flag for material reflectivity */ GLGE.M_REFLECT=64; /** * @constant * @description Flag for material emision */ GLGE.M_EMIT=128; /** * @constant * @description Flag for material alpha */ GLGE.M_ALPHA=256; /** * @constant * @description Flag for masking with textures red value */ GLGE.M_MSKR=512; /** * @constant * @description Flag for masking with textures green value */ GLGE.M_MSKG=1024; /** * @constant * @description Flag for masking with textures blue value */ GLGE.M_MSKB=2048; /** * @constant * @description Flag for masking with textures alpha value */ GLGE.M_MSKA=4096; /** * @constant * @description Flag for mapping of the height in parallax mapping */ GLGE.M_HEIGHT=8192; /** * @constant * @description Enumeration for first UV layer */ GLGE.UV1=0; /** * @constant * @description Enumeration for second UV layer */ GLGE.UV2=1; /** * @constant * @description Enumeration for second normal texture coords */ GLGE.MAP_NORM=3; /** * @constant * @description Enumeration for second object texture coords */ GLGE.MAP_OBJ=4; /** * @constant * @description Enumeration for mix blending mode */ GLGE.BL_MIX=0; /** * @constant * @description Enumeration for mix blending mode */ GLGE.BL_MUL=1; GLGE.Material.prototype.layers=null; GLGE.Material.prototype.textures=null; GLGE.Material.prototype.color=null; GLGE.Material.prototype.specColor=null; GLGE.Material.prototype.specular=null; GLGE.Material.prototype.emit=null; GLGE.Material.prototype.shine=null; GLGE.Material.prototype.reflect=null; GLGE.Material.prototype.lights=null; GLGE.Material.prototype.alpha=null; GLGE.Material.prototype.shadow=true; /** * Sets the flag indicateing the material should or shouldn't recieve shadows * @param {boolean} value The recieving shadow flag */ GLGE.Material.prototype.setShadow=function(value){ this.shadow=value }; /** * gets the show flag * @returns {boolean} The shadow flag */ GLGE.Material.prototype.getShadow=function(value){ return this.shadow; }; /** * Sets the base colour of the material * @param {string} color The colour of the material */ GLGE.Material.prototype.setColor=function(color){ if(!color.r){ color=GLGE.colorParse(color); } this.color={r:color.r,g:color.g,b:color.b}; }; /** * Sets the red base colour of the material * @param {Number} r The new red level 0-1 */ GLGE.Material.prototype.setColorR=function(value){ this.color.r=value; }; /** * Sets the green base colour of the material * @param {Number} g The new green level 0-1 */ GLGE.Material.prototype.setColorG=function(value){ this.color.g=value; }; /** * Sets the blue base colour of the material * @param {Number} b The new blue level 0-1 */ GLGE.Material.prototype.setColorB=function(value){ this.color.b=value; }; /** * Gets the current base color of the material * @return {[r,g,b]} The current base color */ GLGE.Material.prototype.getColor=function(){ return this.color; }; /** * Sets the base specular colour of the material * @param {string} color The new specular colour */ GLGE.Material.prototype.setSpecularColor=function(color){ if(!color.r){ color=GLGE.colorParse(color); } this.specColor={r:color.r,g:color.g,b:color.b}; }; /** * Gets the current base specular color of the material * @return {[r,g,b]} The current base specular color */ GLGE.Material.prototype.getSpecularColor=function(){ return this.specColor; }; /** * Sets the alpha of the material * @param {Number} value how much alpha */ GLGE.Material.prototype.setAlpha=function(value){ this.alpha=value; }; /** * Gets the alpha of the material * @return {Number} The current alpha of the material */ GLGE.Material.prototype.getAlpha=function(){ return this.alpha; }; /** * Sets the specular of the material * @param {Number} value how much specular */ GLGE.Material.prototype.setSpecular=function(value){ this.specular=value; }; /** * Gets the specular of the material * @return {Number} The current specular of the material */ GLGE.Material.prototype.getSpecular=function(){ return this.specular; }; /** * Sets the shininess of the material * @param {Number} value how much shine */ GLGE.Material.prototype.setShininess=function(value){ this.shine=value; }; /** * Gets the shininess of the material * @return {Number} The current shininess of the material */ GLGE.Material.prototype.getShininess=function(){ return this.shine; }; /** * Sets how much the material should emit * @param {Number} value how much to emit (0-1) */ GLGE.Material.prototype.setEmit=function(value){ this.emit=value; }; /** * 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; }; /** * Gets the materials reflectivity * @return {Number} The reflectivity of the material */ GLGE.Material.prototype.getReflectivity=function(){ return this.reflect; }; /** * Add a new layer to the material * @param {MaterialLayer} layer The material layer to add to the material * @returns {Number} index of the added layer */ GLGE.Material.prototype.addMaterialLayer=function(layer){ this.layers.push(layer); return this.layers.length-1; }; /** * 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 fragment shader program for this material * @private */ GLGE.Material.prototype.getFragmentShader=function(lights){ var shader=""; for(var i=0; i0.0){\n"; shader=shader+"att = 1.0 / (lightAttenuation"+i+"[0] + lightAttenuation"+i+"[1] * lightdist"+i+" + lightAttenuation"+i+"[2] * lightdist"+i+" * lightdist"+i+");\n"; if(lights[i].diffuse){ shader=shader+"lightvalue += att * dotN * lightcolor"+i+";\n"; } if(lights[i].specular){ shader=shader+"specvalue += att * specC * lightcolor"+i+" * spec * pow(max(dot(normal,normalize(eyevec)),0.0), sh);\n"; } shader=shader+"}\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+") {\n"; shader=shader+"spotEffect = pow(spotEffect, spotExp"+i+");"; //spot shadow stuff if(lights[i].getCastShadows() && this.shadow){ shader=shader+"if(castshadows"+i+"){\n"; shader=shader+"spotCoords=lightmat"+i+"*vec4(OBJCoord,1.0);"; shader=shader+"spotCoords=(vec4(spotCoords.xy/(spotCoords.z*tan(acos(spotCosCutOff"+i+"))),0.0,1.0)/2.0)-0.5;"; shader=shader+"vec4 dist = texture2D(TEXTURE"+shadowlights[i]+", -spotCoords.xy);"; shader=shader+"float depth = (dist.r*65536.0+dist.g*256.0+dist.b)/65536.0;"; shader=shader+"if(depth*(1000.0+shadowbias"+i+")0.0){\n"; shader=shader+"att = spotEffect / (lightAttenuation"+i+"[0] + lightAttenuation"+i+"[1] * lightdist"+i+" + lightAttenuation"+i+"[2] * lightdist"+i+" * lightdist"+i+");\n"; if(lights[i].diffuse){ shader=shader+"lightvalue += att * dotN * lightcolor"+i+";\n"; } if(lights[i].specular){ shader=shader+"specvalue += att * specC * lightcolor"+i+" * spec * pow(max(dot(normal,normalize(eyevec)),0.0), sh);\n"; } shader=shader+"}\n}\n"; } if(lights[i].type==GLGE.L_DIR){ shader=shader+"dotN=max(dot(normal,normalize(-lightdir"+i+")),0.0);\n"; if(lights[i].diffuse){ shader=shader+"lightvalue += dotN * lightcolor"+i+";\n"; } if(lights[i].specular){ shader=shader+"specvalue += specC * lightcolor"+i+" * spec * pow(max(dot(normal,normalize(eyevec)),0.0), sh);\n"; } } } //shader=shader+"float fogfact=clamp((fogfar - eyevec.z) / (fogfar - fognear),0.0,1.0);\n"; shader=shader+"float fogfact=1.0;"; shader=shader+"if(fogtype=="+GLGE.FOG_QUADRATIC+") fogfact=clamp(pow(max((fogfar - eyevec.z) / (fogfar - fognear),0.0),2.0),0.0,1.0);\n"; shader=shader+"if(fogtype=="+GLGE.FOG_LINEAR+") fogfact=clamp((fogfar - eyevec.z) / (fogfar - fognear),0.0,1.0);\n"; shader=shader+"lightvalue = (lightvalue+specvalue)*ref;\n" shader=shader+"if(al<0.01){gl_FragDepth=1.0; al=max(al-0.5,0.0);}else gl_FragDepth=min(eyevec.z/far,1.0);\n"; shader=shader+"gl_FragColor = (vec4(color.r*em+(color.r*lightvalue.r*(1.0-em)),color.g*em+(color.g*lightvalue.g*(1.0-em)),color.b*em+(color.b*lightvalue.b*(1.0-em)),al))*fogfact+vec4(fogcolor,al)*(1.0-fogfact);\n"; //shader=shader+"gl_FragColor = (vec4(specvalue,0.0)+vec4(color.r*em+(color.r*lightvalue.r*(1.0-em)),color.g*em+(color.g*lightvalue.g*(1.0-em)),color.b*em+(color.b*lightvalue.b*(1.0-em)),al))*fogfact+vec4(fogcolor,al)*(1.0-fogfact);\n"; shader=shader+"}\n"; return shader; }; /** * Set the uniforms needed to render this material * @private */ GLGE.Material.prototype.textureUniforms=function(gl,shaderProgram,lights){ if(this.animation) this.animate(); gl.uniform4f(GLGE.getUniformLocation(gl,shaderProgram, "baseColor"), this.color.r,this.color.g,this.color.b,this.color.a); gl.uniform3f(GLGE.getUniformLocation(gl,shaderProgram, "specColor"), this.specColor.r,this.specColor.g,this.specColor.b); gl.uniform1f(GLGE.getUniformLocation(gl,shaderProgram, "specular"), this.specular); gl.uniform1f(GLGE.getUniformLocation(gl,shaderProgram, "shine"), this.shine); gl.uniform1f(GLGE.getUniformLocation(gl,shaderProgram, "reflect"), this.reflect); gl.uniform1f(GLGE.getUniformLocation(gl,shaderProgram, "emit"), this.emit); gl.uniform1f(GLGE.getUniformLocation(gl,shaderProgram, "alpha"), this.alpha); var cnt=0; var num=0; for(var i=0; i