//===================================================================================================
// Uniform Variables
//===================================================================================================
float4x4 ViewProj;
float4x4 World;
float4x4 WorldInverseTranspose;
float4x4 LightViewProj1;
float4x4 LightViewProj2;

float4x4 EyePostion;
float4x4 EyePostion1;
float4x4 EyePostion2;
float4x4 EyePostion3;

int ScreenWidth;
int ScreenHeight;

//Is the player dead?
bool playerIsDead;

float4 pixelColor1;
float4 pixelColor2;

float4 fogColor;
float fogDensity;
float zMaxDepth;
float fogDropOff;

float4x4 light0;
float4x4 light1;
float coreShininess;

float WaveRadius;
float SphereRadius;
float4 particleType;
float4 particleLookVector;
float particleEnergyValue;

float4 coreMaterialDiffuse;
float4 coreMaterialSpecular;

float3 halfwayVector1;
float3 halfwayVector2;
float diffuse0;
float diffuse1;
float specular0;
float specular1;
float4 ambientColor;
float4 diffuseColor;
float4 specularColor;
float4 textureValue;

//Hit Values
float4 hitTime;
float4x4 hits;

//Blending Variables
float worldMinY;
float worldMaxY;

float4x4 targetFeedbackArray;
float btime;
uniform extern texture ScreenTexture;    

float particleRichtor = 5.0f;
float particleAmplitude = 0.05f;			// 
float particleRedShift =  0.3f;			// Increase red components of color
float waveFormScaler = 0.5f;			// Scale the height of the flame

bool LightUpTerrainMod;
float3 PlaneRayIntersectionPoint;
float TerrainModRange;

float3 normal;

// Player Position for Terrain LOD calculations
float2 playerPosition;
float terrainMapSize;
float terrainScaleFactor;

// Animation Stuff
float4x4 MatrixPalette[56];

//===================================================================================================
// Textures and Samplers
//===================================================================================================
sampler ScreenS = sampler_state
{
    Texture = <ScreenTexture>;    
};

//- modelTexture1 --
texture modelTexture1; 
sampler modelTextureSampler1 = sampler_state 
{
	texture		= <modelTexture1>; 
	AddressU	= MIRROR; 
	AddressV	= MIRROR; 
	AddressW	= MIRROR; 
	MIPFILTER	= ANISOTROPIC;	
	MINFILTER	= ANISOTROPIC;	
	MAGFILTER	= ANISOTROPIC;
};

//- modelTexture2 --
texture modelTexture2; 
sampler modelTextureSampler2 = sampler_state 
{
	texture		= <modelTexture2>; 
	AddressU	= MIRROR;	
	AddressV	= MIRROR;	
	AddressW	= MIRROR; 
	MIPFILTER	= ANISOTROPIC;	
	MINFILTER	= ANISOTROPIC;	
	MAGFILTER	= ANISOTROPIC;
};

//- modelTexture3 --
texture modelTexture3; 
sampler modelTextureSampler3 = sampler_state 
{
	texture		= <modelTexture3>; 
	AddressU	= MIRROR;	
	AddressV	= MIRROR;	
	AddressW	= MIRROR; 
	MIPFILTER	= ANISOTROPIC;	
	MINFILTER	= ANISOTROPIC;	
	MAGFILTER	= ANISOTROPIC;
};

//- modelTexture4 --
texture modelTexture4; 
sampler modelTextureSampler4 = sampler_state 
{
	texture		= <modelTexture4>;
	AddressU	= MIRROR;	
	AddressV	= MIRROR;	
	AddressW	= MIRROR; 
	MIPFILTER	= ANISOTROPIC;	
	MINFILTER	= ANISOTROPIC;	
	MAGFILTER	= ANISOTROPIC;
};

//- modelTexture5 --
texture modelTexture5; 
sampler modelTextureSampler5 = sampler_state 
{
	texture		= <modelTexture5>; 
	AddressU	= MIRROR;	
	AddressV	= MIRROR;	
	AddressW	= MIRROR; 
	MIPFILTER	= ANISOTROPIC;	
	MINFILTER	= ANISOTROPIC;	
	MAGFILTER	= ANISOTROPIC;
};

//- modelTexture6 --
texture modelTexture6; 
sampler modelTextureSampler6 = sampler_state 
{
	texture		= <modelTexture6>;
	AddressU	= MIRROR;	
	AddressV	= MIRROR;	
	AddressW	= MIRROR; 
	MIPFILTER	= ANISOTROPIC;	
	MINFILTER	= ANISOTROPIC;	
	MAGFILTER	= ANISOTROPIC;
};

//- bumpTexture1 --
texture bumpTexture1; 
sampler bumpTextureSampler1 = sampler_state 
{
	texture		= <bumpTexture1>; 
	AddressU	= MIRROR;	
	AddressV	= MIRROR;	
	AddressW	= MIRROR; 
	MIPFILTER	= ANISOTROPIC;	
	MINFILTER	= ANISOTROPIC;	
	MAGFILTER	= ANISOTROPIC;
};

//- bumpTexture2 --
texture bumpTexture2; 
sampler bumpTextureSampler2 = sampler_state 
{
	texture		= <bumpTexture2>; 
	AddressU	= MIRROR;	
	AddressV	= MIRROR;	
	AddressW	= MIRROR; 
	MIPFILTER	= ANISOTROPIC;	
	MINFILTER	= ANISOTROPIC;	
	MAGFILTER	= ANISOTROPIC;
};

//- bumpTexture3 --
texture bumpTexture3; 
sampler bumpTextureSampler3 = sampler_state 
{
	texture		= <bumpTexture3>; 
	AddressU	= MIRROR;	
	AddressV	= MIRROR;	
	AddressW	= MIRROR; 
	MIPFILTER	= ANISOTROPIC;	
	MINFILTER	= ANISOTROPIC;	
	MAGFILTER	= ANISOTROPIC;
};

//- bumpTexture4 --
texture bumpTexture4; 
sampler bumpTextureSampler4 = sampler_state 
{
	texture		= <bumpTexture4>; 
	AddressU	= MIRROR;	
	AddressV	= MIRROR;	
	AddressW	= MIRROR; 
	MIPFILTER	= ANISOTROPIC;	
	MINFILTER	= ANISOTROPIC;	
	MAGFILTER	= ANISOTROPIC;
};

//- bumpTexture5 --
texture bumpTexture5; 
sampler bumpTextureSampler5 = sampler_state 
{
	texture		= <bumpTexture5>; 
	AddressU	= MIRROR;	
	AddressV	= MIRROR;	
	AddressW	= MIRROR; 
	MIPFILTER	= ANISOTROPIC;	
	MINFILTER	= ANISOTROPIC;	
	MAGFILTER	= ANISOTROPIC;
};

//- bumpTexture6 --
texture bumpTexture6; 
sampler bumpTextureSampler6 = sampler_state 
{
	texture		= <bumpTexture6>; 
	AddressU	= MIRROR;	
	AddressV	= MIRROR;	
	AddressW	= MIRROR; 
	MIPFILTER	= ANISOTROPIC;	
	MINFILTER	= ANISOTROPIC;	
	MAGFILTER	= ANISOTROPIC;
};

//- shadowMapTexture1 --
texture shadowTexture1; 
sampler shadowMapSampler1 = sampler_state 
{
	texture		= <shadowTexture1>; 
	AddressU	= MIRROR;	
	AddressV	= MIRROR;	
	AddressW	= MIRROR; 
	MIPFILTER	= ANISOTROPIC;	
	MINFILTER	= ANISOTROPIC;	
	MAGFILTER	= ANISOTROPIC;
};

//- shadowMapTexture2 --
texture shadowTexture2; 
sampler shadowMapSampler2 = sampler_state 
{
	texture		= <shadowTexture2>; 
	AddressU	= MIRROR;	
	AddressV	= MIRROR;	
	AddressW	= MIRROR; 
	MIPFILTER	= ANISOTROPIC;	
	MINFILTER	= ANISOTROPIC;	
	MAGFILTER	= ANISOTROPIC;
};


//- terrainModTexture --
texture terrainModTexture; 
sampler terrainModTextureSampler = sampler_state 
{
	texture		= <terrainModTexture>; 
	AddressU	= MIRROR;	
	AddressV	= MIRROR;	
	AddressW	= MIRROR; 
	MIPFILTER	= ANISOTROPIC;	
	MINFILTER	= ANISOTROPIC;	
	MAGFILTER	= ANISOTROPIC;
};

//- heightMapTexture --
texture heightMapTexture;
sampler heightMapTextureSampler = sampler_state 
{
	texture		= <heightMapTexture>; 
	AddressU	= CLAMP;	
	AddressV	= CLAMP;	
	AddressW	= CLAMP; 
	MIPFILTER	= ANISOTROPIC;	
	MINFILTER	= ANISOTROPIC;	
	MAGFILTER	= ANISOTROPIC;
};

