//--------------------------------------------------------------------------------------
// File: BasicHLSL.fx
//
// The effect file for the BasicHLSL sample.  
// 
// Copyright (c) Microsoft Corporation. All rights reserved.
//--------------------------------------------------------------------------------------

#include "GlobalDefines.txt"
#include "Shadows.txt"

//--------------------------------------------------------------------------------------
// Global variables
//--------------------------------------------------------------------------------------
float3 g_LightPos;			        // Light's position in world space
float3 g_LightDir;
float4 g_LightDiffuse;				// Light's diffuse color
float3 g_LightAttenuation;

float3 g_CamPos;					// Camera position

texture g_DiffuseMap;				// Diffuse texture
texture g_ThicknessMap;				// Thickness-map
texture g_NormalMap;				// Normal-map
																
float4x4 g_mWorld;                  // World matrix for object
float4x4 g_mWorldViewProjection;    // World * View * Projection matrix

float4x4 g_mWorldToLightProj;		// Matrix to transform from world space to lights projection space



//--------------------------------------------------------------------------------------
// Texture samplers
//--------------------------------------------------------------------------------------
sampler DiffuseMapSampler = 
sampler_state
{
    Texture = <g_DiffuseMap>;
    MipFilter = LINEAR;
    MinFilter = LINEAR;
    MagFilter = LINEAR;
    AddressU = Clamp;
    AddressV = Clamp;
};

sampler ThicknessMapSampler = 
sampler_state
{
    Texture = <g_ThicknessMap>;
    MipFilter = LINEAR;
    MinFilter = LINEAR;
    MagFilter = LINEAR;
    AddressU = Clamp;
    AddressV = Clamp;
};

sampler NormalMapSampler = 
sampler_state
{
    Texture = <g_NormalMap>;
    MipFilter = LINEAR;
    MinFilter = LINEAR;
    MagFilter = LINEAR;
    AddressU = Clamp;
    AddressV = Clamp;
};


//--------------------------------------------------------------------------------------
// Vertex shader output structure
//--------------------------------------------------------------------------------------
struct VS_OUTPUT
{
    float4 Position		: POSITION;		// vertex position
    float2 TextureUV	: TEXCOORD0;	// vertex texture coords 
    float3 Light		: TEXCOORD1;	// Un-normalised light vector in tangent space
    float3 LightWorld	: TEXCOORD2;	// Un-normalised light vector in world space
    float4 PosLight		: TEXCOORD3;	// Fragment position in light's projection space
};


//--------------------------------------------------------------------------------------
// This shader computes standard transform and lighting
//--------------------------------------------------------------------------------------
VS_OUTPUT RenderSceneVS( float4 vPos : POSITION, 
                         float3 vNormal : NORMAL,
						 float3 vTangent : TANGENT0,
                         float2 vTexCoord0 : TEXCOORD0 )
{
    VS_OUTPUT Output;

    // Transform the position from object space to homogeneous projection space
    Output.Position = mul(vPos, g_mWorldViewProjection);
    
    // Calculate world position
    float3 vWorldPos = mul(vPos, g_mWorld);  
  
	float3 vWorldNormal = mul(vNormal, (float3x3)g_mWorld); // (model space)
    float3 vWorldTangent = mul(vTangent, (float3x3)g_mWorld); // (model space)
    float3 vWorldBiNorm = cross( vTangent, vNormal ); // (model space)
  
	// Copy texture coordinate through
	Output.TextureUV = vTexCoord0; 

	// Calculate light vector
	Output.LightWorld = g_LightPos - vWorldPos;
		
	// Transform light vector to tangent space
	Output.Light = float3( dot( Output.LightWorld, vWorldTangent ), dot( Output.LightWorld, vWorldBiNorm ), dot( Output.LightWorld, vWorldNormal ) );
  
	// Transform fragment position to lights projection space
	Output.PosLight = mul( vPos, g_mWorldToLightProj );
		
    return Output;    
}



