cbuffer cbPerFrame
{
	float gFogRadius;
	float2 gPlayerPos;
	bool gGlowTexIsActive;
};

cbuffer cbPerObject
{
	float4x4 gWorld;
	float4x4 gWorldViewProj;

	int gKeyframeIndices[4];
	int gNrOfKeyframes[4];

	bool gTopLayerCanGlow;
	bool gObjectUnaffectedByFog;
};

Texture2D gBottomLayerTex;
Texture2D gMiddleLowLayerTex;
Texture2D gMiddleHighLayerTex;
Texture2D gTopLayerTex;

SamplerState samAnisotropic
{
	Filter = ANISOTROPIC;
	MaxAnisotropy = 4;

	AddressU = CLAMP;
	AddressV = CLAMP;
};

struct VertexIn
{
	float3 PosL		: POSITION;
	float2 Tex		: TEXCOORD;
};

struct VertexOut
{
	float4 PosH		: SV_POSITION;
	float3 PosW		: POSITION;
	float2 Tex		: TEXCOORD;
};

DepthStencilState DisableDepth
{
    DepthEnable = FALSE;
    //DepthWriteMask = ALL;
    //DepthFunc = LESS_EQUAL;
};

RasterizerState rs
{
	FillMode = Solid;
	CullMode = Back;
};

VertexOut VS( VertexIn vIn )
{
	VertexOut vOut;

	// Transform to world space.
	vOut.PosW		= mul( float4( vIn.PosL, 1.0f ), gWorld ).xyz;

	// Transform to homogenous clip space.
	vOut.PosH		= mul( float4( vIn.PosL, 1.0f ), gWorldViewProj );

	vOut.Tex = vIn.Tex;

	return vOut;
}