//- terrainNormalMapTexture --
texture terrainNormalMapTexture;
sampler terrainNormalMapTextureSampler = sampler_state 
{
	texture		= <terrainNormalMapTexture>; 
	AddressU	= CLAMP;	
	AddressV	= CLAMP;	
	AddressW	= CLAMP; 
	MIPFILTER	= ANISOTROPIC;	
	MINFILTER	= ANISOTROPIC;	
	MAGFILTER	= ANISOTROPIC;
};

//===================================================================================================
// Uniform, Varying, and FrameBuffer "Stream" Structures - 
// Used to Communicate between CPU, VertexProcessor, FragmentProcessor, and FrameBuffer
//===================================================================================================
struct VertexInput 
{
    float4	position				: POSITION0;		// Position
	half4	indices					: BLENDINDICES0;
	float4	weights					: BLENDWEIGHT0;
	float4  fog						: FOG;
    float3	normal					: NORMAL0;			// Normal vector
	float	pointSize				: PSIZE0;			// Point size
    float4	color					: COLOR0;			// Color
    float4	texCoord				: TEXCOORD0;		// Texture coordinates
    float4	tangent					: TANGENT0;			// Tangent
    float4	binormal				: BINORMAL0;		// Binormal
	float	tessFactor				: TESSFACTOR0; 		// Tessellation factor	
};

struct VertexInternal
{
    // Location
    float3 lastPosition;
    float3 currentPosition;
    float3 referencePosition;

    // Orientation
    half normalVectorZenith;		    // Half types are 16-bit floating point
    half normalVectorAzimuth;
    half upVectorZenith;
    half upVectorAzimuth;
    half perpVectorZenith;
    half perpVectorAzimuth;

    // Physical motion 
    float3 velocity;
    float3 totalForce;
    half scale;
    half mass;
    half adhesion;
    half cohesion;
    half energy;
    half stateChangeThreshold;
};

struct VertexOutput
{
	// These values are used directly by the rasterizer
	float4	position				: POSITION; 		// Position
	float2	fog						: FOG; 			// Point size

	// These values are interpolated and sent to FragIn
	float4	color					: COLOR0; 			// Color (example: COLOR0)
	float4	texCoord				: TEXCOORD0; 		// Texture coordinates (example: TEXCOORD0)
    float3	normal 					: TEXCOORD1;		// Texture coordinates 
    float3	worldPos  				: TEXCOORD2;		// Texture coordinates 
    float4	shadowMapSamplingPos1	: TEXCOORD3;		// Texture coordinates 	
	float4	shadowMapSamplingPos2	: TEXCOORD4;		// Texture coordinates 	
	float2	realDepth				: TEXCOORD5;
	float3	tangent					: TEXCOORD6;
	float3	binormal				: TEXCOORD7;
};

struct FragmentInput
{
	float4	color					: COLOR0; 			// Color (example: COLOR0)
	float2	fog						: FOG;
	
    float4	texCoord				: TEXCOORD0;		// Texture coordinates 
    float3	normal					: TEXCOORD1;		// Texture coordinates 
    float3	worldPos				: TEXCOORD2;		// Texture coordinates 
	float4	shadowMapSamplingPos1	: TEXCOORD3;
	float4	shadowMapSamplingPos2	: TEXCOORD4;		// Texture coordinates 	
	float2	realDepth				: TEXCOORD5;
	float3	tangent					: TEXCOORD6;
	float3	binormal				: TEXCOORD7;
};

struct FragmentInternal{};

struct FragmentOutput
{
	float4	color				: COLOR0; 			// Color for render target n
};
 

//===================================================================================================
// Vertex and Fragment Shaders
//===================================================================================================

// Terrain LOD Shader
//---------------------------------------------------------------------------------------------------
VertexInput VS_TerrainLOD(VertexInput IN)
{
	float3 vertexWorldPosition = mul(IN.position, World).xyz;
	if(vertexWorldPosition.x >= 0.0f && 
	   vertexWorldPosition.z >= 0.0f && 
	   vertexWorldPosition.x <= terrainMapSize * terrainScaleFactor &&
	   vertexWorldPosition.z <= terrainMapSize * terrainScaleFactor)
	{
		IN.texCoord.x = (vertexWorldPosition.z / (terrainMapSize * terrainScaleFactor));
		IN.texCoord.y = (vertexWorldPosition.x / (terrainMapSize * terrainScaleFactor));
		
		//int lodLevel = length(vertexWorldPosition.xz - playerPosition) / 1024.0f;

		IN.position.y = tex2Dlod(heightMapTextureSampler, float4(IN.texCoord.x, IN.texCoord.y, 0, 0)).x * 255.0f;
		IN.normal = tex2Dlod(terrainNormalMapTextureSampler, float4(IN.texCoord.x, IN.texCoord.y, 0, 0)).rgb;
		
		//HACK  - Non-MODABLE TERRAIN
		if(IN.position.y == 255.0f){IN.position.y += 100.0f;}
		
		
	}
	else
	{
		IN.texCoord.x = -1.0f;
		IN.texCoord.y = -1.0f;
	}
	
	return IN;
}

FragmentOutput FS_TerrainLOD(FragmentInput IN, FragmentOutput OUT)
{
	clip(IN.texCoord.xy);
	return OUT;
}

// Terrain Bump Map Shader
//---------------------------------------------------------------------------------------------------
FragmentOutput FS_TerrainBumpMapping(FragmentInput IN, FragmentOutput OUT)
{
	//Lookup from the normal map
	float3 normalLow = tex2D(bumpTextureSampler1, IN.texCoord * 40);
	float3 normalMid = tex2D(bumpTextureSampler2, IN.texCoord * 40);
	float3 normalHigh = tex2D(bumpTextureSampler3, IN.texCoord * 40);
	float3 normalSlope = tex2D(bumpTextureSampler4, IN.texCoord * 60);
	float3 normalNew;
	
	// Shift Y Position between 0 - 1
	float maxY = worldMaxY - worldMinY;
	float YPosition = IN.worldPos.y / maxY ;

	if (YPosition < .5)
	{
		normalNew = lerp(normalLow, normalMid, YPosition * 2);
	}
	else
	{
		normalNew = lerp(normalMid, normalHigh, (YPosition - .5)  * 2);
	}
	
	// Apply lighting to the color
	float angle = degrees(acos(dot(IN.normal, float3(0, 1, 0))));
	angle = abs(angle);
	if (angle > 90)
	{
		angle = abs(360 - angle);
	}
	angle = angle / 90;
	if (angle > .80)
	{
		normalNew = lerp(normalNew,  normalSlope, angle * .2);
	}
	else if (angle > .60)
	{
		normalNew = lerp(normalNew,  normalHigh, angle * .15);
	}
	else if (angle > .40)
	{
		normalNew = lerp(normalNew,  normalMid, angle * .10);
	}
	else 
	{
		normalNew = lerp(normalNew,  normalLow, angle * .05);
	}

	//unpack the normal map
	normalNew.xyz -= 0.5;
	//normalNew.xyz = normalize(normalNew.x * IN.tangent + normalNew.y * IN.binormal + normalNew.z * IN.normal);
	normal = normalize(normalNew);
	
	return OUT;
}

// Lerp Bump Map Shader
//---------------------------------------------------------------------------------------------------
FragmentOutput FS_LerpBumpMapping(FragmentInput IN, FragmentOutput OUT)
{
	//Lookup from the normal map
	float3 normalNew1 = tex2D(bumpTextureSampler1, IN.texCoord);
	float3 normalNew2 = tex2D(bumpTextureSampler2, IN.texCoord);
	float3 normalNew = lerp(normalNew1, normalNew2, particleEnergyValue);
	
	//unpack the normal map
	normalNew.xyz -= 0.5;
	//normalNew.xyz = normalize(IN.normal.xyz + normalNew.xyz);
	normal = normalize(normalNew);
	
	return OUT;
}

// Single Bump Map Shader
//---------------------------------------------------------------------------------------------------
FragmentOutput FS_BumpMapping(FragmentInput IN, FragmentOutput OUT)
{
	//Lookup from the normal map
	float3 normalNew = tex2D(bumpTextureSampler1, IN.texCoord);
	
	//unpack the normal map
	normalNew.xyz -= 0.5; 
	//normalNew.xyz = normalize(IN.normal.xyz + normalNew.xyz);
	normal = normalize(normalNew);
	
	return OUT;
}

// No Bump Mapping Shader
//---------------------------------------------------------------------------------------------------
FragmentOutput FS_NoBumpMapping(FragmentInput IN, FragmentOutput OUT)
{
	normal = IN.normal;	
	return OUT;
}

