From 86a801c057fc3b0580d6130be5740c2ee503444f Mon Sep 17 00:00:00 2001
From: hwc487
Date: Fri, 27 Jan 2012 15:52:36 -0800
Subject: updated from old repo

---
 js/helper-classes/RDGE/GLCircle.js                 |  10 +-
 js/helper-classes/RDGE/GLGeomObj.js                |   3 +
 js/helper-classes/RDGE/GLMaterial.js               |  29 +++
 js/helper-classes/RDGE/GLRectangle.js              |  17 +-
 js/helper-classes/RDGE/GLWorld.js                  | 211 ++++++++++++++++++---
 .../RDGE/Materials/BumpMetalMaterial.js            |  66 +++++--
 js/helper-classes/RDGE/Materials/FlatMaterial.js   |   2 +
 .../RDGE/Materials/IridescentScalesMaterial.js     |   5 +-
 js/helper-classes/RDGE/Materials/JuliaMaterial.js  |   3 +
 .../RDGE/Materials/KeleidoscopeMaterial.js         |   3 +
 .../RDGE/Materials/LinearGradientMaterial.js       |   4 +
 js/helper-classes/RDGE/Materials/MandelMaterial.js |   4 +
 js/helper-classes/RDGE/Materials/PulseMaterial.js  |  15 +-
 .../RDGE/Materials/RadialBlurMaterial.js           |   3 +
 .../RDGE/Materials/RadialGradientMaterial.js       | 188 ++++++++++--------
 js/helper-classes/RDGE/Materials/TunnelMaterial.js |   3 +
 js/helper-classes/RDGE/Materials/TwistMaterial.js  |   3 +
 js/helper-classes/RDGE/Materials/UberMaterial.js   |  25 ++-
 js/helper-classes/RDGE/MaterialsLibrary.js         |  40 ++--
 js/helper-classes/RDGE/rdge-compiled.js            | 102 +++++-----
 .../RDGE/src/core/script/init_state.js             |   7 +-
 js/helper-classes/RDGE/src/core/script/renderer.js |  14 +-
 .../RDGE/src/core/script/run_state.js              |  10 +-
 js/helper-classes/RDGE/src/core/script/runtime.js  |   2 +-
 24 files changed, 554 insertions(+), 215 deletions(-)

(limited to 'js/helper-classes')

diff --git a/js/helper-classes/RDGE/GLCircle.js b/js/helper-classes/RDGE/GLCircle.js
index fc2e6460..8f7a5d30 100644
--- a/js/helper-classes/RDGE/GLCircle.js
+++ b/js/helper-classes/RDGE/GLCircle.js
@@ -63,14 +63,16 @@ function GLCircle()
 
 		this.m_world = world;
 
+
 		if(strokeMaterial)
-		{
 			this._strokeMaterial = strokeMaterial;
-		}
+		else
+			this._strokeMaterial = new FlatMaterial();
+
 		if(fillMaterial)
-		{
 			this._fillMaterial = fillMaterial;
-		}
+		else 
+			this._fillMaterial = new FlatMaterial();
 	}
 
     ///////////////////////////////////////////////////////////////////////
diff --git a/js/helper-classes/RDGE/GLGeomObj.js b/js/helper-classes/RDGE/GLGeomObj.js
index 72019703..e04b3283 100644
--- a/js/helper-classes/RDGE/GLGeomObj.js
+++ b/js/helper-classes/RDGE/GLGeomObj.js
@@ -99,6 +99,9 @@ function GLGeomObj()
 				}
 			}
 		}
+
+		var world = this.getWorld();
+		if (world)  world.restartRenderLoop();
 	}
 
 	this.setFillColor   = function(c)		{  this.setMaterialColor(c, "fill");		}
diff --git a/js/helper-classes/RDGE/GLMaterial.js b/js/helper-classes/RDGE/GLMaterial.js
index 51c27ace..c633f679 100644
--- a/js/helper-classes/RDGE/GLMaterial.js
+++ b/js/helper-classes/RDGE/GLMaterial.js
@@ -62,6 +62,10 @@ function GLMaterial( world )
 	this.getShader			= function()			{  return this._shader;				}
 	this.getMaterialNode	= function()			{  return this._materialNode;		}
 
+	// a material can be animated or not. default is not.  
+	// Any material needing continuous rendering should override this method
+	this.isAnimated			= function()			{  return false;					}
+
 
     ///////////////////////////////////////////////////////////////////////
     // Common Material Methods
@@ -174,6 +178,31 @@ function GLMaterial( world )
 		// animated materials should implement the update method
 	}
 
+	this.registerTexture = function( texture )
+	{
+		// the world needs to know about the texture map
+		var world = this.getWorld();
+		if (!world)
+			console.log( "**** world not defined for registering texture map: " + texture.lookUpName );
+		else
+			world.textureToLoad( texture );
+	}
+
+	this.loadTexture = function( texMapName, wrap, mips )
+	{
+		var tex;
+		var world = this.getWorld();
+		if (!world)
+			console.log( "world not defined for material with texture map" );
+		else
+		{
+			var renderer = world.getRenderer();
+			tex = renderer.getTextureByName(texMapName, wrap, mips );
+			this.registerTexture( tex );
+		}
+		return tex;
+	}
+
 	this.export = function()
 	{
 		// this function should be overridden by subclasses
diff --git a/js/helper-classes/RDGE/GLRectangle.js b/js/helper-classes/RDGE/GLRectangle.js
index 1334d7e6..bc3b1478 100644
--- a/js/helper-classes/RDGE/GLRectangle.js
+++ b/js/helper-classes/RDGE/GLRectangle.js
@@ -80,13 +80,14 @@ function GLRectangle()
 		this._materialSpecular = [0.4, 0.4, 0.4,  1.0];
 
 		if(strokeMaterial)
-		{
 			this._strokeMaterial = strokeMaterial;
-		}
+		else
+			this._strokeMaterial = new FlatMaterial();
+
 		if(fillMaterial)
-		{
 			this._fillMaterial = fillMaterial;
-		}
+		else 
+			this._fillMaterial = new FlatMaterial();
 	}
 
 	///////////////////////////////////////////////////////////////////////
@@ -278,10 +279,10 @@ function GLRectangle()
 		brRadius = -z*(r-l)/(2.0*zn)*brRadiusNDC;
 
 		// stroke
-		var strokeMaterial = this.makeStrokeMaterial();
-		prim = this.createStroke([x,y],  2*xFill,  2*yFill,  strokeSize,  tlRadius, blRadius, brRadius, trRadius, strokeMaterial)
-        this._primArray.push( prim );
-		this._materialNodeArray.push( strokeMaterial.getMaterialNode() );
+//		var strokeMaterial = this.makeStrokeMaterial();
+//		prim = this.createStroke([x,y],  2*xFill,  2*yFill,  strokeSize,  tlRadius, blRadius, brRadius, trRadius, strokeMaterial)
+//        this._primArray.push( prim );
+//		this._materialNodeArray.push( strokeMaterial.getMaterialNode() );
 
 		// fill
 		tlRadius -= strokeSize;  if (tlRadius < 0)  tlRadius = 0.0;
diff --git a/js/helper-classes/RDGE/GLWorld.js b/js/helper-classes/RDGE/GLWorld.js
index cc44da50..dd9b6977 100644
--- a/js/helper-classes/RDGE/GLWorld.js
+++ b/js/helper-classes/RDGE/GLWorld.js
@@ -65,6 +65,11 @@ function GLWorld( canvas, use3D )
 
 	this._camera;
 
+	// keep a flag indicating whether a render has been completed.
+	// this allows us to turn off automatic updating if there are
+	// no animated materials
+	this._firstRender = true;
+
     ///////////////////////////////////////////////////////////////////////
     // Property accessors
     ///////////////////////////////////////////////////////////////////////
@@ -103,6 +108,8 @@ function GLWorld( canvas, use3D )
 
 	this.isWebGL				= function()		{  return this._useWebGL;			}
 
+	this.getRenderer			= function()		{  return this.renderer;			}
+
   ////////////////////////////////////////////////////////////////////////////////////
   // RDGE
   // local variables
@@ -114,6 +121,10 @@ function GLWorld( canvas, use3D )
     this.strokeShader = null;
     this.renderer = null;
 
+	// keep an array of texture maps that need to be loaded
+	this._texMapsToLoad = [];
+	this._allMapsLoaded = true;
+
 	// this is the node to which objects get hung
 	this._rootNode;
 
@@ -214,18 +225,149 @@ function GLWorld( canvas, use3D )
     {
 		if (this._useWebGL)
 		{
-			var ctx = g_Engine.getContext();
-			//console.log( "RDGE state: " + ctx.ctxStateManager.currentState().name);
-
-			var renderer = ctx.renderer;
-			renderer.disableCulling();
-			this.myScene.render();
+			if (this._allMapsLoaded)
+			{
+				var ctx = g_Engine.getContext();
+				//console.log( "RDGE state: " + ctx.ctxStateManager.currentState().name);
+
+				/////////////////////////////
+				var ctx1 = g_Engine.ctxMan.handleToObject(this._canvas.rdgeCtxHandle);
+				if (ctx1 != ctx)  console.log( "***** different contexts (2) *****" );
+				var aRenderer = ctx1.renderer;
+				//////////////////////////////////////////
+
+				var renderer = ctx.renderer;
+				if (renderer != aRenderer)  console.log( "***** DIFFERENT RENDERERS *****" );
+				renderer.disableCulling();
+				this.myScene.render();
+
+				if (this._firstRender)
+				{
+					this._firstRender = false;
+
+					if (!this.hasAnimatedMaterials())
+					{
+						this.myScene.render();
+						this._canvas.task.stop();
+					}
+				}
+			}
 		}
 		else
 		{
 			this.render();
 		}
     }
