//---------------------------------------------------------------------------------------------------------------------------------------------------
// <copyright file="FXSourceCode.cs" company="DarkWynter Studios">
//     Copyright (C)2007 DarkWynter Studios.  All rights reserved.
// </copyright>
//---------------------------------------------------------------------------------------------------------------------------------------------------
// {Contact : darkwynter.com for licensing information
//---------------------------------------------------------------------------------------------------------------------------------------------------

namespace DarkWynter.Stream
{
    #region Using Statements
    using System;
    using System.Collections.Generic;
    using Microsoft.Xna.Framework;
    using Microsoft.Xna.Framework.Audio;
    using Microsoft.Xna.Framework.Content;
    using Microsoft.Xna.Framework.Graphics;
    using Microsoft.Xna.Framework.Input;
    using Microsoft.Xna.Framework.Storage;
    using System.Xml;
    using System.Diagnostics;
    using System.Threading;
    using PhysicsGpu;
    #endregion

    /// <summary>
    /// Compiles and stores all HLSL source code
    /// </summary>
    public class FXSourceCode
    {
        #region AI Vision Source
        private string AIVisionSource = @"
//===================================================================================================
// Uniform Variables
//===================================================================================================
float4x4 ViewProj;
float4x4 inverseViewProj;
float numberOfPlayers;

//-- aiVisionTexture --
texture aiVisionTexture; 
sampler aiVisionSampler = sampler_state 
{
	texture		= <aiVisionTexture>; 
	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
    float4	texCoord				: TEXCOORD0;		// Texture coordinates
};

struct VertexOutput
{
	// These values are used directly by the rasterizer
	float4	position				: POSITION; 		// Position
	float4	color					: COLOR0; 			// Color (example: COLOR0)
	float4	texCoord				: TEXCOORD0; 		// Texture coordinates (example: TEXCOORD0)
};

struct FragmentInput
{
	float4	color					: COLOR0; 			// Color (example: COLOR0)
    float4	texCoord				: TEXCOORD0;		// Texture coordinates 
};

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

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

// AI Vision - Texture Scan Main
//--------------------------------------------------------------------------------------------------
VertexOutput AI_Vision_VertexTextureScan(VertexInput IN)
{
	VertexOutput OUT = (VertexOutput)0;
	
	OUT.position = IN.position;
	OUT.texCoord = IN.texCoord;
	
	float4 textureOut = tex2Dlod(aiVisionSampler, float4(IN.texCoord.x, IN.texCoord.y, 0, 0));
	
	if(textureOut.r >= 0.1f)
	{
		// player index
		int index = round(textureOut.a * numberOfPlayers);
	
		OUT.position.x = (index % 4) / 4.0f;
		OUT.position.y = round(index / 4) / 4.0f;
		
		OUT.color.a = 1.0f;
		OUT.color.rgb = mul(float2(IN.texCoord.x, IN.texCoord.y), inverseViewProj);
	}
	else
	{
		OUT.position.xy = -1.0f;
		OUT.color = 0.4f;
	}

	OUT.position = mul(OUT.position, ViewProj);

	return OUT;
}

FragmentOutput AI_Vision_FragmentTextureScan(FragmentInput IN)
{
	FragmentOutput OUT = (FragmentOutput)0;

	OUT.color = IN.color;
	
	return OUT;
}

// AI Vision - Scan AI Texture
//--------------------------------------------------------------------------------------------------
technique AI_Vision_TextureScan
{
	pass Pass0
	{
		VertexShader  = compile vs_3_0 AI_Vision_VertexTextureScan();
		PixelShader =  compile ps_3_0 AI_Vision_FragmentTextureScan();
		
		// Alpha blending
        AlphaBlendEnable = true; SrcBlend = SrcAlpha; DestBlend = InvSrcAlpha;
		FillMode = Solid;
	}
}";
        #endregion

        #region ElementalGPU
        private string ElementalGPUSource = @"
// Copywrited by its developers at darkwynter.com
// All Rights Reserved Without Prejudice.

//===================================================================================================
// Textures and Samplers
//===================================================================================================
//- ScreenTexture1 --
texture ScreenTexture;
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;
};

//- 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;
};

//- Position --
texture CurrentPosition; 
sampler CurrentPositionSampler = sampler_state 
{
	texture		= <CurrentPosition>; 
	AddressU	= CLAMP;	
	AddressV	= CLAMP;	
	AddressW	= CLAMP; 
	MIPFILTER	= ANISOTROPIC;	
	MINFILTER	= ANISOTROPIC;	
	MAGFILTER	= ANISOTROPIC;
};


//===================================================================================================
// Uniform Variables
//===================================================================================================

// Viewport Projection Matrix
float4x4 ViewProj;

// Object position in 3D space
float4x4 World;

// ViewPort position in 3D space
float4x4 EyePostion;

// Raster Dimensions
int ScreenWidth;
int ScreenHeight;

// Player Dead Shader
bool playerIsDead;

// Light Properties
float3 lightPosition0;
float4 lightAmbient0;
float4 lightDiffuse0;
float4 lightSpecular0;
float3 lightPosition1;
float4 lightAmbient1;
float4 lightDiffuse1;
float4 lightSpecular1;

// Object Material Properties
float4 materialDiffuse;
float4 materialSpecular;
float4 textureValue;
float4 ambientColor;
float4 diffuseColor;
float4 specularColor;
float shininess;

// Lighting Calcs
float3 lightVector1;
float3 lightVector2;
float3 vertexToEyeVector;
float3 halfwayVector1;
float3 halfwayVector2;

// Terrain Height Scale
float worldMinY;
float worldMaxY;

// Terrain
float3 PlaneRayIntersectionPoint;
float terrainScaleFactor;
float TerrainModRange;
float terrainBarrierWallHeight;
bool terrainModEnabled;
float mapSizeXScaleFactor;

// Screen Saver Update
float screenSaverTime;

// Particle Uniform Variables
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
float WaveRadius;
float particleType;
float particleEnergyValue;

float3 normal;

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

// Animation Stuff
float4x4 MatrixPalette[56];

float scaleRange;
float minimumValue;

float fogStart, fogEnd, fogDropOff;

// G2L shader
float2 blendTexturePosition1;
float2 blendTexturePosition2;

//===================================================================================================
// Uniform, Varying, and FrameBuffer Stream Structures - 
// Used to Communicate between CPU, VertexProcessor, FragmentProcessor, and FrameBuffer
//===================================================================================================
struct VertexInput 
{
    float4	position				: POSITION0;		// Position
	float4	indices					: BLENDINDICES0;
	float4	weights					: BLENDWEIGHT0;
    float3	normal					: NORMAL0;			// Normal vector
    float4	texCoord				: TEXCOORD0;		// Texture coordinates
	float4  fog						: TEXCOORD1;		// {-|
    float4	binormal				: TEXCOORD2;		// {-|---- Instancing
    float4	tangent					: TEXCOORD3;		// {-|---- Buffers
    float4  depth					: TEXCOORD4;		// {-|
};

struct VertexOutput
{
	// These values are used directly by the rasterizer
	float4	position				: POSITION; 		// Position
	float2	fog						: TEXCOORD3; 		// 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 
};

struct FragmentInput
{
	float4	color					: COLOR0; 			// Color (example: COLOR0)
	float2	fog						: TEXCOORD3;
	
    float4	texCoord				: TEXCOORD0;		// Texture coordinates 
    float3	normal					: TEXCOORD1;		// Texture coordinates 
    float3	worldPos				: TEXCOORD2;		// Texture coordinates 
};

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

//===================================================================================================
// Depricated Shaders
//===================================================================================================