// Basic Lighting Shader
//---------------------------------------------------------------------------------------------------
VertexOutput VS_BasicLighting(VertexInput IN, VertexOutput OUT)
{	
	// Texturing
    OUT.texCoord			= IN.texCoord;

	// Positional Calculations
	OUT.worldPos			= mul(IN.position, World).xyz;					// World Space Position
	OUT.position			= mul(IN.position, mul(World, ViewProj));		// Raster Position
	OUT.normal				= mul(IN.normal, World).xyz;					// Normal vector   
	OUT.binormal 			= mul(IN.binormal, World).xyz;
	OUT.tangent				= mul(IN.tangent, World).xyz;

	// Shadow Stuff
	OUT.shadowMapSamplingPos1 = mul(IN.position, mul(World, LightViewProj1));
	OUT.shadowMapSamplingPos2 = mul(IN.position, mul(World, LightViewProj2));
	OUT.realDepth.x = OUT.shadowMapSamplingPos1.z / zMaxDepth;
	OUT.realDepth.y = OUT.shadowMapSamplingPos2.z / zMaxDepth;

    return OUT;    
}

void FS_AlphaClip(FragmentInput IN)
{
	// Get texture value
 	textureValue = tex2D(modelTextureSampler1, IN.texCoord);

	clip(textureValue.a - 0.2f);
}

FragmentOutput FS_BasicLighting(FragmentInput IN, FragmentOutput OUT)
{
	//Per Vertex Light Calculations
	float3 lightVector1			= float3(light0[0][0], light0[0][1], light0[0][2]);
	float3 lightVector2			= float3(light1[0][0], light1[0][1], light1[0][2]);

	// Calculate the pixel to light source vectors
	lightVector1				-= IN.worldPos;																// Vertex to Light source 1 vector 
	lightVector2				-= IN.worldPos;																// Vertex to Light source 2 vector 
	
	lightVector1 = normalize(lightVector1);
	lightVector2 = normalize(lightVector2);

	// Per Player Per Vertex Calculations
	float3 vertexToEyeVector	= normalize(EyePostion[3].xyz - IN.worldPos);	// eye vector

    diffuse0					= 0.0f;
	diffuse1					= 0.0f;
	specular0					= 0.0f;
	specular1					= 0.0f;

	float2 ProjectedTexCoords1;
    ProjectedTexCoords1[0]		= IN.shadowMapSamplingPos1.x / IN.shadowMapSamplingPos1.w / 2.0f + 0.5f;
    ProjectedTexCoords1[1]		= -IN.shadowMapSamplingPos1.y / IN.shadowMapSamplingPos1.w / 2.0f + 0.5f;
    
	// Calculate the diffuse and specular contributions of Light 0
	if ((clamp(ProjectedTexCoords1.x, 0.0f, 1.0f) == ProjectedTexCoords1.x) && (clamp(ProjectedTexCoords1.y, 0.0f, 1.0f) == ProjectedTexCoords1.y))
    {
		float storedDepthInShadowMap = tex2D(shadowMapSampler1, ProjectedTexCoords1).x;
		if ((IN.realDepth.x - 1.0f/100.0f) <= storedDepthInShadowMap)
		{
			diffuse0		= max(0, dot(normal, lightVector1));				// Diffuse component
			if(diffuse0 > 0.0f)
			{
				// Calculate light source's halfway vector
				float3 halfwayVector1 = normalize(vertexToEyeVector + lightVector1);	// Halfway vector
				specular0	= pow(dot(normal, halfwayVector1), coreShininess);			// Specular component
			}
		}
	}
	
	if(length(lightVector1 - lightVector2) != 0.0)
	{
		float2 ProjectedTexCoords2;
		ProjectedTexCoords2[0]		= IN.shadowMapSamplingPos2.x / IN.shadowMapSamplingPos2.w / 2.0f + 0.5f;
		ProjectedTexCoords2[1]		= -IN.shadowMapSamplingPos2.y / IN.shadowMapSamplingPos2.w / 2.0f + 0.5f;

		// Calculate the diffuse and specular contributions of Light 1
		if ((clamp(ProjectedTexCoords2.x, 0.0f, 1.0f) == ProjectedTexCoords2.x) && (clamp(ProjectedTexCoords2.y, 0.0f, 1.0f) == ProjectedTexCoords2.y))
		{
			float storedDepthInShadowMap = tex2D(shadowMapSampler2, ProjectedTexCoords2).x;
			if ((IN.realDepth.y - 1.0f/100.0f) <= storedDepthInShadowMap)
			{
				diffuse1			= max(0, dot(normal, lightVector2));					// Diffuse component
				if(diffuse1 > 0.0f)
				{
				  	float3 halfwayVector2 = normalize(vertexToEyeVector + lightVector2);	// Halfway vector
					specular1		= pow(dot(normal, halfwayVector2), coreShininess);		// Specular component
				}
			}
		}
	}
	
	ambientColor	= coreMaterialDiffuse	* (				float4(light0[1][0], light0[1][1], light0[1][2], light0[1][3]) +
															float4(light1[1][0], light1[1][1], light1[1][2], light1[1][3]));
															
	diffuseColor	= coreMaterialDiffuse	* (diffuse0  *	float4(light0[2][0], light0[2][1], light0[2][2], light0[2][3]) + 
											   diffuse1  *	float4(light1[2][0], light1[2][1], light1[2][2], light1[2][3]));
											   
	specularColor	= coreMaterialSpecular  * (specular0 *	float4(light0[3][0], light0[3][1], light0[3][2], light0[3][3]) + 
											   specular1 *	float4(light1[3][0], light1[3][1], light1[3][2], light1[3][3]));
	
	// Apply lighting to the color
 	OUT.color += (diffuseColor * textureValue) + (ambientColor * textureValue) + specularColor;
 	 	
 	// To frambuffer
 	return OUT;
}

// Effect to apply energy based coloring
FragmentOutput FS_PlayerEnergyShader(FragmentInput IN, FragmentOutput OUT)
{
	if (particleEnergyValue > 0.6f)
	{
		//apply red coloring
		OUT.color.r = OUT.color.r + particleEnergyValue;
	}
	else if (particleEnergyValue < 0.4f)
	{
		//apply blue coloring
		OUT.color.rgb = OUT.color.b + particleEnergyValue;
	}
 	return OUT;
}

// Effect to apply when player is dead
//---------------------------------------------------------------------------------------------------
FragmentOutput FS_PlayerDeadShader(FragmentInput IN, FragmentOutput OUT)
{
	if (playerIsDead)
 	{
 		//take the inverse of the average of all colors
 		float invAvg = 1.2f - (OUT.color.r + OUT.color.g + OUT.color.b)/3.0f;
 		if (invAvg < 0)
 		{
 			invAvg = 0;
 		}
 		//make it a grayscale image
 		OUT.color.r = invAvg;
 		OUT.color.g = invAvg;
 		OUT.color.b = invAvg;
 		OUT.color.a = 1.0f;
 	}
 	return OUT;
}


// Energy Beam Shader
//---------------------------------------------------------------------------------------------------
VertexOutput VS_EnergyBeam(VertexInput IN, VertexOutput OUT)
{	
	// Texturing
    OUT.texCoord			= IN.texCoord;

	// Positional Calculations
	OUT.position			= mul(IN.position, ViewProj);		// Raster Position

    return OUT;    
}

// Advanced Player Shader
//---------------------------------------------------------------------------------------------------
FragmentOutput FS_PlayerHole(FragmentInput IN, FragmentOutput OUT)
{	
	if(any(hitTime))
	{
		if(hitTime.x > 0)
		{
			float dist = sqrt(pow(IN.worldPos.x - hits[0][0], 2) + pow(IN.worldPos.y - hits[0][1], 2) + pow(IN.worldPos.z - hits[0][2], 2));
			if(hitTime.x < .5)		
			{
				if( dist < (3.75 * hitTime.x * 4))
    			{
    				if(dist < (2.55 * hitTime.x * 4))
    				{
    					clip(-1.0);
    				}
    				else
    				{
    					if(hits[0][3] == 0)
    					{
    						OUT.color = float4(0,.5,0,1);
    					}
    					else if(hits[0][3] == 1)
    					{
    						OUT.color = float4(0,0,.5,1);
    					}
    					else if(hits[0][3] == 2)
    					{
    						OUT.color = float4(.5,.5,.5,1);
    					}
    					else if (hits[0][3] == 3)
    					{
    						OUT.color = float4(.5,0,0,1);
    					}
    					else if (hits[0][3] == 4)
    					{
    						OUT.color = float4(.5,.5,.5,1);
    					}
    				}  		
    			}
			}
			else
			{
				if( dist < (3.75 * .5 * 4) - (3.75 * (hitTime.x-.5) * 4))
    			{	
    				if(dist < (2.55 * .5 * 4) - (2.55 * (hitTime.x-.5) * 4))
    				{
    					clip(-1.0);
    				}
    				else
    				{
    					if(hits[0][3] == 0)
    					{
    						OUT.color = float4(0,.5,0,1);
    					}
    					else if(hits[0][3] == 1)
    					{
    						OUT.color = float4(0,0,.5,1);
    					}
    					else if(hits[0][3] == 2)
    					{
    						OUT.color = float4(.5,.5,0,1);
    					}
    					else if (hits[0][3] == 3)
    					{
    						OUT.color = float4(.5,0,0,1);
    					}
    					else if (hits[0][3] == 4)
    					{
    						OUT.color = float4(.5,.5,.5,1);
    					}
    				}  
    			}
			}
		}
	}
	return OUT;
}

