aboutsummaryrefslogtreecommitdiff
path: root/demos/webgl/glge.js
diff options
context:
space:
mode:
authorAlon Zakai <azakai@mozilla.com>2010-11-07 16:07:47 -0800
committerAlon Zakai <azakai@mozilla.com>2010-11-07 16:07:47 -0800
commit98a9576c6e3c357960bd7741f9e0ad964f206e29 (patch)
treea12dd6801c7fce111584a8c18cf1692c7a731c68 /demos/webgl/glge.js
parent54b3d3ec052aac293524da742000167cd0be5067 (diff)
wip bullet/webgl demo
Diffstat (limited to 'demos/webgl/glge.js')
-rw-r--r--demos/webgl/glge.js7883
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){