// -----------------------------------------------------------------------------------
FragmentOutput FS_FlickerFlame(FragmentInput IN, FragmentOutput OUT)
{
    OUT.color =  tex2D(modelTextureSampler1, IN.texCoord + blendTexturePosition1); 

    float4 color2 = tex2D(bumpTextureSampler1, IN.texCoord + blendTexturePosition2); 
  // float4 color3 = tex2D(modelTextureSampler6, IN.texCoord); 
    
    // Blend
    if (OUT.color.a > 0)
    {
		//OUT.color.r = 0.5f;
		//OUT.color.g = 0.7f;
		//OUT.color.b = 0.6f;
	    OUT.color = (OUT.color * .750f) + (color2 * .25f);
	    // + (color3 * .25f);
    }
    
    return OUT;
}
VertexOutput VS_FlickerFlame(VertexInput IN, VertexOutput OUT) 
{
	OUT.position = mul(IN.position, mul(World, ViewProj));
    OUT.texCoord = IN.texCoord;
    OUT.normal = IN.normal;

    return OUT;
}
FragmentOutput FlickerFlameFragmenMain(FragmentInput FS_IN)
{
	FragmentOutput FS_OUT = (FragmentOutput)0;
	FS_OUT = FS_FlickerFlame(FS_IN, FS_OUT);

	return FS_OUT;
}

VertexOutput FlickerFlameVertexMain(VertexInput VS_IN)
{
	VertexOutput VS_OUT = (VertexOutput)0;
	VS_OUT = VS_FlickerFlame(VS_IN, VS_OUT);
	return VS_OUT;
}

// FlickerFlame Shader
// --------------------------------------------------------------------------
technique FlickerFlame
{
    pass Pass0
    {
        PixelShader = compile ps_3_0 FlickerFlameFragmenMain();
   		VertexShader = compile vs_3_0 FlickerFlameVertexMain();
        AlphaBlendEnable = true; SrcBlend = SrcAlpha; DestBlend = InvSrcAlpha;
		FillMode = Solid;

    }
}

// 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 == 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 == 1.0f)
	{
		shininess = 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 == 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;    
}


//===================================================================================================
// 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 <= mapSizeXScaleFactor &&
	   vertexWorldPosition.z <= mapSizeXScaleFactor)
	{
		IN.texCoord.x = (vertexWorldPosition.z / mapSizeXScaleFactor);
		IN.texCoord.y = (vertexWorldPosition.x / mapSizeXScaleFactor);
		
		IN.position.y = (tex2Dlod(heightMapTextureSampler, float4(IN.texCoord.x, IN.texCoord.y, 0, 0)).x * (worldMaxY - worldMinY)) + worldMinY;
  	}
	else
	{
		IN.texCoord.xy = -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)
{
   	// Get texture value
 	float4 lowTex =	tex2D(bumpTextureSampler1, IN.texCoord * 200); 	
    float4 middleTex = tex2D(bumpTextureSampler2, IN.texCoord * 100);
    float4 highTex = tex2D(bumpTextureSampler3, IN.texCoord * 10);

	// Shift Y Position between 0 - 1
	float YRatio = IN.worldPos.y / (worldMaxY - worldMinY);

	float4 low = lerp(lowTex, middleTex, YRatio);
	float4 high = lerp(middleTex, highTex, YRatio);
	float4 value = lerp(low, high, YRatio);		

	// ERROR: Algorithm calcs height and not angle
	// Check by replacing modTex in XML with a florecent colored texture
	// Get the angle between normal and up
	// float4 modTex = tex2D(bumpTextureSampler4, IN.texCoord * 200);
	// float angle = abs( degrees(acos(dot(IN.normal, float3(0, 1, 0)))));
	// value = lerp(value, modTex,  angle/90.0f);

	//unpack the normal map
	value.xyz = 2.0f * (value.xyz - 0.5);
	normal = normalize(value + IN.normal);
	
	return OUT;
}

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

	// Shift Y Position between 0 - 1
	float YRatio = IN.worldPos.y / (worldMaxY - worldMinY) ;

	// Multi Texture Mixing
	float4 low = lerp(lowTex, middleTex, YRatio);
	float4 high = lerp(middleTex, highTex, YRatio);
	float4 value = lerp(low, high, YRatio);		
	
	// ERROR: Algorithm calcs height and not angle
	// Check by replacing modTex in XML with a florecent colored texture
	// Get the angle between normal and up
    // float4 modTex = tex2D(modelTextureSampler4, IN.texCoord * 200);
	// float angle = abs( degrees(acos(dot(IN.normal, float3(0, 1, 0)))));
	// value = lerp(value, modTex,  angle/90.0f);

	// Mix color value with lighting
  	//OUT.color = (diffuseColor + ambientColor) * value + specularColor;
  	textureValue = value;

	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 = 2.0f * (normalNew.xyz - 0.5);
	normal = normalize(normalNew + IN.normal);
	
	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 = 2.0f * (normalNew.xyz - 0.5);
	normal = normalize(normalNew + IN.normal);
	
	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

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

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

	// Calculate each light source's halfway vector
	halfwayVector1			= normalize(vertexToEyeVector + lightVector1);						// Halfway vector
  	halfwayVector2			= normalize(vertexToEyeVector + lightVector2);						// Halfway vector

    return OUT;    
}

FragmentOutput FS_BasicLighting(FragmentInput IN, FragmentOutput OUT)
{
    float diffuse0				= 0.0f;
	float diffuse1				= 0.0f;
	float specular0				= 0.0f;
	float specular1				= 0.0f;
	
	diffuse0					= max(0.0f, dot(normal, lightVector1));						// Diffuse component
	
	if(diffuse0 > 0.0f)
	{
		// If statement stops objects from becoming backlit
		specular0				= pow(dot(normal, halfwayVector1), shininess);				// Specular component
	}
	
	if(length(lightVector1 - lightVector2) != 0.0)
	{
		diffuse1				= max(0.0f, dot(normal, lightVector2));						// Diffuse component
		if(diffuse1 > 0.0f)
		{
			specular1			= pow(dot(normal, halfwayVector2), shininess);				// Specular component
		}
	}
	
	// Mix Components of Lighting with Material Properties
	ambientColor	= materialDiffuse	* (lightAmbient0 + lightAmbient1);														
	diffuseColor	= materialDiffuse	* ((diffuse0  * lightDiffuse0)  + (diffuse1  *  lightDiffuse1));
	specularColor	= materialSpecular  * ((specular0 *	lightSpecular0) + (specular1 * lightSpecular1));
	
	// Apply lighting to the color
 	OUT.color = (diffuseColor + ambientColor + specularColor) * textureValue;
 	
 	//=== HACK POINT
 	// Limit the number of colors to create splotchy effects
 	//float3 rgb = float3((int)(OUT.color.r * 256.0f), (int) (OUT.color.g * 256.0f), (int) (OUT.color.b * 256.0f)); 	
 	//OUT.color.rgb = rgb	/ 256.0f;
 	//=== END HACK POINT
 	 	
 	// To frambuffer
 	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;    
}

// Terrain Mod Shader
//--------------------------------------------------------------------------------------------------
FragmentOutput FS_TerrainModTexture(FragmentInput IN, FragmentOutput OUT) 
{
	if(terrainModEnabled == true)
	{
		// Project 
		PlaneRayIntersectionPoint.xz = PlaneRayIntersectionPoint.zx;
		PlaneRayIntersectionPoint.x = PlaneRayIntersectionPoint.x + 0.5f;		
		PlaneRayIntersectionPoint.z = (-PlaneRayIntersectionPoint.z) - 0.5f;
		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;
			}
		}	
	}
	return OUT;
}

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

    return OUT;
}

FragmentOutput FS_DrawQuad(FragmentInput IN, FragmentOutput OUT)
{
	OUT.color = tex2D(modelTextureSampler1, IN.texCoord);
	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 = tex2D(modelTextureSampler1, IN.texCoord);
	OUT.color.a = 1.0f;
	
	return OUT;
}

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

// Generate instanced World matrix
//--------------------------------------------------------------------------------------------------
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.depth.x;
	World._m31 = IN.depth.y;
	World._m32 = IN.depth.z;
	World._m33 = IN.depth.w;
}

// 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
//--------------------------------------------------------------------------------------------------
float4x4 GetRotationMatrix(float4 q)
{
	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;
    
    return rotationMatrix;
}

float4x4 GetTranslationMatrix(float4 tangent)
{
    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 = tangent.x;
	translationMatrix._m31 = tangent.y;
	translationMatrix._m32 = tangent.z;
	
	return translationMatrix;
}

float4x4 GetScaleMatrix(float4 fog)
{
    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 = fog.x;
	scaleMatrix._m11 = fog.y;
	scaleMatrix._m22 = fog.z;
	
	return scaleMatrix;
}

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