// Basic Lighting Without Shadows
//----------------------------------------------------------------------------------------------------------------
FragmentOutput FS_BasicLightingNoShadows(FragmentInput IN, FragmentOutput OUT)
{
	//Per Vertex Light Calculations
	float3 lightVector1			= float3(light0[0][0], light0[0][1], light0[0][2]);
	float3 lightVector2			= float3(light1[0][0], light1[0][1], light1[0][2]);

	// Calculate the pixel to light source vectors
	lightVector1				-= IN.worldPos;																// Vertex to Light source 1 vector 
	lightVector2				-= IN.worldPos;																// Vertex to Light source 2 vector 

	lightVector1 = normalize(lightVector1);
	lightVector2 = normalize(lightVector2);

	// Per Player Per Vertex Calculations
	float3 vertexToEyeVector	= normalize(EyePostion[3].xyz - IN.worldPos);	// eye vector

    diffuse0					= 0.0f;
	diffuse1					= 0.0f;
	specular0					= 0.0f;
	specular1					= 0.0f;

	diffuse0		= max(0, dot(normal, lightVector1));			// Diffuse component
	if(diffuse0 > 0.0f)
	{
		float3 halfwayVector1		= normalize(vertexToEyeVector + lightVector1);						// Halfway vector
		specular0	= pow(dot(normal, halfwayVector1), coreShininess);	// Specular component
	}

	// Calculate Ambient, Diffuse, and Specular color components
    diffuse1		= max(0, dot(normal, lightVector2));			// Diffuse component
	if(diffuse1 > 0.0f)
	{
	  	float3 halfwayVector2 = normalize(vertexToEyeVector + lightVector2);						// Halfway vector
		specular1	= pow(dot(normal, halfwayVector2), coreShininess);	// Specular component
	}
	
	ambientColor	= coreMaterialDiffuse	* (				float4(light0[1][0], light0[1][1], light0[1][2], light0[1][3]) +
															float4(light1[1][0], light1[1][1], light1[1][2], light1[1][3]));
															
	diffuseColor	= coreMaterialDiffuse	* (diffuse0  *	float4(light0[2][0], light0[2][1], light0[2][2], light0[2][3]) + 
											   diffuse1  *	float4(light1[2][0], light1[2][1], light1[2][2], light1[2][3]));
											   
	specularColor	= coreMaterialSpecular  * (specular0 *	float4(light0[3][0], light0[3][1], light0[3][2], light0[3][3]) + 
											   specular1 *	float4(light1[3][0], light1[3][1], light1[3][2], light1[3][3]));
											  
	// Apply lighting to the color
 	OUT.color += (diffuseColor * textureValue) + (ambientColor * textureValue) + specularColor;
 	
 	// To framebuffer
 	return OUT;
}

// Particle Shader
//----------------------------------------------------------------------------------------------------------------
FragmentOutput FS_Particle(FragmentInput IN, FragmentOutput OUT)
{
	float4 col1, col2, colFinal;

	col1 = tex2D(modelTextureSampler1, IN.texCoord);
	col2 = tex2D(modelTextureSampler2, IN.texCoord);
	colFinal = lerp(col1, col2, particleEnergyValue);

	textureValue = colFinal;
	clip(textureValue.a - 0.2f);

	OUT.color = colFinal;
    return OUT;
}

VertexOutput VS_Particle(inout VertexInput IN, VertexOutput OUT)
{	 
	/*
	// WaveForm Calculations (returns values 1-2)
	float waveForm = 1.0f + abs( cos(WaveRadius * WaveRadius * length(IN.position)));

	// Stop NaN errors and extreme values here
	if( waveForm < 0.001f) { waveForm = 0.001f; }			
	
	modPosition.y = IN.position.y + 10.0f/ sqrt(0.5f + (abs(IN.position.x) + abs(IN.position.z)) * waveForm);
	*/

	// Squash the sphere on the y-axis
	float4 modPosition = IN.position;
	modPosition.y = 0.3f * modPosition.y; 
	float waveForm;
	
	// Earth
	if(particleType.y == 0.0f)
	{
		if( IN.position.y > 0.0f ) 
		{
			/*
			// Distance between vertex and wave crest
			float waveDistance = abs( length(IN.position) - WaveRadius );
			
			// See Fire Shader Notes for explanation
			waveForm =
						//sqrt(					// Create sharp wave...  log() for rounded??
						abs(cos( 				// Ensure that wave burns upward
						waveDistance			// Cos creates a circular algorithm from linear distance
						) );  //);

			// New vertex height
			modPosition *=  waveForm; // * particleLookVector;
			*/
			
			// WaveForm Calculations (returns values 1-2)
			waveForm = 1.0f + abs( cos(WaveRadius * WaveRadius * length(IN.position)) ) ;

			// Stop NaN errors and extreme values here
			if( waveForm < 0.001f) { waveForm = 0.001f; }			

			// waveForm = abs( cos( distance( IN.position, 0.0f) + WaveRadius )); 
			// IN.position.y = distance( IN.position , 0.0f) /4.0f  * waveForm;
			
			modPosition.y = IN.position.y * waveForm;
		}

		if(particleEnergyValue >= 0.4f)
		{	
			IN.position = (IN.position * (1.0f - particleEnergyValue)) + (modPosition * particleEnergyValue );
			IN.position.y *= 0.6f * (1.0f - particleEnergyValue) + 0.3f;
		}
	}

	// Water
	if(particleType.y == 1.0f)
	{
		coreShininess = 1.0f;
		// Don't modify vertices below a specific latitude
		if(	IN.position.y > 0.0f )
		{
			// WaveForm Calculations (returns values 1-2)
			waveForm = 1.0f + abs( cos(WaveRadius * WaveRadius * length(IN.position)) ) ;

			// Stop NaN errors and extreme values here
			if( waveForm < 0.001f) { waveForm = 0.001f; }			

			// waveForm = abs( cos( distance( IN.position, 0.0f) + WaveRadius )); 
			// IN.position.y = distance( IN.position , 0.0f) /4.0f  * waveForm;
			
			modPosition.y = IN.position.y * waveForm;
		}
		
		if(particleEnergyValue >= 0.4f)
		{	
			IN.position = (IN.position * (1.0f - particleEnergyValue)) + (modPosition * particleEnergyValue );
			IN.position.y *= 0.5f;
		}
	}

	// Air
	if(particleType.y == 2.0f)
	{
		// WaveForm Calculations (returns values 1-2)
		waveForm = 1.0f + abs( cos(WaveRadius * WaveRadius * length(IN.position)) ) ;

		// Stop NaN errors and extreme values here
		if( waveForm < 0.001f) { waveForm = 0.001f; }			

		if(	IN.position.y < 0.0f )
		{
			// WaveForm Calculations (0-1)
			//waveForm =		abs( cos(abs(IN.position.x) + abs(IN.position.z) + WaveRadius) );
			
			IN.position.y = (abs(IN.position.x) + abs(IN.position.z)) * waveForm;
			IN.position.y -= 0.5f;
		}
		else
		{
			IN.position.y = (abs(IN.position.x) + abs(IN.position.z)) * waveForm;
		}
	}
		
    return OUT;    
}

// Terrain Mod Shader
//--------------------------------------------------------------------------------------------------
FragmentOutput FS_TerrainModTexture(FragmentInput IN, FragmentOutput OUT) 
{
	if(LightUpTerrainMod == true)
	{
		// Project 
		PlaneRayIntersectionPoint.xz = PlaneRayIntersectionPoint.zx;
		PlaneRayIntersectionPoint.z = - PlaneRayIntersectionPoint.z;
		PlaneRayIntersectionPoint = mul(PlaneRayIntersectionPoint, World);

		// Find the range  to be shaded		
		float3 highCorner = PlaneRayIntersectionPoint + (float3) TerrainModRange;
		float3 lowCorner =  PlaneRayIntersectionPoint - (float3) TerrainModRange;

		// See if this fragement falls within the range to be shaded
		if(lowCorner.x < IN.worldPos.x && IN.worldPos.x < highCorner.x )
		{ 
			if(lowCorner.z < IN.worldPos.z && IN.worldPos.z < highCorner.z )
			{
				OUT.color.r += tex2D(terrainModTextureSampler, (IN.worldPos.xz - lowCorner.xz) / TerrainModRange).a;
				//OUT.color.a += 1.0f;
			}
		}	
	}
	return OUT;
}