+	
+    this.onRunState = function()
+	{
+		console.log( "GLWorld.onRunState" );
+	}
+	
+    this.onLoadState = function()
+	{
+		console.log( "GLWorld.onLoadState" );
+	}
+
+	this.textureToLoad = function( texture )
+	{
+		if (!texture.previouslyReferenced)
+		{
+			var name = texture.lookUpName;
+			texture._world = this;
+			texture.callback = this.textureMapLoaded;
+			this._texMapsToLoad[name] = true;
+			this._allMapsLoaded = false;
+
+			// stop the draw loop until all textures have been loaded
+			this._canvas.task.stop();
+		}
+	}
+
+	this.textureMapLoaded = function( texture )
+	{
+		var world = texture._world;
+		if (!world)
+		{
+			console.log( "**** loaded texture does not have world defined ****" );
+			return;
+		}
+
+		var name = texture.lookUpName;
+		if (!world._texMapsToLoad[name])
+		{
+			console.log( "loaded an unregistered texture map: " + name );
+		}
+		else
+		{
+			//console.log( "loaded a registered texture map: " + name );
+			world._texMapsToLoad[name] = undefined;
+		}
+
+		// check if all the texture maps are loaded.  if so, resume the render loop
+		world._allMapsLoaded = world.allTextureMapsLoaded();
+		if (world._allMapsLoaded)
+			world._canvas.task.start();
+	}
+
+	this.allTextureMapsLoaded = function()
+	{
+		for (var name in this._texMapsToLoad)
+		{
+			var needsLoad = this._texMapsToLoad[name];
+			if (needsLoad)  return false;
+		}
+
+		return true;
+	}
+
+	this.textureLoadedCallback = function( name )
+	{
+		console.log( "*** material texture loaded: " + name );
+
+		var world = this._world;
+		if (!world)
+			console.log( "**** world not defined for loaded texture map: " + name );
+		else
+			world.textureMapLoaded( name );
+	}
+	
+	this.hasAnimatedMaterials = function()
+	{
+		var root = this.getGeomRoot();
+		var rtnVal = false;
+		if (root)
+			rtnVal = this.hHasAnimatedMaterials( root );
+
+		return rtnVal;
+	}
+
+	this.hHasAnimatedMaterials = function( obj )
+	{
+		if (obj)
+		{
+			if (obj.getFillMaterial())
+			{
+				if (obj.getFillMaterial().isAnimated())  return true;
+			}
+
+			if (obj.getStrokeMaterial())
+			{
+				if (obj.getStrokeMaterial().isAnimated())  return true;
+			}
+
+
+			// do the sibling
+			var hasAnim = false;
+			if  (obj.getNext())  hasAnim = this.hHasAnimatedMaterials( obj.getNext() );
+			if (hasAnim)  return true;
+			if  (obj.getChild())  hasAnim = this.hHasAnimatedMaterials( obj.getChild() );
+			if (hasAnim)  return true;
+		}
+
+		return false;
+	}
+
 
 	// END RDGE
 	////////////////////////////////////////////////////////////////////////////////////
@@ -233,23 +375,20 @@ function GLWorld( canvas, use3D )
     
     // start RDGE passing your runtime object, and false to indicate we don't need a an initialization state
     // in the case of a procedurally built scene an init state is not needed for loading data
-	//if (this._useWebGL)
+	if (this._useWebGL)
 	{
-		if (this._useWebGL)
-		{
-			rdgeStarted = true;
+		rdgeStarted = true;
 
-            // TODO - temporary fix for RDGE id's
-            this._canvas.id = this._canvas.uuid;
+        // TODO - temporary fix for RDGE id's
+        this._canvas.id = this._canvas.uuid;
 
-			g_Engine.registerCanvas(this._canvas, this);
-			RDGEStart( this._canvas );
+		g_Engine.registerCanvas(this._canvas, this);
+		RDGEStart( this._canvas );
 
-			//this._canvas.fpsTracker = new fpsTracker( '0' );
-			//this._canvas.task = new RDGETask(this._canvas, true);
-			//this._canvas.task.stop()
-			//this._canvas.task.start()
-		}
+		//this._canvas.fpsTracker = new fpsTracker( '0' );
+		this._canvas.task = new RDGETask(this._canvas, false);
+		this._canvas.task.stop()
+		//this._canvas.task.start()
 	}
 }
 
@@ -334,10 +473,6 @@ GLWorld.prototype.addObject = function( obj )
 
         obj.setWorld( this );
 
-		// build the WebGL buffers
-		if (this._useWebGL)
-			obj.buildBuffers();
-
         if (this._geomRoot == null)
         {
             this._geomRoot = obj;
@@ -349,6 +484,13 @@ GLWorld.prototype.addObject = function( obj )
             go.setNext( obj );
             obj.setPrev( go );
         }
+
+		// build the WebGL buffers
+		if (this._useWebGL)
+		{
+			obj.buildBuffers();
+			this.restartRenderLoop();
+		}
     }
     catch(e)
     {
@@ -356,16 +498,23 @@ GLWorld.prototype.addObject = function( obj )
     }
 }
 
+GLWorld.prototype.restartRenderLoop = function()
+{
+	this._firstRender = true;
+	if (this._allMapsLoaded)
+		this._canvas.task.start();
+	else
+		this._canvas.task.stop();
+}
+
 //append to the list of objects if obj doesn't already exist
 //if obj exists, then don't add to list of objects