// Physix Vertex Instancing
//--------------------------------------------------------------------------------------------------
void VS_GeneratePhysixWorldMatrix(VertexInput IN)
{
	VS_GenerateWorldMatrix(IN);	

	float3 currentPosition = tex2Dlod(CurrentPositionSampler, float4(IN.depth.x, IN.depth.y, 0.0f, 0.0f));

	float scaleRangeY = worldMaxY - worldMinY;

	World._m30 = (currentPosition.x * scaleRange);// + minimumValue;
	World._m31 = (currentPosition.y * scaleRange);// + minimumValue;
	World._m32 = (currentPosition.z * scaleRange);// + minimumValue;
}

VertexInput VS_PhysixInstancing(VertexInput IN)
{
	VertexInput output = IN;
	
	VS_GeneratePhysixWorldMatrix(IN);	
	
	return output;
}

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

	// 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 = 2.0f * (normalNew.xyz - 0.5);
	normal = normalize(normalNew);

    return OUT;
}

void VS_GenerateWorldMatrix_Particle(VertexInput IN)
{
	float4x4 rotationMatrix = GetRotationMatrix(IN.binormal);
	
	float4x4 translationMatrix = GetTranslationMatrix(IN.tangent);
	
    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 = IN.fog.y;
	particleEnergyValue = IN.fog.z;
	WaveRadius = IN.fog.w;

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

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


// Toon (Cell shading) Main
//--------------------------------------------------------------------------------------------------
VertexOutput VS_Toon(VertexInput IN, VertexOutput OUT) 
{
	OUT.position = mul(IN.position, mul(World, ViewProj));
    OUT.texCoord = IN.texCoord;
    OUT.normal = IN.normal;

    return OUT;
}

FragmentOutput FS_Toon(FragmentInput IN, FragmentOutput OUT)
{
    float3 lightDir = normalize(lightPosition0);
	float intensity = dot(lightDir,normalize(IN.normal));
	
	if (intensity > 0.95)
		OUT.color = float4(1.0,0.5,0.5,1.0);
	else if (intensity > 0.5)
		OUT.color = float4(0.6,0.3,0.8,1.0);
	else if (intensity > 0.25)
		OUT.color = float4(0.4,0.8,0.2,1.0);
	else
		OUT.color = float4(0.8,0.1,0.1,1.0);
		

    //get our colour
    OUT.color = tex2D(modelTextureSampler1, IN.texCoord);

    //return final pixel colour
	return OUT;
}

VertexOutput ToonVertexMain(VertexInput VS_IN)
{
	VertexOutput VS_OUT = (VertexOutput)0;
	VS_OUT = VS_Toon(VS_IN, VS_OUT);
	return VS_OUT;
}

FragmentOutput ToonFragmentMain(FragmentInput FS_IN)
{
    FragmentOutput FS_OUT = (FragmentOutput)0;    
	FS_OUT = FS_Toon(FS_IN, FS_OUT);
	return FS_OUT;
}
technique ToonShaderMain
{
	pass Pass0
	{		
		VertexShader = compile vs_3_0 ToonVertexMain();
		PixelShader = compile ps_3_0 ToonFragmentMain();
		
		// Alpha blending
        AlphaBlendEnable = true; SrcBlend = SrcAlpha; DestBlend = InvSrcAlpha;
		FillMode = Solid;
	}
}
//--------------------------------------------------------------------------------------------------

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

FragmentOutput FS_FogTransparency(FragmentInput IN, FragmentOutput OUT)
{
	OUT.color.a = fogDropOff * OUT.color.a;
	
	return OUT;
}

void FS_DistanceAlphaClip(FragmentInput IN)
{
	float fog = length(EyePostion[3].xyz - IN.worldPos);
	fogDropOff = (fogEnd - fog) / (fogEnd - fogStart) ;//1.0f / fog * fogDensity;
	//if(fogDropOff < 0.1f){ fogDropOff = 0.1f; } // Substitute for broken clamp op
	saturate(fogDropOff);
	
	clip(fogDropOff - 0.01f);
}

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

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

	clip(textureValue.a - 0.1f);
}
//==================================================================================================
// 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_PlayerDeadShader(FS_IN, FS_OUT);
	
	//wanted to do transparent water but having trouble with instancing
	if (particleType == 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_PlayerDeadShader(FS_IN, FS_OUT);
	
	//wanted to do transparent water but having trouble with instancing
	if (FS_IN.fog.x == 1.0f)
	{
		//Water type
		FS_OUT.color.a = 1.4f - FS_IN.fog.y;
	}
	
	FS_OUT = FS_FogTransparency(FS_IN, FS_OUT);
	
	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_DistanceAlphaClip(FS_IN);
    FS_AlphaClip(FS_IN);
	FS_OUT = FS_Particle(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_DistanceAlphaClip(FS_IN);
    FS_OUT = FS_BumpMapping(FS_IN, FS_OUT);
	FS_OUT = FS_BasicLighting(FS_IN, FS_OUT);
	FS_OUT = FS_PlayerDeadShader(FS_IN, FS_OUT);
	FS_OUT = FS_FogTransparency(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_DistanceAlphaClip(FS_IN);
	FS_OUT = FS_NoBumpMapping(FS_IN, FS_OUT);
	FS_OUT = FS_BasicLighting(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;
}

// Physix Instancing Main
//--------------------------------------------------------------------------------------------------
VertexOutput GPUPhysixInstancedVertexMain(VertexInput VS_IN)
{
	VertexOutput VS_OUT = (VertexOutput)0;
	VS_IN = VS_PhysixInstancing(VS_IN);
	VS_OUT = VS_BasicLighting(VS_IN, VS_OUT);

	return VS_OUT;
}

// Terrain Instanced Main
//--------------------------------------------------------------------------------------------------
VertexOutput TerrainInstancedVertexMain(VertexInput VS_IN)
{
	VertexOutput VS_OUT =  (VertexOutput)0;
	VS_GenerateWorldMatrix(VS_IN);
	VS_IN = VS_TerrainLOD(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);

	return VS_OUT;
}

FragmentOutput TerrainFragmentMain(FragmentInput FS_IN)
{
	FragmentOutput FS_OUT = (FragmentOutput)0;
	FS_OUT = FS_TerrainLOD(FS_IN, FS_OUT);
	FS_DistanceAlphaClip(FS_IN);
	FS_OUT = FS_TerrainBumpMapping(FS_IN, FS_OUT);
	FS_OUT = FS_RenderTerrain(FS_IN, FS_OUT);
	FS_OUT = FS_BasicLighting(FS_IN, FS_OUT);
	FS_OUT = FS_TerrainModTexture(FS_IN, FS_OUT);
	//FS_OUT = FS_PlayerDeadShader(FS_IN, FS_OUT);
	//FS_OUT = FS_FogTransparency(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_DistanceAlphaClip(FS_IN);
	FS_OUT = FS_NoBumpMapping(FS_IN, FS_OUT);
	FS_OUT = FS_RenderTerrain(FS_IN, FS_OUT);
	FS_OUT = FS_BasicLighting(FS_IN, FS_OUT);
	FS_OUT = FS_TerrainModTexture(FS_IN, FS_OUT);
	//FS_OUT = FS_PlayerDeadShader(FS_IN, FS_OUT);
	FS_OUT = FS_FogTransparency(FS_IN, FS_OUT);

	return FS_OUT;
}

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

FragmentOutput DrawQuadFragmentMain(FragmentInput FS_IN)
{
	FragmentOutput FS_OUT = (FragmentOutput)0;
	FS_OUT = FS_DrawQuad(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;
}

// Instanced Animation Main
//--------------------------------------------------------------------------------------------------
VertexOutput InstancedAnimationVertexMain(VertexInput VS_IN)
{
	VertexOutput VS_OUT = (VertexOutput)0;
	VS_IN = VS_Skin(VS_IN);
	VS_Instancing(VS_IN);
	VS_OUT = VS_BasicLighting(VS_IN, VS_OUT);

	return VS_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;
}

//===================================================================================================
// 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 (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;
	}
}

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

// Terrain Instanced Shader Technique
//--------------------------------------------------------------------------------------------------
technique TerrainInstanced
{
	pass Pass0
	{
		VertexShader  = compile vs_3_0 TerrainInstancedVertexMain();
		PixelShader =  compile ps_3_0 TerrainFragmentMain();
		
		// 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 Instanced (no bump-mapping) Shader Technique
//--------------------------------------------------------------------------------------------------
technique TerrainNoBumpsInstanced
{
	pass Pass0
	{
		VertexShader  = compile vs_3_0 TerrainInstancedVertexMain();
		PixelShader =  compile ps_3_0 TerrainNoBumpsFragmentMain();
		
		// 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 TerrainFragmentMain();
		
		// Alpha blending
        AlphaBlendEnable = true; SrcBlend = SrcAlpha; DestBlend = InvSrcAlpha;
		FillMode = Solid;
	}
}

// Draw Quad Technique
//--------------------------------------------------------------------------------------------------
technique DrawQuad
{
	pass Pass0
	{
		VertexShader	= compile vs_3_0 DrawQuadVertexMain();
		PixelShader		= compile ps_3_0 DrawQuadFragmentMain();

		// 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();
	}
}

// Instanced Animation Technique
//--------------------------------------------------------------------------------------------------
technique InstancedAnimation
{
	pass Pass0
	{
		VertexShader = compile vs_3_0 InstancedAnimationVertexMain();
		PixelShader = compile ps_3_0 BasicLightingFragmentMain();
		
		// Alpha blending
        AlphaBlendEnable = true; SrcBlend = SrcAlpha; DestBlend = InvSrcAlpha;
		FillMode = Solid;
	}
}

// Skinned Player Technique
//--------------------------------------------------------------------------------------------------
technique SkinnedPlayerShaderMain
{
	pass Pass0
	{		
		VertexShader = compile vs_3_0 SkinnedPlayerVertexMain();
		PixelShader = compile ps_3_0 BasicLightingFragmentMain();
		
		// 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 BasicLightingFragmentMain();
		
		// Alpha blending
        AlphaBlendEnable = true; SrcBlend = SrcAlpha; DestBlend = InvSrcAlpha;
		FillMode = Solid;
	}
}

//##################################################################################################
//-------------------------------------------- AI Vision -------------------------------------------
//##################################################################################################

float playerIndex;
float numberOfPlayers;

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

VertexOutput VS_AIVision(VertexInput IN, VertexOutput OUT)
{
	OUT.position = mul(IN.position, mul(World, ViewProj));
	OUT.worldPos = mul(IN.position, World).xyz;
	
	return OUT;
}

FragmentOutput FS_AIVisionPlayer(FragmentInput IN, FragmentOutput OUT)
{
	OUT.color = 1.0f;
	OUT.color.a = playerIndex;
	
	return OUT;
}

FragmentOutput FS_AIVisionTerrain(FragmentInput IN, FragmentOutput OUT)
{
	OUT.color = 0.0f;
	
	return OUT;
}

// Player Main
//--------------------------------------------------------------------------------------------------
VertexOutput AI_Vision_PlayerVertexMain(VertexInput VS_IN)
{
	VertexOutput VS_OUT = (VertexOutput)0;
	VS_IN = VS_Skin(VS_IN);
	VS_OUT = VS_AIVision(VS_IN, VS_OUT);

	return VS_OUT;
}

FragmentOutput AI_Vision_PlayerFragmentMain(FragmentInput FS_IN)
{
    FragmentOutput FS_OUT = (FragmentOutput)0;
	FS_DistanceAlphaClip(FS_IN);
 	FS_OUT = FS_AIVisionPlayer(FS_IN, FS_OUT);
	FS_OUT = FS_FogTransparency(FS_IN, FS_OUT);

	return FS_OUT;
}

// AI Vision Render Terrain Main
//--------------------------------------------------------------------------------------------------
VertexOutput AI_Vision_TerrainVertexMain(VertexInput VS_IN)
{
	VertexOutput VS_OUT =  (VertexOutput)0;
	VS_GenerateWorldMatrix(VS_IN);
	VS_IN = VS_TerrainLOD(VS_IN);
	VS_OUT = VS_AIVision(VS_IN, VS_OUT);

	return VS_OUT;
}

FragmentOutput AI_Vision_TerrainFragmentMain(FragmentInput FS_IN)
{
	FragmentOutput FS_OUT = (FragmentOutput)0;
	FS_DistanceAlphaClip(FS_IN);
	FS_OUT = FS_TerrainLOD(FS_IN, FS_OUT);
	FS_OUT = FS_AIVisionTerrain(FS_IN, FS_OUT);
	FS_OUT = FS_FogTransparency(FS_IN, FS_OUT);

	return FS_OUT;
}

// AI Vision - Player Technique
//--------------------------------------------------------------------------------------------------
technique AI_Vision_PlayerShaderMain
{
	pass Pass0
	{		
		VertexShader = compile vs_3_0 AI_Vision_PlayerVertexMain();
		PixelShader = compile ps_3_0 AI_Vision_PlayerFragmentMain();
		
		// Alpha blending
        AlphaBlendEnable = true; SrcBlend = SrcAlpha; DestBlend = InvSrcAlpha;
		FillMode = Solid;
	}
}

// AI Vision - Terrain Shader Technique
//--------------------------------------------------------------------------------------------------
technique AI_Vision_TerrainShaderMain
{
	pass Pass0
	{
		VertexShader  = compile vs_3_0 AI_Vision_TerrainVertexMain();
		PixelShader =  compile ps_3_0 AI_Vision_TerrainFragmentMain();
		
		// Alpha blending
        AlphaBlendEnable = true; SrcBlend = SrcAlpha; DestBlend = InvSrcAlpha;
		FillMode = Solid;
	}
}
";
        #endregion

        #region GPU Physics Source
        private string GPUPhysicsSource = @"
//===================================================================================================
// Uniform Variables
//===================================================================================================
float dt;

float4x4 ViewProj;
float4x4 World;
float4x4 WorldInverseTranspose;

float gpuObjectScale;
float gravity = 0.01f;

float scaleMinY;
float scaleRangeY;

float cpScaleMinY;
float cpScaleRangeY;

float2 playerPosition;

float invSpatMapHeight;
float invSpatMapWidth;

int IndexedPass;

float3 normalComponent;

float3 normalForce;

float3 mass1Velocity;
float3 mass1CurrentPosition;

float mass;

//===================================================================================================
// Object Properties
//===================================================================================================

//- LocationMap --
texture LocationMap; 
sampler LocationMapSampler = sampler_state 
{
	texture		= <LocationMap>; 
	AddressU	= CLAMP;	
	AddressV	= CLAMP;	
	AddressW	= CLAMP; 
	MIPFILTER	= POINT;	
	MINFILTER	= POINT;	
	MAGFILTER	= POINT;
};

//- TerrainHeightMap --
texture TerrainHeightMap;
sampler TerrainHeightMapSampler = sampler_state 
{
	texture		= <TerrainHeightMap>; 
	AddressU	= CLAMP;	
	AddressV	= CLAMP;	
	AddressW	= CLAMP; 
	MIPFILTER	= POINT;	
	MINFILTER	= POINT;	
	MAGFILTER	= POINT;
};

//- TerrainNormalMap --
texture TerrainNormalMap;
sampler TerrainNormalMapSampler = sampler_state 
{
	texture		= <TerrainNormalMap>; 
	AddressU	= CLAMP;	
	AddressV	= CLAMP;	
	AddressW	= CLAMP; 
	MIPFILTER	= POINT;	
	MINFILTER	= POINT;	
	MAGFILTER	= POINT;
};

//- Position --
texture CurrentPosition; 
sampler CurrentPositionSampler = sampler_state 
{
	texture		= <CurrentPosition>; 
	AddressU	= CLAMP;	
	AddressV	= CLAMP;	
	AddressW	= CLAMP; 
	MIPFILTER	= POINT;	
	MINFILTER	= POINT;	
	MAGFILTER	= POINT;
};

//- Rotation --
texture Rotation; 
sampler RotationSampler = sampler_state 
{
	texture		= <Rotation>; 
	AddressU	= CLAMP;	
	AddressV	= CLAMP;	
	AddressW	= CLAMP; 
	MIPFILTER	= POINT;	
	MINFILTER	= POINT;	
	MAGFILTER	= POINT;
};

//- Scale --
texture Scale; 
sampler ScaleSampler = sampler_state 
{
	texture		= <Scale>; 
	AddressU	= CLAMP;	
	AddressV	= CLAMP;	
	AddressW	= CLAMP; 
	MIPFILTER	= POINT;	
	MINFILTER	= POINT;	
	MAGFILTER	= POINT;
};

//- Mass --
texture Mass; 
sampler MassSampler = sampler_state 
{
	texture		= <Mass>;
	AddressU	= CLAMP;	
	AddressV	= CLAMP;	
	AddressW	= CLAMP; 
	MIPFILTER	= POINT;	
	MINFILTER	= POINT;	
	MAGFILTER	= POINT;
};

//- Velocity --
texture Velocity; 
sampler VelocitySampler = sampler_state 
{
	texture		= <Velocity>;
	AddressU	= CLAMP;	
	AddressV	= CLAMP;	
	AddressW	= CLAMP; 
	MIPFILTER	= POINT;	
	MINFILTER	= POINT;	
	MAGFILTER	= POINT;
};

//- Acceleration --
texture Acceleration; 
sampler AccelerationSampler = sampler_state 
{
	texture		= <Acceleration>; 
	AddressU	= CLAMP;	
	AddressV	= CLAMP;	
	AddressW	= CLAMP; 
	MIPFILTER	= POINT;	
	MINFILTER	= POINT;	
	MAGFILTER	= POINT;
};

//- LastPosition --
texture LastPosition; 
sampler LastPositionSampler = sampler_state 
{
	texture		= <LastPosition>;
	AddressU	= CLAMP;	
	AddressV	= CLAMP;	
	AddressW	= CLAMP; 
	MIPFILTER	= POINT;	
	MINFILTER	= POINT;	
	MAGFILTER	= POINT;
};

//- TotalForce --
texture TotalForce; 
sampler TotalForceSampler = sampler_state 
{
	texture		= <TotalForce>; 
	AddressU	= CLAMP;	
	AddressV	= CLAMP;	
	AddressW	= CLAMP; 
	MIPFILTER	= POINT;	
	MINFILTER	= POINT;	
	MAGFILTER	= POINT;
};

//- WindMap --
texture WindMap; 
sampler WindMapSampler = sampler_state 
{
	texture		= <WindMap>; 
	AddressU	= CLAMP;	
	AddressV	= CLAMP;	
	AddressW	= CLAMP; 
	MIPFILTER	= POINT;	
	MINFILTER	= POINT;	
	MAGFILTER	= POINT;
};

//- Radius --
texture Radius; 
sampler RadiusSampler = sampler_state 
{
	texture		= <Radius>; 
	AddressU	= CLAMP;	
	AddressV	= CLAMP;	
	AddressW	= CLAMP; 
	MIPFILTER	= POINT;	
	MINFILTER	= POINT;	
	MAGFILTER	= POINT;
};

//- Dummy --
texture Dummy; 
sampler DummySampler = sampler_state 
{
	texture		= <Dummy>; 
	AddressU	= CLAMP;	
	AddressV	= CLAMP;	
	AddressW	= CLAMP; 
	MIPFILTER	= POINT;	
	MINFILTER	= POINT;	
	MAGFILTER	= POINT;
};


//===================================================================================================
// Uniform, Varying, and FrameBuffer Stream Structures - 
// Used to Communicate between CPU, VertexProcessor, FragmentProcessor, and FrameBuffer
//===================================================================================================
struct VertexInput 
{
    float4	position				: POSITION0;		// Position

    float4	texCoord				: TEXCOORD0;		// Texture coordinates
};

struct VertexOutput
{
	// These values are used directly by the rasterizer
	float4	position				: POSITION; 		// Position

	// These values are interpolated and sent to FragIn
	float4	color					: COLOR0; 			// Color (example: COLOR0)
	float4	texCoord				: TEXCOORD0; 		// Texture coordinates (example: TEXCOORD0)
};

struct FragmentInput
{
	float4	color					: COLOR0; 			// Color (example: COLOR0)
    float4	texCoord				: TEXCOORD0;		// Texture coordinates 
};

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

//===================================================================================================
// Utility Functions
//===================================================================================================

// Gets Indexed Coordinates from an objects Spatial Position Data
float4 GetIndexedPosition(float2 spatialPosition)
{
    return tex2D(LocationMapSampler, spatialPosition);   
}

// Gets Spatial Coordinates from an objects Indexed Position Data
float4 GetSpatialPosition(float2 indexedPosition)
{
    return tex2D(CurrentPositionSampler, indexedPosition);
}

float GetUnscaledHeight(float2 texCoord)
{
	float2 hackTexCoords;
	
	hackTexCoords.xy = texCoord.yx;
	
	float height = tex2D(TerrainHeightMapSampler, hackTexCoords).g * 3.0f;
	height += tex2D(TerrainHeightMapSampler, float2(hackTexCoords.x-invSpatMapWidth, hackTexCoords.y+invSpatMapWidth)).g;
	height += tex2D(TerrainHeightMapSampler, float2(hackTexCoords.x+invSpatMapWidth, hackTexCoords.y+invSpatMapWidth)).g;
	height += tex2D(TerrainHeightMapSampler, float2(hackTexCoords.x-invSpatMapWidth, hackTexCoords.y-invSpatMapWidth)).g;
	height += tex2D(TerrainHeightMapSampler, float2(hackTexCoords.x+invSpatMapWidth, hackTexCoords.y-invSpatMapWidth)).g;
	height = (height) / 7.0f;
	
	height = (height * scaleRangeY) + scaleMinY;
	height = (height) / cpScaleRangeY;
		
	return height;
}

void CalculateVectorComponents(float3 referenceNormal, float3 objectVelocity)
{
	if( length(objectVelocity) >= 0.01f && !isinf(length(objectVelocity)) )
	{
		normalComponent = dot(objectVelocity, referenceNormal) * referenceNormal;
	}
	else
	{
		normalComponent = (float3) 0.0f;
	}
}

void CalculateNormalForces(float mass2, float3 normalVelocity1, float3 normalVelocity2, float COR)
{
	float3 resultantVelocity1, resultantVelocity2;
	float3 eV1MinusV2, m1V1PlusM2V2;
	float totalMass = mass + mass2;
	//float totalMass = 2.0f * mass;

	eV1MinusV2 = COR * (normalVelocity1 - normalVelocity2);

	m1V1PlusM2V2 = (mass * normalVelocity1) + (mass2 * normalVelocity2);

	resultantVelocity1 = (m1V1PlusM2V2 - (mass2 * eV1MinusV2)) / totalMass;

	normalForce = resultantVelocity1 * mass / dt;
}

float3 GetVelocity(float2 texCoord)
{	
	return tex2D(VelocitySampler, tex2D(LocationMapSampler, texCoord).xy);
}

float4 GetPosition(float2 texCoord)
{
	return tex2D(CurrentPositionSampler, tex2D(LocationMapSampler, texCoord).xy);
}

float GetMass(float2 texCoord)
{	
	return tex2D(MassSampler, tex2D(LocationMapSampler, texCoord).xy).x;
}

//===================================================================================================
// Indexed Functions
//===================================================================================================

void FS_Dummy(inout FragmentInput IN, inout FragmentOutput OUT)
{
	//--- HACK : READ BELOW ----
	// This function exists b/c the our multipass sequence must be null-terminated...
	// Because of something with xna, or dx, or my code.. the last Render To Texture in a sequence will sometimes come out black.   
	// So we make a extra trivial pass so the graphics card has a chance to finalize the previous texture.
	
	OUT.color = tex2D(DummySampler, IN.texCoord);
}

//===================================================================================================
// Collision Detection
//===================================================================================================

// HACK - Assuming that all gpuObjects have the same Mass.mass values
float4 ObjObjCollision(float mass2, float3 mass2Velocity, float4 mass2CurrentPosition)
{
	float3 object1NormalVelocity;
	float3 object2NormalVelocity;
	
	float3 normalVectorOfImpact;
	float3 zeroVector = (float3) 0.0f;
	
	if(mass2CurrentPosition.a == 1.0f)
	{
		normalVectorOfImpact = mass2CurrentPosition - mass1CurrentPosition;
		
		// HACK - This condition needs to be put back in when we start using more than one spatmap
		//if (distance(normalVectorOfImpact, zeroVector) != 0.0f)
		//{
			normalize(normalVectorOfImpact);
		//}

		// Calculate Mass1's normal velocity component
		CalculateVectorComponents(normalVectorOfImpact, mass1Velocity);
		object1NormalVelocity = normalComponent;

		// Calculate Mass2's normal velocity component
		CalculateVectorComponents(normalVectorOfImpact, mass2Velocity);
		object2NormalVelocity = normalComponent;

		normalForce = (float3) 0.0f;
		if (length(mass1Velocity) > length(mass2Velocity))
		{
			// Ensure that mass1's velocity is not equal to 0
			if (length(mass1Velocity) != 0.0f)
			{
				// Check that the velocity is not moving away from the impact, ie, the angle between velocity
				// and impact vector is between 90->0->270. If so the two objects are moving away from each
				// other, so return.
				if (dot(mass1Velocity, normalVectorOfImpact) / length(mass1Velocity) > 0.0f)
				{
					CalculateNormalForces(mass2, object1NormalVelocity, object2NormalVelocity, 1.0f);
				}
			}
		}
		else
		{
			// Ensure that mass2's velocity is not equal to 0
			if (length(mass2Velocity) != 0.0f)
			{
				// Check that the velocity is not moving away from the impact, ie, the angle between velocity
				// and impact vector is between 90->180->270. If so the two objects are moving away from each
				// other, so return.
				if (dot(mass2Velocity, normalVectorOfImpact) / length(mass2Velocity) < 0.0f)
				{
					CalculateNormalForces(mass2, object1NormalVelocity, object2NormalVelocity, 1.0f);
				}
			}
		}
	}

	return (float4)(normalForce, 0.0f);
}

float4 GetForce(float2 spatialPosition)
{	
    // Get Indexed Position of Object from SpatialPosition
    float4 ip = tex2D(LocationMapSampler, spatialPosition);   

	// If object exists return it's force
	if(ip.a > 0.0f)
	{
	    float4 v = tex2D(VelocitySampler, ip.xy);   
		float4 m = tex2D(MassSampler, ip.xy);   

		// Low-pass filter * velocity * mass (only stored in r channel)
	    return v * (float4)m.r;
	}
	else{
		return (float4)0.0f;
	}
}

void FS_TotalForce(inout FragmentInput IN, inout FragmentOutput OUT)
{   
    // Indexed CurrentPosition holds the object's Spatial Location
    float4 spatialPosition = tex2D(CurrentPositionSampler, IN.texCoord);
	
	//if(true)
	if(spatialPosition.a == 1.0f)
	{
	/*
		// Get any surrounding objects, and apply resultant force    
		float4 sumForces = (float4)0.0f;  
		      
		sumForces += GetForce( float2(1 - spatialPosition.x - invSpatMapWidth	, spatialPosition.z - invSpatMapHeight) );
		sumForces += GetForce( float2(1 - spatialPosition.x - invSpatMapWidth	, spatialPosition.z					  ) );
		sumForces += GetForce( float2(1 - spatialPosition.x - invSpatMapWidth	, spatialPosition.z + invSpatMapHeight) );
		sumForces += GetForce( float2(1 - spatialPosition.x						, spatialPosition.z - invSpatMapHeight) );
		sumForces += GetForce( float2(1 - spatialPosition.x						, spatialPosition.z + invSpatMapHeight) );
		sumForces += GetForce( float2(1 - spatialPosition.x + invSpatMapWidth	, spatialPosition.z - invSpatMapHeight) );
		sumForces += GetForce( float2(1 - spatialPosition.x + invSpatMapWidth	, spatialPosition.z					  ) );
		sumForces += GetForce( float2(1 - spatialPosition.x + invSpatMapWidth	, spatialPosition.z + invSpatMapHeight) );
		OUT.color = sumForces / 8.0f;
	*/
			
		mass1Velocity = tex2D(VelocitySampler, IN.texCoord);
		mass1CurrentPosition = spatialPosition;
		mass = tex2D(MassSampler, IN.texCoord).x;
		
		// Get any surrounding objects, and apply resultant force    
		float4 sumForces = (float4)0.0f;  

		float2 currentNeighbor;
		currentNeighbor = float2(1 - spatialPosition.x - invSpatMapWidth	, spatialPosition.z - invSpatMapHeight);
		sumForces += ObjObjCollision(GetMass(currentNeighbor), GetVelocity(currentNeighbor), GetPosition(currentNeighbor));
		
		currentNeighbor = float2(1 - spatialPosition.x - invSpatMapWidth	, spatialPosition.z					  );
		sumForces += ObjObjCollision(GetMass(currentNeighbor), GetVelocity(currentNeighbor), GetPosition(currentNeighbor));
		
		currentNeighbor = float2(1 - spatialPosition.x - invSpatMapWidth	, spatialPosition.z + invSpatMapHeight);
		sumForces += ObjObjCollision(GetMass(currentNeighbor), GetVelocity(currentNeighbor), GetPosition(currentNeighbor));
		
		currentNeighbor = float2(1 - spatialPosition.x						, spatialPosition.z - invSpatMapHeight);
		sumForces += ObjObjCollision(GetMass(currentNeighbor), GetVelocity(currentNeighbor), GetPosition(currentNeighbor));
		
		currentNeighbor = float2(1 - spatialPosition.x						, spatialPosition.z + invSpatMapHeight);
		sumForces += ObjObjCollision(GetMass(currentNeighbor), GetVelocity(currentNeighbor), GetPosition(currentNeighbor));
		
		currentNeighbor = float2(1 - spatialPosition.x + invSpatMapWidth	, spatialPosition.z - invSpatMapHeight);
		sumForces += ObjObjCollision(GetMass(currentNeighbor), GetVelocity(currentNeighbor), GetPosition(currentNeighbor));
		
		currentNeighbor = float2(1 - spatialPosition.x + invSpatMapWidth	, spatialPosition.z					  );
		sumForces += ObjObjCollision(GetMass(currentNeighbor), GetVelocity(currentNeighbor), GetPosition(currentNeighbor));
		
		currentNeighbor = float2(1 - spatialPosition.x + invSpatMapWidth	, spatialPosition.z + invSpatMapHeight);
		sumForces += ObjObjCollision(GetMass(currentNeighbor), GetVelocity(currentNeighbor), GetPosition(currentNeighbor));
		
		OUT.color = sumForces;

		// Wind Force (Scale to match lastForce value)
		float4 windForce = tex2D(WindMapSampler, spatialPosition.xz);	// Get wind force from map
		windForce = (windForce - 0.5f) / 100000.0f;						
		
		// Get Last TotalForce (removing gravity component)
		float4 lastForce = tex2D(TotalForceSampler, IN.texCoord);
		lastForce.g += .00065f;		
		    
		// Resultant wind force = windFriction - windForce;
		OUT.color += (.25f * lastForce- windForce);
		    
		// Add Gravity
		OUT.color.g -= .00065f;
	    
		// ------------ Start Object Reflex --------------	
		// Object distance below terrain (positive if below terrain).
		float objectReflexHeight = GetUnscaledHeight(OUT.color.xz) - OUT.color.g; 
	    
		//-- Reset Object Position To Terrain Height
		if( objectReflexHeight > 000.0f )
		{
			// Add difference to object's height value
			//OUT.color.g += .0012f;
			//OUT.color.r = -OUT.color.r;
			//OUT.color.b = -OUT.color.b; 
		}      	
		// ------------ End Object Reflex --------------		     

		OUT.color.a = 1.0f;
	}
	else
	{
		clip(-1.0f);
	}
}

//===================================================================================================
// Physics
//===================================================================================================
//--- Equation: acceleration = totalForce / mass;
void FS_Acceleration(inout FragmentInput IN, inout FragmentOutput OUT)
{
    float4 tf = tex2D(TotalForceSampler, IN.texCoord);
    float4 m = tex2D(MassSampler, IN.texCoord);

	if(tf.a == 1.0f)
	{
		OUT.color.r = tf.r/m.r; 
		OUT.color.g = tf.g/m.r; 
		OUT.color.b = tf.b/m.r; 
		OUT.color.a = 1.0f; 
	}
	else
	{
		clip(-1.0f);
	}
}


//--- Equation: velocity += acceleration * dt;
void FS_Velocity(inout FragmentInput IN, inout FragmentOutput OUT)
{
    float4 a = tex2D(AccelerationSampler, IN.texCoord);
    float4 v0 = tex2D(VelocitySampler, IN.texCoord);

	if(v0.a == 1.0f)
	{
		// v = v0 + at
		OUT.color = v0 + a * dt; 
		OUT.color.a = 1.0f;
	}
	else
	{
		clip(-1.0f);
	}
}


//--- Equation: angular momentum
void FS_Rotation(inout FragmentInput IN, inout FragmentOutput OUT)
{
    OUT.color = tex2D(RotationSampler, IN.texCoord);
}

//--- Equation: currentPosition = lastPosition + velocity * dt + (0.5f * acceleration * dt * dt);
void FS_CurrentPosition(inout FragmentInput IN, inout FragmentOutput OUT)
{
	// Get Parameters    
    float4 lp = tex2D(CurrentPositionSampler, IN.texCoord);
    float4 v = tex2D(VelocitySampler, IN.texCoord);
    float4 a = tex2D(AccelerationSampler, IN.texCoord); 
    
    if(lp.a == 1.0f)
    {
		// Calc new position using standard physics
		OUT.color = lp + v*dt + (0.5f * a * dt*dt);
		OUT.color.a = 1.0f;

		// Bounding for TerrainMap Positions (ENTIRE BOARD)
		float xmin = 0.0f;
		float xmax = 1.0f;	
		float ymax = 1.0f;
		float zmin = 0.0f;
		float zmax = 1.0f;

		// ------------ Start Object Recycler --------------	
		// Axis Mins to Maxs
		if(OUT.color.x < xmin){ OUT.color.x = xmax; }
		if(OUT.color.z < zmin){ OUT.color.z = zmax; }
		
		// Axis Maxs to Mins
		if(OUT.color.x > xmax){ OUT.color.x = xmin; }
		if(OUT.color.y > ymax){ OUT.color.y = -1.0f; }
		if(OUT.color.z > zmax){ OUT.color.z = zmin; }
		// ------------ End Object Recycler --------------
		
		
		// ------------ Start Object/Terrain Reset --------------	
		// Object distance below terrain (positive if below terrain).
		float objectResetHeight = GetUnscaledHeight(OUT.color.xz) - OUT.color.g; 
	    
		// If object below terrain, to terrain height
		if( objectResetHeight > 0.0f )
		{
			// Add difference to object's height value
			OUT.color.g += objectResetHeight; 
		}      	
		// ------------ End Object/Terrain Reset --------------		
	}
	else
	{
		clip(-1.0f);
	}
}

//--- Trivial vertex shader for Indexed Fragment Shaders
void VS_Indexed(inout VertexInput IN, inout VertexOutput OUT)
{
    // Copy OUT to IN
    OUT.position = mul(IN.position, ViewProj);
    OUT.texCoord = IN.texCoord;
}



//==================================================================================================
// Spatial Function
// Using a Quad of Verts mapped to the CurrentPosition indexed map,
// relocate each vert to it's spatial position and render to LocationMap
//==================================================================================================
void FS_Spatial(inout FragmentInput IN, inout FragmentOutput OUT)
{    
	clip(IN.texCoord);
    OUT.color = IN.color;
}

void VS_Spatial(inout VertexInput IN, inout VertexOutput OUT)
{	    
    // Set Vertex Position to the location stored in Position Indexed Map
    OUT.position = tex2Dlod(CurrentPositionSampler, float4(IN.position.x, IN.position.y, 0, 0));    // IN.position;
    if(OUT.position.a == 1.0f)
    {
		OUT.position.g = OUT.position.b;
		OUT.position.b = 0.0f;
	    
		OUT.position = mul(OUT.position, ViewProj);

		// Pack data into pixel values
		OUT.color.rg = IN.texCoord.xy;          // Pointer to Indexed Object
		OUT.color.b = 0.0f;						// Empty
		OUT.color.a = 1.0f;                     // isObject Flag - marks object as active

		//HACK FOR VISIBILITY
		//OUT.color.r = 1.0f;

		// Pass texCoords along
		OUT.texCoord = IN.position;
    }
    else
    {
		OUT.position = (float4) -1.0f;
		OUT.texCoord = -1.0f;
    }
}


//===================================================================================================
// Mains and Techniques
//===================================================================================================

// Indexed Mains
//--------------------------------------------------------------------------------------------------
//--- Indexed Vertex Shaders
VertexOutput IndexedVertexMain(VertexInput VS_IN)
{
	VertexOutput VS_OUT = (VertexOutput)0;
	VS_Indexed(VS_IN, VS_OUT);
	return VS_OUT;
}

//--- Indexed Fragment Shaders
FragmentOutput TotalForceFragmentMain(FragmentInput FS_IN)
{
    FragmentOutput FS_OUT = (FragmentOutput)0;
    FS_TotalForce(FS_IN, FS_OUT);        
	return FS_OUT;
}
FragmentOutput AccelerationFragmentMain(FragmentInput FS_IN)
{
    FragmentOutput FS_OUT = (FragmentOutput)0;
    FS_Acceleration(FS_IN, FS_OUT);            
	return FS_OUT;
}
FragmentOutput VelocityFragmentMain(FragmentInput FS_IN)
{
    FragmentOutput FS_OUT = (FragmentOutput)0;
    FS_Velocity(FS_IN, FS_OUT);        
	return FS_OUT;
}
FragmentOutput RotationFragmentMain(FragmentInput FS_IN)
{
    FragmentOutput FS_OUT = (FragmentOutput)0;
    FS_Rotation(FS_IN, FS_OUT);            
	return FS_OUT;
}
FragmentOutput CurrentPositionFragmentMain(FragmentInput FS_IN)
{
    FragmentOutput FS_OUT = (FragmentOutput)0;
    FS_CurrentPosition(FS_IN, FS_OUT);            
	return FS_OUT;
}
FragmentOutput DummyFragmentMain(FragmentInput FS_IN)
{
    FragmentOutput FS_OUT = (FragmentOutput)0;
    FS_Dummy(FS_IN, FS_OUT);            
	return FS_OUT;
}

// Indexed Techniques
//--------------------------------------------------------------------------------------------------
technique TotalForce
{
    pass Pass0
    {
        VertexShader = compile vs_3_0 IndexedVertexMain();
        PixelShader = compile ps_3_0 TotalForceFragmentMain();        
        AlphaBlendEnable = true; SrcBlend = SrcAlpha; DestBlend = InvSrcAlpha;
		FillMode = Solid;
    }
}
technique Acceleration
{
    pass Pass0
    {
        VertexShader = compile vs_3_0 IndexedVertexMain();
        PixelShader = compile ps_3_0 AccelerationFragmentMain();        
        AlphaBlendEnable = true; SrcBlend = SrcAlpha; DestBlend = InvSrcAlpha;
		FillMode = Solid;
    }
}
technique Velocity
{
    pass Pass0
    {
        VertexShader = compile vs_3_0 IndexedVertexMain();
        PixelShader = compile ps_3_0 VelocityFragmentMain();        
        AlphaBlendEnable = true; SrcBlend = SrcAlpha; DestBlend = InvSrcAlpha;
		FillMode = Solid;
    }
}
technique Rotation
{
    pass Pass0
    {
        VertexShader = compile vs_3_0 IndexedVertexMain();
        PixelShader = compile ps_3_0 RotationFragmentMain();        
        AlphaBlendEnable = true; SrcBlend = SrcAlpha; DestBlend = InvSrcAlpha;
		FillMode = Solid;
    }
}
technique CurrentPosition
{
    pass Pass0
    {
        VertexShader = compile vs_3_0 IndexedVertexMain();
        PixelShader = compile ps_3_0 CurrentPositionFragmentMain();        
        AlphaBlendEnable = true; SrcBlend = SrcAlpha; DestBlend = InvSrcAlpha;
		FillMode = Solid;
    }
}
technique Dummy
{
    pass Pass0
    {
        VertexShader = compile vs_3_0 IndexedVertexMain();
        PixelShader = compile ps_3_0 DummyFragmentMain();        
        AlphaBlendEnable = true; SrcBlend = SrcAlpha; DestBlend = InvSrcAlpha;
		FillMode = Solid;
    }
}


// Spatial Mains
//--------------------------------------------------------------------------------------------------
VertexOutput SpatialVertexMain(VertexInput VS_IN)
{
	VertexOutput VS_OUT = (VertexOutput)0;
	VS_Spatial(VS_IN, VS_OUT);
	return VS_OUT;
}
FragmentOutput SpatialFragmentMain(FragmentInput FS_IN)
{
    FragmentOutput FS_OUT = (FragmentOutput)0;
	FS_Spatial(FS_IN, FS_OUT);
	return FS_OUT;
}


// SpatialMapping Techniques
//--------------------------------------------------------------------------------------------------
technique SpatialMain
{
    pass Pass0
    {
        VertexShader = compile vs_3_0 SpatialVertexMain();
        PixelShader = compile ps_3_0 SpatialFragmentMain();
        
        AlphaBlendEnable = true; SrcBlend = SrcAlpha; DestBlend = InvSrcAlpha;
		FillMode = Solid;
    }
}
";
        #endregion

        #region Terrain Normal generation Source
        private string TerrainNormalSource = @"
//===================================================================================================
// Uniform Variables
//===================================================================================================
float4x4 ViewProj;
float4x4 World;
float invMapWidth;
float terrainHeightScale;
float terrainScaleMinY;

float3 positionXZ, positionX1Z, positionXZ1, positionX1Z1;
float2 texCoordX1Z, texCoordXZ1, texCoordX1Z1;
float3 edge1, edge2, normal;

//- heightMapTexture --
texture heightMapTexture;
sampler heightMapTextureSampler = sampler_state 
{
	texture		= <heightMapTexture>; 
	AddressU	= MIRROR;	
	AddressV	= MIRROR;	
	AddressW	= MIRROR; 
	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
    float4	texCoord				: TEXCOORD0;		// Texture coordinates
};

struct VertexOutput
{
	// These values are used directly by the rasterizer
	float4	position				: POSITION; 		// Position
	float4	texCoord				: TEXCOORD0; 		// Texture coordinates (example: TEXCOORD0)
};

struct FragmentInput
{
	float4	color					: COLOR0; 			// Color (example: COLOR0)
    float4	texCoord				: TEXCOORD0;		// Texture coordinates 
};

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

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

// Helper functions
//--------------------------------------------------------------------------------------------------

float GetTerrainHeight(float2 texCoord)
{
	return (tex2D(heightMapTextureSampler, texCoord).r);
}

// Generate Terrain Normals Main
//--------------------------------------------------------------------------------------------------
VertexOutput VS_GenerateTerrainNormals(VertexInput IN)
{
	VertexOutput OUT = (VertexOutput)0;
	
	OUT.position = mul(IN.position, mul(World, ViewProj));
    OUT.texCoord = IN.texCoord;

	return OUT;
}

FragmentOutput FS_GenerateTerrainNormals(FragmentInput IN)
{
	FragmentOutput OUT = (FragmentOutput)0;
		
	// Set up the texture coordinates needed
	texCoordX1Z = float2(IN.texCoord.x + invMapWidth, IN.texCoord.y);
	texCoordXZ1 = float2(IN.texCoord.x, IN.texCoord.y + invMapWidth);
	texCoordX1Z1 = float2(IN.texCoord.x + invMapWidth, IN.texCoord.y + invMapWidth);
	
	// Set up the necessary position vectors
	positionXZ = float3(	IN.texCoord.x,	GetTerrainHeight(IN.texCoord.xy),	IN.texCoord.y);
	positionX1Z = float3(	texCoordX1Z.x,	GetTerrainHeight(texCoordX1Z),		texCoordX1Z.y);
	positionXZ1 = float3(	texCoordXZ1.x,	GetTerrainHeight(texCoordXZ1),		texCoordXZ1.y);
	positionX1Z1 = float3(	texCoordX1Z1.x,	GetTerrainHeight(texCoordX1Z1),		texCoordX1Z1.y);
	
	// Calculate edge vectors for first triangle on this fragment
	edge1 = positionXZ1 - positionXZ;
	edge2 = positionXZ - positionX1Z1;
	
	// Calculate the normal based on these two edges
	normal = cross(edge2, edge1);
	OUT.color.xyz = normal;
	
	// Calculate edge vectors for the second triangle on this fragment
	edge1 = positionXZ - positionX1Z;
	edge2 = positionX1Z - positionX1Z1;
	
	// Calculate the normal based on the two new edges
	normal = cross(edge2, edge1);
	OUT.color.xyz += normal;
	
	// Normalize and then save normal data to texture
	OUT.color.xyz = normalize(OUT.color.zyx);
	OUT.color.a = 1.0f;
	
	return OUT;
}

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

// Generate Terrain Normals technique
//--------------------------------------------------------------------------------------------------
technique GenerateTerrainNormals
{
	pass Pass0
	{
		VertexShader  = compile vs_3_0 VS_GenerateTerrainNormals();
		PixelShader =  compile ps_3_0 FS_GenerateTerrainNormals();
		
		// Alpha blending
        AlphaBlendEnable = true; SrcBlend = SrcAlpha; DestBlend = InvSrcAlpha;
		FillMode = Solid;
	}
}
";
        #endregion

        /// <summary>
        /// Constructor
        /// </summary>
        public FXSourceCode() { }

        /// <summary>
        /// Load compiled AI Vision Source
        /// </summary>
        /// <returns>Effect generated from source</returns>
        public Effect LoadAIVisionFX()
        {
            CompiledEffect shader = Effect.CompileEffectFromSource(AIVisionSource,
                                                                   null,
                                                                   null,
                                                                   CompilerOptions.None,
                                                                   TargetPlatform.Windows);

            if (shader.Success)
            {
                return new Effect(Statics_Stream.RenderSettings.graphics.GraphicsDevice,
                                  shader.GetEffectCode(),
                                  CompilerOptions.None,
                                  null);
            }
            else
            {
                throw new Exception("Missing Shader Code");
            }
        }

        /// <summary>
        /// Load compiled Elemental GPU Source
        /// </summary>
        /// <returns>Effect generated from source</returns>
        public Effect LoadElementalGPUFX()
        {
            CompiledEffect shader = Effect.CompileEffectFromSource(ElementalGPUSource,
                                                                   null,
                                                                   null,
                                                                   CompilerOptions.None,
                                                                   TargetPlatform.Windows);

            if (shader.Success)
            {
                return new Effect(Statics_Stream.RenderSettings.graphics.GraphicsDevice,
                                  shader.GetEffectCode(),
                                  CompilerOptions.Debug,
                                  null);
            }
            else
            {
                throw new Exception("Missing Shader Code");
            }
        }

        /// <summary>
        /// Load compiled GPUPhysics Source
        /// </summary>
        /// <returns>Effect generated from source</returns>
        public Effect LoadGPUPhysicsFX()
        {
            CompiledEffect shader = Effect.CompileEffectFromSource(GPUPhysicsSource,
                                                                   null,
                                                                   null,
                                                                   CompilerOptions.None,
                                                                   TargetPlatform.Windows);

            if (shader.Success)
            {
                return new Effect(Statics_Stream.RenderSettings.graphics.GraphicsDevice,
                                  shader.GetEffectCode(),
                                  CompilerOptions.None,
                                  null);
            }
            else
            {
                throw new Exception("Missing Shader Code");
            }
        }

        /// <summary>
        /// Load compiled Terrain Normal Source
        /// </summary>
        /// <returns>Effect generated from source</returns>
        public Effect LoadTerrainNormalsFX()
        {
            CompiledEffect shader = Effect.CompileEffectFromSource(TerrainNormalSource,
                                                                   null,
                                                                   null,
                                                                   CompilerOptions.None,
                                                                   TargetPlatform.Windows);

            if (shader.Success)
            {
                return new Effect(Statics_Stream.RenderSettings.graphics.GraphicsDevice,
                                  shader.GetEffectCode(),
                                  CompilerOptions.None,
                                  null);
            }
            else
            {
                throw new Exception("Missing Shader Code");
            }
        }
    }
}