// Render Terrain Shader
//--------------------------------------------------------------------------------------------------
FragmentOutput FS_RenderTerrain(FragmentInput IN, FragmentOutput OUT) 
{
	// Get texture value
 	float4 lowTex =	tex2D(modelTextureSampler1, IN.texCoord * 40); 	
	float4 middleTex = tex2D(modelTextureSampler2, IN.texCoord * 40);
	float4 highTex = tex2D(modelTextureSampler3, IN.texCoord * 40);
	float4 modTex = tex2D(modelTextureSampler4, IN.texCoord * 40);
	float4 texFinal;

	// Shift Y Position between 0 - 1
	float maxY = worldMaxY - worldMinY;
	float YPosition = IN.worldPos.y / maxY ;
	
	if(YPosition < .5)
	{
		texFinal = lerp(lowTex, middleTex, YPosition * 2);
	}
	else
	{
		texFinal = lerp(middleTex, highTex, (YPosition - .5) * 2);
	}	
	
	// Apply lighting to the color
	float angle = degrees(acos(dot(IN.normal, float3(0, 1, 0))));
	angle = abs(angle);
	if(angle > 90)
	{
		angle = abs(360 - angle);
	}
	angle = angle / 90;
	if (angle > .80)
	{
		texFinal = lerp(texFinal, modTex, angle * .2);
	}
	else if (angle > .60)
	{
		texFinal = lerp(texFinal, highTex, angle * .15);
	}
	else if (angle > .40)
	{
		texFinal = lerp(texFinal, middleTex, angle * .10);
	}
	else 
	{
		texFinal = lerp(texFinal, lowTex, angle * .05);
	}
	
 	OUT.color = (diffuseColor * texFinal) + (ambientColor * texFinal) + specularColor;

	return OUT;
}

// RenderToTexture Shader
//--------------------------------------------------------------------------------------------------
VertexOutput VS_RenderToTexture(VertexInput IN, VertexOutput OUT)
{
	OUT.position = mul(IN.position, mul(World, ViewProj));
    OUT.texCoord = IN.texCoord;

    return OUT;
}
FragmentOutput FS_RenderToTexture(FragmentInput IN, FragmentOutput OUT)
{
    OUT.color = tex2D(modelTextureSampler1, IN.texCoord);

    return OUT;
}

// Anti Aliasing Shader
//---------------------------------------------------------------------------------------------------
VertexOutput VS_AntiAliasing(VertexInput IN, VertexOutput OUT)
{
	OUT.position = mul(IN.position, mul(World, ViewProj));
    OUT.texCoord = IN.texCoord;

    return OUT;    
}

FragmentOutput FS_AntiAliasing(FragmentInput IN, FragmentOutput OUT)
{
	float2 duvdx = ddx(IN.texCoord);
	float2 duvdy = ddy(IN.texCoord);
	OUT.color = tex2D(modelTextureSampler1, IN.texCoord, duvdx, duvdy);
	
	return OUT;
}

// Fog Shader
//--------------------------------------------------------------------------------------------------
FragmentOutput FS_Fog(FragmentInput IN, FragmentOutput OUT)
{
	float fog = length(EyePostion[3].xyz - IN.worldPos);
	fogDropOff = 1.0f / exp(fog * fogDensity * fog * fogDensity * fog * fogDensity * fog * fogDensity);
	fogDropOff = saturate(fogDropOff);
	//if(fogDropOff < 0.0f){ fogDropOff = 0.0f; } // Substitute for broken clamp op
	
	OUT.color.rgb = ((1.0f - fogDropOff) * fogColor) + (fogDropOff * OUT.color.rgb);
	
	return OUT;
}

// Shield Shader
//--------------------------------------------------------------------------------------------------
VertexOutput VS_Shield(VertexInput IN, VertexOutput OUT)
{
	OUT.position = mul(IN.position, mul(World, ViewProj));
    OUT.texCoord = IN.texCoord;

    return OUT;
}

FragmentOutput FS_Shield(FragmentInput IN, FragmentOutput OUT)
{
	OUT.color.rgb = tex2D(modelTextureSampler1, IN.texCoord).rgb;
	OUT.color.a = 0.1f;
	
	return OUT;
}

// Shadow Map Shader
//--------------------------------------------------------------------------------------------------
VertexOutput VS_ShadowMap(VertexInput IN, VertexOutput OUT)
{
	OUT.position = mul(IN.position, mul(World, LightViewProj1));
	OUT.worldPos = OUT.position;
	
	return OUT;
}

FragmentOutput FS_ShadowMap(FragmentInput IN, FragmentOutput OUT)
{
	OUT.color = IN.worldPos.z / zMaxDepth;
	OUT.color.a = 1.0f;
	
	return OUT;
}

// Full Screen Anti-Burn
//--------------------------------------------------------------------------------------------------
float4 AntiBurnFSMain(float2 texCoord: TEXCOORD0) : Color
{
	float time =  (btime % 10)/10 + .1; 
	float4 color;
	if (time > .5)
	{
		color = tex2D(ScreenS, texCoord) * time;
	}
	else
	{
		color = tex2D(ScreenS, texCoord)* 1 - time; 
	}
	return color;
}

// Skin Alteration for Animation
//--------------------------------------------------------------------------------------------------
VertexInput VS_Skin(VertexInput IN)
{
	VertexInput output = IN;
	output.position = 0.0f;
	output.normal	= 0.0f;

    float lastWeight = 1.0;
    float weight = 0;
    for (int i = 0; i < 3; ++i)
    {
        weight = IN.weights[i];
        lastWeight -= weight;
        output.position     += mul(IN.position, MatrixPalette[IN.indices[i]]) * weight;
        output.normal       += mul(IN.normal  , MatrixPalette[IN.indices[i]]) * weight;
    }
    output.position     += mul(IN.position, MatrixPalette[IN.indices[3]]) * lastWeight;
    output.normal       += mul(IN.normal  , MatrixPalette[IN.indices[3]]) * lastWeight;

    return output;
}

// Vertex Instancing
//--------------------------------------------------------------------------------------------------
void VS_GenerateWorldMatrix(VertexInput IN)
{
	World._m00 = IN.fog.x;
	World._m01 = IN.fog.y;
	World._m02 = IN.fog.z;
	World._m03 = IN.fog.w;
	
	World._m10 = IN.binormal.x;
	World._m11 = IN.binormal.y;
	World._m12 = IN.binormal.z;
	World._m13 = IN.binormal.w;
	
	World._m20 = IN.tangent.x;
	World._m21 = IN.tangent.y;
	World._m22 = IN.tangent.z;
	World._m23 = IN.tangent.w;
	
	World._m30 = IN.weights.x;
	World._m31 = IN.weights.y;
	World._m32 = IN.weights.z;
	World._m33 = IN.weights.w;
}

VertexInput VS_Instancing(VertexInput IN)
{
	VertexInput output = IN;
	
	VS_GenerateWorldMatrix(IN);	
	
	return output;
}

// Particle Instancing
//--------------------------------------------------------------------------------------------------
FragmentOutput FS_InstancedParticle(FragmentInput IN, FragmentOutput OUT)
{
	float4 col1, col2, colFinal;
	col1 = 0;
	col2 = 0;
	colFinal = 0;

	// Earth
	if(IN.fog.x == 0.0f)
	{
		col1 = tex2D(modelTextureSampler3, IN.texCoord);
		col2 = tex2D(modelTextureSampler4, IN.texCoord);
	}
	// Water
	else if(IN.fog.x == 1.0f)
	{
		col1 = tex2D(modelTextureSampler5, IN.texCoord);
		col2 = tex2D(modelTextureSampler6, IN.texCoord);
	}
	// Air
	else if(IN.fog.x == 2.0f)
	{
		col1 = tex2D(modelTextureSampler1, IN.texCoord);
		col2 = tex2D(modelTextureSampler2, IN.texCoord);
	}
	
	colFinal = lerp(col1, col2, IN.fog.y);

	textureValue = colFinal;
	clip(textureValue.a - 0.1f);

	OUT.color = colFinal;
    return OUT;
}