//--------------------------------------------------------------------------------------
// Pixel shader output structure
//--------------------------------------------------------------------------------------
struct PS_OUTPUT
{
    float4 RGBColor : COLOR0;  // Pixel color    
};


//--------------------------------------------------------------------------------------
// This shader outputs the pixel's color by modulating the texture's
//       color with diffuse material color
//--------------------------------------------------------------------------------------
PS_OUTPUT RenderScenePS( VS_OUTPUT In, uniform bool bBackFace, uniform bool bShadow, uniform bool bShadowsPCF ) 
{ 
    PS_OUTPUT Output;
	
	float3 vLWorld = normalize( In.LightWorld );
		
	float fDot = dot( vLWorld, g_LightDir );

	//float fSpotMul = (fDot > g_LightAttenuation.z) ? 1 : 0;
	float fSpotMul = (fDot > 0.5) ? 1 : 0;
	
	float3 vDiffuse = float3(fSpotMul,fSpotMul,fSpotMul);
	
   	// Calculate distance to light
  	float1 fLightDist = length(In.LightWorld);
  	
	vDiffuse *= CalculateShadowColour( In.PosLight, fLightDist, bShadow, bShadowsPCF );
                           
	// Calculate L
	float3 vL = normalize( In.Light );
	
	// Calculate N	
	float3 vN = tex2D(NormalMapSampler, In.TextureUV) * 2.0 - 1.0;
	vN.y = -vN.y;
	//float3 vN = float3(0,0,1);
			
	// N.L
	float NdotL = dot( vN, vL );
		
	vDiffuse *= NdotL;
		
	// Two Sided lighting
	if (bBackFace)
	{
		NdotL = NdotL*1.3 + 0.3;
		
		// Get per-pixel thickness
		//float1 thick = tex2D(ThicknessMapSampler, In.TextureUV).r;
		//NdotL *= thick;
	}	
	
	// Attenuation
	NdotL = NdotL * clamp(g_LightAttenuation.x - g_LightAttenuation.y*sqrt(fLightDist), 0.0, 1.0);

	// Lookup mesh texture and modulate it with diffuse
	Output.RGBColor.rgba = tex2D(DiffuseMapSampler, In.TextureUV) * float4(g_LightDiffuse*vDiffuse,1);
	Output.RGBColor.a = 1;
				
    return Output;
}


//--------------------------------------------------------------------------------------
// Renders scene to render target
//--------------------------------------------------------------------------------------
technique RenderScene_High
{
    pass P0
    {   
		CullMode = CCW;
		//SrcBlend = SrcAlpha;
		//DestBlend = Zero;
        VertexShader = compile vs_1_1 RenderSceneVS();
        PixelShader  = compile ps_2_0 RenderScenePS(false, SHADOWS, SHADOWS_PCF );
    }
    pass P1
    {   
		CullMode = CW;
		//SrcBlend = SrcAlpha;
		//DestBlend = Zero;
        VertexShader = compile vs_1_1 RenderSceneVS();
        PixelShader  = compile ps_2_0 RenderScenePS(true, SHADOWS, SHADOWS_PCF);
    }
}

technique RenderScene_Medium
{
    pass P0
    {   
		CullMode = CCW;
        VertexShader = compile vs_1_1 RenderSceneVS();
        PixelShader  = compile ps_2_0 RenderScenePS(false, SHADOWS, SHADOWS_PCF);
    }
    pass P1
    {   
		CullMode = CW;
        VertexShader = compile vs_1_1 RenderSceneVS();
        PixelShader  = compile ps_2_0 RenderScenePS(true, SHADOWS, SHADOWS_PCF);
    }
}

technique RenderScene_Low
{
    pass P0
    {   
		CullMode = CCW;
        VertexShader = compile vs_1_1 RenderSceneVS();
        PixelShader  = compile ps_2_0 RenderScenePS(false, false, false);
    }
    pass P1
    {   
		CullMode = CW;
        VertexShader = compile vs_1_1 RenderSceneVS();
        PixelShader  = compile ps_2_0 RenderScenePS(true, false, false);
    }
}