-GLWorld.prototype.addIfNewObject = function (obj) {
+GLWorld.prototype.addIfNewObject = function (obj)
+{
     if (!obj) return;
 
     try {
         obj.setWorld(this);
-        // build the WebGL buffers
-		if (this._useWebGL)
-            obj.buildBuffers();
 
         if (this._geomRoot == null) {
             this._geomRoot = obj;
@@ -384,8 +533,16 @@ GLWorld.prototype.addIfNewObject = function (obj) {
 
                 go.setNext(obj);
                 obj.setPrev(go);
+
             }
         }
+
+		// build the WebGL buffers
+		if (this._useWebGL)
+		{
+			obj.buildBuffers();
+			this.restartRenderLoop();
+		}
     }
     catch (e) {
         alert("Exception in GLWorld.addIfNewObject " + e);
diff --git a/js/helper-classes/RDGE/Materials/BumpMetalMaterial.js b/js/helper-classes/RDGE/Materials/BumpMetalMaterial.js
index 0aa3ee78..17be0cd7 100644
--- a/js/helper-classes/RDGE/Materials/BumpMetalMaterial.js
+++ b/js/helper-classes/RDGE/Materials/BumpMetalMaterial.js
@@ -22,9 +22,9 @@ function BumpMetalMaterial()
 	this._shaderName = "bumpMetal";
 
 	this._lightDiff = [0.3, 0.3, 0.3, 1.0];
-	this._diffuseTexture = "metal";
-	this._specularTexture = "silver";
-	this._normalTexture = "normalMap";
+	this._diffuseTexture = "assets/images/metal.png";
+	this._specularTexture = "assets/images/silver.png";
+	this._normalTexture = "assets/images/normalMap.png";
 
     ///////////////////////////////////////////////////////////////////////
     // Property Accessors
@@ -37,17 +37,16 @@ function BumpMetalMaterial()
 													if (this._shader && this._shader.default)
 														this._shader.default.u_light0Diff.set( ld );	}
 
-	this.getDiffuseTexture	= function()		{	return this._diffuseTexture;					}
-	this.setDiffuseTexture	= function(dt)		{	this._diffuseTexture = dt;
-													if (this._materialNode)  this._materialNode.setDiffuseTexture( dt );	}
+	this.getDiffuseTexture	= function()		{  return this._propValues[this._propNames[1]] ? this._propValues[this._propNames[1]].slice() : null	}
+	this.setDiffuseTexture	= function(m)		{  this._propValues[this._propNames[1]] = m ? m.slice(0) : null;  this.updateTexture(1);  	}	
 
-	this.getSpecularTexture	= function()		{	return this._specularTexture;					}
-	this.setSpecularTexture	= function(st)		{	this._specularTexture = st;
-													if (this._materialNode)  this._materialNode.setSpecularTexture( st );	}
+	this.getNormalTexture	= function()		{  return this._propValues[this._propNames[2]] ? this._propValues[this._propNames[2]].slice() : null	}
+	this.setNormalTexture	= function(m)		{  this._propValues[this._propNames[2]] = m ? m.slice(0) : null;  this.updateTexture(2);  	}	
 
-	this.getNormalTexture	= function()		{	return this._normalTexture;						}
-	this.setNormalTexture	= function(nt)		{	this._normalTexture = nt;
-													if (this._materialNode)  this._materialNode.setNormalTexture( nt );		}
+	this.getSpecularTexture	= function()		{  return this._propValues[this._propNames[3]] ? this._propValues[this._propNames[3]].slice() : null	}
+	this.setSpecularTexture	= function(m)		{  this._propValues[this._propNames[3]] = m ? m.slice(0) : null;  this.updateTexture(3);  	}	
+
+	this.isAnimated			= function()		{  return true;					}
 
     ///////////////////////////////////////////////////////////////////////
     // Material Property Accessors
@@ -59,7 +58,7 @@ function BumpMetalMaterial()
 
 	this._propValues[ this._propNames[0] ] = this._lightDiff.slice(0);
 	this._propValues[ this._propNames[1] ] = this._diffuseTexture.slice(0);
-	this._propValues[ this._propNames[2] ] = this._specularTexture.slice(0);
+	this._propValues[ this._propNames[2] ] = this._normalTexture.slice(0);
 	this._propValues[ this._propNames[3] ] = this._specularTexture.slice(0);
 
     // TODO - shader techniques are not all named the same, i.e., FlatMaterial uses "colorMe" and BrickMaterial uses "default"
@@ -95,8 +94,11 @@ function BumpMetalMaterial()
 	// duplcate method requirde
 	this.dup = function()	{  return new BumpMetalMaterial();	} 
 
-	this.init = function()
+	this.init = function( world )
 	{
+		// save the world
+		if (world)  this.setWorld( world );
+
 		// set up the shader
 		this._shader = new jshader();
 		this._shader.def = bumpMetalMaterialDef;
@@ -108,9 +110,36 @@ function BumpMetalMaterial()
 		this._materialNode.setShader(this._shader);
 
 		// set some image maps
-		this._materialNode.setDiffuseTexture( this.getDiffuseTexture() );
-        this._materialNode.setSpecTexture( this.getSpecularTexture() );
-        this._materialNode.setNormalTexture( this.getNormalTexture() );
+		this.updateTexture(1);
+        this.updateTexture(2);
+        this.updateTexture(3);
+	}
+
+	this.updateTexture = function( index )
+	{
+		var material = this._materialNode;
+		if (material)
+		{
+			var technique = material.shaderProgram.default;
+			var renderer = g_Engine.getContext().renderer;
+			if (renderer && technique)
+			{
+				var texMapName = this._propValues[this._propNames[index]];
+				var wrap = 'REPEAT',  mips = true;
+				var tex = this.loadTexture( texMapName, wrap, mips );
+
+				if (tex)
+				{
+					switch (index)
+					{
+						case 1:		technique.u_colMap.set( tex );		break;
+						case 2:		technique.u_normalMap.set( tex );	break;
+						case 3:		technique.u_glowMap.set( tex );		break;
+						default:	console.log( "invalid map index in BumpMetalMaterial, " + index );
+					}
+				}
+			}
+		}
 	}
 
 	this.export = function()
@@ -229,6 +258,9 @@ bumpMetalShaderDef =
 				{
 					'u_light0Diff' : { 'type' : 'vec4' },
 					//'u_matDiffuse' : { 'type' : 'vec4' }
+					'u_colMap': { 'type' : 'tex2d' },
+					'u_normalMap': { 'type' : 'tex2d' },
+					'u_glowMap': { 'type' : 'tex2d' },
 				},
 
                 // render states
diff --git a/js/helper-classes/RDGE/Materials/FlatMaterial.js b/js/helper-classes/RDGE/Materials/FlatMaterial.js
index 5177a8a0..db66ca42 100644
--- a/js/helper-classes/RDGE/Materials/FlatMaterial.js
+++ b/js/helper-classes/RDGE/Materials/FlatMaterial.js
@@ -29,6 +29,8 @@ function FlatMaterial()
 	this.getColor			= function()	{  return this._color;		}
 	this.getShaderName		= function()	{  return this._shaderName;	}
 
+	this.isAnimated			= function()	{  return true;				}
+
     //////////////////////////////////s/////////////////////////////////////
     // Methods
     ///////////////////////////////////////////////////////////////////////
diff --git a/js/helper-classes/RDGE/Materials/IridescentScalesMaterial.js b/js/helper-classes/RDGE/Materials/IridescentScalesMaterial.js
index ac1d3fe7..a8b1c18b 100644
--- a/js/helper-classes/RDGE/Materials/IridescentScalesMaterial.js
+++ b/js/helper-classes/RDGE/Materials/IridescentScalesMaterial.js
@@ -80,8 +80,11 @@ function IridescentScalesMaterial()
     /////////////////////////////////////////////////////////////////////// 
 	this.dup = function()	{  return new IridescentScalesMaterial();	}
 
-	this.init = function()
+	this.init = function( world )
 	{
+		// save the world
+		if (world)  this.setWorld( world );
+
 		// set up the shader
 		this._shader = new jshader();
 		this._shader.def = iridescentScalesShaderDef;
diff --git a/js/helper-classes/RDGE/Materials/JuliaMaterial.js b/js/helper-classes/RDGE/Materials/JuliaMaterial.js
index 69884d18..f95263f4 100644
--- a/js/helper-classes/RDGE/Materials/JuliaMaterial.js
+++ b/js/helper-classes/RDGE/Materials/JuliaMaterial.js
@@ -64,6 +64,9 @@ function JuliaMaterial()
 
 	this.init = function( world )
 	{
+		// save the world
+		if (world)  this.setWorld( world );
+
 		// set up the shader
 		this._shader = new jshader();
 		this._shader.def = JuliaMaterialDef;
diff --git a/js/helper-classes/RDGE/Materials/KeleidoscopeMaterial.js b/js/helper-classes/RDGE/Materials/KeleidoscopeMaterial.js
index 8f94f47b..1547aca9 100644
--- a/js/helper-classes/RDGE/Materials/KeleidoscopeMaterial.js
+++ b/js/helper-classes/RDGE/Materials/KeleidoscopeMaterial.js
@@ -62,6 +62,9 @@ function KeleidoscopeMaterial()
 
 	this.init = function( world )
 	{
+		// save the world
+		if (world)  this.setWorld( world );
+
 		// set up the shader
 		this._shader = new jshader();
 		this._shader.def = keleidoscopeMaterialDef;
diff --git a/js/helper-classes/RDGE/Materials/LinearGradientMaterial.js b/js/helper-classes/RDGE/Materials/LinearGradientMaterial.js
index 357ce275..f026cd15 100644
--- a/js/helper-classes/RDGE/Materials/LinearGradientMaterial.js
+++ b/js/helper-classes/RDGE/Materials/LinearGradientMaterial.js
@@ -98,6 +98,8 @@ function LinearGradientMaterial()
 													this._shader.default.u_cos_sin_angle.set([Math.cos(a), Math.sin(a)]);
 											}
 
+	this.isAnimated			= function()			{  return true;					}
+
     ///////////////////////////////////////////////////////////////////////
     // Material Property Accessors
     ///////////////////////////////////////////////////////////////////////
@@ -146,6 +148,8 @@ function LinearGradientMaterial()
 
 		// send the current values to the shader
 		this.updateShaderValues();
+
+		console.log( "**** LinearGradientMaterial initialized" );
 	}
 
 	this.updateShaderValues= function()
diff --git a/js/helper-classes/RDGE/Materials/MandelMaterial.js b/js/helper-classes/RDGE/Materials/MandelMaterial.js
index 76083b76..25b08404 100644
--- a/js/helper-classes/RDGE/Materials/MandelMaterial.js
+++ b/js/helper-classes/RDGE/Materials/MandelMaterial.js
@@ -42,6 +42,7 @@ function MandelMaterial()
 
     ///////////////////////////////////////////////////////////////////////
 
+	this.isAnimated = function()  {  return true;  }
 
     ///////////////////////////////////////////////////////////////////////
     // Methods
@@ -64,6 +65,9 @@ function MandelMaterial()
 
 	this.init = function( world )
 	{
+		// save the world
+		if (world)  this.setWorld( world );
+
 		// set up the shader
 		this._shader = new jshader();
 		this._shader.def = MandelMaterialDef;
diff --git a/js/helper-classes/RDGE/Materials/PulseMaterial.js b/js/helper-classes/RDGE/Materials/PulseMaterial.js
index 5bee818e..3d6107fb 100644
--- a/js/helper-classes/RDGE/Materials/PulseMaterial.js
+++ b/js/helper-classes/RDGE/Materials/PulseMaterial.js
@@ -33,9 +33,11 @@ function PulseMaterial()
 	this.getName		= function()	{ return this._name;			}
 	this.getShaderName	= function()	{  return this._shaderName;		}
 
-	this.getTextureMap			= function()		{  return this._texMap.slice(0);	}
+	this.getTextureMap			= function()		{  return this._propValues[this._propNames[0]] ? this._propValues[this._propNames[0]].slice() : null	}
 	this.setTextureMap			= function(m)		{  this._propValues[this._propNames[0]] = m ? m.slice(0) : null;  this.updateTexture();  	}	
 
+	this.isAnimated			= function()			{  return true;					}
+
     ///////////////////////////////////////////////////////////////////////
     // Material Property Accessors
     ///////////////////////////////////////////////////////////////////////
@@ -72,6 +74,9 @@ function PulseMaterial()
 	// duplcate method requirde
 	this.dup = function( world )
 	{
+		// save the world
+		if (world)  this.setWorld( world );
+
 		// allocate a new uber material
 		var newMat = new PulseMaterial();
 
@@ -87,6 +92,9 @@ function PulseMaterial()
 
 	this.init = function( world )
 	{
+		// save the world
+		if (world)  this.setWorld( world );
+
 		// set up the shader
 		this._shader = new jshader();
 		this._shader.def = pulseMaterialDef;
@@ -116,7 +124,10 @@ function PulseMaterial()
 			if (renderer && technique)
 			{
 				var texMapName = this._propValues[this._propNames[0]];
-				var tex = renderer.getTextureByName(texMapName, 'REPEAT');
+				var wrap = 'REPEAT',  mips = true;
+				//var tex = renderer.getTextureByName(texMapName, wrap, mips );
+				//this.registerTexture( tex );
+				var tex = this.loadTexture( texMapName, wrap, mips );
 				if (tex)
 					technique.u_tex0.set( tex );
 			}
diff --git a/js/helper-classes/RDGE/Materials/RadialBlurMaterial.js b/js/helper-classes/RDGE/Materials/RadialBlurMaterial.js
index 25331b54..9acb4213 100644
--- a/js/helper-classes/RDGE/Materials/RadialBlurMaterial.js
+++ b/js/helper-classes/RDGE/Materials/RadialBlurMaterial.js
@@ -92,6 +92,9 @@ function RadialBlurMaterial()
 
 	this.init = function( world )
 	{
+		// save the world
+		if (world)  this.setWorld( world );
+
 		// set up the shader
 		this._shader = new jshader();
 		this._shader.def = radialBlurMaterialDef;
diff --git a/js/helper-classes/RDGE/Materials/RadialGradientMaterial.js b/js/helper-classes/RDGE/Materials/RadialGradientMaterial.js
index 70c0e952..5f912dec 100644
--- a/js/helper-classes/RDGE/Materials/RadialGradientMaterial.js
+++ b/js/helper-classes/RDGE/Materials/RadialGradientMaterial.js
@@ -21,13 +21,15 @@ function RadialGradientMaterial()
 	this._name = "RadialGradientMaterial";
 	this._shaderName = "radialGradient";
 
-	this._startColor = [1, 0, 0, 1];
-	this._stopColor  = [0, 1, 0, 1];
-
-	this._mainCircleRadius = 0.5;
-	this._innerCircleRadius = 0.05;
-	this._innerCircleCenter = [0.5, 0.5];
-	this._mainCircleCenter = [0.5, 0.5];
+	this._color1		= [1,0,0,1];
+	this._color2		= [0,1,0,1];
+	this._color3		= [0,0,1,1];
+	this._color4		= [0,1,1,1];
+	this._colorStop1	= 0.0;
+	this._colorStop2	= 0.3;
+	this._colorStop3	= 0.6;
+	this._colorStop4	= 1.0;
+	this._colorCount	= 4;
 
     ///////////////////////////////////////////////////////////////////////
     // Property Accessors
@@ -35,42 +37,79 @@ function RadialGradientMaterial()
 	this.getName		= function()	{ return this._name;			}
 	this.getShaderName	= function()	{  return this._shaderName;		}
 
-	this.getStartColor			= function()		{  return this._startColor.slice(0);	}
-	this.setStartColor			= function(c)		{  this._startColor = c.slice(0);		}	
-
-	this.getStopColor			= function()		{  return this._stopColor.slice(0);		}
-	this.setStopColor			= function(c)		{  this._stopColor = c.slice(0);		}	
-
-	this.getMainCircleRadius	= function()		{  return this._mainCircleRadius;		}
-	this.setMainCircleRadius	= function(r)		{  this._mainCircleRadius = r;			}
-
-	this.getInnerCircleRadius	= function()		{  return this._innerCircleRadius;		}
-	this.setInnerCircleRadius	= function(r)		{  this._innerCircleRadius = r;			}
+	
+	this.getColor1	= function()		{	return this._color1;		}
+	this.setColor1	= function(c)		{	this._color1 = c.slice();
+												if (this._shader && this._shader.default)
+													this._shader.default.u_color1.set(c);
+										}
+
+	this.getColor2	= function()		{	return this._color2;		}
+	this.setColor2	= function(c)		{	this._color2 = c.slice();
+												if (this._shader && this._shader.default)
+													this._shader.default.u_color2.set(c);
+										}
+
+	this.getColor3	= function()		{	return this._color3;		}
+	this.setColor3	= function(c)		{	this._color3 = c.slice();
+												if (this._shader && this._shader.default)
+													this._shader.default.u_color3.set(c);
+										}
+
+	this.getColor4	= function()		{	return this._color4;		}
+	this.setColor4	= function(c)		{	this._color4 = c.slice();
+												if (this._shader && this._shader.default)
+													this._shader.default.u_color4.set(c);
+										}
+
+	this.getColorStop1 = function()		{  return this._colorStop1;		}
+	this.setColorStop1 = function(s)	{  this._colorStop1 = s;
+												if (this._shader && this._shader.default)
+													this._shader.default.u_colorStop1.set([s]);
+										}
+
+	this.getColorStop2 = function()		{  return this._colorStop2;		}
+	this.setColorStop2 = function(s)	{  this._colorStop2 = s;
+												if (this._shader && this._shader.default)
+													this._shader.default.u_colorStop2.set([s]);
+										}
+
+	this.getColorStop3 = function()		{  return this._colorStop3;		}
+	this.setColorStop3 = function(s)	{  this._colorStop3 = s;
+												if (this._shader && this._shader.default)
+													this._shader.default.u_colorStop3.set([s]);
+										}
+
+	this.getColorStop4 = function()		{  return this._colorStop4;		}
+	this.setColorStop4 = function(s)	{  this._colorStop4 = s;
+												if (this._shader && this._shader.default)
+													this._shader.default.u_colorStop4.set([s]);
+										}
+
+	this.getColorCount	= function()	{  return this._colorCount;		}
+	this.setColorCount	= function(c)	{  this._colorCount = c;
+												if (this._shader && this._shader.default)
+													this._shader.default.u_colorCount.set([c]);
+										}
+
+	this.isAnimated		= function()	{  return true;					}
 
-	this.getInnerCircleCenter	= function()		{  return this._innerCircleCenter;		}
-	this.setInnerCircleCenter	= function(c)		{  this._innerCircleCenter = c;			}
-
-	this.getMainCircleCenter	= function()		{  return this._mainCircleCenter;		}
-	this.setMainCircleCenter	= function(c)		{  this._mainCircleCenter = c;			}
 
     ///////////////////////////////////////////////////////////////////////
     // Material Property Accessors
     ///////////////////////////////////////////////////////////////////////
-	this._propNames			= ["startColor",	"stopColor",	"mainCircleRadius",		"innerCircleRadius",	"mainCircleCenter",		"innerCircleCenter"];
-	this._propLabels		= ["Start Color",	"Stop Color",	"Main Circle Radius",	"Inner Circle Radius",	"Main Circle Center",	"Inner Circle Center"];
-	this._propTypes			= ["color",			"color",		"float",				"float",				"vector2d",				"vector2d"];
+	this._propNames			= ["color1",		"color2",		"angle"];
+	this._propLabels		= ["Start Color",	"Stop Color",	"Angle"];
+	this._propTypes			= ["color",			"color",		"float"];
 	this._propValues		= [];
 
-	this._propValues[ this._propNames[0] ] = this._startColor.slice(0);
-	this._propValues[ this._propNames[1] ] = this._stopColor.slice(0);
-	this._propValues[ this._propNames[2] ] = this.getMainCircleRadius();
-	this._propValues[ this._propNames[3] ] = this.getInnerCircleRadius();
-	this._propValues[ this._propNames[4] ] = this.getMainCircleCenter();
-	this._propValues[ this._propNames[5] ] = this.getInnerCircleCenter();
+	this._propValues[ this._propNames[0] ] = this._color1.slice(0);
+	this._propValues[ this._propNames[1] ] = this._color4.slice(0);
+	this._propValues[ this._propNames[2] ] = this._angle;
 
     this.setProperty = function( prop, value )
 	{
-		if (prop === "color")  prop = "startColor";
+		if (prop === "color")  prop = "color1";
 
 		// make sure we have legitimate imput
 		var ok = this.validateProperty( prop, value );
@@ -79,12 +118,9 @@ function RadialGradientMaterial()
 
 		switch (prop)
 		{
-			case "startColor":				this.setStartColor(value);				break;
-			case "stopColor":				this.setStopColor(value);				break;
-			case "innerCircleRadius":		this.setInnerCircleRadius( value );		break;
-			case "mainCircleRadius":		this.setMainCircleRadius( value );		break;
-			case "innerCircleCenter":		this.setInnerCircleCenter( value );		break;
-			case "mainCircleCenter":		this.setMainCircleCenter( value );		break;
+			case "color1":		this.setColor1( value );		break;
+			case "color2":		this.setColor2( value );		break;
+			case "angle":		this.setAngle( value );			break;
 		}
 
 		this.updateValuesInShader();
@@ -115,25 +151,30 @@ function RadialGradientMaterial()
 
 	this.updateValuesInShader = function()
 	{
-		if (!this._shader || !this._shader.default)  return;
-
-		// calculate values
-		var mainCircleRadius  = this.getMainCircleRadius();
-		var innerCircleRadius = this.getInnerCircleRadius();
-		var innerCircleCenter = this.getInnerCircleCenter();
-		var mainCircleCenter  = this.getMainCircleCenter();
-		var radiusDelta = innerCircleRadius - mainCircleRadius;
-		var innerCircleCenterMinusCenter = VecUtils.vecSubtract( 2, innerCircleCenter,  mainCircleCenter );
-		var	u_A = VecUtils.vecDot( 2, innerCircleCenterMinusCenter, innerCircleCenterMinusCenter) - (radiusDelta * radiusDelta)
-
-		// set values
-		this._shader.default.u_center.set( innerCircleCenter );
-		this._shader.default.u_startColor.set( this.getStartColor() );
-		this._shader.default.u_stopColor.set( this.getStopColor() );
-		this._shader.default.u_innerCircleCenterMinusCenter.set( innerCircleCenterMinusCenter );
-		this._shader.default.u_radius.set( [mainCircleRadius] );
-		this._shader.default.u_A.set( [ u_A] );
-		this._shader.default.u_radiusDelta.set( [radiusDelta] );
+		if (this._shader && this._shader.default)
+		{
+			//this._shader.default.u_colorCount.set( [4] );
+
+			var c;
+			c = this.getColor1();
+			this._shader.default.u_color1.set( c );
+			c = this.getColor2();
+			this._shader.default.u_color2.set( c );
+			c = this.getColor3();
+			this._shader.default.u_color3.set( c );
+			c = this.getColor4();
+			this._shader.default.u_color4.set( c );
+
+			var s;
+			s = this.getColorStop1();
+			this._shader.default.u_colorStop1.set( [s] );
+			s = this.getColorStop2();
+			this._shader.default.u_colorStop2.set( [s] );
+			s = this.getColorStop3();
+			this._shader.default.u_colorStop3.set( [s] );
+			s = this.getColorStop4();
+			this._shader.default.u_colorStop4.set( [s] );
+		}
 	}
 
 	this.export = function()
@@ -190,13 +231,13 @@ function RadialGradientMaterial()
 
 ///////////////////////////////////////////////////////////////////////////////////////
 // RDGE shader
- 
+
 // shader spec (can also be loaded from a .JSON file, or constructed at runtime)
 var radialGradientMaterialDef =
 {'shaders': 
 	{
 		'defaultVShader':"assets/shaders/radialGradient.vert.glsl",
-		'defaultFShader':"assets/shaders/radialGradient.frag.glsl",
+		'defaultFShader':"assets/shaders/radialGradient.frag.glsl"
 	},
 	'techniques':
 	{ 
@@ -210,18 +251,21 @@ var radialGradientMaterialDef =
 				{
 					'vert'	:	{ 'type' : 'vec3' },
 					'normal' :	{ 'type' : 'vec3' },
-					'texcoord'	:	{ 'type' : 'vec2' },
+					'texcoord'	:	{ 'type' : 'vec2' }
 				},
 				// parameters
 				'params' : 
 				{
-					'u_startColor' : { 'type' : 'vec4' },									
-					'u_stopColor' : { 'type' : 'vec4' },
-					'u_center' : { 'type' : 'vec2' },
-					'u_radius' : { 'type' : 'float' },
-					'u_A' : { 'type' : 'float' },
-					'u_radiusDelta' : { 'type' : 'float' },									
-					'u_innerCircleCenterMinusCenter' : { 'type' : 'vec2' },
+						'u_color1' :		{ 'type' : 'vec4' },									
+						'u_color2' :		{ 'type' : 'vec4' },									
+						'u_color3' :		{ 'type' : 'vec4' },									
+						'u_color4' :		{ 'type' : 'vec4' },
+						'u_colorStop1':		{ 'type' : 'float' },									
+						'u_colorStop2':		{ 'type' : 'float' },									
+						'u_colorStop3':		{ 'type' : 'float' },									
+						'u_colorStop4':		{ 'type' : 'float' },									
+						'u_cos_sin_angle' : { 'type' : 'vec2' }
+						//'u_colorCount':		{'type' : 'int' }
 				},
 
 				// render states
@@ -229,12 +273,8 @@ var radialGradientMaterialDef =
 				{
 					'depthEnable' : true,
 					'offset':[1.0, 0.1]
-				},
-			},
+				}
+			}
 		]
 	}
 };
-
-
-
-
diff --git a/js/helper-classes/RDGE/Materials/TunnelMaterial.js b/js/helper-classes/RDGE/Materials/TunnelMaterial.js
index fe277af6..9b12e197 100644
--- a/js/helper-classes/RDGE/Materials/TunnelMaterial.js
+++ b/js/helper-classes/RDGE/Materials/TunnelMaterial.js
@@ -62,6 +62,9 @@ function TunnelMaterial()
 
 	this.init = function( world )
 	{
+		// save the world
+		if (world)  this.setWorld( world );
+
 		// set up the shader
 		this._shader = new jshader();
 		this._shader.def = tunnelMaterialDef;
diff --git a/js/helper-classes/RDGE/Materials/TwistMaterial.js b/js/helper-classes/RDGE/Materials/TwistMaterial.js
index c3094621..b113965b 100644
--- a/js/helper-classes/RDGE/Materials/TwistMaterial.js
+++ b/js/helper-classes/RDGE/Materials/TwistMaterial.js
@@ -62,6 +62,9 @@ function TwistMaterial()
 
 	this.init = function( world )
 	{
+		// save the world
+		if (world)  this.setWorld( world );
+
 		// set up the shader
 		this._shader = new jshader();
 		this._shader.def = twistMaterialDef;
diff --git a/js/helper-classes/RDGE/Materials/UberMaterial.js b/js/helper-classes/RDGE/Materials/UberMaterial.js
index a8254465..afb745d1 100644
--- a/js/helper-classes/RDGE/Materials/UberMaterial.js
+++ b/js/helper-classes/RDGE/Materials/UberMaterial.js
@@ -270,6 +270,7 @@ function UberMaterial()
 					if (renderer && technique)
 					{
 						var tex = renderer.getTextureByName(value, caps.environmentMap.wrap);
+						this.registerTexture( tex );
 						technique.s_environmentMap.set( tex );
 					}
 				}
@@ -307,6 +308,7 @@ function UberMaterial()
 					if (renderer && technique)
 					{
 						var tex = renderer.getTextureByName(value, caps.diffuseMap.wrap);
+						this.registerTexture( tex );
 						technique.s_diffuseMap.set( tex );
 					}
 				}
@@ -344,6 +346,7 @@ function UberMaterial()
 					if (renderer && technique)
 					{
 						var tex = renderer.getTextureByName(value, caps.specularMap.wrap);
+						this.registerTexture( tex );
 						technique.s_specularMap.set( tex );
 					}
 				}
@@ -381,6 +384,7 @@ function UberMaterial()
 					if (renderer && technique)
 					{
 						var tex = renderer.getTextureByName(value, caps.normalMap.wrap);
+						this.registerTexture( tex );
 						technique.s_normalMap.set( tex );
 					}
 				}
@@ -411,8 +415,11 @@ function UberMaterial()
 		return newMat;
 	} 
 
-	this.init = function()
+	this.init = function( world )
 	{
+		// save the world
+		if (world)  this.setWorld( world );
+
 		// set up the shader
 		this._shader = this.buildUberShader( this._ubershaderCaps );
 
@@ -579,16 +586,24 @@ function UberMaterial()
 	
 		renderer = g_Engine.getContext().renderer;
 		if(this._useDiffuseMap) {
-			technique.s_diffuseMap.set(renderer.getTextureByName(caps.diffuseMap.texture, caps.diffuseMap.wrap, caps.diffuseMap.mips));
+			var tex = renderer.getTextureByName(caps.diffuseMap.texture, caps.diffuseMap.wrap, caps.diffuseMap.mips);
+			this.registerTexture( tex );
+			technique.s_diffuseMap.set( tex );
 		}
 		if(this._useNormalMap) {
-			technique.s_normalMap.set(renderer.getTextureByName(caps.normalMap.texture, caps.normalMap.wrap, caps.normalMap.mips));
+			var tex = renderer.getTextureByName(caps.normalMap.texture, caps.normalMap.wrap, caps.normalMap.mips);
+			this.registerTexture( tex );
+			technique.s_normalMap.set( tex );
 		}    
 		if(this._useSpecularMap) {
-			technique.s_specMap.set(renderer.getTextureByName(caps.specularMap.texture, caps.specularMap.wrap));
+			var tex = renderer.getTextureByName(caps.specularMap.texture, caps.specularMap.wrap);
+			this.registerTexture( tex );
+			technique.s_specMap.set( tex );
 		}
 		if(this._useEnvironmentMap) {
-			technique.s_envMap.set(renderer.getTextureByName(caps.environmentMap.texture, caps.environmentMap.wrap));
+			var tex = renderer.getTextureByName(caps.environmentMap.texture, caps.environmentMap.wrap);
+			this.registerTexture( tex );
+			technique.s_envMap.set( tex );
 			technique.u_envReflection.set([ caps.environmentMap.envReflection || 1.0 ] );
 		}
 
diff --git a/js/helper-classes/RDGE/MaterialsLibrary.js b/js/helper-classes/RDGE/MaterialsLibrary.js
index edc4f7da..5f82a996 100644
--- a/js/helper-classes/RDGE/MaterialsLibrary.js
+++ b/js/helper-classes/RDGE/MaterialsLibrary.js
@@ -170,28 +170,28 @@ var MaterialsLibrary = Object.create(Object.prototype, {
 // create the library of stroke and fill materials
 
 var uberMaterial				= new UberMaterial();
-//var linearGradientMaterial		= new LinearGradientMaterial();
-//var radialGradientMaterial		= new RadialGradientMaterial();
-//var radialBlurMaterial			= new RadialBlurMaterial();
-//var pulseMaterial				= new PulseMaterial();
-//var tunnelMaterial				= new TunnelMaterial();
-//var twistMaterial				= new TwistMaterial();
-//var keleidoscopeMaterial		= new KeleidoscopeMaterial();
-//var juliaMaterial				= new JuliaMaterial();
-//var mandelMaterial				= new MandelMaterial();
-//var plasmaMaterial				= new PlasmaMaterial();
+var linearGradientMaterial		= new LinearGradientMaterial();
+var radialGradientMaterial		= new RadialGradientMaterial();
+var radialBlurMaterial			= new RadialBlurMaterial();
+var pulseMaterial				= new PulseMaterial();
+var tunnelMaterial				= new TunnelMaterial();
+var twistMaterial				= new TwistMaterial();
+var keleidoscopeMaterial		= new KeleidoscopeMaterial();
+var juliaMaterial				= new JuliaMaterial();
+var mandelMaterial				= new MandelMaterial();
+var plasmaMaterial				= new PlasmaMaterial();
 var bumpMetalMaterial			= new BumpMetalMaterial();
 
-//MaterialsLibrary.addMaterial(linearGradientMaterial);
-//MaterialsLibrary.addMaterial(radialGradientMaterial);
-//MaterialsLibrary.addMaterial(radialBlurMaterial);
-//MaterialsLibrary.addMaterial(pulseMaterial);
-//MaterialsLibrary.addMaterial(tunnelMaterial);
-//MaterialsLibrary.addMaterial(twistMaterial);
-//MaterialsLibrary.addMaterial(keleidoscopeMaterial);
-//MaterialsLibrary.addMaterial(juliaMaterial);
-//MaterialsLibrary.addMaterial(mandelMaterial);
-//MaterialsLibrary.addMaterial(plasmaMaterial);
+MaterialsLibrary.addMaterial(linearGradientMaterial);
+MaterialsLibrary.addMaterial(radialGradientMaterial);
+MaterialsLibrary.addMaterial(radialBlurMaterial);
+MaterialsLibrary.addMaterial(pulseMaterial);
+MaterialsLibrary.addMaterial(tunnelMaterial);
+MaterialsLibrary.addMaterial(twistMaterial);
+MaterialsLibrary.addMaterial(keleidoscopeMaterial);
+MaterialsLibrary.addMaterial(juliaMaterial);
+MaterialsLibrary.addMaterial(mandelMaterial);
+MaterialsLibrary.addMaterial(plasmaMaterial);
 MaterialsLibrary.addMaterial(bumpMetalMaterial);
 MaterialsLibrary.addMaterial(uberMaterial);
 
diff --git a/js/helper-classes/RDGE/rdge-compiled.js b/js/helper-classes/RDGE/rdge-compiled.js
index 4b74aa17..e55516db 100644
--- a/js/helper-classes/RDGE/rdge-compiled.js
+++ b/js/helper-classes/RDGE/rdge-compiled.js
@@ -19,14 +19,14 @@ vec4.equal=function(a,b,f){f||(f=0.0010);return vec4.distanceSq(a,b)<f*f};vec4.l
 mat4={string:function(a){var b="{ ";b+=a[0]+", "+a[1]+", "+a[2]+", "+a[3]+", ";b+=a[4]+", "+a[5]+", "+a[6]+", "+a[7]+", ";b+=a[8]+", "+a[9]+", "+a[10]+", "+a[11]+", ";b+=a[12]+", "+a[13]+", "+a[14]+", "+a[15]+" }";return b},toCSSString:function(a,b){var f=10;b&&(f=b);var g="matrix3d(";g+=a[0].toFixed(10)+", "+a[1].toFixed(10)+", "+a[2].toFixed(10)+", "+a[3].toFixed(10)+", ";g+=a[4].toFixed(10)+", "+a[5].toFixed(10)+", "+a[6].toFixed(10)+", "+a[7].toFixed(10)+", ";g+=a[8].toFixed(10)+", "+a[9].toFixed(10)+
 ", "+a[10].toFixed(10)+", "+a[11].toFixed(10)+", ";g+=a[12].toFixed(10)*f+", "+(600-a[13].toFixed(10)*f)+", "+a[14].toFixed(10)*f+", "+a[15].toFixed(10)+")";return g},verify:function(a){if(a==void 0||a.length==void 0||a.length<16)return!1;for(var b=16;b--;)if(typeof a[b]!="number")return!1;return!0},copy:function(a){return[a[0],a[1],a[2],a[3],a[4],a[5],a[6],a[7],a[8],a[9],a[10],a[11],a[12],a[13],a[14],a[15]]},inplace_copy:function(a,b){a[0]=b[0];a[1]=b[1];a[2]=b[2];a[3]=b[3];a[4]=b[4];a[5]=b[5];a[6]=
 b[6];a[7]=b[7];a[8]=b[8];a[9]=b[9];a[10]=b[10];a[11]=b[11];a[12]=b[12];a[13]=b[13];a[14]=b[14];a[15]=b[15]},identity:function(){return[1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1]},zero:function(){return[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]},basis:function(a,b,f,g){return g==null||g==void 0?[a[0],a[1],a[2],0,b[0],b[1],b[2],0,f[0],f[1],f[2],0,0,0,0,1]:[a[0],a[1],a[2],a.length==4?a[3]:0,b[0],b[1],b[2],b.length==4?b[3]:0,f[0],f[1],f[2],f.length==4?f[3]:0,g[0],g[1],g[2],g.length==4?g[3]:1]},angleAxis:function(a,b){a*=
-Math.PI/180;a/=2;var f=Math.sin(a),g=Math.cos(a),h=f*f;vec3.normalize(b);vec3.lengthSq(b)<=0&&(b=[0,0,0,1]);var l=mat4.identity();if(b[0]==1&&b[1]==0&&b[2]==0)l[5]=1-2*h,l[6]=2*f*g,l[9]=-2*f*g,l[10]=1-2*h;else if(b[0]==0&&b[1]==1&&b[2]==0)l[0]=1-2*h,l[2]=-2*f*g,l[8]=2*f*g,l[10]=1-2*h;else if(b[0]==0&&b[1]==0&&b[2]==1)l[0]=1-2*h,l[1]=2*f*g,l[4]=-2*f*g,l[5]=1-2*h;else{var n=b[0],o=b[1],q=b[2],p=n*n,r=o*o,s=q*q;l[0]=1-2*(r+s)*h;l[1]=2*(n*o*h+q*f*g);l[2]=2*(n*q*h-o*f*g);l[4]=2*(o*n*h-q*f*g);l[5]=1-2*
-(s+p)*h;l[6]=2*(o*q*h+n*f*g);l[8]=2*(q*n*h+o*f*g);l[9]=2*(q*o*h-n*f*g);l[10]=1-2*(p+r)*h}return l}};mat4.lookAt=function(a,b,f){b=vec3.normalize(vec3.sub(a,b));vec3.length(b)<1.0E-4&&(b=[0,0,1]);var f=vec3.normalize(vec3.cross(f,b)),g=vec3.normalize(vec3.cross(b,f)),h=mat4.identity();mat4.setRow(h,0,f);mat4.setRow(h,1,g);mat4.setRow(h,2,b);mat4.setRow(h,3,a);return h};
-mat4.frustum=function(a,b,f,g,h,l){var n=b-a,o=g-f,q=l-h,p=2*h,r=mat4.zero();r[0]=p/n;r[5]=p/o;r[8]=(b+a)/n;r[9]=(g+f)/o;r[10]=-(l+h)/q;r[11]=-1;r[14]=-(p*l)/q;return r};mat4.perspective=function(a,b,f,g){var a=Math.tan(a*Math.PI/360)*f,h=-a;return mat4.frustum(b*h,b*a,h,a,f,g)};mat4.orthographic=function(a,b,f,g,h,l){var n=(a+b)/(a-b),o=(f+g)/(f-g),q=(l+h)/(l-h),p=mat4.zero();p[0]=2/(a-b);p[5]=2/(f-g);p[10]=-2/(l-h);p[12]=n;p[13]=o;p[14]=q;p[15]=1;return p};
-mat4.mul=function(a,b){var f=a[0],g=a[1],h=a[2],l=a[3],n=a[4],o=a[5],q=a[6],p=a[7],r=a[8],s=a[9],u=a[10],v=a[11],x=a[12],w=a[13],y=a[14],z=a[15],A=b[0],C=b[1],D=b[2],B=b[3],E=b[4],F=b[5],G=b[6],H=b[7],I=b[8],J=b[9],K=b[10],L=b[11],M=b[12],N=b[13],O=b[14],P=b[15];return[f*A+g*E+h*I+l*M,f*C+g*F+h*J+l*N,f*D+g*G+h*K+l*O,f*B+g*H+h*L+l*P,n*A+o*E+q*I+p*M,n*C+o*F+q*J+p*N,n*D+o*G+q*K+p*O,n*B+o*H+q*L+p*P,r*A+s*E+u*I+v*M,r*C+s*F+u*J+v*N,r*D+s*G+u*K+v*O,r*B+s*H+u*L+v*P,x*A+w*E+y*I+z*M,x*C+w*F+y*J+z*N,x*D+w*G+
-y*K+z*O,x*B+w*H+y*L+z*P]};mat4.mul4x3=function(a,b){var f=a[0],g=a[1],h=a[2],l=a[4],n=a[5],o=a[6],q=a[8],p=a[9],r=a[10],s=a[12],u=a[13],v=a[14],x=b[0],w=b[1],y=b[2],z=b[4],A=b[5],C=b[6],D=b[8],B=b[9],E=b[10];return[f*x+g*z+h*D,f*w+g*A+h*B,f*y+g*C+h*E,0,l*x+n*z+o*D,l*w+n*A+o*B,l*y+n*C+o*E,0,q*x+p*z+r*D,q*w+p*A+r*B,q*y+p*C+r*E,0,s*x+u*z+v*D+b[12],s*w+u*A+v*B+b[13],s*y+u*C+v*E+b[14],1]};mat4._det2x2=function(a,b,f,g){return a*g-b*f};
-mat4._det3x3=function(a,b,f,g,h,l,n,o,q){return a*mat4._det2x2(h,l,o,q)-g*mat4._det2x2(b,f,o,q)+n*mat4._det2x2(b,f,h,l)};mat4._det4x4=function(a){var b=a[1],f=a[2],g=a[3],h=a[4],l=a[5],n=a[6],o=a[7],q=a[8],p=a[9],r=a[10],s=a[11],u=a[12],v=a[13],x=a[14],w=a[15];return a[0]*mat4._det3x3(l,p,v,n,r,x,o,s,w)-b*mat4._det3x3(h,q,u,n,r,x,o,s,w)+f*mat4._det3x3(h,q,u,l,p,v,o,s,w)-g*mat4._det3x3(h,q,u,l,p,v,n,r,x)};
-mat4._adjoint=function(a){var b=a[0],f=a[1],g=a[2],h=a[3],l=a[4],n=a[5],o=a[6],q=a[7],p=a[8],r=a[9],s=a[10],u=a[11],v=a[12],x=a[13],w=a[14],a=a[15];return[mat4._det3x3(n,r,x,o,s,w,q,u,a),-mat4._det3x3(f,r,x,g,s,w,h,u,a),mat4._det3x3(f,n,x,g,o,w,h,q,a),-mat4._det3x3(f,n,r,g,o,s,h,q,u),-mat4._det3x3(l,p,v,o,s,w,q,u,a),mat4._det3x3(b,p,v,g,s,w,h,u,a),-mat4._det3x3(b,l,v,g,o,w,h,q,a),mat4._det3x3(b,l,p,g,o,s,h,q,u),mat4._det3x3(l,p,v,n,r,x,q,u,a),-mat4._det3x3(b,p,v,f,r,x,h,u,a),mat4._det3x3(b,l,v,f,
-n,x,h,q,a),-mat4._det3x3(b,l,p,f,n,r,h,q,u),-mat4._det3x3(l,p,v,n,r,x,o,s,w),mat4._det3x3(b,p,v,f,r,x,g,s,w),-mat4._det3x3(b,l,v,f,n,x,g,o,w),mat4._det3x3(b,l,p,f,n,r,g,o,s)]};mat4.inverse=function(a){var b=mat4._det4x4(a);if(Math.abs(b)<1.0E-8)return null;a=mat4._adjoint(a);b=1/b;return[a[0]*b,a[1]*b,a[2]*b,a[3]*b,a[4]*b,a[5]*b,a[6]*b,a[7]*b,a[8]*b,a[9]*b,a[10]*b,a[11]*b,a[12]*b,a[13]*b,a[14]*b,a[15]*b]};
+Math.PI/180;a/=2;var f=Math.sin(a),g=Math.cos(a),h=f*f;vec3.normalize(b);vec3.lengthSq(b)<=0&&(b=[0,0,0,1]);var l=mat4.identity();if(b[0]==1&&b[1]==0&&b[2]==0)l[5]=1-2*h,l[6]=2*f*g,l[9]=-2*f*g,l[10]=1-2*h;else if(b[0]==0&&b[1]==1&&b[2]==0)l[0]=1-2*h,l[2]=-2*f*g,l[8]=2*f*g,l[10]=1-2*h;else if(b[0]==0&&b[1]==0&&b[2]==1)l[0]=1-2*h,l[1]=2*f*g,l[4]=-2*f*g,l[5]=1-2*h;else{var n=b[0],o=b[1],p=b[2],q=n*n,r=o*o,s=p*p;l[0]=1-2*(r+s)*h;l[1]=2*(n*o*h+p*f*g);l[2]=2*(n*p*h-o*f*g);l[4]=2*(o*n*h-p*f*g);l[5]=1-2*
+(s+q)*h;l[6]=2*(o*p*h+n*f*g);l[8]=2*(p*n*h+o*f*g);l[9]=2*(p*o*h-n*f*g);l[10]=1-2*(q+r)*h}return l}};mat4.lookAt=function(a,b,f){b=vec3.normalize(vec3.sub(a,b));vec3.length(b)<1.0E-4&&(b=[0,0,1]);var f=vec3.normalize(vec3.cross(f,b)),g=vec3.normalize(vec3.cross(b,f)),h=mat4.identity();mat4.setRow(h,0,f);mat4.setRow(h,1,g);mat4.setRow(h,2,b);mat4.setRow(h,3,a);return h};
+mat4.frustum=function(a,b,f,g,h,l){var n=b-a,o=g-f,p=l-h,q=2*h,r=mat4.zero();r[0]=q/n;r[5]=q/o;r[8]=(b+a)/n;r[9]=(g+f)/o;r[10]=-(l+h)/p;r[11]=-1;r[14]=-(q*l)/p;return r};mat4.perspective=function(a,b,f,g){var a=Math.tan(a*Math.PI/360)*f,h=-a;return mat4.frustum(b*h,b*a,h,a,f,g)};mat4.orthographic=function(a,b,f,g,h,l){var n=(a+b)/(a-b),o=(f+g)/(f-g),p=(l+h)/(l-h),q=mat4.zero();q[0]=2/(a-b);q[5]=2/(f-g);q[10]=-2/(l-h);q[12]=n;q[13]=o;q[14]=p;q[15]=1;return q};
+mat4.mul=function(a,b){var f=a[0],g=a[1],h=a[2],l=a[3],n=a[4],o=a[5],p=a[6],q=a[7],r=a[8],s=a[9],u=a[10],v=a[11],x=a[12],w=a[13],y=a[14],z=a[15],A=b[0],C=b[1],D=b[2],B=b[3],E=b[4],F=b[5],G=b[6],H=b[7],I=b[8],J=b[9],K=b[10],L=b[11],M=b[12],N=b[13],O=b[14],P=b[15];return[f*A+g*E+h*I+l*M,f*C+g*F+h*J+l*N,f*D+g*G+h*K+l*O,f*B+g*H+h*L+l*P,n*A+o*E+p*I+q*M,n*C+o*F+p*J+q*N,n*D+o*G+p*K+q*O,n*B+o*H+p*L+q*P,r*A+s*E+u*I+v*M,r*C+s*F+u*J+v*N,r*D+s*G+u*K+v*O,r*B+s*H+u*L+v*P,x*A+w*E+y*I+z*M,x*C+w*F+y*J+z*N,x*D+w*G+
+y*K+z*O,x*B+w*H+y*L+z*P]};mat4.mul4x3=function(a,b){var f=a[0],g=a[1],h=a[2],l=a[4],n=a[5],o=a[6],p=a[8],q=a[9],r=a[10],s=a[12],u=a[13],v=a[14],x=b[0],w=b[1],y=b[2],z=b[4],A=b[5],C=b[6],D=b[8],B=b[9],E=b[10];return[f*x+g*z+h*D,f*w+g*A+h*B,f*y+g*C+h*E,0,l*x+n*z+o*D,l*w+n*A+o*B,l*y+n*C+o*E,0,p*x+q*z+r*D,p*w+q*A+r*B,p*y+q*C+r*E,0,s*x+u*z+v*D+b[12],s*w+u*A+v*B+b[13],s*y+u*C+v*E+b[14],1]};mat4._det2x2=function(a,b,f,g){return a*g-b*f};
+mat4._det3x3=function(a,b,f,g,h,l,n,o,p){return a*mat4._det2x2(h,l,o,p)-g*mat4._det2x2(b,f,o,p)+n*mat4._det2x2(b,f,h,l)};mat4._det4x4=function(a){var b=a[1],f=a[2],g=a[3],h=a[4],l=a[5],n=a[6],o=a[7],p=a[8],q=a[9],r=a[10],s=a[11],u=a[12],v=a[13],x=a[14],w=a[15];return a[0]*mat4._det3x3(l,q,v,n,r,x,o,s,w)-b*mat4._det3x3(h,p,u,n,r,x,o,s,w)+f*mat4._det3x3(h,p,u,l,q,v,o,s,w)-g*mat4._det3x3(h,p,u,l,q,v,n,r,x)};
+mat4._adjoint=function(a){var b=a[0],f=a[1],g=a[2],h=a[3],l=a[4],n=a[5],o=a[6],p=a[7],q=a[8],r=a[9],s=a[10],u=a[11],v=a[12],x=a[13],w=a[14],a=a[15];return[mat4._det3x3(n,r,x,o,s,w,p,u,a),-mat4._det3x3(f,r,x,g,s,w,h,u,a),mat4._det3x3(f,n,x,g,o,w,h,p,a),-mat4._det3x3(f,n,r,g,o,s,h,p,u),-mat4._det3x3(l,q,v,o,s,w,p,u,a),mat4._det3x3(b,q,v,g,s,w,h,u,a),-mat4._det3x3(b,l,v,g,o,w,h,p,a),mat4._det3x3(b,l,q,g,o,s,h,p,u),mat4._det3x3(l,q,v,n,r,x,p,u,a),-mat4._det3x3(b,q,v,f,r,x,h,u,a),mat4._det3x3(b,l,v,f,
+n,x,h,p,a),-mat4._det3x3(b,l,q,f,n,r,h,p,u),-mat4._det3x3(l,q,v,n,r,x,o,s,w),mat4._det3x3(b,q,v,f,r,x,g,s,w),-mat4._det3x3(b,l,v,f,n,x,g,o,w),mat4._det3x3(b,l,q,f,n,r,g,o,s)]};mat4.inverse=function(a){var b=mat4._det4x4(a);if(Math.abs(b)<1.0E-8)return null;a=mat4._adjoint(a);b=1/b;return[a[0]*b,a[1]*b,a[2]*b,a[3]*b,a[4]*b,a[5]*b,a[6]*b,a[7]*b,a[8]*b,a[9]*b,a[10]*b,a[11]*b,a[12]*b,a[13]*b,a[14]*b,a[15]*b]};
 mat4.rigidInverse=function(a){out=mat4.transpose3x3(a);out[12]=-vec3.dot([out[0],out[4],out[8]],[a[12],a[13],a[14]]);out[13]=-vec3.dot([out[1],out[5],out[9]],[a[12],a[13],a[14]]);out[14]=-vec3.dot([out[2],out[6],out[10]],[a[12],a[13],a[14]]);return out};mat4.transpose=function(a){return[a[0],a[4],a[8],a[12],a[1],a[5],a[9],a[13],a[2],a[6],a[10],a[14],a[3],a[7],a[11],a[15]]};mat4.transpose3x3=function(a){return[a[0],a[4],a[8],a[3],a[1],a[5],a[9],a[7],a[2],a[6],a[10],a[11],a[12],a[13],a[14],a[15]]};
 mat4.transformPoint=function(a,b){var f=b[0],g=b[1],h=b[2],l=b.length>=4?b[3]:1;return[a[0]*f+a[4]*g+a[8]*h+a[12]*l,a[1]*f+a[5]*g+a[9]*h+a[13]*l,a[2]*f+a[6]*g+a[10]*h+a[14]*l,a[3]*f+a[7]*g+a[11]*h+a[15]*l]};mat4.transformVector=function(a,b){var a=mat4.inverse(a),f=b[0],g=b[1],h=b[2],l=b.length>=4?b[3]:0;return[a[0]*f+a[1]*g+a[2]*h+a[3]*l,a[4]*f+a[5]*g+a[6]*h+a[7]*l,a[8]*f+a[9]*g+a[10]*h+a[11]*l,a[12]*f+a[13]*g+a[14]*h+a[15]*l]};
 mat4.transformPoint4x3=function(a,b){var f=b[0],g=b[1],h=b[2];return[a[0]*f+a[4]*g+a[8]*h+a[12],a[1]*f+a[5]*g+a[9]*h+a[13],a[2]*f+a[6]*g+a[10]*h+a[14],1]};mat4.transformVector4x3=function(a,b){var a=mat4.inverse(a),f=b[0],g=b[1],h=b[2];return[a[0]*f+a[1]*g+a[2]*h,a[4]*f+a[5]*g+a[6]*h,a[8]*f+a[9]*g+a[10]*h,0]};mat4.getRow=function(a,b){b*=4;return[a[b],a[b+1],a[b+2],a[b+3]]};mat4.getCol=function(a,b){return[a[b],a[b+4],a[b+8],a[b+12]]};
@@ -36,7 +36,7 @@ mat4.translateY=function(a,b){return mat4.translate(a,[0,b,0])};mat4.translateZ=
 b[2]-a[2]*b[1],a[3]*b[1]-a[0]*b[2]+a[1]*b[3]+a[2]*b[0],a[3]*b[2]+a[0]*b[1]-a[1]*b[0]+a[2]*b[3]]},addMul:function(a,b,f){return f.length!=void 0&&f.length>=4?[a[0]+b[0]*f[0],a[1]+b[1]*f[1],a[2]+b[2]*f[2],a[3]+b[3]*f[3]]:[a[0]+b[0]*f,a[1]+b[1]*f,a[2]+b[2]*f,a[3]+b[3]*f]},scale:function(a,b){return b.length!=void 0&&b.length>=4?[a[0]*b[0],a[1]*a[1],a[2]*b[2],a[3]*b[3]]:[a[0]*b,a[1]*b,a[2]*b,a[3]*b]},lengthSq:function(a){return a[0]*a[0]+a[1]*a[1]+a[2]*a[2]+a[3]*a[3]},length:function(a){return Math.sqrt(a[0]*
 a[0]+a[1]*a[1]+a[2]*a[2]+a[3]*a[3])},normalize:function(a){var b=Math.sqrt(a[0]*a[0]+a[1]*a[1]+a[2]*a[2]+a[3]*a[3]);return Math.abs(1-b)>1.0E-4?(b=1/b,[a[0]*b,a[1]*b,a[2]*b,a[3]*b]):a},inverse:function(a){var b=vec4.lengthSq(a);return b>1.0E-5?(b=1/b,[a[0]*-b,a[1]*-b,a[2]*-b,a[3]]):a},dot:function(a,b){return a[0]*b[0]+a[1]*b[1]+a[2]*b[2]+a[3]*b[3]}};quat.applyRotation=function(a,b){return mat4.transformPoint(quat.toMatrix(a),b)};
 quat.lerp=function(a,b,f){return quat.normalize([a[0]+(b[0]-a[0])*f,a[1]+(b[1]-a[1])*f,a[2]+(b[2]-a[2])*f,a[3]+(b[3]-a[3])*f])};quat.slerp=function(a,b,f){var g=quat.dot(a,b);if(g>=0.9)return quat.lerp(a,b,f);var h=Math.sqrt(Math.abs(1-g*g));if(h<0.0010)return a;var g=g<0?-1:1,l=Math.asin(h),n=1/h,h=Math.sin((1-f)*l)*n,f=Math.sin(f*l)*n*g;quat.scale(a,h);quat.scale(b,f);return quat.normalize(quat.add(a,b))};
