package 
{
//	import flash.display.Stage;
	import flash.display.Sprite;
	import flash.display.Stage3D;
	import flash.display3D.Context3D;
	import flash.display3D.textures.Texture;
	import flash.geom.*;
	import flash.display3D.*;
	import com.adobe.utils.*;
	import ModelImporter;
	
// need to move all textures and shaders inits here!
// nothing rendering related should be left in main
	
	public class RenderFrame 
	{
		// Matrices that affect mesh location and camera 
		public var projectionMatrix:PerspectiveMatrix3D = new PerspectiveMatrix3D();
		public var matrixPlayer:Matrix3D = new Matrix3D();
		public var modelMatrix:Matrix3D = new Matrix3D();
		public var viewMatrix:Matrix3D = new Matrix3D();
		public var modelViewProjection:Matrix3D = new Matrix3D();
		
		// Blend Factors
		public var C_ONE:String 				= Context3DBlendFactor.ONE;
		public var C_ZERO:String 				= Context3DBlendFactor.ZERO;
		public var C_SOURCEALPHA:String 		= Context3DBlendFactor.SOURCE_ALPHA;
		public var C_1MINUSSOURCEALPHA:String 	= Context3DBlendFactor.ONE_MINUS_SOURCE_ALPHA;
		public var C_SOURCECOLOR:String 		= Context3DBlendFactor.SOURCE_COLOR;
		
		private var ccLess:String				= Context3DCompareMode.LESS;
		private var ccNever:String				= Context3DCompareMode.NEVER;
		private var ccAlways:String				= Context3DCompareMode.ALWAYS;
		
		// Testing
		private var colorRed:Vector. = new Vector.([ 1, 0, 0, 1 ]);
		private var colorWhite:Vector. = new Vector.([ 1, 1, 1, 1 ]);
		
		public function RenderFrame():void
		{
		}
		
		
		public function update(sSprite:Sprite, _player:Player, _vars:GameVars, _renderF:RenderFrame, _mathF:MathFunctions, context3D:Context3D, _models:Models, _shaders:Shaders, _textures:Textures, _animations:Animations, _map:Map, _cine:Cinematic, _mobs:Mobs, _projectiles:Projectiles, _items:Items):void
		{
			context3D.clear(0, 0, 0);	// clear scene before rendering is mandatory	
			
			// Set view matrix
			_renderF.viewMatrix = _mathF.camMatrixSet( _player.posNow.clone(), _vars.cameraOffset, _vars.cameraRotation);
			
			// Find Mouse position on plane
			if (_player.playerMoved) { _vars.vIntersect = _mathF.mousePosTo3D(_renderF.projectionMatrix.clone(), _vars.swfWidth, _vars.swfHeight, _player, _vars); }
			else { _vars.vIntersect = new Vector3D(0, 0, 500); }
			
			_renderF.player(_player, context3D, _models, _shaders, _textures, _renderF, _animations);
			_renderF.genB(context3D, _map.currentMap, _shaders.sp_MultTex, _map.currentTex1, _map.currentTex2, _renderF.C_ONE, _renderF.C_ZERO, _renderF, new Vector3D(0,0,0),new Vector3D(0,0,0,1), 1);
			_cine.background(_map.currentRoom, context3D, _models, _textures, _shaders, _animations, _renderF, _mathF, sSprite);
			_renderF.enemies(context3D, _mobs, _models, _animations, _shaders, _textures, _renderF);
			_renderF.playerShots(_projectiles.arrayProjectiles, context3D, _models, _shaders, _textures, _renderF);
			_renderF.powerUps(_items.ArrayPowerUps, _models, _shaders, _textures, _renderF, context3D);
			_renderF.vfx(context3D, _mobs, _models, _animations, _shaders, _textures, _renderF);						// Render VFX
			
			//tests
			
		/*	for (var eny:int = 0; eny < _mobs.ArrayMobs.length; eny++)
			{
				if ( _mobs.ArrayMobs[eny].ID == 7)
				{
					trace(_mobs.ArrayMobs[eny].posNow);
					var posV1:Vector3D = new Vector3D(_mobs.ArrayMobs[eny].posNow.x, -_mobs.ArrayMobs[eny].posNow.y, 0, 0);
					var rotV:Vector3D = new Vector3D(0, 0, 0, 1);
					_renderF.genA(context3D, _models.UI_Target, _shaders.shaderProgram2, _textures.tex_Mobs, null, _renderF.C_ONE, _renderF.C_ZERO, _renderF, posV1, rotV, .25, false, _renderF.ccAlways);
				}
			}
		*/	
		/*	for (var eny:int = 0; eny < _mobs.ArrayMobs.length; eny++)
			{
				var posV1:Vector3D = new Vector3D(_mobs.ArrayMobs[eny].posNow.x, -_mobs.ArrayMobs[eny].posNow.y, 0, 0);
				var posV2:Vector3D = new Vector3D(_mobs.ArrayMobs[eny].dropPoint.x, -_mobs.ArrayMobs[eny].dropPoint.y , 0, 0);
				var posV3:Vector3D = new Vector3D(_mobs.ArrayMobs[eny].posTry.x, _mobs.ArrayMobs[eny].posTry.y, 0, 0);
				
				var rotV:Vector3D = new Vector3D(0, 0, 0, 1);
				
				_renderF.genA(context3D, _models.UI_Target, _shaders.shaderProgram2, _textures.tex_Mobs, null, _renderF.C_ONE, _renderF.C_ZERO, _renderF, posV1, rotV, .25, false, _renderF.ccAlways);
				_renderF.genA(context3D, _models.test_box, _shaders.shaderProgram2, _textures.tex_Mobs, null, _renderF.C_ONE, _renderF.C_ZERO, _renderF, posV2, rotV, 1, false, _renderF.ccAlways);
				_renderF.genA(context3D, _models.test_sphere, _shaders.shaderProgram2, _textures.tex_Mobs, null, _renderF.C_ONE, _renderF.C_ZERO, _renderF, posV3, rotV, .5, false, _renderF.ccAlways);
			}
		*/	
			// Render Mouse 
			_renderF.genA(context3D, _models.UI_Target, _shaders.shaderProgram2, _textures.tex_Mobs, null, _renderF.C_SOURCEALPHA, _renderF.C_1MINUSSOURCEALPHA, _renderF, _vars.vIntersect,new Vector3D(0,0,0,1), 1, false, ccAlways);
			
			context3D.present();		// present/flip back buffer
			
		}
		
		
		public function player(_player:Player, context3D:Context3D, _models:Models, _shaders:Shaders, _textures:Textures, _renderF:RenderFrame, _animations:Animations):void
		{
			if (_player.animNow == null){_player.animNow = _animations.anim_Player_Idle; }		// Set initial current anim
			if (_player.animPast == null) { _player.animPast = _animations.anim_Player_Idle; }	// Set initial past anim
			
			// Shader
			context3D.setTextureAt(0, _textures.tex_Mobs);						// fs0
			context3D.setTextureAt(1, null);									// fs1 clear			
			context3D.setProgram(_shaders.shaderProgram2a);						// Shader			
			context3D.setBlendFactors (C_ONE, C_ZERO);							// Blend Factors
			
			if (_player.hitFrame)												// Color player if being hit
			{ 
				context3D.setProgramConstantsFromVector(Context3DProgramType.FRAGMENT, 0, Vector.([ 1, 0, 0, 1 ]) ); 			// fc0 Red
				_player.hitFrame = false;
			} 
			else { context3D.setProgramConstantsFromVector(Context3DProgramType.FRAGMENT, 0, Vector.([ 0, 0, 0, 1 ]) ); } 		// fc0 White
		
			// Player transform
			var modelMatrixTemp:Matrix3D = new Matrix3D; 
			var v3temp:Vector. = new Vector.(3);			// Temp vector
			v3temp[0] = new Vector3D(_player.posNow.x, -_player.posNow.y, 0);	// Position
			v3temp[1] = new Vector3D(0,( _player.yRot + 90)* -0.0174, 0);		//.0174 is PI / 180 to convert degrees to radians.  Adding 90 so that Mob goes down correct axis  	
			v3temp[2] = new Vector3D(1, 1, 1);									// Scale is always 1
			modelMatrixTemp.recompose(v3temp, "eulerAngles");					// Model Matrix
				
			// Anim selection and Blending
			if (_player.blendTime > 0)											// If a blend is happening don't change anims - just blend and decrement blend time
			{
				_player.blendTime --;
			}
			else																// If not blending set anims 
			{
				// Move current anim to past anim if not blending
				_player.animPast = _player.animNow;
				// Find correct current anim
				
				if (_player.HPcurrent <= 0){_player.animNow = _animations.anim_Player_Die;}
				else
				{
					if (_player.moveFrame) 																			// If Moving
					{ 
						_player.animNow = _animations.anim_Player_RunF;
						
						switch(true)
						{
						case ( _player.angleDiff  > 45 &&  _player.angleDiff <=135):
						//_player.animNow = _animations.anim_Player_RunL;
						_player.animNow = _animations.anim_Player_RunF;
						break;
						case (_player.angleDiff  > 135 && _player.angleDiff  <= 225):
						_player.animNow = _animations.anim_Player_RunB;
						break;
						case (_player.angleDiff  > 225 &&  _player.angleDiff  <= 315):
						//_player.animNow = _animations.anim_Player_RunR;
						_player.animNow = _animations.anim_Player_RunF;
						break;
						}
					}						
					else {_player.animNow = _animations.anim_Player_Idle; }											// Idle
				}
				// check if anim changed
				if (_player.animNow != _player.animPast)
				{
					_player.blendTime = _player.blendTimeMax;		// Set blend time to max
					_player.frameNumPast = _player.frameNum;		// Copy frame number to past frame number
					_player.frameNum = -1;							// Setting to -1 since its incremented below
				}
			}
			// Increment frames - set back to 0 if out of bounds
			_player.frameNum ++;	
			if (_player.frameNum >= _player.animNow.animLen) {_player.frameNum = 0;}
			
			_player.frameNumPast ++;					
			if (_player.frameNumPast >= _player.animPast.animLen) {_player.frameNumPast = 0;}
			
			context3D.setDepthTest(true,Context3DCompareMode.LESS);
			
			// Render all pieces of Player 
			for (var loopCnt_Parts:uint = 0; loopCnt_Parts < _models.Player.numNodes; loopCnt_Parts++)
			{
				modelMatrix.identity();
				// Get pos,rotation of each part from anim file
				var v3:Vector. = new Vector.(3);
				v3[0] = _player.animNow.posData[loopCnt_Parts][_player.frameNum];
				v3[1] = _player.animNow.rotData[loopCnt_Parts][_player.frameNum]; 
				v3[2] = _player.animNow.scaData[loopCnt_Parts][_player.frameNum]; 
				modelMatrix.recompose(v3, "quaternion");
				
				// if blending - get pos and rotation from old anim
				if (_player.blendTime > 0)
				{
					var modelMatrixPast:Matrix3D = new Matrix3D;
					var v3a:Vector. = new Vector.(3);
					v3a[0] = _player.animPast.posData[loopCnt_Parts][_player.frameNumPast];
					v3a[1] = _player.animPast.rotData[loopCnt_Parts][_player.frameNumPast]; 
					v3a[2] = _player.animPast.scaData[loopCnt_Parts][_player.frameNumPast]; 
					modelMatrixPast.recompose(v3a, "quaternion");
					var blendAmt:Number = (_player.blendTime / _player.blendTimeMax);
					modelMatrix.interpolateTo(modelMatrixPast, blendAmt);
				}	
				modelMatrix.append(modelMatrixTemp);
				
				_renderF.modelViewProjection.identity();							// Model, View and Projection are three separate matrices. 
				_renderF.modelViewProjection.append(modelMatrix);					// Model maps from an object's local coordinate space into world space 
				_renderF.modelViewProjection.append(_renderF.viewMatrix);			// View maps from world space to camera space
				_renderF.modelViewProjection.append(_renderF.projectionMatrix);		// Projection maps from camera to screen
				
				context3D.setProgramConstantsFromMatrix(Context3DProgramType.VERTEX, 0, _renderF.modelViewProjection, true ); //vc0
				
				context3D.setVertexBufferAt(0, _models.Player.bufferArray[loopCnt_Parts][3], 0, Context3DVertexBufferFormat.FLOAT_3); //va0 (x,y,z)
				context3D.setVertexBufferAt(1, _models.Player.bufferArray[loopCnt_Parts][3], 3, Context3DVertexBufferFormat.FLOAT_2); //va2 (u,v)
				context3D.setVertexBufferAt(2, null); //clear out vertex buffer
				context3D.setVertexBufferAt(3, null); //clear out vertex buffer
				
				context3D.drawTriangles(_models.Player.bufferArray[loopCnt_Parts][2], 0, _models.Player.bufferArray[loopCnt_Parts][5] / 3);
			}
		}		
		
		// Projectile Render
		public function playerShots(arrayProjectiles:Array,context3D:Context3D,_models:Models, _shaders:Shaders, _textures:Textures, _renderF:RenderFrame):void
		{
			context3D.setTextureAt(0, _textures.tex_Mobs);			// fs0
			context3D.setTextureAt(1, null);						// fs1 clear
			context3D.setProgram(_shaders.shaderProgram2);			// Set Shader
			
			// Loop over each shot
			for (var tmpArrCnt:int = 0; tmpArrCnt < arrayProjectiles.length; tmpArrCnt++)
			{
				var modelMatrix:Matrix3D = new Matrix3D;  			
				var projectileModel:Object = _models.P01_Standard;
				
				if (arrayProjectiles[tmpArrCnt][0] == -1)			// player shot
				{
					switch(true)
					{
						case(arrayProjectiles[tmpArrCnt][9] > 0):
						projectileModel = _models.P02_Bouncing;
						break;	
						case(arrayProjectiles[tmpArrCnt][10] > 0):
						projectileModel = _models.P03_Homing;
						break;	
						case(arrayProjectiles[tmpArrCnt][7] > 0):
						projectileModel = _models.P04_Explosive;
						break;	
					}
				}
				else
				{
					projectileModel = _models.P00_Enemy;			// Enemy Shot
				}
				
				// Shot transform
				var v3temp:Vector. = new Vector.(3);
				v3temp[0] = new Vector3D(arrayProjectiles[tmpArrCnt][1].x,-arrayProjectiles[tmpArrCnt][1].y, 0);	// Position
				v3temp[1] = new Vector3D(0, -1.566, ( arrayProjectiles[tmpArrCnt][3])* -0.0174);					//.0174 is PI / 180 to convert degrees to radians.  Adding 90 so that Mob goes down correct axis  	
				v3temp[2] = new Vector3D(1, 1, 1);																// Scale is always 1
				modelMatrix.recompose(v3temp, "eulerAngles");
				
				_renderF.modelViewProjection.identity();						// Model, View and Projection are three separate matrices. 
				_renderF.modelViewProjection.append(modelMatrix);			// Model maps from an object's local coordinate space into world space 
				_renderF.modelViewProjection.append(_renderF.viewMatrix);				// View maps from world space to camera space
				_renderF.modelViewProjection.append(_renderF.projectionMatrix);		// Projection maps from camera to screen
				
				context3D.setProgramConstantsFromMatrix(Context3DProgramType.VERTEX, 0, _renderF.modelViewProjection, true ); //vc0
				
				context3D.setVertexBufferAt(0, projectileModel.vertexBuffer, 0, Context3DVertexBufferFormat.FLOAT_3); //va0 (x,y,z)
				context3D.setVertexBufferAt(1, projectileModel.vertexBuffer, 3, Context3DVertexBufferFormat.FLOAT_2); //va1 (u,v)
				context3D.setVertexBufferAt(2, null); //clear out vertex buffer
				context3D.setVertexBufferAt(3, null); //clear out vertex buffer
				
				context3D.setBlendFactors (	Context3DBlendFactor.SOURCE_ALPHA, Context3DBlendFactor.ONE_MINUS_SOURCE_ALPHA);	
				
				context3D.setDepthTest(true,Context3DCompareMode.LESS);
				context3D.setCulling(Context3DTriangleFace.NONE);
				context3D.setColorMask(true, true, true, true);
// Make generic				
				context3D.drawTriangles(projectileModel.indexBuffer, 0, projectileModel.indexListLength / 3);
			}
		}			
		
		// PowerUp Render
		public function powerUps(ArrayPowerUps:Array, _models:Models, _shaders:Shaders, _textures:Textures, _renderF:RenderFrame, context3D:Context3D):void
		{
			context3D.setTextureAt(0, _textures.tex_Mobs);			// fs0
			context3D.setTextureAt(1, null);						// fs1 clear
			context3D.setProgram(_shaders.shaderProgram2);			// Set Shader
			
			// Loop over each PowerUp
			for (var tmpArrCnt:int = 0; tmpArrCnt < ArrayPowerUps.length; tmpArrCnt++)
			{
				var powerUpID:ModelImporter;
				var renderIt:Boolean = false;
				
				switch(ArrayPowerUps[tmpArrCnt][0])
				{
					case "W01_OneShot":
					powerUpID = _models.W01_OneShot;
					renderIt = true;
					break;
					case "W02_ThreeWay":
					powerUpID = _models.W02_ThreeWay;
					renderIt = true;
					break;
					case "W03_RapidFire":
					powerUpID = _models.W03_RapidFire;
					renderIt = true;
					break;
					case "R01_Bouncing":
					powerUpID = _models.R01_Bouncing;
					renderIt = true;
					break;
					case "R02_Explosive":
					powerUpID = _models.R02_Explosive;
					renderIt = true;
					break;
					case "R03_Homing":
					powerUpID = _models.R03_Homing;
					renderIt = true;
					break;
					case "H01_Health":
					powerUpID = _models.H01_Health;
					renderIt = true;
					break;
					case "H02_Health":
					powerUpID = _models.H02_Health;
					renderIt = true;					
					break;
					case "L01_LifeUp":
					powerUpID = _models.L01_LifeUp;
					renderIt = true;
					break;
					case "U01_DamageUp":
					powerUpID = _models.U01_DamageUp;
					renderIt = true;
					break;
					case "U02_SpeedUp":
					powerUpID = _models.U02_SpeedUp;
					renderIt = true;
					break;
					case "U03_HeatLimitUp":
					powerUpID = _models.U03_HeatLimitUp;
					renderIt = true;
					break;
				}
				
				if (renderIt)
				{
					// Power Up transform
					var modelMatrix:Matrix3D = new Matrix3D; 
					var v3temp:Vector. = new Vector.(3);
					v3temp[0] = new Vector3D(ArrayPowerUps[tmpArrCnt][1].x, -ArrayPowerUps[tmpArrCnt][1].y, 0);							// Position
					v3temp[1] = new Vector3D(0,(ArrayPowerUps[tmpArrCnt][2]* -0.0174), 0);												//.0174 is PI / 180 to convert degrees to radians.  Adding 90 so that Mob goes down correct axis  	
					v3temp[2] = new Vector3D(ArrayPowerUps[tmpArrCnt][3], ArrayPowerUps[tmpArrCnt][3], ArrayPowerUps[tmpArrCnt][3]);	// Scale 
					modelMatrix.recompose(v3temp, "eulerAngles");
					
					_renderF.modelViewProjection.identity();						// Model, View and Projection are three separate matrices. 
					_renderF.modelViewProjection.append(modelMatrix);				// Model maps from an object's local coordinate space into world space 
					_renderF.modelViewProjection.append(_renderF.viewMatrix);		// View maps from world space to camera space
					_renderF.modelViewProjection.append(_renderF.projectionMatrix);	// Projection maps from camera to screen
					
					context3D.setProgramConstantsFromMatrix(Context3DProgramType.VERTEX, 0, _renderF.modelViewProjection, true ); //vc0
					
					context3D.setVertexBufferAt(0, powerUpID.vertexBuffer, 0, Context3DVertexBufferFormat.FLOAT_3); //va0 (x,y,z)
					context3D.setVertexBufferAt(1, powerUpID.vertexBuffer, 3, Context3DVertexBufferFormat.FLOAT_2); //va1 (u,v)
					context3D.setVertexBufferAt(2, null); //clear out vertex buffer
					context3D.setVertexBufferAt(3, null); //clear out vertex buffer
					
					context3D.setBlendFactors (Context3DBlendFactor.ONE, Context3DBlendFactor.ZERO);	
					
					context3D.setDepthTest(true,Context3DCompareMode.LESS);
					context3D.setCulling(Context3DTriangleFace.NONE);
					context3D.setColorMask(true, true, true, true);			
					context3D.drawTriangles(powerUpID.indexBuffer, 0, powerUpID.indexListLength / 3);
				}
			}
		}
		
		// Render all Enemies
		public function enemies(context3D:Context3D,_mobs:Mobs,_models:Models, _animations:Animations, _shaders:Shaders, _textures:Textures, _renderF:RenderFrame):void
		{
			context3D.setTextureAt(0, _textures.tex_Mobs);		// fs0
			context3D.setTextureAt(1, null);					// fs1 clear
			
			context3D.setProgram(_shaders.shaderProgram2a);		// Set Shader
			context3D.setDepthTest(true,Context3DCompareMode.LESS);
			context3D.setCulling(Context3DTriangleFace.BACK);
			context3D.setColorMask(true, true, true, true);	
			context3D.setBlendFactors (	Context3DBlendFactor.ONE, Context3DBlendFactor.ZERO);
			
			// Loop through all enemies
			for (var tmpEnyCnt:int = 0; tmpEnyCnt < _mobs.ArrayMobs.length; tmpEnyCnt++)
			{
				var tstMob:Object = _mobs.ArrayMobs[tmpEnyCnt];		// Using shorter name 				
				var modelMatrix:Matrix3D = new Matrix3D;		 	// Mob position
				
				// Color mob if being hit
				if (tstMob.hitFrame)
				{ 
					context3D.setProgramConstantsFromVector(Context3DProgramType.FRAGMENT, 0, Vector.([ 1, 0, 0, 1 ]) ); //fc0 - Red
					tstMob.hitFrame = false;
				} 
				else { context3D.setProgramConstantsFromVector(Context3DProgramType.FRAGMENT, 0, Vector.([ 0, 0, 0, 1 ]) ); } // White
				
				// Mob transform
				var modelMatrixTemp:Matrix3D = new Matrix3D; 
				var v3temp:Vector. = new Vector.(3);									// Temp vector
				v3temp[0] = new Vector3D(tstMob.posNow.x, -tstMob.posNow.y, 0);								// Position
				if (tstMob.vertRotation) {v3temp[1] = new Vector3D(0,( tstMob.yRot + 90)* -0.0174, 0);}		//.0174 is PI / 180 to convert degrees to radians.  Adding 90 so that Mob goes down correct axis  	
				else{v3temp[1] = new Vector3D(0, 0, ( tstMob.yRot - 90)* -0.0174);}							// If mob rotates sideways
				v3temp[2] = new Vector3D(1, 1, 1);															// Scale is always 1
				modelMatrixTemp.recompose(v3temp, "eulerAngles");											// Model Matrix
				
				
				// Anim selection and Blending
				
				// Check for undefined anims - set to sleep if undefined
				if (tstMob.animPast == undefined) { tstMob.animPast = _animations.animMobArray[tstMob.ID][6]; }
				if (tstMob.animNow == undefined) { tstMob.animNow = _animations.animMobArray[tstMob.ID][6];}
				
				// If a blend is happening don't change anims - just blend and decrement blend time
				if (tstMob.blendTime > 0)
				{
					tstMob.blendTime --;

				}
				else	// If not blending set anims 
				{
					// Move current anim to past anim if not blending
					tstMob.animPast = tstMob.animNow;
					
					// Find correct current anim - this will have more cases like attacking etc...
					if (tstMob.HPcurrent <= 0) { tstMob.animNow = _animations.animMobArray[tstMob.ID][4]; }			// If dead
					else if (!tstMob.awake) {tstMob.animNow =  _animations.animMobArray[tstMob.ID][6];}		// asleep
					else if (tstMob.waking) { tstMob.animNow =  _animations.animMobArray[tstMob.ID][5]; }			// wake up
					else if (!tstMob.alerted) { tstMob.animNow =  _animations.animMobArray[tstMob.ID][6]; }	// temp: if can't see player sleep
					else if (tstMob.speed == 0) { tstMob.animNow =  _animations.animMobArray[tstMob.ID][0]; }		// if can't move play idle
					else if (tstMob.collide) { tstMob.animNow =  _animations.animMobArray[tstMob.ID][1]; }	// collided 
					else if (tstMob.collidePlayer) { tstMob.animNow =  _animations.animMobArray[tstMob.ID][1]; }	// collided 
					else {tstMob.animNow = _animations.animMobArray[tstMob.ID][2];}
					
					// check if anim changed
					if (tstMob.animNow != tstMob.animPast)
					{
						// If waking
						if (tstMob.animPast == _animations.animMobArray[tstMob.ID][5])
						{
							tstMob.animPast = tstMob.animNow;			// Set to past anim to current anim to avoid blending
						}
						else
						{
							tstMob.blendTime = tstMob.blendTimeMax;		// Set blend time to max
							tstMob.frameNumPast = tstMob.frameNum;		// Copy frame number to past frame number
							tstMob.frameNum = -1;						// Setting to -1 since its incremented below
						}
					}
				}
				// Increment frames - set back to 0 if out of bounds
				tstMob.frameNum ++;	
				// Die Anim - play then hold last frame and remove
				if ((tstMob.HPcurrent <= 0) && (tstMob.frameNum >= tstMob.animNow.animLen) ) { tstMob.frameNum = tstMob.animNow.animLen - 1; tstMob.removeMe = true; }
				// Waking up
				else if ((tstMob.waking) && (tstMob.frameNum >= tstMob.animNow.animLen))  {  tstMob.frameNum = tstMob.animNow.animLen - 1; tstMob.waking = false; }
				else if (tstMob.frameNum >= tstMob.animNow.animLen) {tstMob.frameNum = 0;}
				
				tstMob.frameNumPast ++;					
				if (tstMob.frameNumPast >= tstMob.animPast.animLen) {tstMob.frameNumPast = 0;}
				
				// Render all pieces of enemy 
				for (var loopCnt_Parts:uint = 0; loopCnt_Parts < _models.modelMobArray[tstMob.ID].numNodes; loopCnt_Parts++)
				{
					modelMatrix.identity();
					// Get pos,rotation of each part from anim file
					var v3:Vector. = new Vector.(3);
					v3[0] = tstMob.animNow.posData[loopCnt_Parts][tstMob.frameNum];
					v3[1] = tstMob.animNow.rotData[loopCnt_Parts][tstMob.frameNum]; 
					v3[2] = tstMob.animNow.scaData[loopCnt_Parts][tstMob.frameNum]; 
					modelMatrix.recompose(v3, "quaternion");
					
					// if blending - get pos and rotation from old anim
					if (tstMob.blendTime > 0)
					{
						var modelMatrixPast:Matrix3D = new Matrix3D;
						var v3a:Vector. = new Vector.(3);
						v3a[0] = tstMob.animPast.posData[loopCnt_Parts][tstMob.frameNumPast];
						v3a[1] = tstMob.animPast.rotData[loopCnt_Parts][tstMob.frameNumPast]; 
						v3a[2] = tstMob.animPast.scaData[loopCnt_Parts][tstMob.frameNumPast]; 
						modelMatrixPast.recompose(v3a, "quaternion");
						var blendAmt:Number = (tstMob.blendTime / tstMob.blendTimeMax);
						modelMatrix.interpolateTo(modelMatrixPast, blendAmt);
					}					
					modelMatrix.append(modelMatrixTemp);
					
					_renderF.modelViewProjection.identity();							// Model, View and Projection are three separate matrices. 
					_renderF.modelViewProjection.append(modelMatrix);					// Model maps from an object's local coordinate space into world space 
					_renderF.modelViewProjection.append(_renderF.viewMatrix);			// View maps from world space to camera space
					_renderF.modelViewProjection.append(_renderF.projectionMatrix);		// Projection maps from camera to screen
					
					context3D.setProgramConstantsFromMatrix(Context3DProgramType.VERTEX, 0, _renderF.modelViewProjection, true ); //vc0
					
					context3D.setVertexBufferAt(0, _models.modelMobArray[tstMob.ID].bufferArray[loopCnt_Parts][3], 0, Context3DVertexBufferFormat.FLOAT_3); //va0 (x,y,z)
					context3D.setVertexBufferAt(1, _models.modelMobArray[tstMob.ID].bufferArray[loopCnt_Parts][3], 3, Context3DVertexBufferFormat.FLOAT_2); //va2 (u,v)
					context3D.setVertexBufferAt(2, null); //clear out vertex buffer
					context3D.setVertexBufferAt(3, null); //clear out vertex buffer
					
					context3D.drawTriangles(_models.modelMobArray[tstMob.ID].bufferArray[loopCnt_Parts][2], 0, _models.modelMobArray[tstMob.ID].bufferArray[loopCnt_Parts][5] / 3);
				}
				
			}
		}	
		
		// Render VFX
		public function vfx(context3D:Context3D, _mobs:Mobs,_models:Models, _animations:Animations, _shaders:Shaders, _textures:Textures, _renderF:RenderFrame):void
		{
			for (var tmpVfxCnt:int = 0; tmpVfxCnt < _mobs.arrayVFX.length; tmpVfxCnt++)
			{
				var cVfx:Object = _mobs.arrayVFX[tmpVfxCnt];				// Make var name shorter
				
				// Right now this only works for chompers
				context3D.setTextureAt(0, _textures.tex_VFX);				// fs0				
				context3D.setTextureAt(1, null);							// fs1 clear				
				context3D.setProgram(_shaders.shaderProgram2);				// Set Shader
				context3D.setDepthTest(false,Context3DCompareMode.LESS);	// Render Settings: Depth
				context3D.setCulling(Context3DTriangleFace.BACK);			// Render Settings: Culling
				//context3D.setColorMask(true, true, true, true);	
				context3D.setBlendFactors (	Context3DBlendFactor.SOURCE_ALPHA, Context3DBlendFactor.ONE);
				
				// VFX position
				var modelMatrix:Matrix3D = new Matrix3D; 
				
				
				// Value to multiply (might make darker as explosion goes on?)
				context3D.setProgramConstantsFromVector(Context3DProgramType.FRAGMENT, 0, Vector.([ 0, 0, 0, 1 ]));
				
				// VFX transform
				var vfxMatrix:Matrix3D = new Matrix3D; 
				var v3temp:Vector. = new Vector.(3);
				v3temp[0] = cVfx[0];										// Position
				v3temp[1] = new Vector3D(0, cVfx[3], 0);					// Rotation in radians	
				v3temp[2] = new Vector3D(1, 1, 1);							// Scale is always 1
				vfxMatrix.recompose(v3temp, "eulerAngles");
				
				// Increment frames - set back to 0 if out of bounds
				cVfx[2] ++;
				var currentAnim:Object;
				
				switch(cVfx[1])
				{
					case ('VFX_Exp01'):
					currentAnim =  _animations.anim_VFX_Exp01;
					break;
					case ('VFX_Imp01'):
					currentAnim =  _animations.anim_VFX_Imp01;
					break;
				}
				
				
				// Render all pieces of VFX
// Need to make generic				
				for (var loopCnt_VFX:uint = 0; loopCnt_VFX < _models.VFX_Exp01.numNodes; loopCnt_VFX++)
				{
					modelMatrix.identity();
					// Get pos,rotation of each part from anim file
					var v3:Vector. = new Vector.(3);
					v3[0] = currentAnim.posData[loopCnt_VFX][cVfx[2]];
					v3[1] = currentAnim.rotData[loopCnt_VFX][cVfx[2]];
					v3[2] = currentAnim.scaData[loopCnt_VFX][cVfx[2]];
					modelMatrix.recompose(v3, "quaternion");
					
					modelMatrix.append(vfxMatrix);
					
					_renderF.modelViewProjection.identity();							// Model, View and Projection are three separate matrices. 
					_renderF.modelViewProjection.append(modelMatrix);					// Model maps from an object's local coordinate space into world space 
					_renderF.modelViewProjection.append(_renderF.viewMatrix);			// View maps from world space to camera space
					_renderF.modelViewProjection.append(_renderF.projectionMatrix);		// Projection maps from camera to screen
					
					context3D.setProgramConstantsFromMatrix(Context3DProgramType.VERTEX, 0, _renderF.modelViewProjection, true ); 						//vc0
					
					context3D.setVertexBufferAt(0, _models.VFX_Exp01.bufferArray[loopCnt_VFX][3], 0, Context3DVertexBufferFormat.FLOAT_3);	//va0 (x,y,z)
					context3D.setVertexBufferAt(1, _models.VFX_Exp01.bufferArray[loopCnt_VFX][3], 3, Context3DVertexBufferFormat.FLOAT_2);	//va2 (u,v)
					context3D.setVertexBufferAt(2, null); //clear out vertex buffer
					context3D.setVertexBufferAt(3, null); //clear out vertex buffer
					
					context3D.drawTriangles(_models.VFX_Exp01.bufferArray[loopCnt_VFX][2], 0, _models.VFX_Exp01.bufferArray[loopCnt_VFX][5] / 3);
				}
				
			if (cVfx[2] >= currentAnim.animLen-1){ _mobs.arrayVFX.splice(tmpVfxCnt, 1);}	
			}	
			
		}		
		
		// Generic Render - should handle a lot of cases with 1 texture max and pos and uv - might extend to handle more vertex buffers
		public function genA(context3D:Context3D, model:ModelImporter, shader:Program3D, texA:Texture, texB:Texture, blendA:String, blendB:String, _renderF:RenderFrame, posV:Vector3D,rotQ:Vector3D,scaleN:Number, depthTest:Boolean, depthC:String):void
		{
			context3D.setTextureAt(0, texA);									// fs0
			context3D.setTextureAt(1, texB);									// fs1
			
			var modelMatrix:Matrix3D = new Matrix3D; 
			var v3:Vector. = new Vector.(3);
			v3[0] = posV;
			v3[1] = rotQ; 														//default is new Vector3D(0, 0, 0, 1); 
			v3[2] = new Vector3D(scaleN, scaleN, scaleN);
			modelMatrix.recompose(v3, "quaternion");
			
			context3D.setProgram(shader);										// Set Shader
			
			_renderF.modelViewProjection.identity();							// Model, View and Projection are three separate matrices. 
			_renderF.modelViewProjection.append(modelMatrix);					// Model maps from an object's local coordinate space into world space 
			_renderF.modelViewProjection.append(_renderF.viewMatrix);			// View maps from world space to camera space
			_renderF.modelViewProjection.append(_renderF.projectionMatrix);		// Projection maps from camera to screen
			
			context3D.setProgramConstantsFromMatrix(Context3DProgramType.VERTEX, 0, _renderF.modelViewProjection, true ); 	//vc0
			
			context3D.setVertexBufferAt(0, model.vertexBuffer, 0, Context3DVertexBufferFormat.FLOAT_3); 					//va0 (x,y,z)
			context3D.setVertexBufferAt(1, model.vertexBuffer, 3, Context3DVertexBufferFormat.FLOAT_2); 					//va1 (u,v)
			context3D.setVertexBufferAt(2, null); 																			//clear out vertex buffer
			context3D.setVertexBufferAt(3, null); 																			//clear out vertex buffer
			
			context3D.setBlendFactors (	blendA, blendB );	
			
			context3D.setDepthTest(depthTest, depthC );
			//context3D.setDepthTest(false,Context3DCompareMode.LESS);
			
			context3D.setCulling(Context3DTriangleFace.BACK);
			context3D.setColorMask(true, true, true, true);
			
			context3D.drawTriangles(model.indexBuffer, 0, model.indexListLength/3);
		}		

		// Generic Render - should handle a lot of cases with 2 textures max and pos and uv - might extend to handle more vertex buffers
		public function genB(context3D:Context3D, model:ModelImporter, shader:Program3D, texA:Texture, texB:Texture, blendA:String, blendB:String, _renderF:RenderFrame, posV:Vector3D,rotQ:Vector3D,scaleN:Number):void
		{
			
			context3D.setTextureAt(0, texA);									// fs0
			context3D.setTextureAt(1, texB);									// fs1
			
			var modelMatrix:Matrix3D = new Matrix3D; 
			var v3:Vector. = new Vector.(3);
			v3[0] = posV;
			v3[1] = rotQ; 														//default is new Vector3D(0, 0, 0, 1); 
			v3[2] = new Vector3D(scaleN, scaleN, scaleN);
			modelMatrix.recompose(v3, "quaternion");
			
			context3D.setProgram(shader);										// Set Shader
			
			_renderF.modelViewProjection.identity();							// Model, View and Projection are three separate matrices. 
			_renderF.modelViewProjection.append(modelMatrix);					// Model maps from an object's local coordinate space into world space 
			_renderF.modelViewProjection.append(_renderF.viewMatrix);			// View maps from world space to camera space
			_renderF.modelViewProjection.append(_renderF.projectionMatrix);		// Projection maps from camera to screen
			
			context3D.setProgramConstantsFromMatrix(Context3DProgramType.VERTEX, 0, _renderF.modelViewProjection, true ); 	//vc0
			
			context3D.setVertexBufferAt(0, model.vertexBuffer, 0, Context3DVertexBufferFormat.FLOAT_3); 					//va0 (x,y,z)
			context3D.setVertexBufferAt(1, model.vertexBuffer, 3, Context3DVertexBufferFormat.FLOAT_2); 					//va1 (u,v)
			context3D.setVertexBufferAt(2, model.vertexBuffer, 5, Context3DVertexBufferFormat.FLOAT_2); 					//va2 (u,v)
			context3D.setVertexBufferAt(3, null); 																			//clear out vertex buffer
			
			context3D.setBlendFactors (	blendA, blendB );	
			
			context3D.setDepthTest(true,Context3DCompareMode.LESS);
			context3D.setCulling(Context3DTriangleFace.BACK);
			context3D.setColorMask(true, true, true, true);
			
			context3D.drawTriangles(model.indexBuffer, 0, model.indexListLength/3);
		}
		
		// Generic heiarchy
		public function genC(twoTex:Boolean, depthTest:Boolean, context3D:Context3D, frame:int, model:ModelImporter, shader:Program3D, t1:Texture, t2:Texture, _renderF:RenderFrame, animation:AnimImporter, scale:Number, color:Vector., blendA:String, blendB:String):void
		{
			// Shader
			context3D.setTextureAt(0, t1);						// fs0
			context3D.setTextureAt(1, t2);						// fs1 clear			
			context3D.setProgram(shader);						// Shader			
			context3D.setBlendFactors (blendA, blendB);			// Blend Factors
			
			context3D.setProgramConstantsFromVector(Context3DProgramType.FRAGMENT, 0, color );  		// fc0 color
			
			// Transform
			var modelMatrixTemp:Matrix3D = new Matrix3D; 
			var v3temp:Vector. = new Vector.(3);			// Temp vector
			v3temp[0] = new Vector3D(0, 0, 0);									// Position
			v3temp[1] = new Vector3D(0, 0, 0);									//.0174 is PI / 180 to convert degrees to radians.  Adding 90 so that Mob goes down correct axis  	
			v3temp[2] = new Vector3D(scale, scale, scale);						// Scale is always 1
			modelMatrixTemp.recompose(v3temp, "eulerAngles");					// Model Matrix
			
			// Render all pieces 
			for (var loopCnt_Parts:uint = 0; loopCnt_Parts < model.numNodes; loopCnt_Parts++)
			{
				if (!depthTest){context3D.setProgramConstantsFromVector(Context3DProgramType.FRAGMENT, 0, Vector.([ 1, 1, 1,animation.clpData[loopCnt_Parts][frame]]));}  		// fc0 color}
				
				modelMatrix.identity();
				// Get pos,rotation of each part from anim file
				var v3:Vector. = new Vector.(3);
				v3[0] = animation.posData[loopCnt_Parts][frame];
				v3[1] = animation.rotData[loopCnt_Parts][frame]; 
				v3[2] = animation.scaData[loopCnt_Parts][frame]; 
				modelMatrix.recompose(v3, "quaternion");
				
				//modelMatrix.append(modelMatrixTemp);
				
				_renderF.modelViewProjection.identity();							// Model, View and Projection are three separate matrices. 
				_renderF.modelViewProjection.append(modelMatrix);					// Model maps from an object's local coordinate space into world space 
				_renderF.modelViewProjection.append(_renderF.viewMatrix);			// View maps from world space to camera space
				_renderF.modelViewProjection.append(_renderF.projectionMatrix);		// Projection maps from camera to screen
				
				context3D.setProgramConstantsFromMatrix(Context3DProgramType.VERTEX, 0, _renderF.modelViewProjection, true ); //vc0
				
				if (twoTex)
				{
					context3D.setVertexBufferAt(0, model.bufferArray[loopCnt_Parts][3], 0, Context3DVertexBufferFormat.FLOAT_3); 					//va0 (x,y,z)
					context3D.setVertexBufferAt(1, model.bufferArray[loopCnt_Parts][3], 3, Context3DVertexBufferFormat.FLOAT_2); 					//va1 (u,v)
					context3D.setVertexBufferAt(2, model.bufferArray[loopCnt_Parts][3], 5, Context3DVertexBufferFormat.FLOAT_2); 					//va2 (u,v)
					context3D.setVertexBufferAt(3, null);
								
				}
				else
				{
					context3D.setVertexBufferAt(0, model.bufferArray[loopCnt_Parts][3], 0, Context3DVertexBufferFormat.FLOAT_3); //va0 (x,y,z)
					context3D.setVertexBufferAt(1, model.bufferArray[loopCnt_Parts][3], 3, Context3DVertexBufferFormat.FLOAT_2); //va2 (u,v)
					context3D.setVertexBufferAt(2, null); 																		//or clear out vertex buffer
					context3D.setVertexBufferAt(3, null); 																		//clear out vertex buffer
				}
				
				if (depthTest) { context3D.setCulling(Context3DTriangleFace.BACK); }
				else { context3D.setCulling(Context3DTriangleFace.NONE); }
				context3D.setDepthTest(depthTest,Context3DCompareMode.LESS);
				context3D.drawTriangles(model.bufferArray[loopCnt_Parts][2], 0, model.bufferArray[loopCnt_Parts][5] / 3);
				
			}
		}
		
		
		
	}
}