FragmentOutput FS_ParticleBumpMapping(FragmentInput IN, FragmentOutput OUT)
{
	float4 normal1, normal2, normalNew;

	// Earth
	if(IN.fog.x == 0.0f)
	{
		normal1 = tex2D(bumpTextureSampler3, IN.texCoord);
		normal2 = tex2D(bumpTextureSampler4, IN.texCoord);
	}
	// Water
	else if(IN.fog.x == 1.0f)
	{
		normal1 = tex2D(bumpTextureSampler5, IN.texCoord);
		normal2 = tex2D(bumpTextureSampler6, IN.texCoord);
	}
	// Air
	else if(IN.fog.x == 2.0f)
	{
		normal1 = tex2D(bumpTextureSampler1, IN.texCoord);
		normal2 = tex2D(bumpTextureSampler2, IN.texCoord);
	}
	
	normalNew = lerp(normal1, normal2, IN.fog.y);

	//unpack the normal map
	normalNew.xyz -= 0.5;
	normal = normalize(normalNew);

    return OUT;
}

void VS_GenerateWorldMatrix_Particle(VertexInput IN)
{
	World._m00 = IN.color.x;
	World._m01 = IN.color.y;
	World._m02 = IN.color.z;
	World._m03 = IN.color.w;
	
	World._m10 = IN.binormal.x;
	World._m11 = IN.binormal.y;
	World._m12 = IN.binormal.z;
	World._m13 = IN.binormal.w;
	
	World._m20 = IN.tangent.x;
	World._m21 = IN.tangent.y;
	World._m22 = IN.tangent.z;
	World._m23 = IN.tangent.w;
	
	World._m30 = IN.weights.x;
	World._m31 = IN.weights.y;
	World._m32 = IN.weights.z;
	World._m33 = IN.weights.w;

/*
	float4 q = IN.binormal;
	float4x4 rotationMatrix = float4x4 (0.0f, 0.0f, 0.0f, 0.0f,
										0.0f, 0.0f, 0.0f, 0.0f,
										0.0f, 0.0f, 0.0f, 0.0f,
										0.0f, 0.0f, 0.0f, 1.0f);

	float sqw = q.z * q.z;
    float sqx = q.w * q.w;
    float sqy = q.x * q.x;
    float sqz = q.y * q.y;

    // invs (inverse square length) is only required if quaternion is not already normalised
    float invs = 1 / (sqx + sqy + sqz + sqw);
    rotationMatrix._m00 = (sqx - sqy - sqz + sqw) * invs; // since sqw + sqx + sqy + sqz =1/invs*invs
    rotationMatrix._m11 = (sqx - sqy + sqz - sqw) * invs;
    rotationMatrix._m22 = (sqx + sqy - sqz - sqw) * invs;

    float tmp1 = q.x * q.y;
    float tmp2 = q.z * q.w;
    rotationMatrix._m10 = 2.0f * (tmp1 + tmp2) * invs;
    rotationMatrix._m01 = 2.0f * (tmp1 - tmp2) * invs;
    
    tmp1 = q.x * q.z;
    tmp2 = q.y * q.w;
    rotationMatrix._m20 = 2.0f * (tmp1 + tmp2) * invs;
    rotationMatrix._m02 = 2.0f * (tmp1 - tmp2) * invs;
    tmp1 = q.y * q.z;
    tmp2 = q.x * q.w;
    rotationMatrix._m21 = 2.0f * (tmp1 + tmp2) * invs;
    rotationMatrix._m12 = 2.0f * (tmp1 - tmp2) * invs;
    
    float4x4 translationMatrix = float4x4 (1.0f, 0.0f, 0.0f, 0.0f,
										   0.0f, 1.0f, 0.0f, 0.0f,
										   0.0f, 0.0f, 1.0f, 0.0f,
										   0.0f, 0.0f, 0.0f, 1.0f);
										
	translationMatrix._m30 = IN.tangent.x;
	translationMatrix._m31 = IN.tangent.y;
	translationMatrix._m32 = IN.tangent.z;
	
    float4x4 scaleMatrix = float4x4 (0.0f, 0.0f, 0.0f, 0.0f,
									 0.0f, 0.0f, 0.0f, 0.0f,
									 0.0f, 0.0f, 0.0f, 0.0f,
									 0.0f, 0.0f, 0.0f, 1.0f);

	scaleMatrix._m00 = scaleMatrix._m11 = scaleMatrix._m22 = IN.fog.x;
	*/
	
	particleType.y = IN.fog.y;
	particleEnergyValue = IN.fog.z;
	WaveRadius = IN.fog.w;

    //World = mul(mul(scaleMatrix, rotationMatrix), translationMatrix);
}

void VS_ParticleInstancing(VertexInput IN)
{
	VertexInput output = IN;
	
	VS_GenerateWorldMatrix_Particle(IN);	
}

//===================================================================================================
//Helpers
//===================================================================================================

float2 split(float val)
{
	float2 ret = float2(0.0, 0.0);
	ret.x = (int)val;
	ret.y = 10 * (val - (int)val);
	return ret;
}

//==================================================================================================
// MAIN
//==================================================================================================

// Particle Main
//--------------------------------------------------------------------------------------------------
VertexOutput ParticleVertexMain(VertexInput VS_IN)
{
	VertexOutput VS_OUT = (VertexOutput)0;
	VS_OUT = VS_Particle(VS_IN, VS_OUT);
	VS_OUT = VS_BasicLighting(VS_IN, VS_OUT);

	return VS_OUT;
}

FragmentOutput ParticleFragmentMain(FragmentInput FS_IN)
{
    FragmentOutput FS_OUT = (FragmentOutput)0;
    //FS_AlphaClip(FS_IN);
	FS_OUT = FS_Particle(FS_IN, FS_OUT);	
	FS_OUT = FS_LerpBumpMapping(FS_IN, FS_OUT);
	FS_OUT = FS_BasicLighting(FS_IN, FS_OUT);
	FS_OUT = FS_Fog(FS_IN, FS_OUT);
	FS_OUT = FS_PlayerDeadShader(FS_IN, FS_OUT);
	
	//wanted to do transparent water but having trouble with instancing
	if (particleType.y == 1.0f)
	{
		//Water type
		FS_OUT.color.a = 1.4f - particleEnergyValue;
	}
	
	return FS_OUT;
}

// Instanced Particle Main
//--------------------------------------------------------------------------------------------------
VertexOutput InstancedParticleVertexMain(VertexInput VS_IN)
{
	VertexOutput VS_OUT = (VertexOutput)0;
	VS_ParticleInstancing(VS_IN);
	VS_OUT = VS_Particle(VS_IN, VS_OUT);
	VS_OUT = VS_BasicLighting(VS_IN, VS_OUT);
	
	VS_OUT.fog.x = VS_IN.fog.y;
	VS_OUT.fog.y = VS_IN.fog.z;
	
	return VS_OUT;
}

FragmentOutput InstancedParticleFragmentMain(FragmentInput FS_IN)
{
    FragmentOutput FS_OUT = (FragmentOutput)0;
    //FS_AlphaClip(FS_IN);
	FS_OUT = FS_InstancedParticle(FS_IN, FS_OUT);	
	FS_OUT = FS_ParticleBumpMapping(FS_IN, FS_OUT);
	FS_OUT = FS_BasicLighting(FS_IN, FS_OUT);
	FS_OUT = FS_Fog(FS_IN, FS_OUT);
	FS_OUT = FS_PlayerDeadShader(FS_IN, FS_OUT);

	if (FS_IN.fog.x == 1.0f)
	{
		//Water type
		FS_OUT.color.a = 1.4f - FS_IN.fog.y;
	}
	
	return FS_OUT;
}

// Energy Beam Main
//--------------------------------------------------------------------------------------------------
VertexOutput EnergyBeamVertexMain(VertexInput VS_IN)
{
	VertexOutput VS_OUT = (VertexOutput)0;
	VS_OUT = VS_EnergyBeam(VS_IN, VS_OUT);

	return VS_OUT;
}

FragmentOutput EnergyBeamFragmentMain(FragmentInput FS_IN)
{
    FragmentOutput FS_OUT = (FragmentOutput)0;
    
    FS_AlphaClip(FS_IN);
	FS_OUT = FS_Particle(FS_IN, FS_OUT);	
	//FS_OUT = FS_BasicLighting(FS_IN, FS_OUT);
	//FS_OUT = FS_Fog(FS_IN, FS_OUT);
	FS_OUT = FS_PlayerDeadShader(FS_IN, FS_OUT);
	
	return FS_OUT;
}

// Basic Lighting Main
//--------------------------------------------------------------------------------------------------
VertexOutput BasicLightingVertexMain(VertexInput VS_IN)
{
	VertexOutput VS_OUT = (VertexOutput)0;
	VS_OUT = VS_BasicLighting(VS_IN, VS_OUT);

	return VS_OUT;
}

FragmentOutput BasicLightingFragmentMain(FragmentInput FS_IN)
{
    FragmentOutput FS_OUT = (FragmentOutput)0;
    FS_AlphaClip(FS_IN);
    FS_OUT = FS_BumpMapping(FS_IN, FS_OUT);
	FS_OUT = FS_BasicLighting(FS_IN, FS_OUT);
	FS_OUT = FS_Fog(FS_IN, FS_OUT);
	FS_OUT = FS_PlayerDeadShader(FS_IN, FS_OUT);

	return FS_OUT;
}