float4 PS( VertexOut pIn ) : SV_Target
{
	// ************** THREE REGULAR TEXTURE LAYERS SAMPLING *********************************
	// **************************************************************************************

	// Red error-ish colors as standard.
	float4 texColor = float4( 1.0f, 0.0f, 0.0f, 1.0f  );
	float4 tempColor = float4( 1.0f, 0.0f, 0.0f, 1.0f  );

	// Texture layers will be sampled if their nrOfKeyframes value is > 0. 
	// If it's not, there is no bound texture to the layer and their initiated value of -1 has not been overwritten. 

	// Always sample from bottom layer if there is a texture for it. 
	if( gNrOfKeyframes[0] > 0 )
	{
		uint width, height;
		gBottomLayerTex.GetDimensions( width, height );

		// Get how far we have to step, in the range 0-1, for the active keyframe.
		float texStep = ( width / gNrOfKeyframes[0] );
		texStep = texStep / width;

		// Get the start position, in 0-1 range, of the active keyframe.
		float startPos = gKeyframeIndices[0] * texStep;

		float2 tempTex = pIn.Tex;
		tempTex.x = startPos + (pIn.Tex.x * texStep );

		// Sample texture
		texColor = gBottomLayerTex.Sample( samAnisotropic, tempTex );
	}

	// Sample from the next layer if there is a texture and the alpha value > 0.01f.
	if( gNrOfKeyframes[1] > 0 )
	{
		uint width, height;
		gMiddleLowLayerTex.GetDimensions( width, height );

		float texStep = ( width / gNrOfKeyframes[1] );
		texStep = texStep / width;

		float startPos = gKeyframeIndices[1] * texStep;

		float2 tempTex = pIn.Tex;
		tempTex.x = startPos + (pIn.Tex.x * texStep );

		// Sample texture
		tempColor = gMiddleLowLayerTex.Sample( samAnisotropic, tempTex );

		// Only set active texel color if alpha is not zero.
		if( tempColor.a > 0.01f )
		{
			texColor = tempColor;
		}
	}

	// Sample from the next layer if there is a texture and the alphavalue > 0.01f.
	if( gNrOfKeyframes[2] > 0 )
	{
		uint width, height;
		gMiddleHighLayerTex.GetDimensions( width, height );

		float texStep = ( width / gNrOfKeyframes[2] );
		texStep = texStep / width;

		float startPos = gKeyframeIndices[2] * texStep;

		float2 tempTex = pIn.Tex;
		tempTex.x = startPos + (pIn.Tex.x * texStep );

		// Sample texture
		tempColor = gMiddleHighLayerTex.Sample( samAnisotropic, tempTex );

		// Only set active texel color if alpha is not zero.
		if( tempColor.a > 0.01f )
		{
			texColor = tempColor;
		}
	}

	// Sample from the fourth layer now if it is not a glowing one. Else wait until AFTER the fog has been added.
	// Sample from this layer here if the object is unaffected by fog.
	if( gNrOfKeyframes[3] > 0 && ( !gTopLayerCanGlow || gObjectUnaffectedByFog ) )
	{
		uint width, height;
		gTopLayerTex.GetDimensions( width, height );

		float texStep = ( width / gNrOfKeyframes[3] );
		texStep = texStep / width;

		float startPos = gKeyframeIndices[3] * texStep;

		float2 tempTex = pIn.Tex;
		tempTex.x = startPos + (pIn.Tex.x * texStep );

		// Sample texture
		tempColor = gTopLayerTex.Sample( samAnisotropic, tempTex );

		// Only set active texel color if alpha is not zero.
		if( tempColor.a > 0.01f )
		{
			texColor = tempColor;
		}
	}
	// **************************************************************************************
	// **************************************************************************************


	// ************** FOG AND GLOW TEXTURE LAYER SAMPLING ***********************************
	// **************************************************************************************

	// Run no fog calculations at all if the object is set to always glow.
	if( !gObjectUnaffectedByFog )
	{
		// Check if the texel should be affected by fog.
		float vecLength = length( pIn.PosW.xy - ( gPlayerPos.xy + float2( 0.5f, 0.5f ) ) );

		float4 fogColor = float4( 0.0f, 0.0f, 0.0f, 1.0f );

		//float fogFactor = 1.0f;

		// If the texel is between the player and the fogradius, apply a gradient.
		if( vecLength < gFogRadius )
		{
			// ------ Exponential fog. ------------------------------------------	
			float fogFactor = 1.0f / ( exp( pow( vecLength * (( vecLength / gFogRadius ) + 0.1f ), 2 ) ) );

			//C = f * Ci + (1-f) * Cf
			texColor.xyz = fogFactor * texColor.xyz + ( 1.0f - fogFactor ) * float3( 0.0f, 0.0f, 0.0f );
		}
	
		// If the texel is outside of the fogradius, set it to the fogcolor.
		else
		{
			texColor = fogColor;
		}

		// If the fourth layer is glowing, it will be sampled here, after the fog, to override the fog effect.
		// Also apply a gradient effect to it so that as he fog increases, the glow increases.
		if( gNrOfKeyframes[3] > 0 && gTopLayerCanGlow && gGlowTexIsActive )
		{
			uint width, height;
			gTopLayerTex.GetDimensions( width, height );

			float texStep = ( width / gNrOfKeyframes[3] );
			texStep = texStep / width;

			float startPos = gKeyframeIndices[3] * texStep;

			float2 tempTex = pIn.Tex;
			tempTex.x = startPos + (pIn.Tex.x * texStep );

			float glowFactor = 0.0f;

			//glowFactor = vecLength / gFogRadius - 0.1f;
			//glowFactor = vecLength / 10.0f - 0.1f;

			glowFactor = 1.0f - (1.0f / ( exp( pow( vecLength * (( vecLength / gFogRadius ) + 0.1f ), 2 ) ) ) ) + 0.2f;

			// Sample texture
			tempColor = gTopLayerTex.Sample( samAnisotropic, tempTex );

			tempColor = tempColor * glowFactor;

			// Only set active texel color if alpha is not zero.
			if( tempColor.a > 0.01f )
			{
				texColor += tempColor;
			}
		}
	}

	// **************************************************************************************
	// **************************************************************************************

	// Discard pixel if texture alpha < 0.1.
	clip( texColor.a - 0.1f );

	return texColor;
}

technique10 BasicTech
{
	pass P0
	{
		SetVertexShader( CompileShader( vs_4_0, VS() ) );
		SetGeometryShader( NULL );
		SetPixelShader( CompileShader( ps_4_0, PS() ) );
		//SetDepthStencilState( DisableDepth, 0 );
		//SetRasterizerState( rs );
	}
}