-quat.toMatrix=function(a){var b=2*a[0],f=2*a[1],g=2*a[2],h=b*a[3],l=f*a[3],n=g*a[3];b*=a[0];var o=f*a[0],q=g*a[0];f*=a[1];var p=g*a[1],a=g*a[2];return[1-(f+a),o+n,q-l,0,o-n,1-(b+a),p+h,0,q+l,p-h,1-(b+f),0,0,0,0,1]};var stat=function(){pages={};dlgId="";self=function(a,b,f,g,h){h==void 0&&(h=!0);category=!a?"default":a;pages[category]||(pages[category]=[]);pages[category].push(this);this.name=b;this.value=this.defValue=f;this.func=g;this.reset=h;this.reportInterval=500;stat.dirty=!0;stat.find=function(a,b){var f=pages[a];for(i=0;i<f.length;++i)if(f[i].name==b)return f[i];return null};stat.closePage=function(a){pages[a]=null;stat.dirty=!0};stat.reportAll=function(b){if(stat.dirty==!0){var f=document.getElementById(b);
+quat.toMatrix=function(a){var b=2*a[0],f=2*a[1],g=2*a[2],h=b*a[3],l=f*a[3],n=g*a[3];b*=a[0];var o=f*a[0],p=g*a[0];f*=a[1];var q=g*a[1],a=g*a[2];return[1-(f+a),o+n,p-l,0,o-n,1-(b+a),q+h,0,p+l,q-h,1-(b+f),0,0,0,0,1]};var stat=function(){pages={};dlgId="";self=function(a,b,f,g,h){h==void 0&&(h=!0);category=!a?"default":a;pages[category]||(pages[category]=[]);pages[category].push(this);this.name=b;this.value=this.defValue=f;this.func=g;this.reset=h;this.reportInterval=500;stat.dirty=!0;stat.find=function(a,b){var f=pages[a];for(i=0;i<f.length;++i)if(f[i].name==b)return f[i];return null};stat.closePage=function(a){pages[a]=null;stat.dirty=!0};stat.reportAll=function(b){if(stat.dirty==!0){var f=document.getElementById(b);
 if(!f)return;var g='<div id="stat_tabs">';g+="<ul>";for(a in pages)pages[a]&&(g+='<li><a href="#'+a+'">'+a+"</a></li>");g+="</ul>";for(a in pages)pages[a]&&(g+='<div id="'+a+'">',g+="</div>");g+="</div>";f.innerHTML=g;$("#stat_tabs").tabs();stat.dirty=!1}for(a in pages)f=document.getElementById(a),stat.report(f,a,b)};stat.report=function(a,b){b||(b="default");var f=pages[b];if(f){outputHTML='<table width="100%" cellspacing = 1 border = 0><tr>';var g=0;for(i=0;i<f.length;++i)if(outputHTML+='<td width=200 align=center bgcolor="#3F3F3F">',
 outputHTML+=f[i].func?f[i].name+" : "+f[i].func(f[i].value):f[i].name+" : "+f[i].value,outputHTML+="</td>",g++>=3&&(outputHTML+="</tr><tr>",g=0),f[i].reset)f[i].value=f[i].defValue;outputHTML+="</tr></table>";a.innerHTML=outputHTML}}};setInterval(function(){self.reportAll("RDGE_STATS")},500);return self}();
 dbCanvas=function(a,b){this.front=document.createElement("canvas");this.front.setAttribute("width",a);this.front.setAttribute("height",b);this.front.setAttribute("style","position:absolute; margin: 0.0em; padding: 0.0em;");this.front.ctx=this.front.getContext("2d");this.back=document.createElement("canvas");this.back.setAttribute("width",a);this.back.setAttribute("height",b);this.front.setAttribute("style","position:absolute; margin: 0.0em; padding: 0.0em;");this.back.ctx=this.back.getContext("2d");
@@ -64,7 +64,7 @@ this.ctx.clearColor(a[0],a[1],a[2],a[3])};this.setClearFlags=function(a){this.cl
 b,h){var l=a.split(".")[1],n=this.textureMap[a];if(n===void 0)n=this.createTexture(a+(l?"":".png"),b,h),this.textureMap[a]=n,n.lookUpName=a;return n};_texparams=function(a,b){this.wrap=a;this.mips=b};this.createTexture=function(a,b,h){var l=this.ctx.createTexture();b===void 0&&(b="CLAMP");h===void 0&&(h=!0);if(l)l.image=new Image,l.image.src=a,l.image.context=g_Engine.getContext(),l.texparams=new _texparams(b,h),l.image.onload=function(){this.context.ctxStateManager.RDGEInitState.loadTexture(l)};
 return l};this.commitTexture=function(a){this.ctx.bindTexture(this.ctx.TEXTURE_2D,a);this.ctx.texImage2D(this.ctx.TEXTURE_2D,0,this.ctx.RGBA,this.ctx.RGBA,this.ctx.UNSIGNED_BYTE,a.image);a.texparams.mips&&this.ctx.generateMipmap(this.ctx.TEXTURE_2D);this.ctx.texParameteri(this.ctx.TEXTURE_2D,this.ctx.TEXTURE_MAG_FILTER,this.ctx.LINEAR);this.ctx.texParameteri(this.ctx.TEXTURE_2D,this.ctx.TEXTURE_MIN_FILTER,a.texparams.mips?this.ctx.LINEAR_MIPMAP_LINEAR:this.ctx.LINEAR);this.ctx.texParameteri(this.ctx.TEXTURE_2D,
 this.ctx.TEXTURE_WRAP_S,a.texparams.wrap==="REPEAT"?this.ctx.REPEAT:this.ctx.CLAMP_TO_EDGE);this.ctx.texParameteri(this.ctx.TEXTURE_2D,this.ctx.TEXTURE_WRAP_T,a.texparams.wrap==="REPEAT"?this.ctx.REPEAT:this.ctx.CLAMP_TO_EDGE);this.ctx.bindTexture(this.ctx.TEXTURE_2D,null)};this.verify=function(a){var b=this.ctx.getError();b!=0&&window.console.log("GLError ( "+a+") : "+b)};this.createRenderTargetTexture=function(a,b,h,l){var n=this.ctx,o=n.createFramebuffer();n.bindFramebuffer(n.FRAMEBUFFER,o);o.width=
-b;o.height=h;b=n.createTexture();n.bindTexture(n.TEXTURE_2D,b);try{n.texImage2D(n.TEXTURE_2D,0,n.RGBA,o.width,o.height,0,n.RGBA,n.UNSIGNED_BYTE,null)}catch(q){h=new WebctxUnsignedByteArray(o.width*o.height*4),n.texImage2D(n.TEXTURE_2D,0,n.RGBA,o.width,o.height,0,n.RGBA,n.UNSIGNED_BYTE,h)}n.texParameteri(n.TEXTURE_2D,n.TEXTURE_MAG_FILTER,n.LINEAR);n.texParameteri(n.TEXTURE_2D,n.TEXTURE_MIN_FILTER,l?n.LINEAR_MIPMAP_NEAREST:n.LINEAR);n.texParameteri(n.TEXTURE_2D,n.TEXTURE_WRAP_S,n.CLAMP_TO_EDGE);n.texParameteri(n.TEXTURE_2D,
+b;o.height=h;b=n.createTexture();n.bindTexture(n.TEXTURE_2D,b);try{n.texImage2D(n.TEXTURE_2D,0,n.RGBA,o.width,o.height,0,n.RGBA,n.UNSIGNED_BYTE,null)}catch(p){h=new WebctxUnsignedByteArray(o.width*o.height*4),n.texImage2D(n.TEXTURE_2D,0,n.RGBA,o.width,o.height,0,n.RGBA,n.UNSIGNED_BYTE,h)}n.texParameteri(n.TEXTURE_2D,n.TEXTURE_MAG_FILTER,n.LINEAR);n.texParameteri(n.TEXTURE_2D,n.TEXTURE_MIN_FILTER,l?n.LINEAR_MIPMAP_NEAREST:n.LINEAR);n.texParameteri(n.TEXTURE_2D,n.TEXTURE_WRAP_S,n.CLAMP_TO_EDGE);n.texParameteri(n.TEXTURE_2D,
 n.TEXTURE_WRAP_T,n.CLAMP_TO_EDGE);l&&n.generateMipmap(n.TEXTURE_2D);l=n.createRenderbuffer();n.bindRenderbuffer(n.RENDERBUFFER,l);n.renderbufferStorage(n.RENDERBUFFER,n.DEPTH_COMPONENT16,o.width,o.height);n.getError(n.bindFramebuffer(n.FRAMEBUFFER,o));n.getError(n.bindRenderbuffer(n.RENDERBUFFER,l));n.getError(n.renderbufferStorage(n.RENDERBUFFER,n.DEPTH_COMPONENT16,o.width,o.height));n.bindRenderbuffer(n.RENDERBUFFER,null);n.getError(n.framebufferTexture2D(n.FRAMEBUFFER,n.COLOR_ATTACHMENT0,n.TEXTURE_2D,
 b,0));n.getError(n.framebufferRenderbuffer(n.FRAMEBUFFER,n.DEPTH_ATTACHMENT,n.RENDERBUFFER,l));n.bindFramebuffer(n.FRAMEBUFFER,null);n.bindTexture(n.TEXTURE_2D,null);n.bindRenderbuffer(n.RENDERBUFFER,null);n.bindFramebuffer(n.FRAMEBUFFER,null);b.id="RT_"+nodeIdGen.getId();b.frameBuffer=o;this.textureMap[a]&&window.console.log("Notification: render target: "+a+" has overwritten an existing render target");return this.textureMap[a]=b};this.defaultShaderDefintion={shaders:{defaultVShader:"assets/shaders/test_vshader.glsl",
 defaultFShader:"assets/shaders/test_fshader.glsl"},techniques:{defaultTechnique:[{vshader:"defaultVShader",fshader:"defaultFShader",attributes:{vert:{type:"vec3"},normal:{type:"vec3"},texcoord:{type:"vec2"}},params:{},states:{depthEnable:!0,blendEnable:!1,culling:!0,cullFace:"BACK"}}]}}};
@@ -91,61 +91,60 @@ g.bufferUsage):(this.ctx.bindBuffer(this.ctx.ARRAY_BUFFER,this.buffers[a.buffers
 0,new Float32Array(a.indexBuffer),a.indexUsage)):this.buffers[a.buffersID].indexHandle=this.createIndexBufferUINT16(a.indexBuffer,a.indexUsage):(this.ctx.bindBuffer(this.ctx.ELEMENT_ARRAY_BUFFER,this.buffers[a.buffersID].indexHandle),this.ctx.bufferSubData(this.ctx.ELEMENT_ARRAY_BUFFER,0,new Float32Array(a.indexBuffer),a.indexUsage)),a.indexCount=b,a.triCount=b/3):a.triCount=a.posCount/3}else this.createPrimitive(a)};
 _renderer.prototype.deletePrimitive=function(a){var b=this.buffers[a.buffersID];if(b){var f=this;b.forEach(function(a){f.ctx.deleteBuffer(a)});delete this.buffers[a.buffersID]}};_renderer.prototype.getPrimitiveBuffer=function(a,b){return this.buffers[a.buffersID][b]};
 _renderer.prototype.drawPrimitive=function(a,b,f){g_renderStats.numDrawCalls.value++;g_renderStats.numTriangles.value+=Math.floor(a.triCount);g_renderStats.numVerts.value+=Math.floor(a.coordCount/3);a.indexCount?this.drawIndexedPrimitive(a,b,f):this.drawNonIndexedPrimitive(a,b,f);a.useDoubleBuffer===!0&&a.flip(this)};
-_renderer.prototype.drawIndexedPrimitive=function(a,b,f){var g=b=0,h=a.buffersID,l="",n=f.length,o=0,q=a.frontBufferIndex*a.doubleBufferOffset;for(g_Engine.getContext();o<n;++o)if(g=f[o].loc,l=f[o].name,a.vertexDefinition[l])b=a.vertexDefinition[l].bufferIndex,this.ctx.enableVertexAttribArray(g),this.ctx.bindBuffer(this.ctx.ARRAY_BUFFER,this.buffers[h][q+b]),this.ctx.vertexAttribPointer(g,a.vertexDefinition[l].type,this.FLOAT,!1,0,0);this.ctx.bindBuffer(this.ctx.ELEMENT_ARRAY_BUFFER,this.buffers[h].indexHandle);
+_renderer.prototype.drawIndexedPrimitive=function(a,b,f){var g=b=0,h=a.buffersID,l="",n=f.length,o=0,p=a.frontBufferIndex*a.doubleBufferOffset;for(g_Engine.getContext();o<n;++o)if(g=f[o].loc,l=f[o].name,a.vertexDefinition[l])b=a.vertexDefinition[l].bufferIndex,this.ctx.enableVertexAttribArray(g),this.ctx.bindBuffer(this.ctx.ARRAY_BUFFER,this.buffers[h][p+b]),this.ctx.vertexAttribPointer(g,a.vertexDefinition[l].type,this.FLOAT,!1,0,0);this.ctx.bindBuffer(this.ctx.ELEMENT_ARRAY_BUFFER,this.buffers[h].indexHandle);
 this.ctx.drawElements(a.type,a.indexCount,a.indexElementSize,0);for(o=0;o<n;++o)this.ctx.disableVertexAttribArray(f[o].loc)};
-_renderer.prototype.drawIndexedPrimitiveWireFrame=function(a,b,f){for(var g=b=0,h=a.buffersID,l="",n=f.length,o=0,q=a.frontBufferIndex*a.doubleBufferOffset;o<n;++o)if(g=f[o].loc,l=f[o].name,a.vertexDefinition[l])b=a.vertexDefinition[l].bufferIndex,this.ctx.enableVertexAttribArray(g),this.ctx.bindBuffer(this.ctx.ARRAY_BUFFER,this.buffers[h][q+b]),this.ctx.vertexAttribPointer(g,a.vertexDefinition[l].type,this.FLOAT,!1,0,0);this.ctx.bindBuffer(this.ctx.ELEMENT_ARRAY_BUFFER,this.buffers[h].indexHandle);
+_renderer.prototype.drawIndexedPrimitiveWireFrame=function(a,b,f){for(var g=b=0,h=a.buffersID,l="",n=f.length,o=0,p=a.frontBufferIndex*a.doubleBufferOffset;o<n;++o)if(g=f[o].loc,l=f[o].name,a.vertexDefinition[l])b=a.vertexDefinition[l].bufferIndex,this.ctx.enableVertexAttribArray(g),this.ctx.bindBuffer(this.ctx.ARRAY_BUFFER,this.buffers[h][p+b]),this.ctx.vertexAttribPointer(g,a.vertexDefinition[l].type,this.FLOAT,!1,0,0);this.ctx.bindBuffer(this.ctx.ELEMENT_ARRAY_BUFFER,this.buffers[h].indexHandle);
 this.ctx.drawElements(this.LINE_LOOP,a.indexCount,a.indexElementSize,0);for(o=0;o<n;++o)this.ctx.disableVertexAttribArray(f[o].loc)};
-_renderer.prototype.drawNonIndexedPrimitive=function(a,b,f){for(var g=b=0,h=a.buffersID,l="",n=f.length,o=0,q=a.frontBufferIndex*a.doubleBufferOffset;o<n;++o)g=f[o].loc,l=f[o].name,b=a.vertexDefinition[l].bufferIndex,a.vertexDefinition[l]&&(this.ctx.enableVertexAttribArray(g),this.ctx.bindBuffer(this.ctx.ARRAY_BUFFER,this.buffers[h][q+b]),this.ctx.vertexAttribPointer(g,a.vertexDefinition[l].type,this.FLOAT,!1,0,0));this.ctx.drawArrays(a.type,0,a.triCount);for(o=0;o<n;++o)this.ctx.disableVertexAttribArray(f[o].loc)};
+_renderer.prototype.drawNonIndexedPrimitive=function(a,b,f){for(var g=b=0,h=a.buffersID,l="",n=f.length,o=0,p=a.frontBufferIndex*a.doubleBufferOffset;o<n;++o)g=f[o].loc,l=f[o].name,b=a.vertexDefinition[l].bufferIndex,a.vertexDefinition[l]&&(this.ctx.enableVertexAttribArray(g),this.ctx.bindBuffer(this.ctx.ARRAY_BUFFER,this.buffers[h][p+b]),this.ctx.vertexAttribPointer(g,a.vertexDe