// Basic Lighting (no bump-mapping) Main
//--------------------------------------------------------------------------------------------------
FragmentOutput BasicLightingNoBumpsFragmentMain(FragmentInput FS_IN)
{
    FragmentOutput FS_OUT = (FragmentOutput)0;
    FS_AlphaClip(FS_IN);
	FS_OUT = FS_NoBumpMapping(FS_IN, FS_OUT);
	FS_OUT = FS_BasicLighting(FS_IN, FS_OUT);
	FS_OUT = FS_Fog(FS_IN, FS_OUT);
	FS_OUT = FS_PlayerDeadShader(FS_IN, FS_OUT);

	return FS_OUT;
}

// Basic Lighting Without Shadows Main
//--------------------------------------------------------------------------------------------------
FragmentOutput BasicLightingNoShadowsFragmentMain(FragmentInput FS_IN)
{
    FragmentOutput FS_OUT = (FragmentOutput)0;
    FS_AlphaClip(FS_IN);
    FS_OUT = FS_BumpMapping(FS_IN, FS_OUT);
	FS_OUT = FS_BasicLightingNoShadows(FS_IN, FS_OUT);
	FS_OUT = FS_Fog(FS_IN, FS_OUT);
	FS_OUT = FS_PlayerDeadShader(FS_IN, FS_OUT);
	
	return FS_OUT;
}

// Basic Lighting w/instancing Main
//--------------------------------------------------------------------------------------------------
VertexOutput BasicLightingInstancedVertexMain(VertexInput VS_IN)
{
	VertexOutput VS_OUT = (VertexOutput)0;
	VS_IN = VS_Instancing(VS_IN);
	VS_OUT = VS_BasicLighting(VS_IN, VS_OUT);

	return VS_OUT;
}

// Render Terrain Main
//--------------------------------------------------------------------------------------------------
VertexOutput TerrainVertexMain(VertexInput VS_IN)
{
	VertexOutput VS_OUT =  (VertexOutput)0;
	VS_IN = VS_TerrainLOD(VS_IN);
	VS_OUT = VS_BasicLighting(VS_IN, VS_OUT);
	//VS_OUT = VS_Fog(VS_IN, VS_OUT);

	return VS_OUT;
}

FragmentOutput TerrainFragmentMain(FragmentInput FS_IN)
{
	FragmentOutput FS_OUT = (FragmentOutput)0;
	FS_OUT = FS_TerrainLOD(FS_IN, FS_OUT);
	FS_OUT = FS_TerrainBumpMapping(FS_IN, FS_OUT);
	FS_OUT = FS_BasicLighting(FS_IN, FS_OUT);
	FS_OUT = FS_RenderTerrain(FS_IN, FS_OUT);
	FS_OUT = FS_TerrainModTexture(FS_IN, FS_OUT);
	FS_OUT = FS_Fog(FS_IN, FS_OUT);
	FS_OUT = FS_PlayerDeadShader(FS_IN, FS_OUT);

	return FS_OUT;
}

// Render Terrain Shadow Map Main
//--------------------------------------------------------------------------------------------------
VertexOutput TerrainShadowMapVertexMain(VertexInput VS_IN)
{
	VertexOutput VS_OUT =  (VertexOutput)0;
	VS_IN = VS_TerrainLOD(VS_IN);
	VS_OUT = VS_ShadowMap(VS_IN, VS_OUT);

	return VS_OUT;
}

FragmentOutput TerrainShadowMapFragmentMain(FragmentInput FS_IN)
{
	FragmentOutput FS_OUT = (FragmentOutput)0;
	FS_OUT = FS_TerrainLOD(FS_IN, FS_OUT);
	FS_OUT = FS_ShadowMap(FS_IN, FS_OUT);
	FS_OUT = FS_PlayerDeadShader(FS_IN, FS_OUT);

	return FS_OUT;
}

// Render Terrain (no bump-mapping) Main
//--------------------------------------------------------------------------------------------------
FragmentOutput TerrainNoBumpsFragmentMain(FragmentInput FS_IN)
{
	FragmentOutput FS_OUT = (FragmentOutput)0;
	FS_OUT = FS_TerrainLOD(FS_IN, FS_OUT);
	FS_OUT = FS_NoBumpMapping(FS_IN, FS_OUT);
	FS_OUT = FS_BasicLighting(FS_IN, FS_OUT);
	FS_OUT = FS_RenderTerrain(FS_IN, FS_OUT);
	FS_OUT = FS_TerrainModTexture(FS_IN, FS_OUT);
	FS_OUT = FS_Fog(FS_IN, FS_OUT);
	FS_OUT = FS_PlayerDeadShader(FS_IN, FS_OUT);

	return FS_OUT;
}

// Shadow Map Shader
//--------------------------------------------------------------------------------------------------
VertexOutput ShadowMapVertexMain(VertexInput VS_IN)
{
	VertexOutput VS_OUT = (VertexOutput)0;
	VS_OUT = VS_ShadowMap(VS_IN, VS_OUT);
	
	return VS_OUT;
}

FragmentOutput ShadowMapFragmentMain(FragmentInput FS_IN)
{
	FragmentOutput FS_OUT = (FragmentOutput)0;
    FS_AlphaClip(FS_IN);
	FS_OUT = FS_ShadowMap(FS_IN, FS_OUT);
	
	return FS_OUT;
}

// Instanced Shadow Map Shader
//--------------------------------------------------------------------------------------------------
VertexOutput InstancedShadowMapVertexMain(VertexInput VS_IN)
{
	VertexOutput VS_OUT = (VertexOutput)0;
	VS_IN = VS_Instancing(VS_IN);
	VS_OUT = VS_ShadowMap(VS_IN, VS_OUT);
	
	return VS_OUT;
}

// Full Screen Anti-Aliasing
//--------------------------------------------------------------------------------------------------
VertexOutput AntiAliasingVertexMain(VertexInput VS_IN)
{
	VertexOutput VS_OUT =  (VertexOutput)0;
	VS_OUT =  VS_AntiAliasing(VS_IN, VS_OUT);
	
	return VS_OUT;
}

FragmentOutput AntiAliasingFragmentMain(FragmentInput FS_IN)
{
	FragmentOutput FS_OUT = (FragmentOutput)0;
	FS_OUT = FS_AntiAliasing(FS_IN, FS_OUT);

	return FS_OUT;
}

// Shield Shader
//--------------------------------------------------------------------------------------------------
VertexOutput ShieldVertexMain(VertexInput VS_IN)
{
	VertexOutput VS_OUT =  (VertexOutput)0;
	VS_OUT = VS_Shield(VS_IN, VS_OUT);
	
	return VS_OUT;
}

FragmentOutput ShieldFragmentMain(FragmentInput FS_IN)
{
	FragmentOutput FS_OUT = (FragmentOutput)0;
	FS_OUT = FS_Shield(FS_IN, FS_OUT);
	FS_OUT = FS_PlayerDeadShader(FS_IN, FS_OUT);

	return FS_OUT;
}

// Skinned Player Main
//--------------------------------------------------------------------------------------------------
VertexOutput SkinnedPlayerVertexMain(VertexInput VS_IN)
{
	VertexOutput VS_OUT = (VertexOutput)0;
	VS_IN = VS_Skin(VS_IN);
	VS_OUT = VS_BasicLighting(VS_IN, VS_OUT);

	return VS_OUT;
}

// Player Main
//--------------------------------------------------------------------------------------------------
VertexOutput PlayerVertexMain(VertexInput VS_IN)
{
	VertexOutput VS_OUT = (VertexOutput)0;
	VS_OUT = VS_BasicLighting(VS_IN, VS_OUT);

	return VS_OUT;
}

FragmentOutput PlayerFragmentMain(FragmentInput FS_IN)
{
    FragmentOutput FS_OUT = (FragmentOutput)0;
    FS_AlphaClip(FS_IN);
    FS_OUT = FS_PlayerHole(FS_IN, FS_OUT);
	FS_OUT = FS_BumpMapping(FS_IN, FS_OUT);
	FS_OUT = FS_BasicLighting(FS_IN, FS_OUT);
	FS_OUT = FS_Fog(FS_IN, FS_OUT);
	FS_OUT = FS_PlayerDeadShader(FS_IN, FS_OUT);

	return FS_OUT;
}

