//------------------------------------------------------------------------
//			Filename: 	dsGeometryAnim.fx
//			Author:		Brian Arpidone
//			Modified:	7/11/2011
//			Created:	7/11/2011
//			Summary:	Basic geometry shader for deferred shading
//------------------------------------------------------------------------

#include "dsPool.fxh"

// Globals
float			g_fPanU;
float			g_fPanV;

// Matrices
extern float4x4 g_Joints[62];

// Textures
texture2D		g_tTextureMap;
texture2D		g_tSpecMap;
texture2D		g_tNormMap;
texture2D		g_tGlowMap;

//------------------------------------------------------------------------
// BUILD PASS STRUCTS
//------------------------------------------------------------------------

struct InputVS_Depth
{
	float3 vPos			: POSITION0;
	float3 vNorm		: NORMAL0;
	float2 vTex0		: TEXCOORD0;
	float4 vWeights		: BLENDWEIGHT;
	float4 vMatInd		: BLENDINDICES;
};

struct OutputVS_Depth
{
	float4 vWorldPos	: POSITION0;
	float2 vDepthCoords	: TEXCOORD1;
};

struct OutputPS_Depth
{
	float4 vDepth		: COLOR0;
};

struct InputVS_Build
{
	float3 vPos			: POSITION0;
	float3 vNorm		: NORMAL0;
	float2 vTex0		: TEXCOORD0;
	float4 vWeights		: BLENDWEIGHT;
	float4 vMatInd		: BLENDINDICES;
	float4 vTangent		: TANGENT0;
	float4 vBitangent	: BINORMAL0;
};

struct OutputVS_Build
{
	float4	vPos		: POSITION0;
	float2  vTex0		: TEXCOORD0;
	float4	vWorldNrm	: TEXCOORD1;	
	float4	vTangent	: TEXCOORD2;
	float4	vBitangent	: TEXCOORD3;
};

struct OutputPS_Build
{
	float4 	normal 		: COLOR0;
	float4 	diffuse 	: COLOR1;
	float4 	material 	: COLOR2;
	float4	glow		: COLOR3;
};

// Object Texture Sampler
sampler	TextureMap = sampler_state
{
	Texture = <g_tTextureMap>;
	// texture filtering
	MinFilter = LINEAR;
	MagFilter = LINEAR;
	MipFilter = LINEAR;
	// texture address modes (available options are WRAP, MIRROR, BORDER, and CLAMP)
	AddressU  = WRAP;
	AddressV  = WRAP;
};

sampler	SpecularMap = sampler_state
{
	Texture = <g_tSpecMap>;
	// texture filtering
	MinFilter = LINEAR;
	MagFilter = LINEAR;
	MipFilter = LINEAR;
	// texture address modes (available options are WRAP, MIRROR, BORDER, and CLAMP)
	AddressU  = WRAP;
	AddressV  = WRAP;
};

sampler	NormalMap = sampler_state
{
	Texture = <g_tNormMap>;
	// texture filtering
	MinFilter = LINEAR;
	MagFilter = LINEAR;
	MipFilter = LINEAR;
	// texture address modes (available options are WRAP, MIRROR, BORDER, and CLAMP)
	AddressU  = WRAP;
	AddressV  = WRAP;
};

sampler	GlowMap = sampler_state
{
	Texture = <g_tGlowMap>;
	// texture filtering
	MinFilter = LINEAR;
	MagFilter = LINEAR;
	MipFilter = LINEAR;
	// texture address modes (available options are WRAP, MIRROR, BORDER, and CLAMP)
	AddressU  = WRAP;
	AddressV  = WRAP;
};

//------------------------------------------------------------------------
// DEPTH PASS PROGRAMS
//------------------------------------------------------------------------
// Vertex Program
OutputVS_Depth DeferredVSDepth( InputVS_Depth i )
{
	OutputVS_Depth o = (OutputVS_Depth)0;
	
	float4 worldPos = float4(0,0,0,0);
	worldPos  = mul(float4(i.vPos, 1.0f), g_Joints[i.vMatInd[0]]) * i.vWeights[0];	
	worldPos += mul(float4(i.vPos, 1.0f), g_Joints[i.vMatInd[1]]) * i.vWeights[1];	
	worldPos += mul(float4(i.vPos, 1.0f), g_Joints[i.vMatInd[2]]) * i.vWeights[2];	
	worldPos += mul(float4(i.vPos, 1.0f), g_Joints[i.vMatInd[3]]) * i.vWeights[3];	

	o.vWorldPos = mul( worldPos, g_mViewProj );
	
	o.vDepthCoords.xy = o.vWorldPos.zw;
	
	return o;
}

// Fragment Program
OutputPS_Depth DeferredPSDepth( OutputVS_Depth vs )
{
	OutputPS_Depth o = (OutputPS_Depth)0;
	o.vDepth = (vs.vDepthCoords.x / vs.vDepthCoords.y);
	
	return o;
}

//------------------------------------------------------------------------
// BUILD PASS PROGRAMS
//------------------------------------------------------------------------

float4 CalculateWorldFromTangentNormal( float4 tanNorm, float4 normal, float4 tangent, float4 bitangent )
{
	float3x3 mat = { 	normalize(tangent.xyz),
						normalize(bitangent.xyz),
						normalize(normal.xyz) };
						
	return float4(normalize(mul( tanNorm.xyz, mat )), 0.0f);
}

