diff options
author | Alon Zakai <azakai@mozilla.com> | 2010-11-07 16:07:47 -0800 |
---|---|---|
committer | Alon Zakai <azakai@mozilla.com> | 2010-11-07 16:07:47 -0800 |
commit | 98a9576c6e3c357960bd7741f9e0ad964f206e29 (patch) | |
tree | a12dd6801c7fce111584a8c18cf1692c7a731c68 /demos/webgl/glge.js | |
parent | 54b3d3ec052aac293524da742000167cd0be5067 (diff) |
wip bullet/webgl demo
Diffstat (limited to 'demos/webgl/glge.js')
-rw-r--r-- | demos/webgl/glge.js | 7883 |
1 files changed, 7883 insertions, 0 deletions
diff --git a/demos/webgl/glge.js b/demos/webgl/glge.js new file mode 100644 index 00000000..ca19e665 --- /dev/null +++ b/demos/webgl/glge.js @@ -0,0 +1,7883 @@ +/* +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){ + + +/** +* 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(i<length){ + c1=str.charCodeAt(i++);c2=str.charCodeAt(i++);c3=str.charCodeAt(i++); + c4=str.charCodeAt(i++);c5=str.charCodeAt(i++);c6=str.charCodeAt(i++); + s1=(s5+c1+c2)%255;s2=(s6+c2+c3)%255;s3=(s1+c3+c4)%255; + s4=(s2+c4+c5)%255;s5=(s3+c5+c6)%255;s6=(s4+c6+c1)%255; + } + var r=[String.fromCharCode(s1),String.fromCharCode(s2),String.fromCharCode(s3), + String.fromCharCode(s4),String.fromCharCode(s5),String.fromCharCode(s6)]; + return r.join(''); +} +/** +* @function check if shader is already created if not then create it +* @private +*/ +GLGE.getGLShader=function(gl,type,str){ + var hash=GLGE.fastHash(str); + if(!gl.shaderCache) gl.shaderCache={}; + if(!gl.shaderCache[hash]){ + var shader=gl.createShader(type); + gl.shaderSource(shader, str); + gl.compileShader(shader); + if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) { + alert(gl.getShaderInfoLog(shader)); + return; + } + gl.shaderCache[hash]=shader; + } + return gl.shaderCache[hash]; +} + +/** +* @function tries to re use programs +* @private +*/ +GLGE.getGLProgram=function(gl,vShader,fShader){ + if(!gl.programCache) gl.programCache=[]; + var programCache=gl.programCache; + for(var i=0; i<programCache.length;i++){ + if(programCache[i].fShader==fShader && programCache[i].vShader==vShader){ + return programCache[i].program; + } + } + var program=gl.createProgram(); + gl.attachShader(program, vShader); + gl.attachShader(program, fShader); + gl.linkProgram(program); + programCache.push({vShader:vShader,fShader:fShader,program:program}); + if(!program.uniformDetails){ + program.uniformDetails={}; + var uniforms = gl.getProgramParameter(program, gl.ACTIVE_UNIFORMS); + for (var i=0;i<uniforms;++i) { + var info=gl.getActiveUniform(program, i); + program.uniformDetails[info.name]={loc:GLGE.getUniformLocation(gl,program,info.name),info:info}; + } + } + return program; +} + + +/** +* function to cache the uniform locations +* @param {glcontext} the gl context of the program +* @param {program} the shader program +* @param {string} the uniform name +* @private +*/ +GLGE.getUniformLocation=function(gl,program, uniform){ + /*if(program.uniformDetails[uniform]){ + return program.uniformDetails[uniform].loc; + }else{ + return gl.getUniformLocation(program, uniform); + }*/ + if(!program.uniformCache) program.uniformCache={}; + if(!program.uniformChecked) program.uniformChecked={}; + if(!program.uniformChecked[uniform]){ + program.uniformCache[uniform]=gl.getUniformLocation(program, uniform); + program.uniformChecked[uniform]=true; + } + return program.uniformCache[uniform]; +}; +/** +* function to cache the attribute locations +* @param {glcontext} the gl context of the program +* @param {program} the shader program +* @param {string} the attribe name +* @private +*/ +GLGE.getAttribLocation=function(gl,program, attrib){ + if(!program.attribCache) program.attribCache={}; + if(!program.attribCache[attrib]){ + program.attribCache[attrib]=gl.getAttribLocation(program, attrib); + } + return program.attribCache[attrib]; +} + +/** +* @class class to implelemnt quick notation +*/ +GLGE.QuickNotation=function(){ +} +/** +* Call to set properties and add children to an object +* @example myObject._({LocX:10,LocY:20},child1,child2,.....); +*/ +GLGE.QuickNotation.prototype._=function(){ + var argument; + for(var i=0; i<arguments.length;i++){ + argument=arguments[i]; + if(typeof argument=="object"){ + if(argument.className && this["add"+argument.className]){ + this["add"+argument.className](argument); + }else{ + for(var key in argument){ + if(this["set"+key]){ + this["set"+key](argument[key]); + } + } + } + } + } + return this; +} + +/** +* @namespace GLGE Messaging System +*/ +GLGE.Message={}; +/** +* @function parses messages and updates the scene graph +*/ +GLGE.Message.parseMessage=function(msg){ + switch(msg.command){ + case "create": + var obj=new GLGE[msg.type](msg.uid); + this.setAttributes(obj,msg.attributes); + if(msg.children) GLGE.Message.addChildren(obj,msg.children); + return obj; + break; + case "update": + var obj=GLGE.Assets.get(msg.uid); + this.setAttributes(obj,msg.attributes); + if(msg.add) GLGE.Message.addChildren(obj,msg.add); + if(msg.remove) GLGE.Message.removeChildren(obj,msg.remove); + return obj; + break; + } + return null; +} +/** +* @function parses the attributes from a message +* @private +*/ +GLGE.Message.setAttributes=function(obj,attribs){ + if(attribs){ + for(var attrib in attribs){ + if(obj["set"+attrib]){ + //check to see if the attribute has to be parsed as a message + if(attribs[attrib].command){ + attribs[attrib]=GLGE.Message.parseMessage(attribs[attrib]); + } + obj["set"+attrib](attribs[attrib]); + } + } + } + return this; +} +/** +* @function parses the children to add +* @private +*/ +GLGE.Message.addChildren=function(obj,children){ + if(!(children instanceof Array)) children=[children]; + for(var i=0;i<children.length;i++){ + if(children[i].command){ + var asset=GLGE.Message.parseMessage(children[i]); + }else{ + var asset=GLGE.Assets.get(children[i]); + } + obj["add"+asset.className](asset); + } +} +/** +* @function parses the children to remove +* @private +*/ +GLGE.Message.removeChildren=function(obj,children){ + if(!(children instanceof Array)) children=[children]; + for(var i=0;i<children.length;i++){ + var asset=GLGE.Assets.get(children[i]); + obj["add"+asset.className](asset); + } +} + +GLGE.Message.toLoad=[]; +GLGE.Message.messageLoader=function(url,callback,priority){ + GLGE.Message.toLoad.push([url,callback,priority]); + if(GLGE.Message.toLoad.length==1) GLGE.Message.loadMessages(); +} +GLGE.Message.loadMessages=function(){ + //TODO: use priority + var nextDoc=GLGE.Message.toLoad.pop(); + var req=new XMLHttpRequest(); + req.onreadystatechange = function() { + if(this.readyState == 4){ + if(this.status == 200 || this.status==0){ + nextDoc[1](this.responseText); + }else{ + GLGE.error("Error loading Document: "+nextDoc[0]+" status "+this.status); + } + } + } + req.open("GET", nextDoc[0], true); + req.send(""); + if(GLGE.Message.toLoad.length>0) 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;i<events.length;i++){ + events[i].call(this,data); + } + } +} +/** +* Adds an event listener +* @param {string} event The name of the event to listen for +* @param {function} fn the event callback +**/ +GLGE.Events.prototype.addEventListener=function(event,fn){ + if(!this.events) this.events={}; + if(!this.events[event]) this.events[event]=[]; + this.events[event].push(fn); +} +/** +* Removes an event listener +* @param {function} fn the event callback to remove +**/ +GLGE.Events.prototype.removeEventListener=function(event,fn){ + var idx=this.events[event].indexOf(fn); + if(idx!=-1) this.events[event].splice(idx,1); +} + +/** +* @class Document class to load scene, object, mesh etc from an external XML file +* @param {string} url URL of the resource to load +*/ +GLGE.Document=function(){ + this.listeners=[]; + this.documents=[]; +} +GLGE.Document.prototype.listeners=null; +GLGE.Document.prototype.documents=null; +GLGE.Document.prototype.rootURL=null; +GLGE.Document.prototype.loadCount=0; +/** +* This is just a fix for a bug in webkit +* @param {string} id the id name to get +* @returns {object} node with teh specified id +* @private +*/ +GLGE.Document.prototype.getElementById=function(id){ + var tags=this.getElementsByTagName("*"); + for(var i=0; i<tags.length;i++){ + if(tags[i].getAttribute("id")==id){ + return tags[i]; + break; + } + } + return null; +} +/** +* Gets the absolute path given an import path and the path it's relative to +* @param {string} path the path to get the absolute path for +* @param {string} relativeto the path the supplied path is relativeto +* @returns {string} absolute path +* @private +*/ +GLGE.Document.prototype.getAbsolutePath=function(path,relativeto){ + if(path.substr(0,7)=="http://" || path.substr(0,7)=="file://" || path.substr(0,7)=="https://"){ + return path; + } + else + { + if(!relativeto){ + relativeto=window.location.href; + } + //find the path compoents + var bits=relativeto.split("/"); + var domain=bits[2]; + var proto=bits[0]; + var initpath=[]; + for(var i=3;i<bits.length-1;i++){ + initpath.push(bits[i]); + } + //relative to domain + if(path.substr(0,1)=="/"){ + initpath=[]; + } + var locpath=path.split("/"); + for(i=0;i<locpath.length;i++){ + if(locpath[i]=="..") initpath.pop(); + else if(locpath[i]!="") initpath.push(locpath[i]); + } + return proto+"//"+domain+"/"+initpath.join("/"); + } +} +/** +* Loads the root document +* @param {string} url URL of the resource to load +*/ +GLGE.Document.prototype.load=function(url){ + this.documents=[]; + this.rootURL=url; + this.loadDocument(url,null); +} +/** +* Loads an additional documents into the collection +* @param {string} url URL of the resource to load +* @param {string} relativeto the path the URL is relative to, null for default +*/ +GLGE.Document.prototype.loadDocument=function(url,relativeto){ + this.loadCount++; + url=this.getAbsolutePath(url,relativeto); + var req = new XMLHttpRequest(); + if(req) { + req.docurl=url; + req.docObj=this; + req.overrideMimeType("text/xml"); + req.onreadystatechange = function() { + if(this.readyState == 4) + { + if(this.status == 200 || this.status==0){ + this.responseXML.getElementById=this.docObj.getElementById; + this.docObj.loaded(this.docurl,this.responseXML); + }else{ + GLGE.error("Error loading Document: "+this.docurl+" status "+this.status); + } + } + }; + req.open("GET", url, true); + req.send(""); + } +} +/** +* Trigered when a document has finished loading +* @param {string} url the absolute url of the document that has loaded +* @param {XMLDoc} responceXML the xml document that has finished loading +* @private +*/ +GLGE.Document.prototype.loaded=function(url,responceXML){ + this.loadCount--; + this.documents[url]={xml:responceXML}; + var imports=responceXML.getElementsByTagName("import"); + for(var i=0; i<imports.length;i++){ + if(!this.documents[this.getAbsolutePath(imports[i].getAttribute("url"),url)]){ + this.documents[this.getAbsolutePath(imports[i].getAttribute("url"),url)]={}; + this.loadDocument(imports[i].getAttribute("url"),url); + } + } + if(this.loadCount==0){ + this.finishedLoading(); + } +} +/** +* Called when all documents have finished loading +* @private +*/ +GLGE.Document.prototype.finishedLoading=function(){ + for(var i=0; i<this.listeners.length;i++){ + this.listeners[i](this.listeners.rootURL); + } + this["onLoad"](); +} +/** +* Called when all documents have finished loading +* @event +*/ +GLGE.Document.prototype["onLoad"]=function(){}; +/** +* Converts and attribute name into a class name +* @param {string} name attribute name to convert +* @private +*/ +GLGE.Document.prototype.classString=function(name){ + if(!name) return false; + var names=name.split("_"); + var converted=""; + for(var i=0;i<names.length;i++){ + converted=converted+names[i][0].toUpperCase()+names[i].substr(1); + } + return converted; +} +/** +* Sets the properties of an object based on the attributes of the corresponding dom element +* @param {object} Obj the DOM element to apply the attributes of +* @private +*/ +GLGE.Document.prototype.setProperties=function(Obj){ + var set_method; + var attribute_name; + var value; + for(var i=0; i<Obj.attributes.length; i++){ + value=false; + set_method="set"+this.classString(Obj.attributes[i].nodeName); + + if(Obj.attributes[i].value[0]=="#"){ + value=this.getElement(Obj.attributes[i].value.substr(1),true); + } + if(!value){ + //if this is a GLGE contsant then set the constant value otherwise just literal + if(typeof(GLGE[Obj.attributes[i].value]) != "undefined"){ + value=GLGE[Obj.attributes[i].value]; + } + else + { + value=Obj.attributes[i].value; + } + } + + if(Obj.object[set_method]) Obj.object[set_method](value); + //if a uid is set in the xml doc then make sure it's registered correctly in the assets + if(Obj.attributes[i].nodeName=="uid"){ + GLGE.Assets.unregisterAsset(Obj.object.uid); + Obj.object.uid=Obj.attributes[i].value; + GLGE.Assets.registerAsset(Obj.object,Obj.attributes[i].value); + } + } +} +/** +* Adds child objects +* @param {object} Obj the DOM element to apply the children of +* @private +*/ +GLGE.Document.prototype.addChildren=function(Obj){ + //loop though and add the children + var add_method; + var child=Obj.firstChild; + while(child){ + add_method="add"+this.classString(child.tagName); + if(Obj.object[add_method]) Obj.object[add_method](this.getElement(child)); + child=child.nextSibling; + } +} +/** +* Gets an object from the XML document based on the dom element +* @param {string|domelement} ele the id of the element to get or the dom node +*/ +GLGE.Document.prototype.getElement=function(ele,noerrors){ + var docele,doc; + if(typeof(ele)=="string"){ + for(doc in this.documents){ + if(this.documents[doc].xml){ + docele=this.documents[doc].xml.getElementById(ele); + if(docele){ + ele=docele; + break; + } + } + } + } + if(typeof(ele)=="string"){ + //if element is still a string at this point there there is an issue + if(!noerrors) GLGE.error("Element "+ele+" not found in document"); + return false; + } + else + { + if(this["get"+this.classString(ele.tagName)]){ + return this["get"+this.classString(ele.tagName)](ele); + } + else + { + return this.getDefault(ele); + } + } +} +/** +* Parses the dom element and creates any objects that are required +* @param {domelement} ele the element to create the objects from +* @private +*/ +GLGE.Document.prototype.getDefault=function(ele){ + if(!ele.object){ + if(GLGE[this.classString(ele.tagName)]){ + ele.object=new GLGE[this.classString(ele.tagName)](); + this.setProperties(ele); + this.addChildren(ele); + } + else + { + GLGE.error("XML Parse Error: GLGE Object not found"); + } + } + return ele.object; +} +/** +* Parses the dom element and creates a texture +* @param {domelement} ele the element to create the objects from +* @private +*/ +GLGE.Document.prototype.getTexture=function(ele){ + if(!ele.object){ + var rel=this.getAbsolutePath(this.rootURL,null); + ele.object=new GLGE[this.classString(ele.tagName)]; + ele.object.setSrc(this.getAbsolutePath(ele.getAttribute("src"),rel)); + ele.removeAttribute("src"); + this.setProperties(ele); + } + return ele.object; +} +GLGE.Document.prototype.getTextureVideo=GLGE.Document.prototype.getTexture; + +/** +* Parses a document node into an array +* @param {node} the node to parse +* @private +*/ +GLGE.Document.prototype.parseArray=function(node){ + var child=node.firstChild; + var prev=""; + var output=[]; + var currentArray; + var i; + while(child){ + currentArray=(prev+child.nodeValue).split(","); + child=child.nextSibling; + if(currentArray[0]=="") currentArray.unshift(); + if(child) prev=currentArray.pop(); + for(i=0;i<currentArray.length;i++) output.push(currentArray[i]); + } + return output; +} + +/** +* Parses the mesh dom to create the mesh object +* @param {domelement} ele the element to create the mesh from +* @private +*/ +GLGE.Document.prototype.getMesh=function(ele){ + 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;i<names.length;i++){ + if(names[i].substr(0,1)=="#"){ + jointObjects.push(this.getElement(names[i].substr(1))); + }else{ + jointObjects.push(names[i]); + } + } + ele.object.setJoints(jointObjects); + break; + case "bind_matrix": + var mats=this.parseArray(child); + var invBind=[]; + for(var i=0;i<mats.length;i++){ + invBind.push(GLGE.Mat4(mats[i].split(" "))); + } + ele.object.setInvBindMatrix(invBind); + break; + case "joints": + ele.object.setVertexJoints(this.parseArray(child),child.getAttribute("count")); + break; + case "weights": + ele.object.setVertexWeights(this.parseArray(child),child.getAttribute("count")); + break; + } + child=child.nextSibling; + } + } + return ele.object; +} + +/** +* Adds a listener to be called when all documents have finished loading +* @param {function} listener the function to call when all loading in complete +*/ +GLGE.Document.prototype.addLoadListener=function(listener){ + this.listeners.append(listener); +} +/** +* Removes a load listener +* @param {function} listener Listener to remove +*/ +GLGE.Document.prototype.removeLoadListener=function(listener){ + for(var i=0; i<this.listeners.length; i++){ + if(this.listeners[i]===listener) this.listeners.splice(i,1); + } +} + +/** +* loads xml from a script tag +* @param {string} id the id of the element to load +*/ +GLGE.Document.prototype.parseScript=function(id){ + this.rootURL=window.location.toString(); + var xmlScript = document.getElementById(id); + if (!xmlScript) { + return null; + } + + var str = ""; + var k = xmlScript.firstChild; + while (k) { + if (k.nodeType == 3) { + str += k.textContent; + } + k = k.nextSibling; + } + + var parser=new DOMParser(); + var xmlDoc=parser.parseFromString(str,"text/xml"); + xmlDoc.getElementById=this.getElementById; + + this.documents["#"+id]={xml:xmlDoc}; + + var imports=xmlDoc.getElementsByTagName("import"); + for(var i=0; i<imports.length;i++){ + if(!this.documents[this.getAbsolutePath(imports[i].getAttribute("url"),url)]){ + this.documents[this.getAbsolutePath(imports[i].getAttribute("url"),url)]={}; + this.loadDocument(imports[i].getAttribute("url")); + } + } + if(this.loadCount==0){ + this.finishedLoading(); + } +} + + + +/** +* @class Abstract class to agument objects that requires position, rotation and scale. +*/ +GLGE.Placeable=function(){ +} +GLGE.Placeable.prototype.locX=0; +GLGE.Placeable.prototype.locY=0; +GLGE.Placeable.prototype.locZ=0; +GLGE.Placeable.prototype.dLocX=0; +GLGE.Placeable.prototype.dLocY=0; +GLGE.Placeable.prototype.dLocZ=0; +GLGE.Placeable.prototype.quatX=0; +GLGE.Placeable.prototype.quatY=0; +GLGE.Placeable.prototype.quatZ=0; +GLGE.Placeable.prototype.quatW=0; +GLGE.Placeable.prototype.rotX=0; +GLGE.Placeable.prototype.rotY=0; +GLGE.Placeable.prototype.rotZ=0; +GLGE.Placeable.prototype.dRotX=0; +GLGE.Placeable.prototype.dRotY=0; +GLGE.Placeable.prototype.dRotZ=0; +GLGE.Placeable.prototype.scaleX=1; +GLGE.Placeable.prototype.scaleY=1; +GLGE.Placeable.prototype.scaleZ=1; +GLGE.Placeable.prototype.dScaleX=0; +GLGE.Placeable.prototype.dScaleY=0; +GLGE.Placeable.prototype.dScaleZ=0; +GLGE.Placeable.prototype.matrix=null; +GLGE.Placeable.prototype.rotOrder=GLGE.ROT_XYZ; +GLGE.Placeable.prototype.lookAt=null; +GLGE.Placeable.prototype.mode=GLGE.P_EULER; + + + +/** +* Gets the root node object +* @returns {object} +*/ +GLGE.Placeable.prototype.getRoot=function(){ + if(this.type==GLGE.G_ROOT){ + return this; + }else if(this.parent){ |