// Render To Texture Main
//--------------------------------------------------------------------------------------------------
VertexOutput RenderToTextureVertexMain(VertexInput VS_IN)
{
	VertexOutput VS_OUT = (VertexOutput)0;
	VS_OUT = VS_RenderToTexture(VS_IN, VS_OUT);
	
	return VS_OUT;
}
FragmentOutput RenderToTextureFragmentMain(FragmentInput FS_IN)
{
    FragmentOutput FS_OUT = (FragmentOutput)0;
	FS_OUT = FS_RenderToTexture(FS_IN, FS_OUT);
	
	return FS_OUT;
}

//===================================================================================================
// Techniques
//===================================================================================================

// Particle Shader Technique
//--------------------------------------------------------------------------------------------------
technique ParticleShaderMain
{
    pass Pass0
    {
        VertexShader = compile vs_3_0 ParticleVertexMain();
        PixelShader = compile ps_3_0 ParticleFragmentMain();
        
		// Alpha blending
        AlphaBlendEnable = true; SrcBlend = SrcAlpha; DestBlend = InvSrcAlpha;
		FillMode = Solid;
    }
}

// Instanced Particle Shader Technique
//--------------------------------------------------------------------------------------------------
technique InstancedParticleShaderMain
{
    pass Pass0
    {
        VertexShader = compile vs_3_0 InstancedParticleVertexMain();
        PixelShader = compile ps_3_0 InstancedParticleFragmentMain();
        
		// Alpha blending
        AlphaBlendEnable = true; SrcBlend = SrcAlpha; DestBlend = InvSrcAlpha;
		FillMode = Solid;
    }
}

// Energy Beam Shader Technique
//--------------------------------------------------------------------------------------------------
technique EnergyBeamShaderMain
{
    pass Pass0
    {
        VertexShader = compile vs_3_0 EnergyBeamVertexMain();
        PixelShader = compile ps_3_0 EnergyBeamFragmentMain();
        
		// Alpha blending
        AlphaBlendEnable = true; SrcBlend = SrcAlpha; DestBlend = InvSrcAlpha;
		FillMode = Solid;
    }
}

// Basic Lighting Technique
//--------------------------------------------------------------------------------------------------
technique BasicLightingShaderMain
{
	pass Pass0
	{
		
		VertexShader = compile vs_3_0 BasicLightingVertexMain();
		PixelShader = compile ps_3_0 BasicLightingFragmentMain();
		
		// Alpha blending
        AlphaBlendEnable = true; SrcBlend = SrcAlpha; DestBlend = InvSrcAlpha;
		FillMode = Solid;
	}
}

// Basic Lighting Technique Without Shadows
//--------------------------------------------------------------------------------------------------
technique BasicLightingNoShadowsShaderMain
{
	pass Pass0
	{
		VertexShader = compile vs_3_0 BasicLightingVertexMain();
		PixelShader = compile ps_3_0 BasicLightingNoShadowsFragmentMain();
		
		// Alpha blending
        AlphaBlendEnable = true; SrcBlend = SrcAlpha; DestBlend = InvSrcAlpha;
		FillMode = Solid;
	}
}

// Basic Lighting (no bump-mapping) Shader Technique
//--------------------------------------------------------------------------------------------------
technique BasicLightingNoBumpsShaderMain
{
	pass Pass0
	{
		
		VertexShader = compile vs_3_0 BasicLightingVertexMain();
		PixelShader = compile ps_3_0 BasicLightingNoBumpsFragmentMain();
		
		// Alpha blending
        AlphaBlendEnable = true; SrcBlend = SrcAlpha; DestBlend = InvSrcAlpha;
		FillMode = Solid;
	}
}

// Basic Lighting Technique with Instancing
//--------------------------------------------------------------------------------------------------
technique BasicLightingInstancedShaderMain
{
	pass Pass0
	{
		
		VertexShader = compile vs_3_0 BasicLightingInstancedVertexMain();
		PixelShader = compile ps_3_0 BasicLightingFragmentMain();
		
		// Alpha blending
        AlphaBlendEnable = true; SrcBlend = SrcAlpha; DestBlend = InvSrcAlpha;
		FillMode = Solid;
	}
}

// Terrain Shader Technique
//--------------------------------------------------------------------------------------------------
technique TerrainShaderMain
{
	pass Pass0
	{
		VertexShader  = compile vs_3_0 TerrainVertexMain();
		PixelShader =  compile ps_3_0 TerrainFragmentMain();
		
		// Alpha blending
        AlphaBlendEnable = true; SrcBlend = SrcAlpha; DestBlend = InvSrcAlpha;
		FillMode = Solid;
	}
}

// Terrain Shadow Map Shader Technique
//--------------------------------------------------------------------------------------------------
technique TerrainShadowMap
{
	pass Pass0
	{
		VertexShader  = compile vs_3_0 TerrainShadowMapVertexMain();
		PixelShader =  compile ps_3_0 TerrainShadowMapFragmentMain();
		
		// Alpha blending
        AlphaBlendEnable = true; SrcBlend = SrcAlpha; DestBlend = InvSrcAlpha;
		FillMode = Solid;
	}
}

// Terrain (no bump-mapping) Shader Technique
//--------------------------------------------------------------------------------------------------
technique TerrainNoBumpsShaderMain
{
	pass Pass0
	{
		VertexShader  = compile vs_3_0 TerrainVertexMain();
		PixelShader =  compile ps_3_0 TerrainNoBumpsFragmentMain();
		
		// Alpha blending
        AlphaBlendEnable = true; SrcBlend = SrcAlpha; DestBlend = InvSrcAlpha;
		FillMode = Solid;
	}
}

// Shadow Map
//--------------------------------------------------------------------------------------------------
technique ShadowMap
{
	pass Pass0
	{
		VertexShader	= compile vs_3_0 ShadowMapVertexMain();
		PixelShader		= compile ps_3_0 ShadowMapFragmentMain();

		// Alpha blending
        AlphaBlendEnable = true; SrcBlend = SrcAlpha; DestBlend = InvSrcAlpha;
		FillMode = Solid;
	}
}

// Instanced Shadow Map
//--------------------------------------------------------------------------------------------------
technique InstancedShadowMap
{
	pass Pass0
	{
		VertexShader	= compile vs_3_0 InstancedShadowMapVertexMain();
		PixelShader		= compile ps_3_0 ShadowMapFragmentMain();

		// Alpha blending
        AlphaBlendEnable = true; SrcBlend = SrcAlpha; DestBlend = InvSrcAlpha;
		FillMode = Solid;
	}
}


// Full Screen Anti-Aliasing Technique
//--------------------------------------------------------------------------------------------------
technique FullScreenAntiAliasing
{
	pass Pass0
	{
		VertexShader	= compile vs_3_0 AntiAliasingVertexMain();
		PixelShader		= compile ps_3_0 AntiAliasingFragmentMain();

		// Alpha blending
        AlphaBlendEnable = true; SrcBlend = SrcAlpha; DestBlend = InvSrcAlpha;
		FillMode = Solid;
	}
}

// Shield Shader Technique
//--------------------------------------------------------------------------------------------------
technique ShieldShaderMain
{
	pass Pass0
	{
		VertexShader	= compile vs_3_0 ShieldVertexMain();
		PixelShader		= compile ps_3_0 ShieldFragmentMain();

		// Alpha blending
        AlphaBlendEnable = true; SrcBlend = SrcAlpha; DestBlend = InvSrcAlpha;
		FillMode = Solid;
	}
}

// AntiBurn
//--------------------------------------------------------------------------------------------------
technique AntiBurn
{
	pass Pass0
	{
		PixelShader = compile ps_2_0 AntiBurnFSMain();
	}
}

// Skinned Player Technique
//--------------------------------------------------------------------------------------------------
technique SkinnedPlayerShaderMain
{
	pass Pass0
	{		
		VertexShader = compile vs_3_0 SkinnedPlayerVertexMain();
		PixelShader = compile ps_3_0 PlayerFragmentMain();
		
		// Alpha blending
        AlphaBlendEnable = true; SrcBlend = SrcAlpha; DestBlend = InvSrcAlpha;
		FillMode = Solid;
	}
}

// Player Technique
//--------------------------------------------------------------------------------------------------
technique PlayerShaderMain
{
	pass Pass0
	{		
		VertexShader = compile vs_3_0 PlayerVertexMain();
		PixelShader = compile ps_3_0 PlayerFragmentMain();
		
		// Alpha blending
        AlphaBlendEnable = true; SrcBlend = SrcAlpha; DestBlend = InvSrcAlpha;
		FillMode = Solid;
	}
}

// Render To Texture Technique
//--------------------------------------------------------------------------------------------------
technique RenderToTextureShaderMain
{
	pass Pass0
	{
		VertexShader = compile vs_3_0 RenderToTextureVertexMain();
		PixelShader = compile ps_3_0 RenderToTextureFragmentMain();
		
		// Alpha blending
        AlphaBlendEnable = true; SrcBlend = SrcAlpha; DestBlend = InvSrcAlpha;
		FillMode = Solid;
	}
}