1 /*
  2 GLGE WebGL Graphics Engine
  3 Copyright (C)2009  Paul Brunt
  4 
  5 This library is free software; you can redistribute it and/or
  6 modify it under the terms of the GNU Lesser General Public
  7 License as published by the Free Software Foundation; either
  8 version 2.1 of the License, or (at your option) any later version.
  9 
 10 This library is distributed in the hope that it will be useful,
 11 but WITHOUT ANY WARRANTY; without even the implied warranty of
 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 13 Lesser General Public License for more details.
 14 
 15 You should have received a copy of the GNU Lesser General Public
 16 License along with this library; if not, write to the Free Software
 17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 18 */
 19 
 20 /**
 21  * @fileOverview
 22  * @name glge.js
 23  * @author paul.brunt@armourhome.co.uk
 24  */
 25 
 26 // Start of compatibility code
 27   try
 28   {
 29     WebGLFloatArray;
 30   }
 31   catch (e)
 32   {
 33     try
 34     {
 35       WebGLFloatArray = CanvasFloatArray;
 36       WebGLUnsignedShortArray = CanvasUnsignedShortArray;
 37     }
 38     catch (e)
 39     {
 40       alert("Could not find any WebGL array types.");
 41     }
 42   }
 43   // End of compatibility code
 44 
 45  
 46 /**
 47 * @namespace Holds the functionality of the library
 48 */
 49 var GLGE={};
 50 
 51 (function(GLGE){
 52 
 53 
 54 
 55 /**
 56 * @constant 
 57 * @description Enumeration for TRUE
 58 */
 59 GLGE.TRUE=1;
 60 /**
 61 * @constant 
 62 * @description Enumeration for FALSE
 63 */
 64 GLGE.FALSE=0;
 65 
 66 /**
 67 * @class Document class to load scene, object, mesh etc from an external XML file 
 68 * @param {string} url URL of the resource to load
 69 */
 70 GLGE.Document=function(url){
 71 	this.listeners=[];
 72 	this.documents=[];
 73 	this.rootURL=url;
 74 	this.loadDocument(url,null);
 75 }
 76 GLGE.Document.prototype.listeners=null;
 77 GLGE.Document.prototype.documents=null;
 78 GLGE.Document.prototype.rootURL=null;
 79 GLGE.Document.prototype.loadCount=0;
 80 /**
 81 * Gets the absolute path given an import path and the path it's relative to
 82 * @param {string} path the path to get the absolute path for
 83 * @param {string} relativeto the path the supplied path is relativeto
 84 * @returns {string} absolute path
 85 * @private
 86 */
 87 GLGE.Document.prototype.getAbsolutePath=function(path,relativeto){
 88 	if(path.substr(0,7)=="http://"){
 89 		return path;
 90 	}
 91 	else
 92 	{
 93 		if(!relativeto){
 94 			relativeto=window.location.href;
 95 		}
 96 		//find the path compoents
 97 		var bits=relativeto.split("/");
 98 		var domain=bits[2];
 99 		var initpath=[];
100 		for(var i=3;i<bits.length-1;i++){
101 			initpath.push(bits[i]);
102 		}
103 		//relative to domain
104 		if(path.substr(0,1)=="/"){
105 			initpath=[];
106 		}
107 		var locpath=path.split("/");
108 		for(i=0;i<locpath.length;i++){
109 			if(locpath[i]=="..") initpath.pop();
110 				else if(locpath[i]!="") initpath.push(locpath[i]);
111 		}
112 		return "http://"+domain+"/"+initpath.join("/");
113 	}
114 }
115 /**
116 * Loads an additional documents into the collection
117 * @param {string} url URL of the resource to load
118 * @param {string} relativeto the path the URL is relative to, null for default
119 */
120 GLGE.Document.prototype.loadDocument=function(url,relativeto){
121 	this.loadCount++;
122 	url=this.getAbsolutePath(url,relativeto);
123 	var req = new XMLHttpRequest();
124 	if(req) {
125 		req.docurl=url;
126 		req.docObj=this;
127 		req.onreadystatechange = function() {
128 			if(this.readyState  == 4)
129 			{
130 				if(this.status  == 200){
131 					this.docObj.loaded(this.docurl,this.responseXML);
132 				}else{ 
133 					GLGE.error("Error loading Document: "+this.docurl);
134 				}
135 			}
136 		};
137 		req.open("GET", url, true);
138 		req.send("");
139 	}	
140 }
141 /**
142 * Trigered when a document has finished loading
143 * @param {string} url the absolute url of the document that has loaded
144 * @param {XMLDoc} responceXML the xml document that has finished loading
145 * @private
146 */
147 GLGE.Document.prototype.loaded=function(url,responceXML){
148 	this.loadCount--;
149 	this.documents[url]={xml:responceXML};
150 	var imports=responceXML.getElementsByTagName("import");
151 	for(var i=0; i<imports.length;i++){
152 		if(!this.documents[this.getAbsolutePath(imports[i].getAttribute("url"),url)]){
153 			this.documents[this.getAbsolutePath(imports[i].getAttribute("url"),url)]={};
154 			this.loadDocument(imports[i].getAttribute("url"),url);
155 		}
156 	}
157 	if(this.loadCount==0){
158 		this.finishedLoading();
159 	}
160 }
161 /**
162 * Called when all documents have finished loading
163 * @private
164 */
165 GLGE.Document.prototype.finishedLoading=function(){
166 	for(var i=0; i<this.listeners.length;i++){
167 		this.listeners[i](this.listeners.rootURL);
168 	}
169 	this.onLoad();
170 }
171 /**
172 * Called when all documents have finished loading
173 * @event
174 */
175 GLGE.Document.prototype.onLoad=function(){};
176 /**
177 * Converts and attribute name into a class name
178 * @param {string} name attribute name to convert
179 * @private
180 */
181 GLGE.Document.prototype.classString=function(name){
182 	if(!name) return false;
183 	var names=name.split("_");
184 	var converted="";
185 	for(var i=0;i<names.length;i++){
186 		converted=converted+names[i][0].toUpperCase()+names[i].substr(1);
187 	}
188 	return converted;
189 }
190 /**
191 * Sets the properties of an object based on the attributes of the corresponding dom element
192 * @param {object} Obj the DOM element to apply the attributes of
193 * @private
194 */
195 GLGE.Document.prototype.setProperties=function(Obj){
196 	var set_method;
197 	var attribute_name;
198 	var value;
199 	for(var i=0; i<Obj.attributes.length; i++){
200 		set_method="set"+this.classString(Obj.attributes[i].nodeName);
201 		if(Obj.attributes[i].value[0]=="#"){
202 			value=this.getElement(Obj.attributes[i].value.substr(1));
203 		}
204 		else
205 		{
206 			//if this is a GLGE contsant then set the constant value otherwise just literal
207 			if(typeof(GLGE[Obj.attributes[i].value]) != "undefined"){
208 				value=GLGE[Obj.attributes[i].value];
209 			}
210 			else
211 			{
212 				value=Obj.attributes[i].value;
213 			}
214 		}
215 		if(Obj.object[set_method]) Obj.object[set_method](value);
216 	}
217 }
218 /**
219 * Adds child objects 
220 * @param {object} Obj the DOM element to apply the children of
221 * @private
222 */
223 GLGE.Document.prototype.addChildren=function(Obj){
224 	//loop though and add the children
225 	var add_method;
226 	var child=Obj.firstChild;
227 	while(child){
228 		add_method="add"+this.classString(child.tagName);
229 		if(Obj.object[add_method]) Obj.object[add_method](this.getElement(child));
230 		child=child.nextSibling;
231 	}
232 }
233 /**
234 * Gets an object from the XML document based on the dom element 
235 * @param {string|domelement} ele the id of the element to get or the dom node
236 */
237 GLGE.Document.prototype.getElement=function(ele){
238 	var docele,doc;
239 	if(typeof(ele)=="string"){
240 		for(doc in this.documents){
241 			if(this.documents[doc].xml){
242 				docele=this.documents[doc].xml.getElementById(ele);
243 				if(docele){
244 					ele=docele;
245 					break;
246 				}
247 			}
248 		}
249 	}
250 	if(typeof(ele)=="string"){
251 		//if element is still a string at this point there there is an issue
252 		GLGE.error("Element "+ele+" not found in document");
253 		return false;
254 	}
255 	else
256 	{
257 		if(this["get"+this.classString(ele.tagName)]){
258 			return this["get"+this.classString(ele.tagName)](ele);
259 		}
260 		else
261 		{
262 			return this.getDefault(ele);
263 		}
264 	}
265 }
266 /**
267 * Parses the dom element and creates any objects that are required
268 * @param {domelement} ele the element to create the objects from
269 * @private
270 */
271 GLGE.Document.prototype.getDefault=function(ele){
272 	if(!ele.object){
273 		if(GLGE[this.classString(ele.tagName)]){
274 			ele.object=new GLGE[this.classString(ele.tagName)]();
275 			this.setProperties(ele);
276 			this.addChildren(ele);
277 		}
278 		else
279 		{
280 			GLGE.error("XML Parse Error: GLGE Object not found"); 
281 		}
282 	}
283 	return ele.object;
284 }
285 /**
286 * Parses the dom element and creates a texture
287 * @param {domelement} ele the element to create the objects from
288 * @private
289 */
290 GLGE.Document.prototype.getTexture=function(ele){
291 	if(!ele.object){
292 		var rel=this.getAbsolutePath(this.rootURL,null);
293 		ele.object=new GLGE.Texture(this.getAbsolutePath(ele.getAttribute("src"),rel));
294 	}
295 	return ele.object;
296 }
297 /**
298 * Parses a document node into an array
299 * @param {node} the node to parse
300 * @private
301 */
302 GLGE.Document.prototype.parseArray=function(node){
303 	var child=node.firstChild;
304 	var prev="";
305 	var output=[];
306 	var currentArray;
307 	while(child){
308 		currentArray=(prev+child.nodeValue).split(",");
309 		child=child.nextSibling;
310 		if(currentArray[0]=="") currentArray.unshift();
311 		if(child) prev=currentArray.pop();
312 		output=output.concat(currentArray);
313 	}
314 	return output;
315 }
316 /**
317 * Parses the skeleton to create the object
318 * @param {domelement} ele the element to create the skeleton
319 * @private
320 */
321 GLGE.Document.prototype.getSkeleton=function(ele){
322 	if(!ele.object){
323 		ele.object=new GLGE.Skeleton();
324 		this.setProperties(ele);
325 		var child=ele.firstChild;
326 		while(child){
327 			switch(child.tagName){
328 				case "bone":
329 					ele.object.addBone(new GLGE.Bone(child.getAttribute("channel"),child.getAttribute("x"),child.getAttribute("y"),child.getAttribute("z")),child.getAttribute("parent"));
330 					break;
331 			}
332 			child=child.nextSibling;
333 		}
334 	}
335 	return ele.object;
336 }
337 /**
338 * Parses the skeletal animation to create the object
339 * @param {domelement} ele the element to create the skeletal animation from
340 * @private
341 */
342 GLGE.Document.prototype.getSkeletalAction=function(ele){
343 	if(!ele.object){
344 		ele.object=new GLGE.SkeletalAction(ele.getAttribute("frames"));
345 		this.setProperties(ele);
346 		var child=ele.firstChild;
347 		while(child){
348 			switch(child.tagName){
349 				case "animation":
350 					ele.object.addAnimationVector(child.getAttribute("channel"),this.getElement(child.getAttribute("vector").substr(1)));
351 					break;
352 			}
353 			child=child.nextSibling;
354 		}
355 	}
356 	return ele.object;
357 }
358 /**
359 * Parses the mesh dom to create the mesh object
360 * @param {domelement} ele the element to create the mesh from
361 * @private
362 */
363 GLGE.Document.prototype.getMesh=function(ele){
364 	if(!ele.object){
365 		ele.object=new GLGE.Mesh();
366 		this.setProperties(ele);
367 		child=ele.firstChild;
368 		while(child){
369 			switch(child.tagName){
370 				case "positions":
371 					ele.object.setPositions(this.parseArray(child));
372 					break;
373 				case "normals":
374 					ele.object.setNormals(this.parseArray(child));
375 					break;				
376 				case "uv1":
377 					ele.object.setUV(this.parseArray(child));
378 					break;
379 				case "faces":
380 					ele.object.setFaces(this.parseArray(child));
381 					break;
382 				case "weights":
383 					ele.object.addBoneWeights(child.getAttribute("channel"),this.parseArray(child));
384 					break;
385 			}
386 			child=child.nextSibling;
387 		}
388 	}
389 	return ele.object;
390 }
391 /**
392 * Parese the animation vector dom to create the mesh object
393 * @param {domelement} ele the element to create the animation vector from
394 * @private
395 */
396 GLGE.Document.prototype.getAnimationVector=function(ele){
397 	if(!ele.object){
398 		ele.object=new GLGE.AnimationVector();
399 		this.setProperties(ele);
400 		child=ele.firstChild;
401 		var point;
402 		var curve;
403 		while(child){
404 			switch(child.tagName){
405 				case "animation_curve":
406 					curve=new GLGE.AnimationCurve();
407 					bezs=child.getElementsByTagName("bez_point");
408 					for(var i=0; i<bezs.length;i++){
409 						point=bezs[i].firstChild.nodeValue.split(",");
410 						curve.addPoint(new GLGE.BezTriple(point[0],point[1],point[2],point[3],point[4],point[5],point[6]));
411 					}
412 					ele.object.addCurve(child.getAttribute("channel"),curve);
413 					
414 					break;
415 			}
416 			child=child.nextSibling;
417 		}
418 	}
419 	return ele.object;
420 }
421 
422 /**
423 * Adds a listener to be called when all documents have finished loading
424 * @param {function} listener the function to call when all loading in complete
425 */
426 GLGE.Document.prototype.addLoadListener=function(listener){
427 	this.listeners.append(listener);
428 }
429 /**
430 * Removes a load listener
431 * @param {function} listener Listener to remove
432 */
433 GLGE.Document.prototype.removeLoadListener=function(listener){
434 	for(var i=0; i<this.listeners.length; i++){
435 		if(this.listeners[i]===listener) this.listeners.splice(i,1);
436 	}
437 }
438 
439 
440 
441 
442 /**
443 * @class Abstract class to agument objects that requires position, rotation and scale.
444 */
445 GLGE.Placeable=function(){
446 	this.matrix=$M.I(4);
447 }
448 GLGE.Placeable.prototype.locX=0;
449 GLGE.Placeable.prototype.locY=0;
450 GLGE.Placeable.prototype.locZ=0;
451 GLGE.Placeable.prototype.dLocX=0;
452 GLGE.Placeable.prototype.dLocY=0;
453 GLGE.Placeable.prototype.dLocZ=0;
454 GLGE.Placeable.prototype.rotX=0;
455 GLGE.Placeable.prototype.rotY=0;
456 GLGE.Placeable.prototype.rotZ=0;
457 GLGE.Placeable.prototype.dRotX=0;
458 GLGE.Placeable.prototype.dRotY=0;
459 GLGE.Placeable.prototype.dRotZ=0;
460 GLGE.Placeable.prototype.scaleX=1;
461 GLGE.Placeable.prototype.scaleY=1;
462 GLGE.Placeable.prototype.scaleZ=1;
463 GLGE.Placeable.prototype.dScaleX=0;
464 GLGE.Placeable.prototype.dScaleY=0;
465 GLGE.Placeable.prototype.dScaleZ=0;
466 GLGE.Placeable.prototype.matrix=null;
467 /**
468 * Gets the rotaion matrix 
469 * @returns {matrix} the objects rotation matrix
470 */
471 GLGE.Placeable.prototype.getRotMatrix=function(){
472 	return $M([
473 		[this.matrix.e(1,1),this.matrix.e(1,2),this.matrix.e(1,3)],
474 		[this.matrix.e(2,1),this.matrix.e(2,2),this.matrix.e(2,3)],
475 		[this.matrix.e(3,1),this.matrix.e(3,2),this.matrix.e(3,3)]]);
476 }
477 /**
478 * Sets the x location of the object
479 * @param {number} value The value to assign to the x position
480 */
481 GLGE.Placeable.prototype.setLocX=function(value){this.locX=value; this.updateMatrix();}
482 /**
483 * Sets the y location of the object
484 * @param {number} value The value to assign to the y position
485 */
486 GLGE.Placeable.prototype.setLocY=function(value){this.locY=value;this.updateMatrix();}
487 /**
488 * Sets the z location of the object
489 * @param {number} value The value to assign to the z position
490 */
491 GLGE.Placeable.prototype.setLocZ=function(value){this.locZ=value;this.updateMatrix();}
492 /**
493 * Sets the location of the object
494 * @param {number} x The value to assign to the x position
495 * @param {number} y The value to assign to the y position
496 * @param {number} z The value to assign to the z position
497 */
498 GLGE.Placeable.prototype.setLoc=function(x,y,z){this.locX=x;this.locY=y;this.locZ=z;this.updateMatrix();}
499 /**
500 * Sets the x location displacement of the object, usefull for animation
501 * @param {number} value The value to assign to the x displacement
502 */
503 GLGE.Placeable.prototype.setDLocX=function(value){this.dLocX=value;this.updateMatrix();}
504 /**
505 * Sets the y location displacement of the object, usefull for animation
506 * @param {number} value The value to assign to the y displacement
507 */
508 GLGE.Placeable.prototype.setDLocY=function(value){this.dLocY=value;this.updateMatrix();}
509 /**
510 * Sets the z location displacement of the object, usefull for animation
511 * @param {number} value The value to assign to the z displacement
512 */
513 GLGE.Placeable.prototype.setDLocZ=function(value){this.dLocZ=value;this.updateMatrix();}
514 /**
515 * Sets the location displacement of the object, useful for animation
516 * @param {number} x The value to assign to the x position
517 * @param {number} y The value to assign to the y position
518 * @param {number} z The value to assign to the z position
519 */
520 GLGE.Placeable.prototype.setDLoc=function(x,y,z){this.dLocX=x;this.dLocY=y;this.dLocZ=z;this.updateMatrix();}
521 /**
522 * Sets the x rotation of the object
523 * @param {number} value The value to assign to the x rotation
524 */
525 GLGE.Placeable.prototype.setRotX=function(value){this.rotX=value;this.updateMatrix();}
526 /**
527 * Sets the y rotation of the object
528 * @param {number} value The value to assign to the y rotation
529 */
530 GLGE.Placeable.prototype.setRotY=function(value){this.rotY=value;this.updateMatrix();}
531 /**
532 * Sets the z rotation of the object
533 * @param {number} value The value to assign to the z rotation
534 */
535 GLGE.Placeable.prototype.setRotZ=function(value){this.rotZ=value;this.updateMatrix();}
536 /**
537 * Sets the rotation of the object
538 * @param {number} x The value to assign to the x rotation
539 * @param {number} y The value to assign to the y rotation
540 * @param {number} z The value to assign to the z rotation
541 */
542 GLGE.Placeable.prototype.setRot=function(x,y,z){this.rotX=x;this.rotY=y;this.rotZ=z;this.updateMatrix();}
543 /**
544 * Sets the x rotation displacement of the object, usefull for animation
545 * @param {number} value The value to assign to the x displacement
546 */
547 GLGE.Placeable.prototype.setDRotX=function(value){this.dRotX=value;this.updateMatrix();}
548 /**
549 * Sets the y rotation displacement of the object, usefull for animation
550 * @param {number} value The value to assign to the y displacement
551 */
552 GLGE.Placeable.prototype.setDRotY=function(value){this.dRotY=value;this.updateMatrix();}
553 /**
554 * Sets the z rotation displacement of the object, usefull for animation
555 * @param {number} value The value to assign to the z displacement
556 */
557 GLGE.Placeable.prototype.setDRotZ=function(value){this.dRotZ=value;this.updateMatrix();}
558 /**
559 * Sets the rotation displacement of the object, useful for animation
560 * @param {number} x The value to assign to the x rotation
561 * @param {number} y The value to assign to the y rotation
562 * @param {number} z The value to assign to the z rotation
563 */
564 GLGE.Placeable.prototype.setDRot=function(x,y,z){this.dRotX=x;this.dRotY=y;this.dRotZ=z;this.updateMatrix();}
565 /**
566 * Sets the x scale of the object
567 * @param {number} value The value to assign to the x scale
568 */
569 GLGE.Placeable.prototype.setScaleX=function(value){this.scaleX=value;this.updateMatrix();}
570 /**
571 * Sets the y scale of the object
572 * @param {number} value The value to assign to the y scale
573 */
574 GLGE.Placeable.prototype.setScaleY=function(value){this.scaleY=value;this.updateMatrix();}
575 /**
576 * Sets the z scale of the object
577 * @param {number} value The value to assign to the z scale
578 */
579 GLGE.Placeable.prototype.setScaleZ=function(value){this.scaleZ=value;this.updateMatrix();}
580 /**
581 * Sets the scale of the object
582 * @param {number} x The value to assign to the x scale
583 * @param {number} y The value to assign to the y scale
584 * @param {number} z The value to assign to the z scale
585 */
586 GLGE.Placeable.prototype.setScale=function(x,y,z){this.scaleX=x;this.scaleY=y;this.scaleZ=z;this.updateMatrix();}
587 /**
588 * Sets the x scale displacement of the object, usefull for animation
589 * @param {number} value The value to assign to the x displacement
590 */
591 GLGE.Placeable.prototype.setDScaleX=function(value){this.dScaleX=value;this.updateMatrix();}
592 /**
593 * Sets the y scale displacement of the object, usefull for animation
594 * @param {number} value The value to assign to the y displacement
595 */
596 GLGE.Placeable.prototype.setDScaleY=function(value){this.dScaleY=value;this.updateMatrix();}
597 /**
598 * Sets the z scale displacement of the object, usefull for animation
599 * @param {number} value The value to assign to the z displacement
600 */
601 GLGE.Placeable.prototype.setDScaleZ=function(value){this.dScaleZ=value;this.updateMatrix();}
602 /**
603 * Sets the scale displacement of the object, useful for animation
604 * @param {number} x The value to assign to the x scale
605 * @param {number} y The value to assign to the y scale
606 * @param {number} z The value to assign to the z scale
607 */
608 GLGE.Placeable.prototype.setDScale=function(x,y,z){this.dScaleX=x;this.dScaleY=y;this.dScaleZ=z;this.updateMatrix();}
609 /**
610 * Gets the x location of the object
611 * @returns {number}
612 */
613 GLGE.Placeable.prototype.getLocX=function(){return this.locX;}
614 /**
615 * Gets the y location of the object
616 * @returns {number}
617 */
618 GLGE.Placeable.prototype.getLocY=function(){return this.locY;}
619 /**
620 * Gets the z location of the object
621 * @returns {number}
622 */
623 GLGE.Placeable.prototype.getLocZ=function(){return this.locZ;}
624 /**
625 * Gets the x location displacement of the object
626 * @returns {number}
627 */
628 GLGE.Placeable.prototype.getDLocX=function(){return this.dLocX;}
629 /**
630 * Gets the y location displacement of the object
631 * @returns {number}
632 */
633 GLGE.Placeable.prototype.getDLocY=function(){return this.dLocY;}
634 /**
635 * Gets the z location displacement of the object
636 * @returns {number}
637 */
638 GLGE.Placeable.prototype.getDLocZ=function(){return this.dLocZ;}
639 /**
640 * Gets the x rotation of the object
641 * @returns {number}
642 */
643 GLGE.Placeable.prototype.getRotX=function(){return this.rotX;}
644 /**
645 * Gets the y rotation of the object
646 * @returns {number}
647 */
648 GLGE.Placeable.prototype.getRotY=function(){return this.rotY;}
649 /**
650 * Gets the z rotation of the object
651 * @returns {number}
652 */
653 GLGE.Placeable.prototype.getRotZ=function(){return this.rotZ;}
654 /**
655 * Gets the x rotaional displacement of the object
656 * @returns {number}
657 */
658 GLGE.Placeable.prototype.getDRotX=function(){return this.dRotX;}
659 /**
660 * Gets the y rotaional displacement of the object
661 * @returns {number}
662 */
663 GLGE.Placeable.prototype.getDRotY=function(){return this.dRotY;}
664 /**
665 * Gets the z rotaional displacement of the object
666 * @returns {number}
667 */
668 GLGE.Placeable.prototype.getDRotZ=function(){return this.dRotZ;}
669 /**
670 * Gets the x scale of the object
671 * @returns {number}
672 */
673 GLGE.Placeable.prototype.getScaleX=function(){return this.scaleX;}
674 /**
675 * Gets the y scale of the object
676 * @returns {number}
677 */
678 GLGE.Placeable.prototype.getSacleY=function(){return this.scaleY;}
679 /**
680 * Gets the z scale of the object
681 * @returns {number}
682 */
683 GLGE.Placeable.prototype.getScaleZ=function(){return this.scaleZ;}
684 /**
685 * Gets the x scale displacement of the object
686 * @returns {number}
687 */
688 GLGE.Placeable.prototype.getDScaleX=function(){return this.dScaleX;}
689 /**
690 * Gets the y scale displacement of the object
691 * @returns {number}
692 */
693 GLGE.Placeable.prototype.getDScaleY=function(){return this.dScaleY;}
694 /**
695 * Gets the z scale displacement of the object
696 * @returns {number}
697 */
698 GLGE.Placeable.prototype.getDScaleZ=function(){return this.dScaleZ;}
699 /**
700 * Gets the position of the object
701 * @returns {object}
702 */
703 GLGE.Placeable.prototype.getPosition=function(){
704 	var position={};
705 	position.x=parseFloat(this.locX)+parseFloat(this.dLocX);
706 	position.y=parseFloat(this.locY)+parseFloat(this.dLocY);
707 	position.z=parseFloat(this.locZ)+parseFloat(this.dLocZ);
708 	return position;
709 }
710 /**
711 * Gets the rotation of the object
712 * @returns {object}
713 */
714 GLGE.Placeable.prototype.getRotation=function(){
715 	var rotation={};
716 	rotation.x=parseFloat(this.rotX)+parseFloat(this.dRotX);
717 	rotation.y=parseFloat(this.rotY)+parseFloat(this.dRotY);
718 	rotation.z=parseFloat(this.rotZ)+parseFloat(this.dRotZ);
719 	return rotation;
720 }
721 /**
722 * Gets the scale of the object
723 * @returns {object}
724 */
725 GLGE.Placeable.prototype.getScale=function(){
726 	var scale={};
727 	scale.x=parseFloat(this.scaleX)+parseFloat(this.dScaleX);
728 	scale.y=parseFloat(this.scaleY)+parseFloat(this.dScaleY);
729 	scale.z=parseFloat(this.scaleZ)+parseFloat(this.dScaleZ);
730 	return scale;
731 }
732 /**
733 * Updates the model matrix
734 * @private
735 */
736 GLGE.Placeable.prototype.updateMatrix=function(){
737 	this.matrix=null;
738 }
739 /**
740 * Gets the model matrix to transform the model within the world
741 */
742 GLGE.Placeable.prototype.getModelMatrix=function(){
743 	if(!this.matrix){
744 		var position=this.getPosition();
745 		var rotation=this.getRotation();
746 		var scale=this.getScale();
747 		this.matrix=Matrix.transMat(position.x,position.y,position.z).x(Matrix.scaleMat(scale.x,scale.y,scale.z).x(Matrix.rotMat(rotation.x,rotation.y,rotation.z)));
748 	}
749 	return this.matrix;
750 }
751 
752 /**
753 * @class Animation class to agument animatiable objects 
754 */
755 GLGE.Animatable=function(){
756 }
757 GLGE.Animatable.prototype.animationStart=null;
758 GLGE.Animatable.prototype.animation=null;
759 GLGE.Animatable.prototype.lastFrame=null;
760 GLGE.Animatable.prototype.frameRate=25;
761 /**
762 * update animated properties on this object
763 */
764 GLGE.Animatable.prototype.animate=function(){
765 	var now=parseInt(new Date().getTime());
766 	if(this.animation.frames>1){
767 		frame=((now-this.animationStart)/1000*this.frameRate)%(this.animation.frames-1)+1; 
768 	}else{
769 		frame=1;
770 	}
771 	if(frame!=this.lastFrame){
772 		this.lastFrame=frame;
773 		for(property in this.animation.curves){
774 			if(this["set"+property]) this["set"+property](this.animation.curves[property].getValue(frame));
775 		}
776 	}
777 }
778 /**
779 * Sets the animation vector of this object
780 * @param {GLGE.AnimationVector} animationVector the animation to apply to this object
781 */
782 GLGE.Animatable.prototype.setAnimation=function(animationVector){
783 	this.animationStart=parseInt(new Date().getTime());
784 	this.animation=animationVector;
785 }
786 /**
787 * Gets the animation vector of this object
788 * @returns {AnimationVector}
789 */
790 GLGE.Animatable.prototype.getAnimation=function(){
791 	return this.animation;
792 }
793 /**
794 * Sets the frame rate of the animation
795 * @param  {number} value the frame rate to set
796 */
797 GLGE.Animatable.prototype.setFrameRate=function(value){
798 	this.frameRate=value;
799 }
800 /**
801 * Gets the frame rate of the animation
802 * @return {number} the current frame rate
803 */
804 GLGE.Animatable.prototype.getFrameRate=function(){
805 	return this.frameRate;
806 }
807 
808 /**
809 * @class A bezier class to add points to the Animation Curve 
810 * @param {number} x1 x-coord of the first control point
811 * @param {number} y1 y-coord of the first control point
812 * @param {number} x2 x-coord of the second control point
813 * @param {number} y2 y-coord of the second control point
814 * @param {number} x3 x-coord of the third control point
815 * @param {number} y3 y-coord of the third control point
816 */
817 GLGE.BezTriple=function(x1,y1,x2,y2,x3,y3){
818 	this.x1=parseFloat(x1);
819 	this.y1=parseFloat(y1);
820 	this.x2=parseFloat(x2);
821 	this.y2=parseFloat(y2);
822 	this.x3=parseFloat(x3);
823 	this.y3=parseFloat(y3);
824 };
825 
826 /**
827 * @class A curve which interpolates between control points
828 */
829 GLGE.AnimationCurve=function(){
830     this.keyFrames=[];
831     this.solutions={};
832 };
833 GLGE.AnimationCurve.prototype.keyFrames=null;
834 /**
835 * Adds a point to the curve
836 * @param {BezPoint} bezPoint The bezier point to add
837 * @returns {Number} Index of the newly added point
838 */
839 GLGE.AnimationCurve.prototype.addPoint=function(bezPoint){
840 	this.keyFrames.push(bezPoint);
841 	return this.keyFrames.length-1;
842 };
843 /**
844 * Get the value of the curve at any point
845 * @param {Number} frame The frame(x-coord) to return the value for
846 * @returns {Number} The value of the curve at the given point
847 */
848 GLGE.AnimationCurve.prototype.coord=function(x,y){
849 	return {x:x,y:y}
850 }
851 GLGE.AnimationCurve.prototype.getValue=function(frame){
852 	var startKey=0;
853 	var endKey=0;
854 	//find the key frame bounds
855 	for(var i=0; i<this.keyFrames.length;i++){
856 		if(this.keyFrames[i].x2<frame && (this.keyFrames[i].x2>this.keyFrames[startKey].x2 || this.keyFrames[startKey].x2>frame)) startKey=i;
857 		if(this.keyFrames[i].x2>frame && (this.keyFrames[i].x2<this.keyFrames[endKey].x2 || this.keyFrames[endKey].x2<frame)) endKey=i;
858 	}
859 	var C1=this.coord(this.keyFrames[startKey].x2,this.keyFrames[startKey].y2);
860 	var C2=this.coord(this.keyFrames[startKey].x3,this.keyFrames[startKey].y3);
861 	var C3=this.coord(this.keyFrames[endKey].x1,this.keyFrames[endKey].y1);
862 	var C4=this.coord(this.keyFrames[endKey].x2,this.keyFrames[endKey].y2);
863 	return this.atX(frame,C1,C2,C3,C4).y;
864 };
865 /**
866 * Function used to calculate bezier curve
867 * @private
868 */
869 GLGE.AnimationCurve.prototype.B1=function(t) { return t*t*t };
870 /**
871 * Function used to calculate bezier curve
872 * @private
873 */
874 GLGE.AnimationCurve.prototype.B2=function(t) { return 3*t*t*(1-t) };
875 /**
876 * Function used to calculate bezier curve
877 * @private
878 */
879 GLGE.AnimationCurve.prototype.B3=function(t) { return 3*t*(1-t)*(1-t) };
880 /**
881 * Function used to calculate bezier curve
882 * @private
883 */
884 GLGE.AnimationCurve.prototype.B4=function(t) { return (1-t)*(1-t)*(1-t) };
885 /**
886 * Gets the value of a bezier curve at a given point
887 * @private
888 */
889 GLGE.AnimationCurve.prototype.getBezier=function(t,C1,C2,C3,C4) {
890 	var pos = {};
891 	pos.x = C1.x*this.B1(t) + C2.x*this.B2(t) + C3.x*this.B3(t) + C4.x*this.B4(t);
892 	pos.y = C1.y*this.B1(t) + C2.y*this.B2(t) + C3.y*this.B3(t) + C4.y*this.B4(t);
893 	return pos;
894 };
895 /**
896 * Solves cubic equation to get the parametic value of the curve at a specified point
897 * @private
898 */
899 GLGE.AnimationCurve.prototype.Quad3Solve=function(a,b,c,d){
900 	ref=a+"-"+b+"-"+"-"+c+"-"+d;
901 	if(this.solutions[ref]){
902 		return this.solutions[ref];
903 	}
904 	else
905 	{
906 		b /= a;c /= a;d /= a;
907 		var q, r, d1, s, t, t1, r13;
908 		q = (3.0*c - (b*b))/9.0;
909 		r = -(27.0*d) + b*(9.0*c - 2.0*(b*b));
910 		r /= 54.0;
911 		t1 = (b/3.0);
912 		discrim = q*q*q + r*r;
913 		result=[];
914 				
915 		if (discrim > 0) { 
916 		// one real, two complex
917 		 s = r + Math.sqrt(discrim);
918 		 s = ((s < 0) ? -Math.pow(-s, (1.0/3.0)) : Math.pow(s, (1.0/3.0)));
919 		 t = r - Math.sqrt(discrim);
920 		 t = ((t < 0) ? -Math.pow(-t, (1.0/3.0)) : Math.pow(t, (1.0/3.0)));
921 		 result[0] = -t1 + s + t;
922 		 t1 = t1 + (s + t)/2.0;
923 		 result[1] = result[2] = -t1;
924 		 t1 = Math.sqrt(3.0)*(-t + s)/2;
925 		} 
926 		else if (discrim == 0){ 
927 		// All roots real
928 		 r13 = ((r < 0) ? -Math.pow(-r,(1.0/3.0)) : Math.pow(r,(1.0/3.0)));
929 		 result[1] = -t1 + 2.0*r13;
930 		 result[1] = result[2]  = -(r13 + t1);
931 		} 
932 		else
933 		{
934 			q = -q;
935 			d1 = q*q*q;
936 			d1 = Math.acos(r/Math.sqrt(1));
937 			r13 = 2.0*Math.sqrt(q);
938 
939 
940 			result[0] = -t1 + r13*Math.cos(d1/3.0);
941 			result[1] = -t1 + r13*Math.cos((d1 + 2.0*Math.PI)/3.0);
942 			result[2] = -t1 + r13*Math.cos((d1 + 4.0*Math.PI)/3.0);
943 		}
944 		var toreturn=false;
945 		//determine which is the correct result
946 		if(result[0]>=0 && result[0]<=1) toreturn=result[0];
947 		if(!toreturn && result[1]>=0 && result[1]<=1) toreturn=result[1];
948 		if(!toreturn && result[2]>=0 && result[2]<=1) toreturn=result[2];
949 		//cache result for next time
950 		this.solutions[ref]=toreturn;
951 		
952 		return toreturn;
953 	}
954 };
955 /**
956 * Get the value of the a single bezier curve 
957 * @param {Number} x xcoord of point to get
958 * @param {Number} C1 First bezier control point
959 * @param {Number} C2 Second bezier control point
960 * @param {Number} C3 Third bezier control point
961 * @param {Number} C4 Forth bezier control point
962 * @returns {Number} The value of the curve at the given x
963 */
964 GLGE.AnimationCurve.prototype.atX=function(x,C1,C2,C3,C4){
965 	a=C1.x-C2.x*3+C3.x*3-C4.x;
966 	b=C2.x*3-C3.x*6+C4.x*3;
967 	c=C3.x*3-C4.x*3;
968 	d=C4.x-x;
969 	return this.getBezier(this.Quad3Solve(a,b,c,d),C1,C2,C3,C4);
970 };
971 
972 /**
973 * @class The AnimationVectors class allows you to specify the 2D Animation curves that define specific channels of animation within the engine. 
974 */
975 GLGE.AnimationVector=function(){
976     this.curves=[];
977 }
978 GLGE.AnimationVector.prototype.curves=[];
979 GLGE.AnimationVector.prototype.frames=250;
980 /**
981 * Adds an Animation Curve to a channel 
982 * @param {String} channel The name of the curve to be added
983 * @param {GLGE.AnimationCurve} curve The animation curve to add
984 */
985 GLGE.AnimationVector.prototype.addCurve=function(name,curve){
986 	this.curves[name]=curve;
987 }
988 /**
989 * Removes an Animation Curve form a channel
990 * @param {String} channel The name of the curve to be removed
991 */
992 GLGE.AnimationVector.prototype.removeCurve=function(name){
993 	delete(this.curves[name]);
994 }
995 /**
996 * Sets the number of frames in the animation
997 * @param {number} value The number of frames in the animation
998 */
999 GLGE.AnimationVector.prototype.setFrames=function(value){
1000 	this.frames=value;
1001 }
1002 /**
1003 * Sets the number of frames in the animation
1004 * @returns {number} The number of frames in the animation
1005 */
1006 GLGE.AnimationVector.prototype.getFrames=function(){
1007 	return this.frames;
1008 }
1009 
1010 
1011 /**
1012 * Function to augment one object with another
1013 * @param {object} obj1 Source Object
1014 * @param {object} obj2 Destination Object
1015 */
1016 GLGE.augment=function(obj1,obj2){
1017 	for(proto in obj1.prototype){
1018 		obj2.prototype[proto]=obj1.prototype[proto];
1019 	}
1020 }
1021 
1022 
1023 /**
1024 * @class Class defining a bones name and position in a skeleton
1025 * @param {string} name the name of the bone
1026 * @param {number} x the x co-ordinate of the bone
1027 * @param {number} y the y co-ordinate of the bone
1028 * @param {number} z the z co-ordinate of the bone
1029 */
1030 GLGE.Bone=function(name,x,y,z){
1031 	this.name=name;
1032 	this.x=x;
1033 	this.y=y;
1034 	this.z=z;
1035 }
1036 
1037 GLGE.error=function(message){
1038 	alert(message)
1039 }
1040 
1041 /**
1042 * @class Class specifing bones,locations and relationships
1043 */
1044 GLGE.Skeleton=function(){
1045     this.bones=[];
1046 };
1047 GLGE.Skeleton.prototype.bones=[];
1048 /**
1049 * Adds a bone to the skeleton
1050 * @param {GLGE.Bone} bone the bone to add
1051 * NOTE  why don't I just add the parent into the bone object????
1052 */
1053 GLGE.Skeleton.prototype.addBone=function(bone,parent){
1054 	if(parent) bone.parent=parent;
1055 	this.bones.push(bone);
1056 }
1057 /**
1058 * Gets the transform of a bone for a given action at a specified frame
1059 * @param {string} bone the bone to get the matrix for
1060 * @param {GLGE.SkeletalAction} action the action to the the matrix for
1061 * @param {number} frame The frame number to get the matrix for
1062 * @returns Matrix
1063 */
1064 GLGE.Skeleton.prototype.getBoneTransforms=function(bone,action,frame){
1065 	var TRANS1=Matrix.transMat(bone.x*-1,bone.y*-1,bone.z*-1);
1066 	var TRANS2=Matrix.transMat(bone.x,bone.y,bone.z);
1067 
1068 	var result=Matrix.I(4);
1069 	if(action && action.cache[frame][bone.name]) result=TRANS2.x(action.cache[frame][bone.name]).x(TRANS1);
1070 	return result;
1071 }
1072 /**
1073 * Gets the bone object from it's name
1074 * @param {string} name the name of the bone to get
1075 * @returns GLGE.Bone
1076 */
1077 GLGE.Skeleton.prototype.boneFromName=function(name){
1078     for(var i=0; i<this.bones.length;i++){
1079         if(this.bones[i].name==name){
1080             return i;
1081             break;
1082         }
1083     }
1084     return false;
1085 }
1086 /**
1087 * Gets and array containing the transforms of each of the bones
1088 * @param {GLGE.SkeletalAction} action the action to get the transforms for
1089 * @param {number} frame the frame number
1090 * @returns Matrix[]
1091 */
1092 GLGE.Skeleton.prototype.getTransforms=function(action,frame){
1093 	if(!action) alert(frame);
1094 	var transforms={}
1095 	for(var i=0; i<this.bones.length;i++){
1096             bone=this.bones[i];
1097             base=this.getBoneTransforms(bone,action,frame);
1098             while(bone.parent){
1099 		if(!bone.parentIdx) bone.parentIdx=this.boneFromName(bone.parent);
1100                 bone=this.bones[bone.parentIdx];
1101                 base=this.getBoneTransforms(bone,action,frame).x(base);
1102             }
1103             transforms[this.bones[i].name]=({name:this.bones[i].name,matrix:base});
1104         }
1105 	return transforms;
1106 }
1107 
1108 
1109 
1110 
1111 /**
1112 * @class Class to perform an action on a skeleton
1113 */
1114 GLGE.SkeletalAction=function(frames){
1115 	this.frames=frames;
1116 	this.AnimationVectors=[];
1117 }
1118 GLGE.SkeletalAction.prototype.frames=0;
1119 GLGE.SkeletalAction.prototype.frameRate=60;
1120 GLGE.SkeletalAction.prototype.cache=null;
1121 GLGE.SkeletalAction.prototype.AnimationVectors=null;
1122 /**
1123 * Adds an animation to one of the bone
1124 * @param {string} boneName The name of the bone
1125 * @param {GLGE.AnimationVector} AnimationVector The animation to associate with the bone
1126 */
1127 GLGE.SkeletalAction.prototype.addAnimationVector=function(boneName,AnimationVector){
1128 	this.AnimationVectors[boneName]=AnimationVector;
1129 }
1130 /**
1131 * Removed an animation for a bone
1132 * @param {string} boneName The name of the bone
1133 */
1134 GLGE.SkeletalAction.prototype.removeCurve=function(boneName){
1135 	delete(this.AnimationVectors[boneName]);
1136 }
1137 /**
1138 * Get the values of the animation vector for a given bone on a given channel at a given frame
1139 * @param {string} boneName The name of the bone
1140 * @param {string} channel The animation vector channel
1141 * @param {number} frame The frame to get the value for
1142 * @returns {object}
1143 */
1144 GLGE.SkeletalAction.prototype.boneValue=function(boneName,channel,frame){
1145 	var result;
1146 	var result=0;
1147 	if(channel=="ScaleX" || channel=="ScaleY" || channel=="ScaleZ") result=1;
1148 	if(this.AnimationVectors[boneName] && this.AnimationVectors[boneName].curves[channel]){
1149 		result=this.AnimationVectors[boneName].curves[channel].getValue(frame);
1150 	}
1151 	return result;
1152 }
1153 /**
1154 * Get the transformation matrix for the bone at a given frame
1155 * @param {string} boneName The name of the bone
1156 * @param {number} frame The frame to get the value for
1157 * @returns {Matrix}
1158 */
1159 GLGE.SkeletalAction.prototype.getBoneTransform=function(boneName,frame){
1160 	var LOCX=this.boneValue(boneName,"LocX",frame);
1161 	var LOCY=this.boneValue(boneName,"LocY",frame);
1162 	var LOCZ=this.boneValue(boneName,"LocZ",frame);
1163 	var SCALEX=this.boneValue(boneName,"ScaleX",frame);
1164 	var SCALEY=this.boneValue(boneName,"ScaleY",frame);
1165 	var SCALEZ=this.boneValue(boneName,"ScaleZ",frame);
1166 	var QUATX=this.boneValue(boneName,"QuatX",frame);
1167 	var QUATY=this.boneValue(boneName,"QuatY",frame);
1168 	var QUATZ=this.boneValue(boneName,"QuatZ",frame);
1169 	var QUATW=this.boneValue(boneName,"QuatW",frame);
1170 	
1171 
1172 	var QUAT=Matrix.quat2rot(QUATX,QUATY,QUATZ,QUATW);
1173 	var LOC=Matrix.transMat(LOCX,LOCY,LOCZ);
1174 	var SCALE=Matrix.scaleMat(SCALEX,SCALEY,SCALEZ);
1175 	return LOC.x(QUAT).x(SCALE);
1176 }
1177 /**
1178 * Cache all the transforms for this action
1179 */
1180 GLGE.SkeletalAction.prototype.cacheTransforms=function(){
1181 	this.cache=[];
1182 	var transforms;
1183 	for(var frame=1; frame<=this.frames;frame++){
1184 		transforms={};
1185 		for(bone in this.AnimationVectors){
1186 			if(this.AnimationVectors[bone] instanceof GLGE.AnimationVector){
1187 				transforms[bone]=this.getBoneTransform(bone,frame+0.5);
1188 			}
1189 		}
1190 		this.cache[frame]=transforms;
1191 	}
1192 }
1193 
1194 
1195 /**
1196 * @class An object that can be rendered in a scene
1197 * @augments GLGE.Animatable
1198 * @augments GLGE.Placeable
1199 */
1200 GLGE.Object=function(){
1201 }
1202 GLGE.augment(GLGE.Placeable,GLGE.Object);
1203 GLGE.augment(GLGE.Animatable,GLGE.Object);
1204 GLGE.Object.prototype.action=null;
1205 GLGE.Object.prototype.mesh=null;
1206 GLGE.Object.prototype.skeleton=null;
1207 GLGE.Object.prototype.scene=null;
1208 GLGE.Object.prototype.transformMatrix=Matrix.I(4);
1209 GLGE.Object.prototype.material=null;
1210 GLGE.Object.prototype.gl=null;
1211 GLGE.Object.prototype.actionStart=null;
1212 GLGE.Object.prototype.blendState=null;
1213 GLGE.Object.prototype.actionCache=null;
1214 GLGE.Object.prototype.zTrans=false;
1215 /**
1216 * Blend from current skeletal action to another
1217 * @param {GLGE.SkeletalAction} action The action to be blended to
1218 * @param {Number} duration Number of millisecons the blend should last for
1219 */
1220 GLGE.Object.prototype.blendAction=function(action,duration){
1221     this.blendState=this.getBoneTransforms();
1222     this.setAction(action);
1223     this.blendDuration=duration;
1224     this.actionCache=[];
1225 }
1226 /**
1227 * Sets the skeletal action of this object
1228 * @param {GLGE.SkeletalAction} action The action to be blended to
1229 */
1230 GLGE.Object.prototype.setAction=function(action){
1231     this.action=action;
1232     this.actionCache=[];
1233     if(!this.action.cache) this.action.cacheTransforms();
1234     this.actionStart=parseInt(new Date().getTime());
1235 }
1236 /**
1237 * Gets the current skeletal action of this object
1238 * @returns GLGE.SkeletalAction
1239 */
1240 GLGE.Object.prototype.getAction=function(){
1241 	return this.action
1242 }
1243 /**
1244 * Gets the current transfroms for each of the bones
1245 * @returns Matrix[]
1246 * @private
1247 */
1248 GLGE.Object.prototype.getBoneTransforms=function(){
1249 	var now=parseInt(new Date().getTime());
1250 	var frame;
1251 	if(this.action.frames>1){
1252 		frame=((now-this.actionStart)/1000*this.action.frameRate)%(this.action.frames-1)+1; 
1253 	}else{
1254 		frame=1;
1255 	}
1256 	frame=Math.round(frame);
1257 	if(this.actionCache[frame]){
1258 		var transforms=this.actionCache[frame];
1259 	}
1260 	else
1261 	{
1262 		var transforms=this.skeleton.getTransforms(this.action,frame);
1263 		if(this.blendState){
1264 			var blendframe;
1265 			var blendpoint=(now-this.actionStart)/this.blendDuration;
1266 			if(blendpoint>=1){
1267 				this.blendState=null;
1268 				this.actionCache=[];
1269 			}
1270 			else
1271 			{
1272 			    //combine the two sets of transforms
1273 			    var newtransforms={};
1274 			    for(bone in transforms){
1275 				if(transforms[bone].matrix){
1276 					newtransforms[bone]={matrix:this.blendState[bone].matrix.x(1-blendpoint).add(transforms[bone].matrix.x(blendpoint))};
1277 				}
1278 			    }
1279 			    transforms=newtransforms;            
1280 			}
1281 		}
1282 		else
1283 		{
1284 			this.actionCache[frame]=transforms;
1285 		}
1286 	}
1287 	return transforms;
1288 }
1289 /**
1290 * Sets the Z Transparency of this object
1291 * @param {boolean} value Does this object need blending?
1292 */
1293 GLGE.Object.prototype.setZtransparent=function(value){
1294 	this.zTrans=value;
1295 }
1296 /**
1297 * Gets the z transparency
1298 * @returns boolean
1299 */
1300 GLGE.Object.prototype.isZtransparent=function(){
1301 	return this.zTrans;
1302 }
1303 
1304 /**
1305 * Sets the skeletal action of this object
1306 * @param {GLGE.SkeletalAction} action The action to be blended to
1307 */
1308 GLGE.Object.prototype.setSkeleton=function(skeleton){
1309 	this.skeleton=skeleton;
1310 }
1311 /**
1312 * Gets the current skeletal action of this object
1313 * @returns GLGE.SkeletalAction
1314 */
1315 GLGE.Object.prototype.getSkeleton=function(){
1316 	return this.skeleton;
1317 }
1318 /**
1319 * Sets the material associated with the object
1320 * @param GLGE.Material
1321 */
1322 GLGE.Object.prototype.setMaterial=function(material){
1323     this.material=material;
1324 }
1325 /**
1326 * Gets the material associated with the object
1327 * @returns GLGE.Material
1328 */
1329 GLGE.Object.prototype.getMaterial=function(){
1330     return this.material;
1331 }
1332 GLGE.Object.prototype.setScene=function(scene){
1333     this.scene=scene;
1334 }
1335 GLGE.Object.prototype.getScene=function(){
1336     return this.scene;
1337 }
1338 /**
1339 * Sets the mesh associated with the object
1340 * @param GLGE.Mesh
1341 */
1342 GLGE.Object.prototype.setMesh=function(mesh){
1343 	if(this.mesh) this.mesh.removeObject(this);
1344 	this.mesh=mesh;
1345 	mesh.addObject(this);
1346 }
1347 /**
1348 * Gets the mesh associated with the object
1349 * @returns GLGE.Mesh
1350 */
1351 GLGE.Object.prototype.getMesh=function(){
1352 	return this.mesh;
1353 }
1354 /**
1355 * Initiallize all the GL stuff needed to render to screen
1356 * @private
1357 */
1358 GLGE.Object.prototype.GLInit=function(gl){
1359 	this.gl=gl;
1360 	this.GLGenerateShader(gl);
1361 }
1362 /**
1363 * Cleans up all the GL stuff we sets
1364 * @private
1365 */
1366 GLGE.Object.prototype.GLDestory=function(gl){
1367 }
1368 /**
1369 * Updates the GL shader program for the object
1370 * @private
1371 */
1372 GLGE.Object.prototype.updateProgram=function(){
1373 	if(this.gl) this.GLGenerateShader(this.gl);
1374 }
1375 /**
1376 * Creates the shader program for the object
1377 * @private
1378 */
1379 GLGE.Object.prototype.GLGenerateShader=function(gl){
1380 	if(this.GLShaderProgram) gl.deleteProgram(this.GLShaderProgram);
1381 	//create the programs strings
1382 	//Vertex Shader
1383 	var vertexStr="";
1384 	for(var i=0;i<this.mesh.buffers.length;i++){
1385         if(this.mesh.buffers[i].size>1)
1386 	        vertexStr=vertexStr+"attribute vec"+this.mesh.buffers[i].size+" "+this.mesh.buffers[i].name+";\n";
1387         else
1388 	        vertexStr=vertexStr+"attribute float "+this.mesh.buffers[i].name+";\n";
1389 	}
1390 	
1391 	vertexStr=vertexStr+"uniform mat4 MVMatrix;\n";
1392 	vertexStr=vertexStr+"uniform mat4 PMatrix;\n";  
1393 	//normals needed for lighting
1394 	vertexStr=vertexStr+"uniform mat4 uNMatrix;\n"; 
1395 
1396 	for(var i=0; i<this.scene.lights.length;i++){
1397 			vertexStr=vertexStr+"uniform vec3 lightpos"+i+";\n";
1398 			vertexStr=vertexStr+"uniform vec3 lightdir"+i+";\n";
1399 	}
1400   
1401 	for(var i=0; i<this.mesh.boneWeights.length; i++){
1402 		vertexStr=vertexStr+"uniform mat4 "+this.mesh.boneWeights[i].boneName+"Matrix;\n";  
1403 		vertexStr=vertexStr+"uniform mat4 "+this.mesh.boneWeights[i].boneName+"nMatrix;\n";  
1404 	}
1405 	
1406 	vertexStr=vertexStr+"varying vec3 eyevec;\n"; 
1407 	for(var i=0; i<this.scene.lights.length;i++){
1408 			vertexStr=vertexStr+"varying vec3 lightvec"+i+";\n"; 
1409 			vertexStr=vertexStr+"varying float lightdist"+i+";\n"; 
1410 	}
1411     
1412 	vertexStr=vertexStr+"varying vec3 n;\n";  
1413 	vertexStr=vertexStr+"varying vec4 UVCoord;\n";
1414 	
1415 	vertexStr=vertexStr+"void main(void)\n";
1416 	vertexStr=vertexStr+"{\n";
1417 	vertexStr=vertexStr+"UVCoord=UV;\n";
1418 	vertexStr=vertexStr+"vec4 pos = vec4(0.0, 0.0, 0.0, 1.0);\n";
1419 	vertexStr=vertexStr+"vec4 norm = vec4(0.0, 0.0, 0.0, 1.0);\n";
1420 	var cnt=0;
1421 	//calculate the total bone weight
1422 	var totalWeight=0;
1423 	vertexStr=vertexStr+"float totalWeight=0.0";
1424 	for(var i=0; i<this.mesh.boneWeights.length; i=i+4){
1425 		if(!this.mesh.boneWeights[i+1]){
1426 			vertexStr=vertexStr+"+bones"+cnt;
1427 		}else{
1428 			vertexStr=vertexStr+"+bones"+cnt+"["+(i%4)+"]";
1429 		}
1430 		if(this.mesh.boneWeights[i+1]) vertexStr=vertexStr+"+bones"+cnt+"["+(i%4+1)+"]";
1431 		if(this.mesh.boneWeights[i+2]) vertexStr=vertexStr+"+bones"+cnt+"["+(i%4+2)+"]";
1432 		if(this.mesh.boneWeights[i+3]) vertexStr=vertexStr+"+bones"+cnt+"["+(i%4+3)+"]";
1433 		cnt++;
1434 	}
1435 	vertexStr=vertexStr+";\n";
1436 	vertexStr=vertexStr+"if(totalWeight>0.0){\n";
1437 	cnt=0;
1438 	for(var i=0; i<this.mesh.boneWeights.length; i=i+4){
1439 		if(!this.mesh.boneWeights[i+1]){
1440 		    vertexStr=vertexStr+"pos += ("+this.mesh.boneWeights[i].boneName+"Matrix * vec4(position, 1.0))*(bones"+cnt+"/totalWeight);\n";
1441 		    vertexStr=vertexStr+"norm += ("+this.mesh.boneWeights[i].boneName+"nMatrix * vec4(normal, 1.0))*(bones"+cnt+"/totalWeight);\n";
1442 		    }else{
1443 		    vertexStr=vertexStr+"pos += ("+this.mesh.boneWeights[i].boneName+"Matrix * vec4(position, 1.0))*(bones"+cnt+"["+(i%4)+"]/totalWeight);\n";
1444 		    vertexStr=vertexStr+"norm += ("+this.mesh.boneWeights[i].boneName+"nMatrix * vec4(normal, 1.0))*(bones"+cnt+"["+(i%4)+"]/totalWeight);\n";
1445 		}
1446 		if(this.mesh.boneWeights[i+1]) vertexStr=vertexStr+"pos += ("+this.mesh.boneWeights[i+1].boneName+"Matrix * vec4(position, 1.0))*(bones"+cnt+"["+(i%4+1)+"]/totalWeight);\n";
1447 		if(this.mesh.boneWeights[i+2]) vertexStr=vertexStr+"pos += ("+this.mesh.boneWeights[i+2].boneName+"Matrix * vec4(position, 1.0))*(bones"+cnt+"["+(i%4+2)+"]/totalWeight);\n";
1448 		if(this.mesh.boneWeights[i+3]) vertexStr=vertexStr+"pos += ("+this.mesh.boneWeights[i+3].boneName+"Matrix * vec4(position, 1.0))*(bones"+cnt+"["+(i%4+3)+"]/totalWeight);\n";
1449 		if(this.mesh.boneWeights[i+1]) vertexStr=vertexStr+"norm += ("+this.mesh.boneWeights[i+1].boneName+"nMatrix * vec4(normal, 1.0))*(bones"+cnt+"["+(i%4+1)+"]/totalWeight);\n";
1450 		if(this.mesh.boneWeights[i+2]) vertexStr=vertexStr+"norm += ("+this.mesh.boneWeights[i+2].boneName+"nMatrix * vec4(normal, 1.0))*(bones"+cnt+"["+(i%4+2)+"]/totalWeight);\n";
1451 		if(this.mesh.boneWeights[i+3]) vertexStr=vertexStr+"norm += ("+this.mesh.boneWeights[i+3].boneName+"nMatrix * vec4(normal, 1.0))*(bones"+cnt+"["+(i%4+3)+"]/totalWeight);\n";
1452 		cnt++;
1453 	}
1454 	vertexStr=vertexStr+"pos = MVMatrix * vec4(pos.xyz, 1.0);\n";
1455 	vertexStr=vertexStr+"norm = uNMatrix * vec4(norm.xyz, 1.0);\n";
1456 	vertexStr=vertexStr+"}else{\n";
1457 	vertexStr=vertexStr+"pos = MVMatrix * vec4(position, 1.0);\n";
1458 	vertexStr=vertexStr+"norm = uNMatrix * vec4(normal, 1.0);\n";
1459 	vertexStr=vertexStr+"}\n";
1460    
1461     
1462 	vertexStr=vertexStr+"gl_Position = PMatrix * pos;\n";
1463 	vertexStr=vertexStr+"eyevec = -pos.xyz;\n";
1464 	for(var i=0; i<this.scene.lights.length;i++){
1465 			vertexStr=vertexStr+"lightvec"+i+" = (lightpos"+i+"-pos.xyz);\n";
1466 			vertexStr=vertexStr+"lightdist"+i+" = length(lightpos"+i+".xyz-pos.xyz);\n";
1467 	}
1468 	vertexStr=vertexStr+"n = norm.rgb;\n";
1469 	vertexStr=vertexStr+"}\n";
1470 	
1471 	//Fragment Shader
1472 	if(!this.material){
1473 		var fragStr="";
1474 		fragStr=fragStr+"void main(void)\n";
1475 		fragStr=fragStr+"{\n";
1476 		fragStr=fragStr+"gl_FragColor = vec4(1.0,1.0,1.0,1);\n";
1477 		fragStr=fragStr+"}\n";
1478 	}
1479 	else
1480 	{
1481 		fragStr=this.material.getFragmentShader(this.scene.lights);
1482 	}
1483 
1484 	if(!this.GLFragmentShader) this.GLFragmentShader=gl.createShader(gl.FRAGMENT_SHADER);
1485 	if(!this.GLVertexShader) this.GLVertexShader=gl.createShader(gl.VERTEX_SHADER);
1486 
1487 	//set and compile the fragment shader
1488 	//need to set str
1489 	gl.shaderSource(this.GLFragmentShader, fragStr);
1490 	gl.compileShader(this.GLFragmentShader);
1491 	
1492 	/* temp remove for webkit
1493 	if (!gl.getShaderi(this.GLFragmentShader, gl.COMPILE_STATUS))
1494 	{
1495 		GLGE.error(gl.getShaderInfoLog(this.GLFragmentShader));
1496 		return null;
1497 	}*/
1498 	//set and compile the vertex shader
1499 	//need to set str
1500 	gl.shaderSource(this.GLVertexShader, vertexStr);
1501 	gl.compileShader(this.GLVertexShader);
1502 	/* temp remove for webkit
1503 	if (!gl.getShaderi(this.GLVertexShader, gl.COMPILE_STATUS))
1504 	{
1505 		GLGE.error(gl.getShaderInfoLog(this.GLVertexShader));
1506 		return null;
1507 	}
1508 	*/
1509 	
1510 	if(!this.GLShaderProgram) this.GLShaderProgram = gl.createProgram();
1511 	gl.attachShader(this.GLShaderProgram, this.GLVertexShader);
1512 	gl.attachShader(this.GLShaderProgram, this.GLFragmentShader);
1513 	gl.linkProgram(this.GLShaderProgram);	
1514 }
1515 /**
1516 * Sets the shader program uniforms ready for rendering
1517 * @private
1518 */
1519 GLGE.Object.prototype.GLUniforms=function(gl){
1520 	var camMat=this.scene.camera.getViewMatrix();
1521 	//generate and set the modelView matrix
1522 	mvMatrix=camMat.x(this.getModelMatrix());
1523 	
1524 	var mvUniform = gl.getUniformLocation(this.GLShaderProgram, "MVMatrix");
1525 	gl.uniformMatrix4fv(mvUniform, false, new WebGLFloatArray(mvMatrix.flatten()));
1526 	
1527 	var pUniform = gl.getUniformLocation(this.GLShaderProgram, "PMatrix");
1528 	gl.uniformMatrix4fv(pUniform, false, new WebGLFloatArray(this.scene.camera.pMatrix.flatten()));
1529     
1530 	//normalising matrix
1531 	var normalMatrix = mvMatrix.inverse();
1532 	normalMatrix = normalMatrix.transpose();
1533 	var nUniform = gl.getUniformLocation(this.GLShaderProgram, "uNMatrix");
1534 	gl.uniformMatrix4fv(nUniform, false, new WebGLFloatArray(normalMatrix.flatten()));
1535     
1536 	//light
1537 	var pos,lpos;
1538 	for(var i=0; i<this.scene.lights.length;i++){
1539 		pos=camMat.x(this.scene.lights[i].getModelMatrix()).x($V([0,0,0,1])).flatten();
1540 		lpos=camMat.x(this.scene.lights[i].getModelMatrix()).x($V([0,0,-1,1])).flatten();
1541 		gl.uniform3f(gl.getUniformLocation(this.GLShaderProgram, "lightpos"+i), pos[0],pos[1],pos[2]);
1542 		gl.uniform3f(gl.getUniformLocation(this.GLShaderProgram, "lightdir"+i),lpos[0]-pos[0],lpos[1]-pos[1],lpos[2]-pos[2]);
1543 	}
1544        
1545 	//set bone transforms
1546 	var boneUniform;
1547 	var transforms={};
1548 	if(this.action && this.skeleton){
1549 		transforms=this.getBoneTransforms();
1550 	}
1551 	for(var i=0; i<this.mesh.boneWeights.length; i++){
1552 		if(!transforms[this.mesh.boneWeights[i].boneName]) transforms[this.mesh.boneWeights[i].boneName]={matrix:Matrix.I(4)};
1553 		
1554 		boneUniform = gl.getUniformLocation(this.GLShaderProgram, this.mesh.boneWeights[i].boneName+"Matrix");
1555 		gl.uniformMatrix4fv(boneUniform, false, new WebGLFloatArray(transforms[this.mesh.boneWeights[i].boneName].matrix.flatten()));
1556         
1557 		boneUniform = gl.getUniformLocation(this.GLShaderProgram, this.mesh.boneWeights[i].boneName+"nMatrix");
1558 		gl.uniformMatrix4fv(boneUniform, false, new WebGLFloatArray(transforms[this.mesh.boneWeights[i].boneName].matrix.inverse().transpose().flatten()));
1559 	}
1560     
1561 	if(this.material) this.material.textureUniforms(gl,this.GLShaderProgram,this.scene.lights);
1562 }
1563 /**
1564 * Renders the object to the screen
1565 * @private
1566 */
1567 GLGE.Object.prototype.GLRender=function(gl){
1568 	//animate this object
1569 	if(this.animation) this.animate();
1570 	
1571 	var attribslot;
1572 	gl.useProgram(this.GLShaderProgram);
1573 	
1574 	this.mesh.GLAttributes(gl,this.GLShaderProgram);
1575 	gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.mesh.GLfaces);
1576 
1577 	this.GLUniforms(gl);
1578 	//gl.drawArrays(gl.LINE_LOOP, 0, this.GLbuffers["position"].numItems);
1579 	gl.drawElements(gl.TRIANGLES, this.mesh.GLfaces.numItems, gl.UNSIGNED_SHORT, 0);
1580 }
1581 
1582 
1583 
1584 /**
1585 * @class Creates a new mesh to associate with a mesh
1586 * @see GLGE.Object
1587 */
1588 GLGE.Mesh=function(){
1589 	this.GLbuffers=[];
1590 	this.buffers=[];
1591 	this.UV=[];
1592 	this.boneWeights=[];
1593 	this.setBuffers=[];
1594 	this.faces={};
1595 	this.objects=[];
1596 }
1597 GLGE.Mesh.prototype.gl=null;
1598 GLGE.Mesh.prototype.GLbuffers=null;
1599 GLGE.Mesh.prototype.buffers=null;
1600 GLGE.Mesh.prototype.setBuffers=null;
1601 GLGE.Mesh.prototype.GLfaces=null;
1602 GLGE.Mesh.prototype.faces=null;
1603 GLGE.Mesh.prototype.boneWeights=null;
1604 GLGE.Mesh.prototype.UV=null;
1605 GLGE.Mesh.prototype.objects=null;
1606 /**
1607 * Set the UV coord for the first UV layer
1608 * @param {Number[]} jsArray the UV coords in a 1 dimentional array
1609 */
1610 GLGE.Mesh.prototype.setUV=function(jsArray){
1611 	var idx=0;
1612 	for(var i=0; i<jsArray.length;i=i+2){
1613 		this.UV[idx]=jsArray[i];
1614 		this.UV[idx+1]=jsArray[i+1];
1615 		if(!this.UV[idx+2]) this.UV[idx+2]=0;
1616 		if(!this.UV[idx+3]) this.UV[idx+3]=0;
1617 		idx=idx+4;
1618 	}
1619 	this.setBuffer("UV",this.UV,4);
1620 }
1621 /**
1622 * Set the UV coord for the second UV layer
1623 * @param {Number[]} jsArray the UV coords in a 1 dimentional array
1624 */
1625 GLGE.Mesh.prototype.setUV2=function(jsArray){
1626 	var idx=0;
1627 	for(var i=0; i<jsArray.length;i=i+2){
1628 		if(!this.UV[idx]) this.UV[idx]=0;
1629 		if(!this.UV[idx+1]) this.UV[idx+1]=0;
1630 		this.UV[idx+2]=jsArray[i];
1631 		this.UV[idx+3]=jsArray[i+1];
1632 		idx=idx+4;
1633 	}
1634 	this.setBuffer("UV",this.UV,4);
1635 }
1636 /**
1637 * Sets the bone weights for a perticular bone
1638 * @param {String} boneName The name of the bone
1639 * @param {Number[]} jsArray The 1 dimentional array of weights
1640 */
1641 GLGE.Mesh.prototype.addBoneWeights=function(boneName,jsArray){
1642 	var bone={};
1643 	bone.boneName=boneName;
1644 	bone.weights=jsArray;
1645 	this.boneWeights.push(bone);
1646     
1647 	var weights;
1648 	var cnt=0;
1649 	for(var i=0; i<this.boneWeights.length; i=i+4){
1650 		weights=[];
1651 		size=1;
1652 		for(var n=0; n<this.boneWeights[i].weights.length;n++){
1653 			weights.push(this.boneWeights[i].weights[n]);
1654 			if(this.boneWeights[i+1]){
1655 				size=2;
1656 				weights.push(this.boneWeights[i+1].weights[n]);
1657 			}
1658 			if(this.boneWeights[i+2]){
1659 				size=3;
1660 				weights.push(this.boneWeights[i+2].weights[n]);
1661 			}
1662 			if(this.boneWeights[i+3]){
1663 				size=4;
1664 				weights.push(this.boneWeights[i+3].weights[n]);
1665 			}
1666 		}
1667 		this.setBuffer("bones"+cnt,weights,size);
1668 		cnt++;
1669 	}
1670 }
1671 /**
1672 * Sets the positions of the verticies
1673 * @param {Number[]} jsArray The 1 dimentional array of positions
1674 */
1675 GLGE.Mesh.prototype.setPositions=function(jsArray){
1676 	this.setBuffer("position",jsArray,3);
1677 }
1678 /**
1679 * Sets the normals of the verticies
1680 * @param {Number[]} jsArray The 1 dimentional array of normals
1681 */
1682 GLGE.Mesh.prototype.setNormals=function(jsArray){
1683 	this.setBuffer("normal",jsArray,3);
1684 }
1685 /**
1686 * Sets a buffer for the
1687 * @param {String} boneName The name of the bone
1688 * @param {Number[]} jsArray The 1 dimentional array of weights
1689 * @private
1690 */
1691 GLGE.Mesh.prototype.setBuffer=function(bufferName,jsArray,size){
1692 	var buffer;
1693 	for(var i=0;i<this.buffers.length;i++){
1694 		if(this.buffers[i].name==bufferName) buffer=i;
1695 	}
1696 	if(!buffer){
1697 		this.buffers.push({name:bufferName,data:jsArray,size:size,GL:false});
1698 		this.updatePrograms();
1699 	}
1700         else 
1701 	{
1702 		this.buffers[buffer]={name:bufferName,data:jsArray,size:size,GL:false};
1703 	}
1704 }
1705 /**
1706 * Sets the faces for this mesh
1707 * @param {Number[]} jsArray The 1 dimentional array of normals
1708 */
1709 GLGE.Mesh.prototype.setFaces=function(jsArray){
1710 	this.faces={data:jsArray,GL:false};
1711 
1712 }
1713 /**
1714 * Sets the faces for this mesh
1715 * @param {Number[]} jsArray The 1 dimentional array of normals
1716 * @private
1717 */
1718 GLGE.Mesh.prototype.GLSetFaceBuffer=function(gl){
1719 	if(!this.GLfaces) this.GLfaces = gl.createBuffer();
1720 	gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.GLfaces);
1721 	gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new WebGLUnsignedShortArray(this.faces.data), gl.STATIC_DRAW);
1722 	this.GLfaces.itemSize = 1;
1723 	this.GLfaces.numItems = this.faces.data.length;
1724 }
1725 /**
1726 * Sets up a GL Buffer
1727 * @param {WebGLContext} gl The context being drawn on
1728 * @param {String} bufferName The name of the buffer to create
1729 * @param {Number[]}  jsArray The data to add to the buffer
1730 * @param {Number}  size Size of a single element within the array
1731 * @private
1732 */
1733 GLGE.Mesh.prototype.GLSetBuffer=function(gl,bufferName,jsArray,size){
1734 	if(!this.GLbuffers[bufferName]) this.GLbuffers[bufferName] = gl.createBuffer();
1735 	gl.bindBuffer(gl.ARRAY_BUFFER, this.GLbuffers[bufferName]);
1736 	gl.bufferData(gl.ARRAY_BUFFER, new WebGLFloatArray(jsArray), gl.STATIC_DRAW);
1737 	this.GLbuffers[bufferName].itemSize = size;
1738 	this.GLbuffers[bufferName].numItems = jsArray.length/size;
1739 }
1740 /**
1741 * Sets the Attributes for this mesh
1742 * @param {WebGLContext} gl The context being drawn on
1743 * @private
1744 */
1745 GLGE.Mesh.prototype.GLAttributes=function(gl,shaderProgram){
1746 	//disable all the attribute initially arrays - do I really need this?
1747 	for(var i=0; i<8; i++) gl.disableVertexAttribArray(i);
1748 	//check if the faces have been updated
1749 	if(!this.faces.GL){
1750 		this.GLSetFaceBuffer(gl);
1751 		this.faces.GL=true;
1752 	}
1753 	//loop though the buffers
1754 	for(i=0; i<this.buffers.length;i++){
1755 		if(!this.buffers[i].GL){
1756 			this.GLSetBuffer(gl,this.buffers[i].name,this.buffers[i].data,this.buffers[i].size);
1757 			this.buffers[i].GL=true;
1758 		}
1759 		attribslot=gl.getAttribLocation(shaderProgram, this.buffers[i].name);
1760 		if(attribslot>-1){
1761 			gl.bindBuffer(gl.ARRAY_BUFFER, this.GLbuffers[this.buffers[i].name]);
1762 			gl.enableVertexAttribArray(attribslot);
1763 			gl.vertexAttribPointer(attribslot, this.GLbuffers[this.buffers[i].name].itemSize, gl.FLOAT, false, 0, 0);
1764 		}
1765 	}
1766 }
1767 /**
1768 * updates the programs for the objects when buffers are added/removed
1769 * @private
1770 */
1771 GLGE.Mesh.prototype.updatePrograms=function(){
1772 	for(var i=0;i<this.objects.length;i++){
1773 		this.objects[i].updateProgram();
1774 	}
1775 }
1776 /**
1777 * Adds a object to this mesh to be notified when a buffer is added/removed
1778 * @param {GLGE.Object} object the object this mesh has been added to
1779 * @private
1780 */
1781 GLGE.Mesh.prototype.addObject=function(object){
1782 	this.objects.push(object);
1783 }
1784 /**
1785 * Removes the association with an object
1786 * @param {GLGE.Object} object the object this mesh has been added to
1787 * @private
1788 */
1789 GLGE.Mesh.prototype.removeObject=function(object){
1790 	//TODO: add remove code
1791 }
1792 
1793 
1794 /**
1795 * @class Creates a new light source to be added to a scene
1796 * @property {Boolean} diffuse Dose this light source effect diffuse shading
1797 * @property {Boolean} specular Dose this light source effect specular shading
1798 * @augments GLGE.Animatable
1799 * @augments GLGE.Placeable
1800 */
1801 GLGE.Light=function(type){
1802 	this.color={r:1,g:1,b:1};
1803 	this.type=type;
1804 }
1805 GLGE.augment(GLGE.Placeable,GLGE.Light);
1806 GLGE.augment(GLGE.Animatable,GLGE.Light);
1807 /**
1808 * @constant 
1809 * @description Enumeration for an point light source
1810 */
1811 GLGE.L_POINT=1;
1812 /**
1813 * @constant 
1814 * @description Enumeration for an directional light source
1815 */
1816 GLGE.L_DIR=2;
1817 /**
1818 * @constant 
1819 * @description Enumeration for an spot light source
1820 */
1821 GLGE.L_SPOT=3;
1822 
1823 GLGE.Light.prototype.constantAttenuation=1;
1824 GLGE.Light.prototype.linearAttenuation=0.002;
1825 GLGE.Light.prototype.quadraticAttenuation=0.0008;
1826 GLGE.Light.prototype.spotCosCutOff=0.95;
1827 GLGE.Light.prototype.spotExponent=10;
1828 GLGE.Light.prototype.color=null; 
1829 GLGE.Light.prototype.diffuse=true; 
1830 GLGE.Light.prototype.specular=true; 
1831 GLGE.Light.type=GLGE.L_POINT;
1832 /**
1833 * Sets the spot light cut off
1834 * @param {number} value The cos of the angle to limit
1835 */
1836 GLGE.Light.prototype.setSpotCosCutOff=function(value){
1837 	this.spotCosCutOff=value;
1838 }
1839 /**
1840 * Gets the spot light cut off
1841 * @returns {number} The cos of the limiting angle 
1842 */
1843 GLGE.Light.prototype.getSpotCosCutOff=function(){
1844 	return this.spotCosCutOff=value;
1845 }
1846 /**
1847 * Sets the spot light exponent
1848 * @param {number} value The spot lights exponent
1849 */
1850 GLGE.Light.prototype.setSpotExponent=function(value){
1851 	this.spotExponent=value;
1852 }
1853 /**
1854 * Gets the spot light exponent
1855 * @returns {number} The exponent of the spot light
1856 */
1857 GLGE.Light.prototype.getSpotExponent=function(){
1858 	return this.spotExponentf=value;
1859 }
1860 /**
1861 * Sets the light sources Attenuation
1862 * @returns {Object} The components of the light sources attenuation
1863 */
1864 GLGE.Light.prototype.getAttenuation=function(constant,linear,quadratic){
1865 	var attenuation={};
1866 	attenuation.constant=this.constantAttenuation;
1867 	attenuation.linear=this.linearAttenuation;
1868 	attenuation.quadratic=this.quadraticAttenuation;
1869 	return attenuation;
1870 }
1871 /**
1872 * Sets the light sources Attenuation
1873 * @param {Number} constant The constant part of the attenuation
1874 * @param {Number} linear The linear part of the attenuation
1875 * @param {Number} quadratic The quadratic part of the attenuation
1876 */
1877 GLGE.Light.prototype.setAttenuation=function(constant,linear,quadratic){
1878 	this.constantAttenuation=constant;
1879 	this.linearAttenuation=linear;
1880 	this.quadraticAttenuation=quadratic;
1881 }
1882 /**
1883 * Sets the light sources constant attenuation
1884 * @param {Number} value The constant part of the attenuation
1885 */
1886 GLGE.Light.prototype.setAttenuationConstant=function(value){
1887 	this.constantAttenuation=value;
1888 }
1889 /**
1890 * Sets the light sources linear attenuation
1891 * @param {Number} value The linear part of the attenuation
1892 */
1893 GLGE.Light.prototype.setAttenuationLinear=function(value){
1894 	this.linearAttenuation=value;
1895 }
1896 /**
1897 * Sets the light sources quadratic attenuation
1898 * @param {Number} value The quadratic part of the attenuation
1899 */
1900 GLGE.Light.prototype.setAttenuationQuadratic=function(value){
1901 	this.quadraticAttenuation=value;
1902 }
1903 
1904 /**
1905 * Sets the color of the light source
1906 * @param {Number} r The new red level 0-1
1907 * @param {Number} g The new green level 0-1
1908 * @param {Number} b The new blue level 0-1
1909 */
1910 GLGE.Light.prototype.setColor=function(r,g,b){
1911 	this.color={r:r,g:g,b:b};
1912 }
1913 /**
1914 * Sets the red color of the light source
1915 * @param {Number} value The new red level 0-1
1916 */
1917 GLGE.Light.prototype.setColorR=function(value){
1918 	this.color.r=value
1919 }
1920 /**
1921 * Sets the green color of the light source
1922 * @param {Number} value The new green level 0-1
1923 */
1924 GLGE.Light.prototype.setColorG=function(value){
1925 	this.color.g=value
1926 }
1927 /**
1928 * Sets the blue color of the light source
1929 * @param {Number} value The new blue level 0-1
1930 */
1931 GLGE.Light.prototype.setColorB=function(value){
1932 	this.color.b=value
1933 }
1934 /**
1935 * Gets the current color of the light source
1936 * @return {[r,g,b]} The current position
1937 */
1938 GLGE.Light.prototype.getColor=function(){
1939 	return this.color;
1940 }
1941 /**
1942 * Gets the type of the light
1943 * @return {Number} The type of the light source eg GLGE.L_POINT
1944 */
1945 GLGE.Light.prototype.getType=function(){
1946 	return this.type;
1947 }
1948 /**
1949 * Sets the type of the light
1950 * @param {Number} type The type of the light source eg GLGE.L_POINT
1951 */
1952 GLGE.Light.prototype.setType=function(type){
1953 	this.type=type;
1954 }
1955 
1956 
1957 /**
1958 * @class Creates a new camera object
1959 * @augments GLGE.Animatable
1960 * @augments GLGE.Placeable
1961 */
1962 GLGE.Camera=function(){
1963         this.pMatrix=makePerspective(45, 1.0, 0.1, 300.0);
1964 };
1965 GLGE.augment(GLGE.Placeable,GLGE.Camera);
1966 GLGE.augment(GLGE.Animatable,GLGE.Camera);
1967 GLGE.Camera.prototype.pMatrix=null;
1968 /**
1969 * Method gets the current projection matrix of this camera
1970 * @return {Matrix} Returns the camera projection matrix
1971 */
1972 GLGE.Camera.prototype.getProjectionMatrix=function(){
1973 	return this.pMatrix;
1974 };
1975 /**
1976 * Method generates the projection matrix based on the 
1977 * camera paramaters
1978 * @param {Matrix} projection The new projection matrix
1979 */
1980 GLGE.Camera.prototype.setProjectionMatrix=function(projection){
1981 	this.pMatrix=projection;
1982 };
1983 /**
1984 * Method generates the cameras view matrix
1985 * @return Returns the view matrix based on this camera
1986 * @type Matrix
1987 */
1988 GLGE.Camera.prototype.updateMatrix=function(){
1989 	var position=this.getPosition();
1990 	var rotation=this.getRotation();
1991 	var vMatrix=Matrix.transMat(position.x,position.y,position.z);
1992 	vMatrix=vMatrix.x(Matrix.rotMat(rotation.x,rotation.y,rotation.z));
1993 	this.matrix=vMatrix.inverse();
1994 };
1995 /**
1996 * Method generates the cameras view matrix
1997 * @return Returns the view matrix based on this camera
1998 * @type Matrix
1999 */
2000 GLGE.Camera.prototype.getViewMatrix=function(){
2001 	return this.matrix;
2002 };
2003 
2004 /**
2005 * @class Scene class containing the camera, lights and objects
2006 */
2007 GLGE.Scene=function(){
2008 	this.objects=[];
2009 	this.lights=[];
2010 	this.camera=new GLGE.Camera();
2011 	this.backgroundColor={r:1,g:1,b:1};
2012 	this.ambientColor={r:0,g:0,b:0};
2013 }
2014 GLGE.Scene.prototype.camera=null;
2015 GLGE.Scene.prototype.objects=null;
2016 GLGE.Scene.prototype.lights=null;
2017 GLGE.Scene.prototype.renderer=null;
2018 GLGE.Scene.prototype.backgroundColor=null;
2019 GLGE.Scene.prototype.ambientColor=null;
2020 /**
2021 * Gets the scenes background color
2022 * @returns {object} An assoiative array r,g,b
2023 */
2024 GLGE.Scene.prototype.getBackgroundColor=function(){	
2025 	return this.backgroundColor;
2026 }
2027 /**
2028 * Sets the scenes background color
2029 * @param {number} r the red componenent of the background color 0-1
2030 * @param {number} g the green componenent of the background color 0-1
2031 * @param {number} b the blue componenent of the background color 0-1
2032 */
2033 GLGE.Scene.prototype.setBackgroundColor=function(r,g,b){	
2034 	this.backgroundColor={r:r,g:g,b:b};
2035 	if(this.renderer){
2036 		this.renderer.gl.clearColor(this.backgroundColor.r, this.backgroundColor.g, this.backgroundColor.b, 1.0);
2037 	}
2038 }
2039 /**
2040 * Gets the scenes ambient light
2041 * @returns {object} An assoiative array r,g,b
2042 */
2043 GLGE.Scene.prototype.getAmbientColor=function(){	
2044 	return this.ambientColor;
2045 }
2046 /**
2047 * Sets the scenes ambient light
2048 * @param {number} r the red componenent of the ambient light 0-1
2049 * @param {number} g the green componenent of the ambient light 0-1
2050 * @param {number} b the blue componenent of the ambient light 0-1
2051 */
2052 GLGE.Scene.prototype.setAmbientColor=function(r,g,b){	
2053 	this.ambientColor={r:r,g:g,b:b};
2054 	if(this.renderer){
2055 		this.renderer.gl.clearColor(this.backgroundColor.r, this.backgroundColor.g, this.backgroundColor.b, 1.0);
2056 	}
2057 }
2058 /**
2059 * Sets the scenes ambient light
2060 * @param {number} value the red componenent of the ambient light 0-1
2061 */
2062 GLGE.Scene.prototype.setAmbientColorR=function(value){	
2063 	this.ambientColor.r=value;
2064 }
2065 /**
2066 * Sets the scenes ambient light
2067 * @param {number} value the green componenent of the ambient light 0-1
2068 */
2069 GLGE.Scene.prototype.setAmbientColorG=function(value){	
2070 	this.ambientColor.g=value;
2071 }
2072 /**
2073 * Sets the scenes ambient light
2074 * @param {number} value the blue componenent of the ambient light 0-1
2075 */
2076 GLGE.Scene.prototype.setAmbientColorB=function(value){	
2077 	this.ambientColor.b=value;
2078 }
2079 
2080 /**
2081 * Gets an array of all the object in the scene
2082 * @returns {GLGE.Object[]} An array of objects
2083 */
2084 GLGE.Scene.prototype.getObjects=function(){	
2085 	return this.objects;
2086 }
2087 /**
2088 * Gets an array of all the light sources in the scene
2089 * @returns {GLGE.Lights[]} An array of lights
2090 */
2091 GLGE.Scene.prototype.getLights=function(){	
2092 	return this.lights;
2093 }
2094 /**
2095 * Sets the active camera for this scene
2096 * @property {GLGE.Camera} object The object to be added
2097 */
2098 GLGE.Scene.prototype.setCamera=function(camera){	
2099 	this.camera=camera;
2100 }
2101 /**
2102 * Gets the scenes active camera
2103 * @returns {GLGE.Camera} The current camera
2104 */
2105 GLGE.Scene.prototype.getCamera=function(){	
2106 	return this.camera;
2107 }
2108 /**
2109 * Adds an object to the scene
2110 * @property {GLGE.Object} object The object to be added
2111 * @returns {Number} The index of the added object
2112 */
2113 GLGE.Scene.prototype.addObject=function(object){	
2114 	object.scene=this;
2115 	this.objects.push(object);
2116 	if(this.renderer) object.GLInit(this.renderer.gl);
2117 	return this.objects.length-1;
2118 }
2119 /**
2120 * Adds a light source to the scene
2121 * @property {GLGE.Light} light The light to be added
2122 * @returns {Number} The index of the added light
2123 */
2124 GLGE.Scene.prototype.addLight=function(light){	
2125 	light.scene=this;
2126 	this.lights.push(light);
2127 }
2128 /**
2129 * used to initialize all the WebGL buffers etc need for this scene
2130 * @private
2131 */
2132 GLGE.Scene.prototype.init=function(){
2133     this.renderer.gl.clearColor(this.backgroundColor.r, this.backgroundColor.g, this.backgroundColor.b, 1.0);
2134     for(var i=0;i<this.objects.length;i++){
2135         this.objects[i].GLInit(this.renderer.gl);
2136     }
2137 }
2138 /**
2139 * used to clean up all the WebGL buffers etc need for this scene
2140 * @private
2141 */
2142 GLGE.Scene.prototype.destory=function(gl){
2143 }
2144 /**
2145 * renders the scene
2146 * @private
2147 */
2148 GLGE.Scene.prototype.render=function(gl){
2149 	if(this.camera.animation) this.camera.animate();
2150 	for(var i=0;i<this.lights.length;i++){
2151 		if(this.lights[i].animation) this.lights[i].animate();
2152 	}
2153 	this.renderer.gl.disable(this.renderer.gl.BLEND);
2154 	for(var i=0; i<this.objects.length;i++){
2155 		if(!this.objects[i].zTrans) this.objects[i].GLRender(this.renderer.gl);
2156 	}
2157 	this.renderer.gl.enable(this.renderer.gl.BLEND);
2158 	for(var i=0; i<this.objects.length;i++){
2159 		if(this.objects[i].zTrans) this.objects[i].GLRender(this.renderer.gl);
2160 	}
2161 }
2162 
2163 /**
2164 * @class Sets the scene to render
2165 * @param {GLGE.Scene} scene The scene to be rendered
2166 */
2167 GLGE.Renderer=function(canvas){
2168 	try{
2169 	      this.gl = canvas.getContext("webkit-3d");
2170 	    }catch(e){}
2171 	if (!this.gl){
2172 	      try
2173 	      {
2174 		this.gl = canvas.getContext("moz-webgl");
2175 	      }catch(e){}
2176 	}
2177 	if (!this.gl)
2178 	{
2179 	alert("What, What Whaaat? No WebGL!");
2180 	return false;
2181 	}
2182 	//set up defaults
2183 	this.gl.clearDepth(1.0);
2184 	this.gl.enable(this.gl.DEPTH_TEST);
2185 	//this.gl.enable(this.gl.SAMPLE_ALPHA_TO_COVERAGE);
2186     
2187 	this.gl.depthFunc(this.gl.LEQUAL);
2188 	this.gl.blendFuncSeparate(this.gl.SRC_ALPHA,this.gl.ONE_MINUS_SRC_ALPHA,this.gl.ZERO,this.gl.ONE);
2189 	
2190 	this.gl.enable(this.gl.CULL_FACE);
2191 	
2192 };
2193 GLGE.Renderer.prototype.gl=null;
2194 GLGE.Renderer.prototype.scene=null;
2195 /**
2196 * Gets the scene which is set to be rendered
2197 * @returns the current render scene
2198 */
2199 GLGE.Renderer.prototype.getScene=function(gcene){
2200 	return this.scene;
2201 };
2202 /**
2203 * Sets the scene to render
2204 * @param {GLGE.Scene} scene The scene to be rendered
2205 */
2206 GLGE.Renderer.prototype.setScene=function(scene){
2207 	scene.renderer=this;
2208 	this.scene=scene;
2209 	scene.init();
2210 };
2211 /**
2212 * Renders the current scene to the canvas
2213 */
2214 GLGE.Renderer.prototype.render=function(){
2215 	this.gl.clear(this.gl.COLOR_BUFFER_BIT | this.gl.DEPTH_BUFFER_BIT);
2216 	this.scene.render();
2217 };
2218 
2219 
2220 /**
2221 * @class A texture to be included in a material
2222 * @param {string} url the url of the image to use as the texture
2223 * @see GLGE.Material
2224 */
2225 GLGE.Texture=function(url){
2226 	this.image=new Image();
2227 	this.image.texture=this;
2228 	this.image.onload = function(){
2229 		this.texture.state=1;
2230 	}	
2231 	this.image.src=url;	
2232 	this.state=0;
2233 	this.glTexture=null;
2234 }
2235 GLGE.Texture.prototype.image=null;
2236 GLGE.Texture.prototype.texture=null;
2237 GLGE.Texture.prototype.glTexture=null;
2238 
2239 
2240 /**
2241 * @class The material layer describes how to apply this layer to the material
2242 * @param {number} texture the texture index to apply to the layer
2243 * @param {number} mapto how to map this layer on to the material see M_XXXXX constants
2244 * @param {number} mapinput the UV layer to map to, UV1 or UV2
2245 * @param {Object} scale how much scaling the texture eg {x: 10, y:10, z:1}
2246 * @param {Object} offset how much to offset the texture eg {x: 10, y:10, z:1}
2247 * @see GLGE.Material
2248 * @augments GLGE.Animatable
2249 */
2250 GLGE.MaterialLayer=function(texture,mapto,mapinput,scale,offset){
2251 	this.texture=texture;
2252 	this.mapinput=mapinput;
2253 	this.uv=mapinput;
2254 	this.mapto=mapto;
2255 	if(scale){
2256 		this.setScaleX(scale.x);
2257 		this.setScaleY(scale.y);
2258 		this.setScaleZ(scale.z);
2259 	}
2260 	if(offset){
2261 		this.setOffsetX(offset.x);
2262 		this.setOffsetY(offset.y);
2263 		this.setOffsetZ(offset.z);
2264 	}
2265 	this.scale=scale;
2266 	this.offset=offset;
2267 };
2268 GLGE.augment(GLGE.Animatable,GLGE.MaterialLayer);
2269 GLGE.MaterialLayer.prototype.texture=null;
2270 GLGE.MaterialLayer.prototype.mapto=GLGE.M_COLOR;
2271 GLGE.MaterialLayer.prototype.mapinput=GLGE.UV1;
2272 GLGE.MaterialLayer.prototype.scaleX=1;
2273 GLGE.MaterialLayer.prototype.offsetX=0;
2274 GLGE.MaterialLayer.prototype.scaleY=1;
2275 GLGE.MaterialLayer.prototype.offsetY=0;
2276 GLGE.MaterialLayer.prototype.scaleZ=1;
2277 GLGE.MaterialLayer.prototype.offsetZ=0;
2278 GLGE.MaterialLayer.prototype.dScaleX=0;
2279 GLGE.MaterialLayer.prototype.dOffsetX=0;
2280 GLGE.MaterialLayer.prototype.dScaleY=0;
2281 GLGE.MaterialLayer.prototype.dOffsetY=0;
2282 GLGE.MaterialLayer.prototype.dScaleZ=0;
2283 GLGE.MaterialLayer.prototype.dOffsetZ=0;
2284 
2285 /**
2286 * Sets the textures used by the layer
2287 * @param {GLGE.Texture} value the teture to associate with this layer
2288 */
2289 GLGE.MaterialLayer.prototype.setTexture=function(value){
2290 	this.texture=value;
2291 };
2292 /**
2293 * Gets the textures used by the layer
2294 * @return {GLGE.Texture} The current shininess of the material
2295 */
2296 GLGE.MaterialLayer.prototype.getTexture=function(){
2297 	return this.texture;
2298 };
2299 /**
2300 * Sets the flag for how this layer maps to the material
2301 * @param {Number} value the flags to set for this layer
2302 */
2303 GLGE.MaterialLayer.prototype.setMapto=function(value){
2304 	this.mapto=value;
2305 };
2306 /**
2307 * Gets the flag representing the way the layer maps to the material
2308 * @return {Number} The flags currently set for this layer
2309 */
2310 GLGE.MaterialLayer.prototype.getMapto=function(){
2311 	return this.mapto;
2312 };
2313 /**
2314 * Sets the texture coordinate system
2315 * @param {Number} value the mapping to use
2316 */
2317 GLGE.MaterialLayer.prototype.setMapinput=function(value){
2318 	this.mapinput=value;
2319 };
2320 /**
2321 * Gets the texture coordinate system
2322 * @return {Number} The current mapping
2323 */
2324 GLGE.MaterialLayer.prototype.getMapinput=function(){
2325 	return this.mapinput;
2326 };
2327 
2328 /**
2329 * Gets the layers texture offset
2330 * @return {object} the current offset
2331 */
2332 GLGE.MaterialLayer.prototype.getOffset=function(){
2333 	var offset={};
2334 	offset.x=parseFloat(this.getOffsetX())+parseFloat(this.getDOffsetX());
2335 	offset.y=parseFloat(this.getOffsetY())+parseFloat(this.getDOffsetY());
2336 	offset.z=parseFloat(this.getOffsetZ())+parseFloat(this.getDOffsetZ());
2337 	return offset;
2338 };
2339 
2340 /**
2341 * Gets the layers texture scale
2342 * @return {object} the current scale
2343 */
2344 GLGE.MaterialLayer.prototype.getScale=function(){
2345 	var scale={};
2346 	scale.x=parseFloat(this.getScaleX())+parseFloat(this.getDScaleX());
2347 	scale.y=parseFloat(this.getScaleY())+parseFloat(this.getDScaleY());
2348 	scale.z=parseFloat(this.getScaleZ())+parseFloat(this.getDScaleZ());
2349 	return scale;
2350 };
2351 
2352 /**
2353 * Sets the layers texture X offset
2354 * @param {Number} value the amount to offset the texture
2355 */
2356 GLGE.MaterialLayer.prototype.setOffsetX=function(value){
2357 	this.offsetX=value;
2358 };
2359 /**
2360 * Gets the layers texture X offset
2361 * @return {Number} the current offset
2362 */
2363 GLGE.MaterialLayer.prototype.getOffsetX=function(){
2364 	return this.offsetX;
2365 };
2366 /**
2367 * Sets the layers texture Y offset
2368 * @param {Number} value the amount to offset the texture
2369 */
2370 GLGE.MaterialLayer.prototype.setOffsetY=function(value){
2371 	this.offsetY=value;
2372 };
2373 /**
2374 * Gets the layers texture Y offset
2375 * @return {Number} the current offset
2376 */
2377 GLGE.MaterialLayer.prototype.getOffsetY=function(){
2378 	return this.offsetY;
2379 };
2380 /**
2381 * Sets the layers texture Z offset
2382 * @param {Number} value the amount to offset the texture
2383 */
2384 GLGE.MaterialLayer.prototype.setOffsetZ=function(value){
2385 	this.offsetZ=value;
2386 };
2387 /**
2388 * Gets the layers texture Z offset
2389 * @return {Number} the current offset
2390 */
2391 GLGE.MaterialLayer.prototype.getOffsetZ=function(){
2392 	return this.offsetZ;
2393 };
2394 /**
2395 * Sets the layers texture X displacment offset, useful for animation
2396 * @param {Number} value the amount to offset the texture
2397 */
2398 GLGE.MaterialLayer.prototype.setDOffsetX=function(value){
2399 	this.dOffsetX=value;
2400 };
2401 /**
2402 * Gets the layers texture X displacment offset, useful for animation
2403 * @return {Number} the current offset
2404 */
2405 GLGE.MaterialLayer.prototype.getDOffsetX=function(){
2406 	return this.dOffsetX;
2407 };
2408 /**
2409 * Sets the layers texture Y displacment offset, useful for animation
2410 * @param {Number} value the amount to offset the texture
2411 */
2412 GLGE.MaterialLayer.prototype.setDOffsetY=function(value){
2413 	this.dOffsetY=value;
2414 };
2415 /**
2416 * Gets the layers texture Y displacment offset, useful for animation
2417 * @return {Number} the current offset
2418 */
2419 GLGE.MaterialLayer.prototype.getDOffsetY=function(){
2420 	return this.dOffsetY;
2421 };
2422 /**
2423 * Sets the layers texture Z displacment offset, useful for animation
2424 * @param {Number} value the amount to offset the texture
2425 */
2426 GLGE.MaterialLayer.prototype.setDOffsetZ=function(value){
2427 	this.dOffsetZ=value;
2428 };
2429 /**
2430 * Gets the layers texture X displacment offset, useful for animation
2431 * @return {Number} the current offset
2432 */
2433 GLGE.MaterialLayer.prototype.getDOffsetZ=function(){
2434 	return this.dOffsetZ;
2435 };
2436 /**
2437 * Sets the layers texture X scale
2438 * @param {Number} value the amount to scale the texture
2439 */
2440 GLGE.MaterialLayer.prototype.setScaleX=function(value){
2441 	this.scaleX=value;
2442 };
2443 /**
2444 * Gets the layers texture X scale
2445 * @return {Number} the current scale
2446 */
2447 GLGE.MaterialLayer.prototype.getScaleX=function(){
2448 	return this.scaleX;
2449 };
2450 /**
2451 * Sets the layers texture Y scale
2452 * @param {Number} value the amount to scale the texture
2453 */
2454 GLGE.MaterialLayer.prototype.setScaleY=function(value){
2455 	this.scaleY=value;
2456 };
2457 /**
2458 * Gets the layers texture Y scale
2459 * @return {Number} the current scale
2460 */
2461 GLGE.MaterialLayer.prototype.getScaleY=function(){
2462 	return this.scaleY;
2463 };
2464 /**
2465 * Sets the layers texture Z scale
2466 * @param {Number} value the amount to scale the texture
2467 */
2468 GLGE.MaterialLayer.prototype.setScaleZ=function(value){
2469 	this.scaleZ=value;
2470 };
2471 /**
2472 * Gets the layers texture Z offset
2473 * @return {Number} the current offset
2474 */
2475 GLGE.MaterialLayer.prototype.getScaleZ=function(){
2476 	return this.scaleZ;
2477 };
2478 /**
2479 * Sets the layers texture X displacment scale, useful for animation
2480 * @param {Number} value the amount to scale the texture
2481 */
2482 GLGE.MaterialLayer.prototype.setDScaleX=function(value){
2483 	this.dScaleX=value;
2484 };
2485 /**
2486 * Gets the layers texture X displacment scale, useful for animation
2487 * @return {Number} the current scale
2488 */
2489 GLGE.MaterialLayer.prototype.getDScaleX=function(){
2490 	return this.dScaleX;
2491 };
2492 /**
2493 * Sets the layers texture Y displacment scale, useful for animation
2494 * @param {Number} value the amount to scale the texture
2495 */
2496 GLGE.MaterialLayer.prototype.setDScaleY=function(value){
2497 	this.dScaleY=value;
2498 };
2499 /**
2500 * Gets the layers texture Y displacment scale, useful for animation
2501 * @return {Number} the current scale
2502 */
2503 GLGE.MaterialLayer.prototype.getDScaleY=function(){
2504 	return this.dScaleY;
2505 };
2506 /**
2507 * Sets the layers texture Z displacment scale, useful for animation
2508 * @param {Number} value the amount to scale the texture
2509 */
2510 GLGE.MaterialLayer.prototype.setDScaleZ=function(value){
2511 	this.dScaleZ=value;
2512 };
2513 /**
2514 * Gets the layers texture X displacment scale, useful for animation
2515 * @return {Number} the current scale
2516 */
2517 GLGE.MaterialLayer.prototype.getDScaleZ=function(){
2518 	return this.dScaleZ;
2519 };
2520 
2521 
2522 
2523 /**
2524 * @class The Material class creates materials to be applied to objects in the graphics engine
2525 * @see GLGE.Object
2526 * @augments GLGE.Animatable
2527 */
2528 GLGE.Material=function(){
2529 	this.layers=[];
2530 	this.textures=[];
2531 	this.lights=[];
2532 	this.color={r:1,g:1,b:1,a:1};
2533 	this.specColor={r:1,g:1,b:1};
2534 	this.reflect=0.8;
2535 	this.shine=50;
2536 	this.specular=1;
2537 	this.emit=0;
2538 	this.alpha=1;
2539 };
2540 GLGE.augment(GLGE.Animatable,GLGE.Material);
2541 /**
2542 * @constant 
2543 * @description Flag for material colour
2544 */
2545 GLGE.M_COLOR=1; 
2546 /**
2547 * @constant 
2548 * @description Flag for material normal
2549 */
2550 GLGE.M_NOR=2;
2551 /**
2552 * @constant 
2553 * @description Flag for material alpha
2554 */
2555 GLGE.M_ALPHA=4; 
2556 /**
2557 * @constant 
2558 * @description Flag for material specular color
2559 */
2560 GLGE.M_SPECCOLOR=8; 
2561 /**
2562 * @constant 
2563 * @description Flag for material specular cvalue
2564 */
2565 GLGE.M_SPECULAR=16;
2566 /**
2567 * @constant 
2568 * @description Flag for material shineiness
2569 */
2570 GLGE.M_SHINE=32; 
2571 /**
2572 * @constant 
2573 * @description Flag for material reflectivity
2574 */
2575 GLGE.M_REFLECT=64;
2576 /**
2577 * @constant 
2578 * @description Flag for material emision
2579 */
2580 GLGE.M_EMIT=128;
2581 /**
2582 * @constant 
2583 * @description Flag for material alpha
2584 */
2585 GLGE.M_ALPHA=256;
2586 /**
2587 * @constant 
2588 * @description Flag for masking with textures red value
2589 */
2590 GLGE.M_MSKR=512;
2591 /**
2592 * @constant 
2593 * @description Flag for masking with textures green value
2594 */
2595 GLGE.M_MSKG=1024;
2596 /**
2597 * @constant 
2598 * @description Flag for masking with textures blue value
2599 */
2600 GLGE.M_MSKB=2048;
2601 /**
2602 * @constant 
2603 * @description Flag for masking with textures alpha value
2604 */
2605 GLGE.M_MSKA=4096;
2606 
2607 /**
2608 * @constant 
2609 * @description Enumeration for first UV layer
2610 */
2611 GLGE.UV1=0;
2612 /**
2613 * @constant 
2614 * @description Enumeration for second UV layer
2615 */
2616 GLGE.UV2=1;
2617 	
2618 GLGE.Material.prototype.layers=null;
2619 GLGE.Material.prototype.textures=null;
2620 GLGE.Material.prototype.color=null;
2621 GLGE.Material.prototype.specColor=null;
2622 GLGE.Material.prototype.specular=null;
2623 GLGE.Material.prototype.emit=null;
2624 GLGE.Material.prototype.shine=null;
2625 GLGE.Material.prototype.reflect=null;
2626 GLGE.Material.prototype.lights=null;
2627 GLGE.Material.prototype.alpha=null;
2628 
2629 /**
2630 * Sets the base colour of the material
2631 * @param {Number} r The new red level 0-1
2632 * @param {Number} g The new green level 0-1
2633 * @param {Number} b The new blue level 0-1
2634 */
2635 GLGE.Material.prototype.setColor=function(r,g,b){
2636 	this.color={r:r,g:g,b:b};
2637 };
2638 /**
2639 * Gets the current base color of the material
2640 * @return {[r,g,b]} The current base color
2641 */
2642 GLGE.Material.prototype.getColor=function(){
2643 	return this.color;
2644 };
2645 /**
2646 * Sets the base specular colour of the material
2647 * @param {Number} r The new red level 0-1
2648 * @param {Number} g The new green level 0-1
2649 * @param {Number} b The new blue level 0-1
2650 */
2651 GLGE.Material.prototype.setSpecularColor=function(r,g,b){
2652 	this.specColor={r:r,g:g,b:b};
2653 };
2654 /**
2655 * Gets the current base specular color of the material
2656 * @return {[r,g,b]} The current base specular color
2657 */
2658 GLGE.Material.prototype.getSpecularColor=function(){
2659 	return this.specColor;
2660 };
2661 /**
2662 * Sets the alpha of the material
2663 * @param {Number} value how much alpha
2664 */
2665 GLGE.Material.prototype.setAlpha=function(value){
2666 	this.alpha=value;
2667 };
2668 /**
2669 * Gets the alpha of the material
2670 * @return {Number} The current alpha of the material
2671 */
2672 GLGE.Material.prototype.getAlpha=function(){
2673 	return this.alpha;
2674 };
2675 /**
2676 * Sets the specular of the material
2677 * @param {Number} value how much specular
2678 */
2679 GLGE.Material.prototype.setSpecular=function(value){
2680 	this.specular=value;
2681 };
2682 /**
2683 * Gets the specular of the material
2684 * @return {Number} The current specular of the material
2685 */
2686 GLGE.Material.prototype.getSpecular=function(){
2687 	return this.specular;
2688 };
2689 /**
2690 * Sets the shininess of the material
2691 * @param {Number} value how much shine
2692 */
2693 GLGE.Material.prototype.setShininess=function(value){
2694 	this.shine=value;
2695 };
2696 /**
2697 * Gets the shininess of the material
2698 * @return {Number} The current shininess of the material
2699 */
2700 GLGE.Material.prototype.getShininess=function(){
2701 	return this.shine;
2702 };
2703 /**
2704 * Sets how much the material should emit
2705 * @param {Number} value how much to emit (0-1)
2706 */
2707 GLGE.Material.prototype.setEmit=function(value){
2708 	this.emit=value;
2709 };
2710 /**
2711 * Gets the amount this material emits
2712 * @return {Number} The emit value for the material
2713 */
2714 GLGE.Material.prototype.getEmit=function(){
2715 	return this.emit;
2716 };
2717 /**
2718 * Sets reflectivity of the material
2719 * @param {Number} value how much to reflect (0-1)
2720 */
2721 GLGE.Material.prototype.setReflectivity=function(value){
2722 	this.reflect=value;
2723 };
2724 /**
2725 * Gets the materials reflectivity
2726 * @return {Number} The reflectivity of the material
2727 */
2728 GLGE.Material.prototype.getReflectivity=function(){
2729 	return this.reflect;
2730 };
2731 
2732 /**
2733 * Add a new layer to the material
2734 * @param {MaterialLayer} layer The material layer to add to the material
2735 * @returns {Number} index of the added layer
2736 */
2737 GLGE.Material.prototype.addMaterialLayer=function(layer){
2738 	this.layers.push(layer);
2739 	return this.layers.length-1;
2740 };
2741 /**
2742 * Gets all the materials layers
2743 * @returns {GLGE.MaterialLayer[]} all of the layers contained within this material
2744 */
2745 GLGE.Material.prototype.getLayers=function(){
2746 	return this.layers;
2747 };
2748 /**
2749 * Generate the fragment shader program for this material
2750 * @private
2751 */
2752 GLGE.Material.prototype.getFragmentShader=function(lights,ambiantColor){
2753 	var shader="";
2754 	
2755 	for(var i=0; i<lights.length;i++){
2756 		if(lights[i].type==GLGE.L_POINT || lights[i].type==GLGE.L_SPOT || lights[i].type==GLGE.L_DIR){
2757 			shader=shader+"varying vec3 lightvec"+i+";\n"; 
2758 			shader=shader+"varying float lightdist"+i+";\n";  
2759 		}
2760 	}
2761 	shader=shader+"varying vec3 n;\n";  
2762 	shader=shader+"varying vec4 UVCoord;\n";
2763 	shader=shader+"varying vec3 eyevec;\n"; 
2764 
2765 	//texture uniforms
2766 	for(var i=0; i<this.textures.length;i++){
2767 		shader=shader+"uniform sampler2D TEXTURE"+i+";\n";
2768 	}
2769 	for(var i=0; i<lights.length;i++){
2770 			shader=shader+"uniform vec3 lightcolor"+i+";\n";  
2771 			shader=shader+"uniform vec3 lightAttenuation"+i+";\n";  
2772 			shader=shader+"uniform float spotCosCutOff"+i+";\n";  
2773 			shader=shader+"uniform float spotExp"+i+";\n";  
2774 			shader=shader+"uniform vec3 lightdir"+i+";\n";  
2775 	}
2776 	for(i=0; i<this.layers.length;i++){
2777 		shader=shader+"uniform vec3 layer"+i+"Scale;\n";  
2778 		shader=shader+"uniform vec3 layer"+i+"Offset;\n";  
2779 	}
2780 	
2781 	shader=shader+"uniform vec4 baseColor;\n";
2782 	shader=shader+"uniform vec3 specColor;\n";
2783 	shader=shader+"uniform float shine;\n";
2784 	shader=shader+"uniform float specular;\n";
2785 	shader=shader+"uniform float reflect;\n";
2786 	shader=shader+"uniform float emit;\n";
2787 	shader=shader+"uniform float alpha;\n";
2788     
2789 	shader=shader+"void main(void)\n";
2790 	shader=shader+"{\n";
2791 	shader=shader+"float att;\n"; 
2792 	shader=shader+"int texture;\n"; 
2793 	shader=shader+"float mask=1.0;\n";
2794 	shader=shader+"float spec=specular;\n"; 
2795 	shader=shader+"vec3 specC=specColor;\n"; 
2796 	shader=shader+"float ref=reflect;\n";
2797 	shader=shader+"float sh=shine;\n"; 
2798 	shader=shader+"float em=emit;\n"; 
2799 	shader=shader+"float al=alpha;\n"; 
2800 	shader=shader+"vec4 normalmap=vec4(0.5,0.5,0.5,0.5);\n"
2801 	shader=shader+"vec4 color = baseColor;"; //set the initial color
2802 	for(i=0; i<this.layers.length;i++){
2803 		if((this.layers[i].mapto & GLGE.M_COLOR) == GLGE.M_COLOR){
2804 			shader=shader+"color = color*(1.0-mask) + texture2D(TEXTURE"+this.layers[i].texture.idx+", vec2((UVCoord["+(this.layers[i].mapinput*2)+"]+layer"+i+"Offset[0])*layer"+i+"Scale[0],(1.0-UVCoord["+(this.layers[i].mapinput*2+1)+"]+layer"+i+"Offset[1])*layer"+i+"Scale[1]))*mask;\n";
2805 		}        
2806 		if((this.layers[i].mapto & GLGE.M_SPECCOLOR) == GLGE.M_SPECCOLOR){
2807 			shader=shader+"specC = specC*(1.0-mask) + texture2D(TEXTURE"+this.layers[i].texture.idx+", vec2((UVCoord["+(this.layers[i].mapinput*2)+"]+layer"+i+"Offset[0])*layer"+i+"Scale[0],(1.0-UVCoord["+(this.layers[i].mapinput*2+1)+"]+layer"+i+"Offset[1])*layer"+i+"Scale[1])).rgb*mask;\n";
2808 		}
2809 		if((this.layers[i].mapto & GLGE.M_MSKR) == GLGE.M_MSKR){
2810 			shader=shader+"mask = texture2D(TEXTURE"+this.layers[i].texture.idx+", vec2((UVCoord["+(this.layers[i].mapinput*2)+"]+layer"+i+"Offset[0])*layer"+i+"Scale[0],(1.0-UVCoord["+(this.layers[i].mapinput*2+1)+"]+layer"+i+"Offset[1])*layer"+i+"Scale[1])).r;\n";
2811 		}
2812 		if((this.layers[i].mapto & GLGE.M_MSKG) == GLGE.M_MSKG){
2813 			shader=shader+"mask = texture2D(TEXTURE"+this.layers[i].texture.idx+", vec2((UVCoord["+(this.layers[i].mapinput*2)+"]+layer"+i+"Offset[0])*layer"+i+"Scale[0],(1.0-UVCoord["+(this.layers[i].mapinput*2+1)+"]+layer"+i+"Offset[1])*layer"+i+"Scale[1])).g;\n";
2814 		}
2815 		if((this.layers[i].mapto & GLGE.M_MSKG) == GLGE.M_MSKB){
2816 			shader=shader+"mask = texture2D(TEXTURE"+this.layers[i].texture.idx+", vec2((UVCoord["+(this.layers[i].mapinput*2)+"]+layer"+i+"Offset[0])*layer"+i+"Scale[0],(1.0-UVCoord["+(this.layers[i].mapinput*2+1)+"]+layer"+i+"Offset[1])*layer"+i+"Scale[1])).b;\n";
2817 		}
2818 		if((this.layers[i].mapto & GLGE.M_MSKG) == GLGE.M_MSKA){
2819 			shader=shader+"mask = texture2D(TEXTURE"+this.layers[i].texture.idx+", vec2((UVCoord["+(this.layers[i].mapinput*2)+"]+layer"+i+"Offset[0])*layer"+i+"Scale[0],(1.0-UVCoord["+(this.layers[i].mapinput*2+1)+"]+layer"+i+"Offset[1])*layer"+i+"Scale[1])).a;\n";
2820 		}
2821 		if((this.layers[i].mapto & GLGE.M_SPECULAR) == GLGE.M_SPECULAR){
2822 			shader=shader+"spec = spec*(1.0-mask) + texture2D(TEXTURE"+this.layers[i].texture.idx+", vec2((UVCoord["+(this.layers[i].mapinput*2)+"]+layer"+i+"Offset[0])*layer"+i+"Scale[0],(1.0-UVCoord["+(this.layers[i].mapinput*2+1)+"]+layer"+i+"Offset[1])*layer"+i+"Scale[1])).r*mask*10.0;\n";
2823 		}
2824 		if((this.layers[i].mapto & GLGE.M_REFLECT) == GLGE.M_REFLECT){
2825 			shader=shader+"ref = ref*(1.0-mask) + texture2D(TEXTURE"+this.layers[i].texture.idx+", vec2((UVCoord["+(this.layers[i].mapinput*2)+"]+layer"+i+"Offset[0])*layer"+i+"Scale[0],(1.0-UVCoord["+(this.layers[i].mapinput*2+1)+"]+layer"+i+"Offset[1])*layer"+i+"Scale[1])).g*mask;\n";
2826 		}
2827 		if((this.layers[i].mapto & GLGE.M_SHINE) == GLGE.M_SHINE){
2828 			shader=shader+"sh = sh*(1.0-mask) + texture2D(TEXTURE"+this.layers[i].texture.idx+", vec2((UVCoord["+(this.layers[i].mapinput*2)+"]+layer"+i+"Offset[0])*layer"+i+"Scale[0],(1.0-UVCoord["+(this.layers[i].mapinput*2+1)+"]+layer"+i+"Offset[1])*layer"+i+"Scale[1])).b*mask*512.0;\n";
2829 		}
2830 		if((this.layers[i].mapto & GLGE.M_EMIT) == GLGE.M_EMIT){
2831 			shader=shader+"em = em*(1.0-mask) + texture2D(TEXTURE"+this.layers[i].texture.idx+", vec2((UVCoord["+(this.layers[i].mapinput*2)+"]+layer"+i+"Offset[0])*layer"+i+"Scale[0],(1.0-UVCoord["+(this.layers[i].mapinput*2+1)+"]+layer"+i+"Offset[1])*layer"+i+"Scale[1])).r*mask;\n";
2832 		}
2833 		if((this.layers[i].mapto & GLGE.M_NOR) == GLGE.M_NOR){
2834 			shader=shader+"normalmap = normalmap*(1.0-mask) + texture2D(TEXTURE"+this.layers[i].texture.idx+", vec2((UVCoord["+(this.layers[i].mapinput*2)+"]+layer"+i+"Offset[0])*layer"+i+"Scale[0],(1.0-UVCoord["+(this.layers[i].mapinput*2+1)+"]+layer"+i+"Offset[1])*layer"+i+"Scale[1]))*mask;\n";
2835 		}
2836 		if((this.layers[i].mapto & GLGE.M_ALPHA) == GLGE.M_ALPHA){
2837 			shader=shader+"al = al*(1.0-mask) + texture2D(TEXTURE"+this.layers[i].texture.idx+", vec2((UVCoord["+(this.layers[i].mapinput*2)+"]+layer"+i+"Offset[0])*layer"+i+"Scale[0],(1.0-UVCoord["+(this.layers[i].mapinput*2+1)+"]+layer"+i+"Offset[1])*layer"+i+"Scale[1])).a*mask;\n";
2838 		}
2839 	}
2840 	shader=shader+"normalmap=(normalmap-vec4(0.5,0.5,0.5,0.5))*vec4(2.0,2.0,0.0,0.0);\n";
2841 	shader=shader+"vec3 normal = normalize(n+normalmap.rgb);\n";
2842 	shader=shader+"vec3 lightvalue=vec3(0.0,0.0,0.0);\n"; 
2843 	shader=shader+"vec3 specvalue=vec3(0.0,0.0,0.0);\n"; 
2844 	shader=shader+"float dotN,spotEffect;";
2845 	for(var i=0; i<lights.length;i++){
2846 		if(lights[i].type==GLGE.L_POINT){
2847 			shader=shader+"dotN=max(dot(normal,normalize(lightvec"+i+")),0.0);\n";       
2848 			//shader=shader+"if(dotN>0.0){\n";
2849 			shader=shader+"att = 1 / (lightAttenuation"+i+"[0] + lightAttenuation"+i+"[1] * lightdist"+i+" + lightAttenuation"+i+"[2] * lightdist"+i+" * lightdist"+i+");\n";
2850 			if(lights[i].diffuse){
2851 				shader=shader+"lightvalue += att * dotN * lightcolor"+i+";\n";
2852 			}
2853 			if(lights[i].specular){
2854 				shader=shader+"specvalue += att * specC * lightcolor"+i+" * spec  * pow(max(dot(normal,normalize(eyevec)),0.0), sh);\n";
2855 			}
2856 			//shader=shader+"}\n";
2857 		}
2858 		shader=shader+"spotEffect = 0.0;\n";
2859 		if(lights[i].type==GLGE.L_SPOT){
2860 			shader=shader+"spotEffect = dot(normalize(lightdir"+i+"), normalize(-lightvec"+i+"));";
2861 			shader=shader+"if (spotEffect > spotCosCutOff"+i+") {\n";
2862 			shader=shader+"spotEffect = pow(spotEffect, spotExp"+i+");";
2863 			shader=shader+"dotN=max(dot(normal,normalize(lightvec"+i+")),0.0);\n";       
2864 			shader=shader+"if(dotN>0.0){\n";
2865 			shader=shader+"att = spotEffect / (lightAttenuation"+i+"[0] + lightAttenuation"+i+"[1] * lightdist"+i+" + lightAttenuation"+i+"[2] * lightdist"+i+" * lightdist"+i+");\n";
2866 			if(lights[i].diffuse){
2867 				shader=shader+"lightvalue += att * dotN * lightcolor"+i+";\n";
2868 			}
2869 			if(lights[i].specular){
2870 				shader=shader+"specvalue += att * specC * lightcolor"+i+" * spec  * pow(max(dot(normal,normalize(eyevec)),0.0), sh);\n";
2871 			}
2872 			shader=shader+"}\n}\n";
2873 		}
2874 		if(lights[i].type==GLGE.L_DIR){
2875 			shader=shader+"dotN=max(dot(normal,normalize(-lightdir"+i+")),0.0);\n";       
2876 			if(lights[i].diffuse){
2877 				shader=shader+"lightvalue += dotN * lightcolor"+i+";\n";
2878 			}
2879 			if(lights[i].specular){
2880 				shader=shader+"specvalue += specC * lightcolor"+i+" * spec  * pow(max(dot(normal,normalize(eyevec)),0.0), sh);\n";
2881 			}
2882 		}
2883 	}
2884 		
2885 	shader=shader+"lightvalue *= ref;\n"
2886 	shader=shader+"gl_FragColor = vec4(specvalue,0.0)+vec4(color.r*em+(color.r*lightvalue.r*(1.0-em)),color.g*em+(color.g*lightvalue.g*(1.0-em)),color.b*em+(color.b*lightvalue.b*(1.0-em)),al);\n";
2887 	//shader=shader+"gl_FragColor = vec4(normal,al);\n";
2888 	shader=shader+"}\n";
2889 	return shader;
2890 };
2891 /**
2892 * Set the uniforms needed to render this material
2893 * @private
2894 */
2895 GLGE.Material.prototype.textureUniforms=function(gl,shaderProgram,lights){
2896 	if(this.animation) this.animate();
2897 	gl.uniform4f(gl.getUniformLocation(shaderProgram, "baseColor"), this.color.r,this.color.g,this.color.b,this.color.a);
2898 	gl.uniform3f(gl.getUniformLocation(shaderProgram, "specColor"), this.specColor.r,this.specColor.g,this.specColor.b);
2899 	gl.uniform1f(gl.getUniformLocation(shaderProgram, "specular"), this.specular);
2900 	gl.uniform1f(gl.getUniformLocation(shaderProgram, "shine"), this.shine);
2901 	gl.uniform1f(gl.getUniformLocation(shaderProgram, "reflect"), this.reflect);
2902 	gl.uniform1f(gl.getUniformLocation(shaderProgram, "emit"), this.emit);
2903 	gl.uniform1f(gl.getUniformLocation(shaderProgram, "alpha"), this.alpha);
2904 	for(var i=0; i<lights.length;i++){
2905 		    gl.uniform3f(gl.getUniformLocation(shaderProgram, "lightcolor"+i), lights[i].color.r,lights[i].color.g,lights[i].color.b);
2906 		    gl.uniform3f(gl.getUniformLocation(shaderProgram, "lightAttenuation"+i), lights[i].constantAttenuation,lights[i].linearAttenuation,lights[i].quadraticAttenuation);
2907 		    gl.uniform1f(gl.getUniformLocation(shaderProgram, "spotCosCutOff"+i), lights[i].spotCosCutOff);
2908 		    gl.uniform1f(gl.getUniformLocation(shaderProgram, "spotExp"+i), lights[i].spotExponent);
2909 	}
2910 	
2911 	var scale,offset;
2912 	for(i=0; i<this.layers.length;i++){
2913 		if(this.layers[i].animation) this.layers[i].animate();
2914 		scale=this.layers[i].getScale();
2915 		offset=this.layers[i].getOffset();
2916 		gl.uniform3f(gl.getUniformLocation(shaderProgram, "layer"+i+"Scale"), scale.x,scale.y,scale.z);
2917 		gl.uniform3f(gl.getUniformLocation(shaderProgram, "layer"+i+"Offset"), offset.x,offset.y,offset.z);
2918 	}
2919     
2920 	for(var i=0; i<this.textures.length;i++){
2921 		gl.activeTexture(gl["TEXTURE"+i]);
2922 		//create the texture if it's not already created
2923 		if(!this.textures[i].glTexture) this.textures[i].glTexture=gl.createTexture();
2924 		//if the image is loaded then set in the texture data
2925 		if(this.textures[i].state==1){
2926 			gl.bindTexture(gl.TEXTURE_2D, this.textures[i].glTexture);
2927 			gl.texImage2D(gl.TEXTURE_2D, 0, this.textures[i].image);
2928 			gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
2929 			gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_LINEAR);
2930 			gl.generateMipmap(gl.TEXTURE_2D);
2931 			gl.bindTexture(gl.TEXTURE_2D, null);
2932 			this.textures[i].state=2;
2933 		}
2934 		gl.bindTexture(gl.TEXTURE_2D, this.textures[i].glTexture);
2935 		gl.uniform1i(gl.getUniformLocation(shaderProgram, "TEXTURE"+i), i);
2936 	}
2937 };
2938 /**
2939 * Adds a new texture to this material
2940 * @param {String} image URL of the image to be used by the texture
2941 * @return {Number} index of the new texture
2942 */
2943 GLGE.Material.prototype.addTexture=function(texture){	
2944 	this.textures.push(texture);
2945 	texture.idx=this.textures.length-1;
2946 	return texture;
2947 };
2948 })(GLGE);
2949 
2950 
2951