/* 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(!window["GLGE"]){ /** * @namespace Holds the functionality of the library */ window["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){ for(proto in obj1.prototype){ obj2.prototype[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; } } /** * @constant * @description Enumeration for TRUE */ GLGE.TRUE=1; /** * @constant * @description Enumeration for FALSE */ GLGE.FALSE=0; /** * @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 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 no rendering */ GLGE.RENDER_NULL=4; /** * @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; /** * @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; /** * @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){ alert(error); } /** * @namespace Holds the global asset store */ GLGE.Assets={}; GLGE.Assets.assets={}; 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(!uid){ uid=GLGE.Assets.createUUID(); }; obj.uid=uid; 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.fastHash=function(str){ var s1=0;var s2=0;var s3=0;var s4=0;var s5=0;var s6=0; var c1=0;var c2=0;var c3=0;var c4=0;var c5=0;var c6=0; var i=0; var length=str.length; str+="000000"; while(i0) GLGE.Message.loadMessages(); } /** * 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,alpha; //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==8){ red=parseInt("0x"+color.substr(0,2))/255; green=parseInt("0x"+color.substr(2,2))/255; blue=parseInt("0x"+color.substr(4,2))/255; alpha=parseInt("0x"+color.substr(6,2))/255; }else if(color.length==4){ red=parseInt("0x"+color.substr(0,1))/15; green=parseInt("0x"+color.substr(1,1))/15; blue=parseInt("0x"+color.substr(2,1))/15; alpha=parseInt("0x"+color.substr(3,1))/15; }else 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; alpha=1; }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; alpha=1; } }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; alpha=1; }else if(color.substr && color.substr(0,5)=="rgba("){ var colors=color.substr(4).split(","); red=parseInt(colors[0])/255; green=parseInt(colors[1])/255; blue=parseInt(colors[2])/255; alpha=parseInt(colors[3])/255; }else{ red=0; green=0; blue=0; alpha=0; } return {r:red,g:green,b:blue,a:alpha}; } /** * @class A class to load json fragments from remote location or string **/ GLGE.JSONLoader=function(){ } GLGE.JSONLoader.prototype.downloadPriority=0; /** * Loads a json fragment from a url * @param {string} url The URL to load **/ GLGE.JSONLoader.prototype.setJSONSrc=function(url){ var GLGEObj=this; GLGE.Message.messageLoader(url,function(text){ GLGEObj.setJSONString(text); },this.downloadPriority); } /** * Loads a json fragment from a string * @param {string} string The URL to load **/ GLGE.JSONLoader.prototype.setJSONString=function(string){ var message = JSON.parse(string); //check to make sure this is the correct class type if(message.type==this.className){ message.uid=this.uid; //we don't want to create a new one we want to update this one message.command="update"; GLGE.Message.parseMessage(message); } } /** * Sets the download priority * @param {number} value The download priority **/ GLGE.JSONLoader.prototype.setDownloadPriority=function(value){ this.downloadPriority=value; } /** * Gets the download priority * @returns {number} The download priority **/ GLGE.JSONLoader.prototype.getDownloadPriority=function(){ return this.downloadPriority; } /** * @class A events class **/ GLGE.Events=function(){ } /** * Fires an event * @param {string} event The name of the event to fire * @param {object} data the events data **/ GLGE.Events.prototype.fireEvent=function(event,data){ if(this.events && this.events[event]){ var events=this.events[event]; 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 "joint_names": var names=this.parseArray(child); var jointObjects=[]; 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){ frame=this.animFrames; } } }else{ frame=1; } return Math.round(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=parseInt(new Date().getTime()); if(!blendTime) blendTime=0; if(blendTime>0){ if(this.animation){ this.blendInitValues=this.getInitialValues(this.animation,starttime); this.blendTime=blendTime; } } this.animationStart=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.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; 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.pauseTime=parseInt(new Date().getTime()); else this.animationStart=this.animationStart+(parseInt(new Date().getTime())-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; } closure_export(); /** * @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; }; /** * @class A curve which interpolates between control points * @augments GLGE.QuickNotation * @augments GLGE.JSONLoader */ GLGE.AnimationCurve=function(uid){ GLGE.Assets.registerAsset(this,uid); this.keyFrames=[]; this.solutions={}; this.caches={}; }; GLGE.augment(GLGE.QuickNotation,GLGE.AnimationCurve); GLGE.augment(GLGE.JSONLoader,GLGE.AnimationCurve); GLGE.AnimationCurve.prototype.className="AnimationCurve"; 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; }; GLGE.AnimationCurve.prototype.addStepPoint=GLGE.AnimationCurve.prototype.addPoint; GLGE.AnimationCurve.prototype.addLinearPoint=GLGE.AnimationCurve.prototype.addPoint; GLGE.AnimationCurve.prototype.addBezTriple=GLGE.AnimationCurve.prototype.addPoint; /** * 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} } /** * Sets the animation channel this curve animates * @param {string} channel The property to animate */ GLGE.AnimationCurve.prototype.setChannel=function(channel){ this.channel=channel } GLGE.AnimationCurve.prototype.getValue=function(frame){ if(this.keyFrames.length==0) return 0; if(this.caches[frame]) return this.caches[frame]; var startKey; var endKey; var preStartKey; var preEndKey; if(framethis.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); }; /** * @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){ GLGE.Assets.registerAsset(this,uid); this.curves=[]; } 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; } /** * @constant * @description Enumeration for node group type */ GLGE.G_NODE=1; /** * @constant * @description Enumeration for root group type */ GLGE.G_ROOT=2; /** * @class Group class to allow object transform hierarchies * @augments GLGE.Animatable * @augments GLGE.Placeable * @augments GLGE.QuickNotation * @augments GLGE.JSONLoader */ GLGE.Group=function(uid){ GLGE.Assets.registerAsset(this,uid); this.children=[]; } GLGE.augment(GLGE.Placeable,GLGE.Group); GLGE.augment(GLGE.Animatable,GLGE.Group); GLGE.augment(GLGE.QuickNotation,GLGE.Group); GLGE.augment(GLGE.JSONLoader,GLGE.Group); GLGE.Group.prototype.children=null; GLGE.Group.prototype.className="Group"; GLGE.Group.prototype.type=GLGE.G_NODE; /** * Sets the action for this Group * @param {GLGE.Action} action the action to apply */ GLGE.Group.prototype.setAction=function(action,blendTime,loop){ action.start(blendTime,loop,this.getNames()); return this; } /** * Gets the name of the object and names of any sub objects * @returns an object of name */ GLGE.Group.prototype.getNames=function(names){ if(!names) names={}; var thisname=this.getName(); if(thisname!="") names[thisname]=this; for(var i=0;i> 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); } 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()); //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.lastMaterail=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([0,1,2,2,3,0]), gl.STATIC_DRAW); this.GLfaces.itemSize = 1; this.GLfaces.numItems = 6; } /** * @class Creates a new load for a multimaterial * @augments GLGE.QuickNotation * @augments GLGE.JSONLoader */ GLGE.ObjectLod=function(uid){ GLGE.Assets.registerAsset(this,uid); } GLGE.augment(GLGE.QuickNotation,GLGE.ObjectLod); GLGE.augment(GLGE.JSONLoader,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); } var multiMaterial=this; this.meshupdated=function(event){ multiMaterial.GLShaderProgram=null; }; //set event listener for new material mesh.addEventListener("shaderupdate",this.meshupdated); this.GLShaderProgram=null; this.mesh=mesh; return this; } /** * 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); } var ObjectLOD=this; this.materialupdated=function(event){ ObjectLOD.GLShaderProgram=null; }; //set event listener for new material material.addEventListener("shaderupdate",this.materialupdated); 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); } /** * @class Creates a new mesh/material to add to an object * @augments GLGE.QuickNotation * @augments GLGE.JSONLoader */ GLGE.MultiMaterial=function(uid){ GLGE.Assets.registerAsset(this,uid); this.lods=[new GLGE.ObjectLod] } GLGE.augment(GLGE.QuickNotation,GLGE.MultiMaterial); GLGE.augment(GLGE.JSONLoader,GLGE.MultiMaterial); GLGE.MultiMaterial.prototype.className="MultiMaterial"; /** * sets the mesh * @param {GLGE.Mesh} mesh */ GLGE.MultiMaterial.prototype.setMesh=function(mesh){ this.lods[0].setMesh(mesh); return this; } /** * gets the mesh * @returns {GLGE.Mesh} */ GLGE.MultiMaterial.prototype.getMesh=function(){ return this.lods[0].getMesh(); } /** * sets the material * @param {GLGE.Material} material */ GLGE.MultiMaterial.prototype.setMaterial=function(material){ this.lods[0].setMaterial(material); return this; } /** * gets the material * @returns {GLGE.Material} */ GLGE.MultiMaterial.prototype.getMaterial=function(){ return this.lods[0].getMaterial(); } /** * returns the load for a given pixel size * @param {number} pixelsize the current pixel size of the object * @returns {GLGE.ObjectLod} */ GLGE.MultiMaterial.prototype.getLOD=function(pixelsize){ var currentSize=0; var currentLOD=this.lods[0]; if(this.lods.length>1){ for(var i=1; icurrentSize && size0.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(""); /** * 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 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 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=="joints1") joints1=this.mesh.buffers[i]; if(this.mesh.buffers[i].name=="joints2") joints2=this.mesh.buffers[i]; } vertexStr.push("uniform mat4 worldView;\n"); vertexStr.push("uniform mat4 projection;\n"); vertexStr.push("uniform mat4 view;\n"); vertexStr.push("uniform mat4 worldInverseTranspose;\n"); vertexStr.push("uniform mat4 envMat;\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 b;\n"); vertexStr.push("varying vec3 t;\n"); vertexStr.push("varying vec4 UVCoord;\n"); vertexStr.push("varying vec3 OBJCoord;\n"); vertexStr.push("varying vec3 tang;\n"); vertexStr.push("varying vec3 teyevec;\n"); vertexStr.push("void main(void)\n"); vertexStr.push("{\n"); if(UV) vertexStr.push("UVCoord=UV;\n"); vertexStr.push("OBJCoord = position;\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"); 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> 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; } 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){ 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; } } var cameraMatrix=camera.getViewMatrix(); var modelMatrix=this.getModelMatrix(); if(!pc.mvMatrix) pc.mvMatrix={cameraMatrix:null,modelMatrix:null}; var mvCache=pc.mvMatrix; if(mvCache.camerMatrix!=cameraMatrix || mvCache.modelMatrix!=modelMatrix){ try{ //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; } var mvUniform = GLGE.getUniformLocation(gl,program, "worldView"); if(!pgl.mvMatrix){ pgl.mvMatrixT=new Float32Array(mvMatrix); }else{ GLGE.mat4gl(GLGE.transposeMat4(mvMatrix),pgl.mvMatrixT); } 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; if(!program.glarrays.envMat){ pgl.envMatT=new Float32Array(GLGE.transposeMat4(envMat)); }else{ GLGE.mat4gl(GLGE.transposeMat4(envMat),pgl.envMatT); } 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"); if(!pgl.cameraMatrix){ pgl.cameraMatrixT=new Float32Array(GLGE.transposeMat4(cameraMatrix)); }else{ GLGE.mat4gl(GLGE.transposeMat4(cameraMatrix),pgl.cameraMatrixT); } pgl.cameraMatrix=cameraMatrix; GLGE.setUniformMatrix(gl,"Matrix4fv",cUniform, false, pgl.cameraMatrixT); mvCache.camerMatrix=cameraMatrix; mvCache.modelMatrix=modelMatrix; }catch(e){} } var pUniform = GLGE.getUniformLocation(gl,program, "projection"); if(!pgl.pMatrix){ pgl.pMatrixT=new Float32Array(GLGE.transposeMat4(camera.getProjectionMatrix())); }else{ GLGE.mat4gl(GLGE.transposeMat4(camera.getProjectionMatrix()),pgl.pMatrixT); } pgl.pMatrix=camera.getProjectionMatrix(); GLGE.setUniformMatrix(gl,"Matrix4fv",pUniform, false, pgl.pMatrixT); //light //dont' need lighting for picking if(renderType==GLGE.RENDER_DEFAULT){ 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; default: drawType=gl.TRIANGLES; break; } switch(renderType){ case GLGE.RENDER_DEFAULT: if(gl.program!=this.GLShaderProgram){ gl.useProgram(this.GLShaderProgram); gl.program=this.GLShaderProgram; } this.mesh.GLAttributes(gl,this.GLShaderProgram); break; case GLGE.RENDER_SHADOW: if(gl.program!=this.GLShaderProgramShadow){ gl.useProgram(this.GLShaderProgramShadow); gl.program=this.GLShaderProgramShadow; } this.mesh.GLAttributes(gl,this.GLShaderProgramShadow); break; case GLGE.RENDER_NORMAL: if(gl.program!=this.GLShaderProgramNormal){ gl.useProgram(this.GLShaderProgramNormal); gl.program=this.GLShaderProgramNormal; } this.mesh.GLAttributes(gl,this.GLShaderProgramNormal); break; case GLGE.RENDER_PICK: if(gl.program!=this.GLShaderProgramPick){ gl.useProgram(this.GLShaderProgramPick); gl.program=this.GLShaderProgramPick; } this.mesh.GLAttributes(gl,this.GLShaderProgramPick); drawType=gl.TRIANGLES; break; } //render the object this.GLUniforms(gl,renderType,pickindex); 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); } var matrix=this.matrix; var caches=this.caches; for(var n=0;n0){ 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); } } } /** * @class Creates a new light source to be added to a scene * @property {Boolean} diffuse Dose this light source effect diffuse shading * @property {Boolean} specular Dose this light source effect specular shading * @augments GLGE.Animatable * @augments GLGE.Placeable * @augments GLGE.QuickNotation * @augments GLGE.JSONLoader */ GLGE.Light=function(uid){ GLGE.Assets.registerAsset(this,uid); this.color={r:1,g:1,b:1}; } GLGE.augment(GLGE.Placeable,GLGE.Light); GLGE.augment(GLGE.Animatable,GLGE.Light); GLGE.augment(GLGE.QuickNotation,GLGE.Light); GLGE.augment(GLGE.JSONLoader,GLGE.Light); GLGE.Light.prototype.className="Light"; /** * @constant * @description Enumeration for an point light source */ GLGE.L_POINT=1; /** * @constant * @description Enumeration for an directional light source */ GLGE.L_DIR=2; /** * @constant * @description Enumeration for an spot light source */ GLGE.L_SPOT=3; GLGE.Light.prototype.constantAttenuation=1; GLGE.Light.prototype.linearAttenuation=0.002; GLGE.Light.prototype.quadraticAttenuation=0.0008; GLGE.Light.prototype.spotCosCutOff=0.95; GLGE.Light.prototype.spotPMatrix=null; GLGE.Light.prototype.spotExponent=10; GLGE.Light.prototype.color=null; GLGE.Light.prototype.diffuse=true; GLGE.Light.prototype.specular=true; GLGE.Light.prototype.samples=0; GLGE.Light.prototype.softness=0.01; GLGE.Light.prototype.type=GLGE.L_POINT; GLGE.Light.prototype.frameBuffer=null; GLGE.Light.prototype.renderBuffer=null; GLGE.Light.prototype.texture=null; GLGE.Light.prototype.bufferHeight=256; GLGE.Light.prototype.bufferWidth=256; GLGE.Light.prototype.shadowBias=2.0; GLGE.Light.prototype.castShadows=false; /** * Gets the spot lights projection matrix * @returns the lights spot projection matrix * @private */ GLGE.Light.prototype.getPMatrix=function(){ if(!this.spotPMatrix){ var far; if(this.scene && this.scene.camera) far=this.scene.camera.far; else far=1000; this.spotPMatrix=GLGE.makePerspective(Math.acos(this.spotCosCutOff)/3.14159*360, 1.0, 0.1, far); } return this.spotPMatrix; } /** * Sets the shadow casting flag * @param {number} value should cast shadows? */ GLGE.Light.prototype.setCastShadows=function(value){ this.castShadows=value; return this; } /** * Gets the shadow casting flag * @returns {number} true if casts shadows */ GLGE.Light.prototype.getCastShadows=function(){ return this.castShadows; return this; } /** * Sets the shadow bias * @param {number} value The shadow bias */ GLGE.Light.prototype.setShadowBias=function(value){ this.shadowBias=value; return this; } /** * Gets the shadow bias * @returns {number} The shadow buffer bias */ GLGE.Light.prototype.getShadowBias=function(){ return this.shadowBias; } /** * Sets the number of samples for this shadow * @param {number} value The number of samples to perform */ GLGE.Light.prototype.setShadowSamples=function(value){ this.samples=value; return this; } /** * Gets the number of samples for this shadow * @returns {number} The number of samples */ GLGE.Light.prototype.getShadowSamples=function(){ return this.samples; } /** * Sets the shadow softness * @param {number} value The number of samples to perform */ GLGE.Light.prototype.setShadowSoftness=function(value){ this.softness=value; return this; } /** * Gets the shadow softness * @returns {number} The softness of the shadows */ GLGE.Light.prototype.getShadowSamples=function(){ return this.softness; } /** * Sets the shadow buffer width * @param {number} value The shadow buffer width */ GLGE.Light.prototype.setBufferWidth=function(value){ this.bufferWidth=value; return this; } /** * Gets the shadow buffer width * @returns {number} The shadow buffer width */ GLGE.Light.prototype.getBufferHeight=function(){ return this.bufferHeight; } /** * Sets the shadow buffer width * @param {number} value The shadow buffer width */ GLGE.Light.prototype.setBufferHeight=function(value){ this.bufferHeight=value; return this; } /** * Gets the shadow buffer width * @returns {number} The shadow buffer width */ GLGE.Light.prototype.getBufferWidth=function(){ return this.bufferWidth; } /** * Sets the spot light cut off * @param {number} value The cos of the angle to limit */ GLGE.Light.prototype.setSpotCosCutOff=function(value){ this.spotPMatrix=null; this.spotCosCutOff=value; return this; } /** * Gets the spot light cut off * @returns {number} The cos of the limiting angle */ GLGE.Light.prototype.getSpotCosCutOff=function(){ return this.spotCosCutOff; } /** * Sets the spot light exponent * @param {number} value The spot lights exponent */ GLGE.Light.prototype.setSpotExponent=function(value){ this.spotExponent=value; return this; } /** * Gets the spot light exponent * @returns {number} The exponent of the spot light */ GLGE.Light.prototype.getSpotExponent=function(){ return this.spotExponent; } /** * Sets the light sources Attenuation * @returns {Object} The components of the light sources attenuation */ GLGE.Light.prototype.getAttenuation=function(constant,linear,quadratic){ var attenuation={}; attenuation.constant=this.constantAttenuation; attenuation.linear=this.linearAttenuation; attenuation.quadratic=this.quadraticAttenuation; return attenuation; } /** * Sets the light sources Attenuation * @param {Number} constant The constant part of the attenuation * @param {Number} linear The linear part of the attenuation * @param {Number} quadratic The quadratic part of the attenuation */ GLGE.Light.prototype.setAttenuation=function(constant,linear,quadratic){ this.constantAttenuation=constant; this.linearAttenuation=linear; this.quadraticAttenuation=quadratic; return this; } /** * Sets the light sources constant attenuation * @param {Number} value The constant part of the attenuation */ GLGE.Light.prototype.setAttenuationConstant=function(value){ this.constantAttenuation=value; return this; } /** * Sets the light sources linear attenuation * @param {Number} value The linear part of the attenuation */ GLGE.Light.prototype.setAttenuationLinear=function(value){ this.linearAttenuation=value; return this; } /** * Sets the light sources quadratic attenuation * @param {Number} value The quadratic part of the attenuation */ GLGE.Light.prototype.setAttenuationQuadratic=function(value){ this.quadraticAttenuation=value; return this; } /** * Sets the color of the light source * @param {string} color The color of the light */ GLGE.Light.prototype.setColor=function(color){ color=GLGE.colorParse(color); this.color={r:color.r,g:color.g,b:color.b}; return this; } /** * Sets the red color of the light source * @param {Number} value The new red level 0-1 */ GLGE.Light.prototype.setColorR=function(value){ this.color.r=value; return this; } /** * Sets the green color of the light source * @param {Number} value The new green level 0-1 */ GLGE.Light.prototype.setColorG=function(value){ this.color.g=value; return this; } /** * Sets the blue color of the light source * @param {Number} value The new blue level 0-1 */ GLGE.Light.prototype.setColorB=function(value){ this.color.b=value; return this; } /** * Gets the current color of the light source * @return {[r,g,b]} The current position */ GLGE.Light.prototype.getColor=function(){ return this.color; } /** * Gets the type of the light * @return {Number} The type of the light source eg GLGE.L_POINT */ GLGE.Light.prototype.getType=function(){ return this.type; } /** * Sets the type of the light * @param {Number} type The type of the light source eg GLGE.L_POINT */ GLGE.Light.prototype.setType=function(type){ this.type=type; return this; } /** * init for the rendering * @private */ GLGE.Light.prototype.GLInit=function(gl){ this.gl=gl; if(this.type==GLGE.L_SPOT && !this.texture){ this.createSpotBuffer(gl); } } /** * Sets up the WebGL needed to render the depth map for this light source. Only used for spot lights which produce shadows * @private */ GLGE.Light.prototype.createSpotBuffer=function(gl){ this.frameBuffer = gl.createFramebuffer(); this.renderBuffer = gl.createRenderbuffer(); this.texture = gl.createTexture(); gl.bindTexture(gl.TEXTURE_2D, this.texture); try { gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, this.bufferWidth, this.bufferHeight, 0, gl.RGBA, gl.UNSIGNED_BYTE, null); } catch (e) { var tex = new Uint8Array(this.bufferWidth * this.bufferHeight * 4); gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, parseFloat2(this.bufferWidth), parseFloat2(this.bufferHeight), 0, gl.RGBA, gl.UNSIGNED_BYTE, tex); } gl.bindFramebuffer(gl.FRAMEBUFFER, this.frameBuffer); gl.bindRenderbuffer(gl.RENDERBUFFER, this.renderBuffer); gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_COMPONENT16, this.bufferWidth, this.bufferHeight); gl.bindRenderbuffer(gl.RENDERBUFFER, null); gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, this.texture, 0); gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER, this.renderBuffer); gl.bindFramebuffer(gl.FRAMEBUFFER, null); } /** * @constant * @description Enumeration for a perspective camera */ GLGE.C_PERSPECTIVE=1; /** * @constant * @description Enumeration for a orthographic camera */ GLGE.C_ORTHO=2; /** * @class Creates a new camera object * @augments GLGE.Animatable * @augments GLGE.Placeable * @augments GLGE.QuickNotation * @augments GLGE.JSONLoader */ GLGE.Camera=function(uid){ GLGE.Assets.registerAsset(this,uid); }; GLGE.augment(GLGE.Placeable,GLGE.Camera); GLGE.augment(GLGE.Animatable,GLGE.Camera); GLGE.augment(GLGE.QuickNotation,GLGE.Camera); GLGE.augment(GLGE.JSONLoader,GLGE.Camera); GLGE.Camera.prototype.className="Camera"; GLGE.Camera.prototype.fovy=35; GLGE.Camera.prototype.aspect=1.0; GLGE.Camera.prototype.near=0.1; GLGE.Camera.prototype.far=1000.0; GLGE.Camera.prototype.orthoscale=5; GLGE.Camera.prototype.type=GLGE.C_PERSPECTIVE; GLGE.Camera.prototype.pMatrix=null; /** * Method gets the orthographic scale for the camers * @return {Matrix} Returns the orthographic scale */ GLGE.Camera.prototype.getOrthoScale=function(){ if(this.type==GLGE.C_ORTHO) { return this.orthoscale }else{ GLGE.error("You may only get a scale for a orthographic camera"); return 1; } }; /** * Method sets the orthographic scale for the camers * @param {number} scale The new orthographic scale */ GLGE.Camera.prototype.setOrthoScale=function(scale){ if(this.type==GLGE.C_ORTHO) { this.orthoscale=scale; this.pMatrix=null; } else { GLGE.error("You may only set a scale for a orthographic camera"); } return this; }; /** * Method gets the far drawing distance * @return {Matrix} Returns the cameras far draw distance */ GLGE.Camera.prototype.getFar=function(){ return this.far; }; /** * Method sets the far draw distance of the camera * @param {number} distance The far draw distance */ GLGE.Camera.prototype.setFar=function(distance){ this.far=distance; return this; }; /** * Method gets the near drawing distance * @return {Matrix} Returns the cameras near draw distance */ GLGE.Camera.prototype.getNear=function(){ return this.near; }; /** * Method sets the near draw distance of the camera * @param {number} distance The near draw distance */ GLGE.Camera.prototype.setNear=function(distance){ this.near=distance; return this; }; /** * Method gets the current camera type * @return {Matrix} Returns the camera type */ GLGE.Camera.prototype.getType=function(){ return this.type }; /** * Method sets the type of camera GLGE.C_PERSPECTIVE or GLGE.C_ORTHO * @param {number} type The type of this camera */ GLGE.Camera.prototype.setType=function(type){ if(type==GLGE.C_PERSPECTIVE || type==GLGE.C_ORTHO){ this.type=type; this.pMatrix=null; }else{ GLGE.error("unsuported camera type"); } return this; }; /** * Method gets the current yfov if the camera type is GLGE.C_PERSPECTIVE * @return {Matrix} Returns the yfov */ GLGE.Camera.prototype.getFovY=function(){ if(this.type==GLGE.C_PERSPECTIVE) { return this.fovy }else{ GLGE.error("You may only get a yfov for a perspective camera"); return 1; } }; /** * Method sets the yfov of the camera * @param {number} yfov The new yfov of the camera */ GLGE.Camera.prototype.setFovY=function(fovy){ if(this.type==GLGE.C_PERSPECTIVE) { this.fovy=fovy; this.ymax=null; this.pMatrix=null; } else { GLGE.error("You may only set a yfov for a perspective camera"); } return this; }; /** * Method gets the current aspect if the camera type is GLGE.C_PERSPECTIVE * @return {Matrix} Returns the yfov */ GLGE.Camera.prototype.getAspect=function(){ if(this.type==GLGE.C_PERSPECTIVE || this.type==GLGE.C_ORTHO) { return this.aspect } else { GLGE.error("You may only set a aspect for a perspective or orthographic camera"); return 1; } }; /** * Method sets the aspect of the camera * @param {number} aspect The new projection matrix */ GLGE.Camera.prototype.setAspect=function(aspect){ if(this.type==GLGE.C_PERSPECTIVE || this.type==GLGE.C_ORTHO) { this.aspect=aspect; this.pMatrix=null; } else { GLGE.error("You may only set a aspect for a perspective or orthographic camera"); } return this; }; /** * Method gets the current projection matrix of this camera * @return {Matrix} Returns the camera projection matrix */ GLGE.Camera.prototype.getProjectionMatrix=function(){ if(!this.pMatrix){ switch(this.type){ case GLGE.C_PERSPECTIVE: this.pMatrix=GLGE.makePerspective(this.fovy, this.aspect, this.near, this.far); break; case GLGE.C_ORTHO: this.pMatrix=GLGE.makeOrtho(-this.orthoscale*this.aspect,this.orthoscale*this.aspect,-this.orthoscale,this.orthoscale, this.near, this.far); break; } } return this.pMatrix; }; /** * Method generates the projection matrix based on the * camera paramaters * @param {Matrix} projection The new projection matrix */ GLGE.Camera.prototype.setProjectionMatrix=function(projection){ this.pMatrix=projection; return this; }; /** * Method generates the cameras view matrix * @return Returns the view matrix based on this camera * @type Matrix */ GLGE.Camera.prototype.updateMatrix=function(){ var position=this.getPosition(); var vMatrix=GLGE.translateMatrix(position.x,position.y,position.z); vMatrix=GLGE.mulMat4(vMatrix,this.getRotMatrix()); if(this.parent) vMatrix=GLGE.mulMat4(this.parent.getModelMatrix(),vMatrix); this.matrix=GLGE.inverseMat4(vMatrix); }; /** * Method generates the cameras view matrix * @return Returns the view matrix based on this camera * @type Matrix */ GLGE.Camera.prototype.getViewMatrix=function(){ if(!this.matrix || !this.rotmatrix) this.updateMatrix(); return this.matrix; }; /** * Method generates the cameras view projection matrix * @return Returns the view projection matrix based on this camera * @type Matrix */ GLGE.Camera.prototype.getViewProjection=function(){ var projectionMatrix=this.getProjectionMatrix(); var viewMatrix=this.getViewMatrix(); if(projectionMatrix!=this.vpProjectionMatrix || viewMatrix!=this.vpViewMatrix){ this.cameraViewProjection=GLGE.mulMat4(projectionMatrix,viewMatrix); this.vpProjectionMatrix=projectionMatrix; this.vpViewMatrix=viewMatrix; } return this.cameraViewProjection; }; /** * @constant * @description Enumeration for no fog */ GLGE.FOG_NONE=1; /** * @constant * @description Enumeration for linear fall off fog */ GLGE.FOG_LINEAR=2; /** * @constant * @description Enumeration for exponential fall off fog */ GLGE.FOG_QUADRATIC=3; /** * @class Scene class containing the camera, lights and objects * @augments GLGE.Group * @augments GLGE.QuickNotation * @augments GLGE.JSONLoader */ GLGE.Scene=function(uid){ GLGE.Assets.registerAsset(this,uid); this.children=[]; this.camera=new GLGE.Camera(); this.backgroundColor={r:1,g:1,b:1,a:1}; this.ambientColor={r:0,g:0,b:0}; this.fogColor={r:0.5,g:0.5,b:0.5}; this.passes=[]; } GLGE.augment(GLGE.Group,GLGE.Scene); GLGE.augment(GLGE.QuickNotation,GLGE.Scene); GLGE.augment(GLGE.JSONLoader,GLGE.Scene); GLGE.Scene.prototype.camera=null; GLGE.Scene.prototype.className="Scene"; GLGE.Scene.prototype.renderer=null; GLGE.Scene.prototype.backgroundColor=null; GLGE.Scene.prototype.filter=null; GLGE.Scene.prototype.fogColor=null; GLGE.Scene.prototype.ambientColor=null; GLGE.Scene.prototype.fogNear=10; GLGE.Scene.prototype.fogFar=80; GLGE.Scene.prototype.fogType=GLGE.FOG_NONE; GLGE.Scene.prototype.passes=null; GLGE.Scene.prototype.culling=true; /** * Gets the fog falloff type * @returns {number} the far falloff type */ GLGE.Scene.prototype.getFogType=function(){ return this.fogType; } /** * Sets the scenes fog falloff type * @param {number} type The fog falloff type FOG_NONE,FOG_LINEAR,FOG_QUADRATIC */ GLGE.Scene.prototype.setFogType=function(type){ this.fogType=type; return this; } /** * Gets the far fog distance * @returns {number} the far distance of the fog */ GLGE.Scene.prototype.getFogFar=function(){ return this.fogFar; } /** * Sets the scenes fog far distance * @param {number} dist The fog far distance */ GLGE.Scene.prototype.setFogFar=function(dist){ this.fogFar=dist; return this; } /** * Gets the near fog distance * @returns {number} the near distance of the fog */ GLGE.Scene.prototype.getFogNear=function(){ return this.fogNear; } /** * Sets the scenes fog near distance * @param {number} dist The fog near distance */ GLGE.Scene.prototype.setFogNear=function(dist){ this.fogNear=dist; return this; } /** * Gets the fog color * @returns {object} An assoiative array r,g,b */ GLGE.Scene.prototype.getFogColor=function(){ return this.fogColor; } /** * Sets the scenes fog color * @param {string} color The fog color */ GLGE.Scene.prototype.setFogColor=function(color){ color=GLGE.colorParse(color); this.fogColor={r:color.r,g:color.g,b:color.b}; return this; } /** * Gets the scenes background color * @returns {object} An assoiative array r,g,b */ GLGE.Scene.prototype.getBackgroundColor=function(){ return this.backgroundColor; } /** * Sets the scenes background color * @param {string} color The backgorund color */ GLGE.Scene.prototype.setBackgroundColor=function(color){ color=GLGE.colorParse(color); this.backgroundColor={r:color.r,g:color.g,b:color.b,a:color.a}; return this; } /** * Gets the scenes ambient light * @returns {object} An assoiative array r,g,b */ GLGE.Scene.prototype.getAmbientColor=function(){ return this.ambientColor; } /** * Sets the scenes ambient light * @param {string} color The ambient light color */ GLGE.Scene.prototype.setAmbientColor=function(color){ color=GLGE.colorParse(color); this.ambientColor={r:color.r,g:color.g,b:color.b}; if(this.renderer){ this.renderer.gl.clearColor(this.backgroundColor.r, this.backgroundColor.g, this.backgroundColor.b, 1.0); } return this; } /** * Sets the scenes ambient light * @param {number} value the red componenent of the ambient light 0-1 */ GLGE.Scene.prototype.setAmbientColorR=function(value){ this.ambientColor.r=value; return this; } /** * Sets the scenes ambient light * @param {number} value the green componenent of the ambient light 0-1 */ GLGE.Scene.prototype.setAmbientColorG=function(value){ this.ambientColor.g=value; return this; } /** * Sets the scenes ambient light * @param {number} value the blue componenent of the ambient light 0-1 */ GLGE.Scene.prototype.setAmbientColorB=function(value){ this.ambientColor.b=value; return this; } /** * Sets the active camera for this scene * @property {GLGE.Camera} object The object to be added */ GLGE.Scene.prototype.setCamera=function(camera){ if(typeof camera=="string") camera=GLGE.Assets.get(camera); this.camera=camera; return this; } /** * Gets the scenes active camera * @returns {GLGE.Camera} The current camera */ GLGE.Scene.prototype.getCamera=function(){ return this.camera; } /** * Sets the Culling Flag */ GLGE.Scene.prototype.setCull=function(cull){ this.culling=cull; return this; } /** * Gets the Culling Flag */ GLGE.Scene.prototype.getCull=function(){ return this.culling; } /** * used to initialize all the WebGL buffers etc need for this scene * @private */ GLGE.Scene.prototype.GLInit=function(gl){ this.gl=gl; gl.lights=this.getLights(); //sets the camera aspect to same aspect as the canvas this.camera.setAspect(this.renderer.canvas.width/this.renderer.canvas.height); //this.createPickBuffer(gl); this.renderer.gl.clearColor(this.backgroundColor.r, this.backgroundColor.g, this.backgroundColor.b, 1.0); for(var i=0;ibidx){ 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.framebuffer); this.renderPass(gl,renderObjects,this.renderer.getViewportOffsetX(),this.renderer.getViewportOffsetY(),this.renderer.getViewportWidth(),this.renderer.getViewportHeight()); this.applyFilter(gl,renderObjects,null); this.allowPasses=true; } /** * gets the passes needed to render this scene * @private */ GLGE.Scene.prototype.getPasses=function(gl,renderObjects){ for(var i=0; i0){ 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; scene.GLInit(this.gl); this.render(); scene.camera.matrix=null; //reset camera matrix to force cache update return this; }; /** * Renders the current scene to the canvas */ GLGE.Renderer.prototype.render=function(){ if(this.cullFaces) this.gl.enable(this.gl.CULL_FACE); this.scene.render(this.gl); //if this is the first ever pass then render twice to fill shadow buffers if(!this.rendered){ this.scene.render(this.gl); this.rendered=true; } }; /** * @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.Texture=function(uid){ GLGE.Assets.registerAsset(this,uid); } GLGE.augment(GLGE.QuickNotation,GLGE.Texture); GLGE.augment(GLGE.JSONLoader,GLGE.Texture); GLGE.Texture.prototype.className="Texture"; GLGE.Texture.prototype.image=null; GLGE.Texture.prototype.glTexture=null; GLGE.Texture.prototype.url=null; /** * Gets the textures used by the layer * @return {string} The textures image url */ GLGE.Texture.prototype.getSrc=function(){ return this.url; }; /** * Sets the textures image location * @param {string} url the texture image url */ GLGE.Texture.prototype.setSrc=function(url){ this.url=url; this.state=0; this.image=new Image(); var texture=this; this.image.onload = function(){ texture.state=1; } this.image.src=url; if(this.glTexture && this.gl){ this.gl.deleteTexture(this.glTexture); this.glTexture=null; } return this; }; /** * Sets the textures image location * @private **/ GLGE.Texture.prototype.doTexture=function(gl){ 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 if(this.state==1){ gl.bindTexture(gl.TEXTURE_2D, this.glTexture); gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE,this.image); gl.generateMipmap(gl.TEXTURE_2D); gl.bindTexture(gl.TEXTURE_2D, null); this.state=2; } 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_MIPMAP_LINEAR); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT); if(this.state==2) return true; else return false; } /** * @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){ GLGE.Assets.registerAsset(this,uid); this.canvas=document.createElement("canvas"); } GLGE.augment(GLGE.QuickNotation,GLGE.TextureCanvas); GLGE.augment(GLGE.JSONLoader,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); //TODO: fix this when minefield is upto spec try{gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, canvas);} catch(e){gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, 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); } /** * @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){ GLGE.Assets.registerAsset(this,uid); this.video=document.createElement("video"); this.video.style.display="none"; this.video.setAttribute("loop","loop"); 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.augment(GLGE.QuickNotation,GLGE.TextureVideo); GLGE.augment(GLGE.JSONLoader,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); */ } } /** * @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.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.mirrorAxis=GLGE.NONE; GLGE.TextureCamera.prototype.clipAxis=GLGE.NONE; /** * 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)]; 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)]; 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)]; 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)]; 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)-0.5]; 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)-0.5]; 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); } /** * @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.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.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; } /** * @class The material layer describes how to apply this layer to the material * @see GLGE.Material * @augments GLGE.Animatable * @augments GLGE.QuickNotation * @augments GLGE.JSONLoader * @augments GLGE.Events */ GLGE.MaterialLayer=function(uid){ GLGE.Assets.registerAsset(this,uid); this.blendMode=GLGE.BL_MIX; }; GLGE.augment(GLGE.Animatable,GLGE.MaterialLayer); GLGE.augment(GLGE.QuickNotation,GLGE.MaterialLayer); GLGE.augment(GLGE.JSONLoader,GLGE.MaterialLayer); GLGE.augment(GLGE.Events,GLGE.MaterialLayer); /** * @name GLGE.MaterialLayer#shaderupdated * @event Fires when a change will result in a change to the GLSL shader * @param {object} data */ GLGE.MaterialLayer.prototype.className="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.alpha=1; GLGE.MaterialLayer.prototype.height=0.05; 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.mulMat4(GLGE.mulMat4(GLGE.translateMatrix(offset.x,offset.y,offset.z),GLGE.scaleMatrix(scale.x,scale.y,scale.z)),GLGE.rotateMatrix(rotation.x,rotation.y,rotation.z)); } return this.matrix; }; /** * Sets the height for this layer, currently only used for parallax mapping * @param {number} the height of this layer */ GLGE.MaterialLayer.prototype.setHeight=function(value){ this.height=value; return this; }; /** * Gets the height for this layer, currently only used for parallax mapping * @return {number} the height of this layer */ GLGE.MaterialLayer.prototype.getHeight=function(){ return this.height; }; /** * Sets the textures alpha blending value * @param {number} the alpha for this layer */ GLGE.MaterialLayer.prototype.setAlpha=function(value){ this.alpha=value; return this; }; /** * Gets the textures alpha blending value * @return {number} the alpha for this layer */ GLGE.MaterialLayer.prototype.getAlpha=function(){ return this.alpha; }; /** * Sets the textures used by the layer * @param {GLGE.Texture} value the teture to associate with this layer */ GLGE.MaterialLayer.prototype.setTexture=function(value){ if(typeof value=="string") value=GLGE.Assets.get(value); this.texture=value; this.fireEvent("shaderupdate",{}); return this; }; /** * 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; this.fireEvent("shaderupdate",{}); return this; }; /** * 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; this.fireEvent("shaderupdate",{}); return this; }; /** * 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; return this; }; /** * 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; return this; }; /** * 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; return this; }; /** * 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; return this; }; /** * 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; return this; }; /** * 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; return this; }; /** * 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; return this; }; /** * 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; return this; }; /** * 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; return this; }; /** * 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; return this; }; /** * 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; return this; }; /** * 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; return this; }; /** * 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; return this; }; /** * 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; return this; }; /** * 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; return this; }; /** * 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; return this; }; /** * 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; return this; }; /** * 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; return this; }; /** * 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; this.fireEvent("shaderupdate",{}); return this; }; /** * Gets the layers tblending mode * @return {Number} the blend mode for the layer */ GLGE.MaterialLayer.prototype.getBlendMode=function(){ return this.blendMode; }; var materialIdx=0; /** * @class The Material class creates materials to be applied to objects in the graphics engine * @see GLGE.Object * @augments GLGE.Animatable * @augments GLGE.QuickNotation * @augments GLGE.JSONLoader * @augments GLGE.Events */ GLGE.Material=function(uid){ GLGE.Assets.registerAsset(this,uid); this.layers=[]; this.layerlisteners=[]; 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=10; this.specular=1; this.emit=0; this.alpha=1; this.materialIdx=materialIdx++; }; GLGE.augment(GLGE.Animatable,GLGE.Material); GLGE.augment(GLGE.QuickNotation,GLGE.Material); GLGE.augment(GLGE.JSONLoader,GLGE.Material); GLGE.augment(GLGE.Events,GLGE.Material); /** * @name GLGE.Material#shaderupdate * @event fires when the shader for this material needs updating * @param {object} data */ /** * @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 Flag for mapping of the height in parallax mapping */ GLGE.M_AMBIENT=16384; /** * @constant * @description Enumeration for first UV layer */ GLGE.UV1=0; /** * @constant * @description Enumeration for second UV layer */ GLGE.UV2=1; /** * @constant * @description Enumeration for normal texture coords */ GLGE.MAP_NORM=3; /** * @constant * @description Enumeration for object texture coords */ GLGE.MAP_OBJ=4; /** * @constant * @description Enumeration for reflection coords */ GLGE.MAP_REF=5; /** * @constant * @description Enumeration for environment coords */ GLGE.MAP_ENV=6; /** * @constant * @description Enumeration for view coords */ GLGE.MAP_VIEW=7; /** * @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.className="Material"; 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.ambient=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; this.fireEvent("shaderupdate",{}); return this; }; /** * 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}; this.fireEvent("shaderupdate",{}); return this; }; /** * 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; this.fireEvent("shaderupdate",{}); return this; }; /** * 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; this.fireEvent("shaderupdate",{}); return this; }; /** * 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; this.fireEvent("shaderupdate",{}); return this; }; /** * 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:parseFloat(color.r),g:parseFloat(color.g),b:parseFloat(color.b)}; this.fireEvent("shaderupdate",{}); return this; }; /** * Gets the ambient lighting of the material * @return {[r,g,b]} The current ambient lighting */ GLGE.Material.prototype.getAmbient=function(){ return this.ambient; }; /** * Sets the ambient lighting of the material * @param {string} color The new specular colour */ GLGE.Material.prototype.setAmbient=function(color){ if(!color.r){ color=GLGE.colorParse(color); } this.ambient={r:parseFloat(color.r),g:parseFloat(color.g),b:parseFloat(color.b)}; this.fireEvent("shaderupdate",{}); return this; }; /** * 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; this.fireEvent("shaderupdate",{}); return this; }; /** * 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; this.fireEvent("shaderupdate",{}); return this; }; /** * 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){ if (value<=0) value=0.001; this.shine=value; this.fireEvent("shaderupdate",{}); return this; }; /** * 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; this.fireEvent("shaderupdate",{}); return this; }; /** * 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(){ var shader=[]; shader.push("vec4 texturePos;\n"); for(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(reflect(normalize(lightvec), normal),normalize(viewvec)),0.0), 0.3*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+"vec4 dist=texture2D(TEXTURE"+shadowlights[i]+", (((spotcoord"+i+".xy)/spotcoord"+i+".w)+1.0)/2.0);\n"; shader=shader+"float depth = dot(dist, vec4(0.000000059604644775390625,0.0000152587890625,0.00390625,1.0))*100.0;\n"; shader=shader+"spotmul=0.0;\n"; shader=shader+"totalweight=0.0;\n"; shader=shader+"if((depth+shadowbias"+i+"-length(lightvec"+i+"))<0.0) {spotmul=1.0; totalweight=1.0;}\n"; shader=shader+"if(shadowsamples"+i+">0){\n"; shader=shader+"for(cnt=0; cnt<4; cnt++){;\n"; shader=shader+"spotsampleX=-0.707106781;spotsampleY=-0.707106781;\n"; shader=shader+"if(cnt==0 || cnt==3) spotsampleX=0.707106781;\n"; shader=shader+"if(cnt==1 || cnt==3) spotsampleY=0.707106781;\n"; shader=shader+"spotoffset=vec2(spotsampleX,spotsampleY)*0.5;\n"; shader=shader+"dist=texture2D(TEXTURE"+shadowlights[i]+", (((spotcoord"+i+".xy)/spotcoord"+i+".w)+1.0)/2.0+spotoffset*shadowsoftness"+i+");\n"; shader=shader+"depth = dot(dist, vec4(0.000000059604644775390625,0.0000152587890625,0.00390625,1.0))*100.0;\n"; shader=shader+"if((depth+shadowbias"+i+"-length(lightvec"+i+"))<0.0){\n"; shader=shader+"spotmul+=length(spotoffset);\n"; shader=shader+"}\n"; shader=shader+"totalweight+=length(spotoffset);\n"; shader=shader+"};\n"; shader=shader+"};\n"; shader=shader+"if(totalweight!=spotmul){\n"; shader=shader+"spotmul=0.0;\n"; shader=shader+"totalweight=0.0;\n"; shader=shader+"for(cnt=0; cnt0.0) spotEffect=spotEffect*pow(1.0-spotmul/totalweight,3.0);\n"; shader=shader+"}"; } shader=shader+"dotN=max(dot(normal,normalize(-lightvec)),0.0);\n"; shader=shader+"if(dotN>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(reflect(normalize(lightvec), normal),normalize(viewvec)),0.0), 0.3 * sh);\n"; } shader=shader+"}\n}\n"; } if(lights[i].type==GLGE.L_DIR){ shader=shader+"dotN=max(dot(normal,-normalize(lightvec)),0.0);\n"; shader=shader+"if(dotN>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(reflect(normalize(lightvec), normal),normalize(viewvec)),0.0), 0.3 * sh);\n"; } shader=shader+"}\n"; } } shader=shader+"float fogfact=1.0;"; shader=shader+"if(fogtype=="+GLGE.FOG_QUADRATIC+") 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+") fogfact=clamp((fogfar - length(eyevec)) / (fogfar - fognear),0.0,1.0);\n"; shader=shader+"lightvalue = (lightvalue)*ref;\n"; shader=shader+"if(em>0.0){lightvalue=vec3(1.0,1.0,1.0); fogfact=1.0;}\n"; shader=shader+"gl_FragColor =vec4(specvalue.rgb+color.rgb*(em+1.0)*lightvalue.rgb,al)*fogfact+vec4(fogcolor,al)*(1.0-fogfact);\n"; //shader=shader+"gl_FragColor =vec4(color.rgb,1.0);\n"; 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!=this.color){ if(this.ccache!=this.color){ 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.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.emit!=this.emit){ GLGE.setUniform(gl,"1f",GLGE.getUniformLocation(gl,shaderProgram, "emit"), this.emit); pc.emit=this.emit; } if(pc.alpha!=this.alpha){ GLGE.setUniform(gl,"1f",GLGE.getUniformLocation(gl,shaderProgram, "alpha"), this.alpha); pc.alpha=this.alpha; } /* 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=0; 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; i