// Vertex Program
OutputVS_Build DeferredVSBuild( InputVS_Build i )
{
	OutputVS_Build o = (OutputVS_Build)0;
	
	//Pass TexCoords
	o.vTex0 = i.vTex0 + float2(g_fPanU, g_fPanV);
	
	//Translate normals by model transforms?
	o.vWorldNrm  = mul(float4(i.vNorm, 0.0f), g_Joints[i.vMatInd[0]]) * i.vWeights[0];
	o.vWorldNrm += mul(float4(i.vNorm, 0.0f), g_Joints[i.vMatInd[1]]) * i.vWeights[1];
	o.vWorldNrm += mul(float4(i.vNorm, 0.0f), g_Joints[i.vMatInd[2]]) * i.vWeights[2];
	o.vWorldNrm += mul(float4(i.vNorm, 0.0f), g_Joints[i.vMatInd[3]]) * i.vWeights[3];
	
	o.vTangent  = mul(float4(i.vTangent.xyz, 0.0f), g_Joints[i.vMatInd[0]]) * i.vWeights[0];
	o.vTangent += mul(float4(i.vTangent.xyz, 0.0f), g_Joints[i.vMatInd[1]]) * i.vWeights[1];
	o.vTangent += mul(float4(i.vTangent.xyz, 0.0f), g_Joints[i.vMatInd[2]]) * i.vWeights[2];
	o.vTangent += mul(float4(i.vTangent.xyz, 0.0f), g_Joints[i.vMatInd[3]]) * i.vWeights[3];
	
	o.vBitangent  = mul(float4(i.vBitangent.xyz, 0.0f), g_Joints[i.vMatInd[0]]) * i.vWeights[0];
	o.vBitangent += mul(float4(i.vBitangent.xyz, 0.0f), g_Joints[i.vMatInd[1]]) * i.vWeights[1];
	o.vBitangent += mul(float4(i.vBitangent.xyz, 0.0f), g_Joints[i.vMatInd[2]]) * i.vWeights[2];
	o.vBitangent += mul(float4(i.vBitangent.xyz, 0.0f), g_Joints[i.vMatInd[3]]) * i.vWeights[3];
	
	//Translate position.  I hate doing this twice.
	float4 worldPos;
	worldPos  = mul(float4(i.vPos, 1.0f), g_Joints[i.vMatInd[0]]) * i.vWeights[0];	
	worldPos += mul(float4(i.vPos, 1.0f), g_Joints[i.vMatInd[1]]) * i.vWeights[1];	
	worldPos += mul(float4(i.vPos, 1.0f), g_Joints[i.vMatInd[2]]) * i.vWeights[2];	
	worldPos += mul(float4(i.vPos, 1.0f), g_Joints[i.vMatInd[3]]) * i.vWeights[3];

	o.vPos = mul( worldPos, g_mViewProj );
	
	return o;
}

// Fragment Program
OutputPS_Build DeferredPSBuild( OutputVS_Build vs )
{
	OutputPS_Build o = (OutputPS_Build)0;
	
	o.diffuse = tex2D( TextureMap, vs.vTex0 );
	
	float4 tanNormal = (2.0f * tex2D( NormalMap, vs.vTex0 )) - 1.0f;
	float4 worldNorm = CalculateWorldFromTangentNormal( tanNormal, vs.vWorldNrm, vs.vTangent, vs.vBitangent );
	o.normal.rgb = normalize(0.5f * (worldNorm.xyz + 1.0f));
	
	o.material = tex2D( SpecularMap, vs.vTex0 );
	
	o.glow = tex2D( GlowMap, vs.vTex0 );
	o.glow.rgb *= o.glow.a;
	o.glow.a = 1.0f;
	
	return o;
}

OutputPS_Build DeferredPSBuildNoNorm( OutputVS_Build vs )
{
	OutputPS_Build o = (OutputPS_Build)0;
	
	o.diffuse = tex2D( TextureMap, vs.vTex0 );
	
	o.normal.rgb = normalize(0.5f * (vs.vWorldNrm.xyz + 1.0f));
	
	o.material = tex2D( SpecularMap, vs.vTex0 );
	
	o.glow = tex2D( GlowMap, vs.vTex0 );
	o.glow.rgb *= o.glow.a;
	o.glow.a = 1.0f;
	
	return o;
}

technique depthPass
{
	pass p0
	{
		VertexShader =	compile vs_3_0 DeferredVSDepth();
		PixelShader =	compile ps_3_0 DeferredPSDepth();
		
		CullMode = ccw;
		FillMode = solid;
		Zenable = true;
		ZWriteEnable = true;
		ZFunc = less;
		StencilEnable = false;
		AlphaBlendEnable = false;
		AlphaTestEnable = false;
		ColorWriteEnable = red;
	}
}

technique buildPass
{
	pass p0
	{
		VertexShader = 	compile vs_3_0 DeferredVSBuild();
		PixelShader = 	compile ps_3_0 DeferredPSBuild();
		
		CullMode = ccw;
		FillMode = solid;
		Zenable = true;
		ZWriteEnable = false;
		StencilEnable = false;
		AlphaBlendEnable = false;
		AlphaTestEnable = false;		
		ColorWriteEnable = red | green | blue;
	}
}

technique noNormalMap
{
	pass p0
	{
		VertexShader = 	compile vs_3_0 DeferredVSBuild();
		PixelShader = 	compile ps_3_0 DeferredPSBuildNoNorm();
		
		CullMode = ccw;
		FillMode = solid;
		Zenable = true;
		ZWriteEnable = false;
		StencilEnable = false;
		AlphaBlendEnable = false;
		AlphaTestEnable = false;		
		ColorWriteEnable = red | green | blue;
	}
}