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

float3 g_CamPos;					// Camera position

texture g_DiffuseMap;              // Diffuse texture
texture g_SpecularMap;				// Specular-map
texture g_NormalMap;				// Normal-map

float3	g_Diffuse;
float	g_SpecularPow;				// Power to raise specular component by
float	g_SpecularStr;				// Multiplier for specular high-light

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
float4x4 g_mWorldToLightTex;		// Matrix to transform from world space to lights texture space

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

sampler SpecularMapSampler = 
sampler_state
{
    Texture = <g_SpecularMap>;
    MipFilter = LINEAR;
    MinFilter = LINEAR;
    MagFilter = LINEAR;
};

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

//--------------------------------------------------------------------------------------
// Vertex shader output structure
//--------------------------------------------------------------------------------------
struct VS_OUTPUT_LOW
{
    float4 Position		: POSITION;		// vertex position
    float2 TextureUV	: TEXCOORD0;	// vertex texture coords 
    float3 View			: TEXCOORD1;	// Un-normalised view vector in tangent space
    float3 Light		: TEXCOORD2;	// 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
    float2 Depth		: TEXCOORD4;	// Depth in lightspace
    float3 ClipTest		: TEXCOORD5;	// Stores w component of pos-light to do clipping against
};

VS_OUTPUT_LOW RenderSceneVSLow(	float4 vPos : POSITION, 
							float3 vNormal : NORMAL,
							float3 vTangent : TANGENT0,
							float2 vTexCoord0 : TEXCOORD0 )
{
    VS_OUTPUT_LOW 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); // position (world space)   
  
    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
	float3 vLightWorld = g_LightPos - vWorldPos; //(world space)
	
	//vLightWorld = normalize( vLightWorld );
	
	//Output.LightWorld = vLightWorld
				
	// Move light vector to tangent space
    Output.Light = float3( dot( vLightWorld, vWorldTangent ), dot( vLightWorld, vWorldBiNorm ), dot( vLightWorld, vWorldNormal ) );
  	
  	// Calculate view vector
	float3 vView = (g_CamPos - vWorldPos);
		
	// Transform view vector to tangent space
	Output.View = float3( dot( vView, vWorldTangent ), dot( vView, vWorldBiNorm ), dot( vView, vWorldNormal ) );
		
	//Output.View = normalize( Output.View );
	
	// Transform fragment position to lights projection space
	Output.PosLight = mul( vPos, g_mWorldToLightTex );	
		
	Output.Depth = (Output.PosLight.z + SHADOW_NEAR_PLANE) / (SHADOW_FAR_PLANE - SHADOW_NEAR_PLANE);
	
	Output.ClipTest = Output.PosLight.w;
	
    return Output;    
}


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

PS_OUTPUT AmbientLow( VS_OUTPUT_LOW In ) 
{ 
    PS_OUTPUT Output;
			
    Output.RGBColor.rgb = 0;   
	Output.RGBColor.a = 1; 

    return Output;
}

PS_OUTPUT RenderSkinPS2( VS_OUTPUT_LOW In ) 
{ 
    PS_OUTPUT Output;
			  		
	clip( In.ClipTest );			  		
			  				
	// Get per-pixel normal
	float3 vN = tex2D(NormalMapSampler, In.TextureUV * 9) * 2.0 - 1.0;
	
	float3 vL = normalize( In.Light );
	float3 vV = normalize( In.View );
			
	// N.L
	float1 NdotL = saturate( (dot( vN, vL ) + 0.5) / 1.5 ) * 0.7 + 0.2;
	
	float3 vR = reflect( vL, vN );
		
	float fSpecular = saturate( dot( vR, -vV ) );
		
	fSpecular = pow( fSpecular, 4 );
	
	float fSpecStr = tex2D(SpecularMapSampler, In.TextureUV).r;
		
	NdotL += fSpecular * fSpecStr * 0.3;	
	
	float3 vDiffuse = float3(NdotL,NdotL,NdotL);
				
	vDiffuse *= tex2D(DiffuseMapSampler, In.TextureUV);	
			
    // Lookup mesh texture and modulate it with diffuse
    Output.RGBColor.rgb = vDiffuse;   
	Output.RGBColor.a = 1; 

    return Output;
}

//--------------------------------------------------------------------------------------
// Renders scene to render target
//--------------------------------------------------------------------------------------

technique AmbientPass_High
{
    pass P0
    {        
        VertexShader = compile vs_1_1 RenderSceneVSLow();
        PixelShader  = compile ps_2_0 AmbientLow();
    }
}

technique AmbientPass_Medium
{
    pass P0
    {          
        VertexShader = compile vs_1_1 RenderSceneVSLow();
        PixelShader  = compile ps_2_0 AmbientLow();
    }
}

technique AmbientPass_Low
{
    pass P0
    {          
        VertexShader = compile vs_1_1 RenderSceneVSLow();
        PixelShader  = compile ps_2_0 AmbientLow();
    }
}

technique RenderScene_High
{
    pass P0
    {      
        VertexShader = compile vs_2_0 RenderSceneVSLow();
        PixelShader  = compile ps_2_0 RenderSkinPS2();
    }
}
technique RenderScene_Medium
{
    pass P0
    {      
        VertexShader = compile vs_2_0 RenderSceneVSLow();
        PixelShader  = compile ps_2_0 RenderSkinPS2();
    }
}
technique RenderScene_Low
{
    pass P0
    {      
        VertexShader = compile vs_2_0 RenderSceneVSLow();
        PixelShader  = compile ps_2_0 RenderSkinPS2();
    }
}


/*
technique RenderScene_High
{
    pass P0
    {      
        VertexShader = compile vs_1_1 RenderSceneVSMedium();
        PixelShader  = compile ps_2_0 RenderScenePSMedium( true, SHADOWS, SHADOWS_PCF );
    }
}

technique RenderScene_Medium
{
    pass P0
    {          
        VertexShader = compile vs_1_1 RenderSceneVSMedium();
        PixelShader  = compile ps_2_0 RenderScenePSMedium( true, SHADOWS, SHADOWS_PCF );
    }
}

technique RenderScene_Low
{
    pass P0
    {          
        VertexShader = compile vs_1_1 RenderSceneVSLow();
        PixelShader  = compile ps_1_4 RenderScenePSLow();
    }
}*/

