////////////////////////////////////////////////////////////////////////////////////////////////////
// test.fx                                                                                
////////////////////////////////////////////////////////////////////////////////////////////////////



// Transforms
////////////////////////////////////////////////////////////////////////////////////////////////////
float4x4 g_wvp_mtx;
float4x4 g_world_mtx;
float4x4 g_shadow_mtx;



// Lighting
////////////////////////////////////////////////////////////////////////////////////////////////////
float4 g_sun_dir;
float4 g_cam_pos;
float4 g_color;



// Textures & samplers
////////////////////////////////////////////////////////////////////////////////////////////////////
texture2D g_albedo_tex;
textureCUBE g_diffuse_probe_tex;
textureCUBE g_specular_probe_tex;
texture2D g_shadowmap_tex;

sampler2D g_albedo_samp = sampler_state
{
    texture = <g_albedo_tex>;
    MinFilter = LINEAR;
    MagFilter = LINEAR;
    MipFilter = LINEAR;
    AddressU  = WRAP;
    AddressV  = WRAP;
    AddressW  = WRAP;
};

samplerCUBE g_diffuse_probe_samp = sampler_state
{
    texture = <g_diffuse_probe_tex>;
    MinFilter = LINEAR;
    MagFilter = LINEAR;
    MipFilter = LINEAR;
    AddressU  = WRAP;
    AddressV  = WRAP;
    AddressW  = WRAP;
};

samplerCUBE g_specular_probe_samp = sampler_state
{
    texture = <g_specular_probe_tex>;
    MinFilter = LINEAR;
    MagFilter = LINEAR;
    MipFilter = LINEAR;
    AddressU  = WRAP;
    AddressV  = WRAP;
    AddressW  = WRAP;
};

sampler2D g_shadowmap_samp = sampler_state 
{
		texture = <g_shadowmap_tex>;
		MinFilter = POINT;
		MagFilter = POINT;
		MipFilter = NONE;
		AddressU  = CLAMP;        
		AddressV  = CLAMP;
		AddressW  = CLAMP;
};



// Vertex shaders
////////////////////////////////////////////////////////////////////////////////////////////////////
void vs_main(
    in float3 iPos			 : POSITION0,
    in float2 iTc0			 : TEXCOORD0,
    in float3 iNrm			 : NORMAL0,

    out float4 oPos			    : POSITION,
    out float2 oTc0			    : TEXCOORD0,
    out float3 oNrm			    : TEXCOORD1,
    out float4 oWorldPos    : TEXCOORD2,
    out float4 oSurfacePos	: TEXCOORD3  )
{
    // Transform position to clip space
    oPos = mul( float4( iPos.xyz, 1.0 ), g_wvp_mtx );

    // Copy texcoord
    oTc0 = iTc0;

    // Transform normal to world space
    oNrm = mul( iNrm, (float3x3)g_world_mtx );

		// Transform position to world space
		oWorldPos.xyz = mul( float4( iPos.xyz, 1.0 ), g_world_mtx ).xyz;
    oWorldPos.w = saturate( (oPos.z - 100.0) * 0.0004 );
		
		// Transform vertex position to shadow map space
		oSurfacePos = mul( float4( iPos.xyz, 1.0 ), g_shadow_mtx );	
}



////////////////////////////////////////////////////////////////////////////////////////////////////
void vs_main2(
    in float3 iPos			 : POSITION0,
    in float2 iTc0			 : TEXCOORD0,
    in float3 iNrm			 : NORMAL0,

    out float4 oPos			    : POSITION,
    out float2 oTc0			    : TEXCOORD0,
    out float3 oNrm			    : TEXCOORD1,
    out float4 oWorldPos    : TEXCOORD2  )
{
    // Transform position to clip space
    oPos = mul( float4( iPos.xyz, 1.0 ), g_wvp_mtx );

    // Copy texcoord
    oTc0 = iTc0;

    // Transform normal to world space
    oNrm = mul( iNrm, (float3x3)g_world_mtx );

		// Transform position to world space
		oWorldPos.xyz = mul( float4( iPos.xyz, 1.0 ), g_world_mtx ).xyz;
    oWorldPos.w = saturate( (oPos.z - 100.0) * 0.00075 );
}



// Pixel shaders
////////////////////////////////////////////////////////////////////////////////////////////////////
void ps_main(                                                                                   
    in float2 iTc0			  : TEXCOORD0,                                                                 
    in float3 iNrm			  : TEXCOORD1,                                                                 
    in float4 iWorldPos   : TEXCOORD2,
    in float4 iSurfacePos : TEXCOORD3,
    
    out float4 oCol0		  : COLOR0 )                                                                 
{                                                                                               
    // Read texture
    float3 albedo = tex2D( g_albedo_samp, iTc0 ).rgb;
    float3 diffuse = texCUBE( g_diffuse_probe_samp, iNrm );
    
    // Compute reflection vector
    float3 eye = normalize( g_cam_pos - iWorldPos.xyz  );
    float3 n = normalize( iNrm );
    float3 r = reflect( -eye, n );
    float3 specular = texCUBE( g_specular_probe_samp, r );
    
    // Compute fresnel
    float fres = 1.0f - pow( saturate( dot( n, eye ) ), 2.0f );

		// Get shadow
		iSurfacePos.xyz /= iSurfacePos.w;
		float shadowmap_depth = tex2D( g_shadowmap_samp, iSurfacePos.xy ).r;
		float shadow = (shadowmap_depth + 0.00075 > iSurfacePos.z) ? 1.0 : 0.25;
		diffuse *= 0.3;
		diffuse += float3( 1.0, 0.7, 0.3 ) * saturate( dot( n, -g_sun_dir ) ) * shadow * 2.0;

    // Compute final color
    float3 raw_radiance = lerp( diffuse*g_color, specular, fres ) * albedo;	// Laquer
    //float3 raw_radiance = lerp( diffuse, specular, fres ) * albedo * g_color; // Metal

		if( iWorldPos.y < 0.0 )
		{
				//raw_radiance *= 0.65;
				raw_radiance *= 1.0 - (0.35 * saturate( -iWorldPos.y * 100.0 ) );
				raw_radiance = lerp( raw_radiance, float3( 0.03, 0.025, 0.0125 ), saturate( 0.25-iWorldPos.y*0.435 ) );
		}
		raw_radiance = lerp( raw_radiance, float3( 0.7, 0.7, 0.7 ), iWorldPos.w );
		
		// Done, output color!
    //oCol0 = float4( raw_radiance, saturate( iWorldPos.y ) );
    oCol0 = float4( raw_radiance, 1.0 );
}                                                                                               



////////////////////////////////////////////////////////////////////////////////////////////////////
void ps_main2(                                                                                   
    in float2 iTc0			  : TEXCOORD0,                                                                 
    in float3 iNrm			  : TEXCOORD1,                                                                 
    in float4 iWorldPos   : TEXCOORD2,
    
    out float4 oCol0		  : COLOR0 )                                                                 
{                                                                                               
    // Read texture
    float3 albedo = 1.0 - tex2D( g_albedo_samp, float2( -iTc0.x, iTc0.y ) ).rgb*0.8;
    float3 diffuse = texCUBE( g_diffuse_probe_samp, iNrm );
    
    // Compute reflection vector
    float3 eye = normalize( g_cam_pos - iWorldPos.xyz  );
    float3 n = normalize( iNrm );
    float3 r = reflect( -eye, n );
    float3 specular = texCUBE( g_specular_probe_samp, r );
    
    // Compute fresnel
    float fres = 1.0f - pow( saturate( dot( n, eye ) ), 1.0f );

    // Compute final color
    float3 raw_radiance = lerp( diffuse*g_color, specular, fres ) * albedo;	// Laquer
    //float3 raw_radiance = lerp( diffuse*g_color* albedo, specular, fres );	// Laquer
		
		// Done, output color!
    oCol0 = float4( raw_radiance, 1.0 );
}                                                                                               



////////////////////////////////////////////////////////////////////////////////////////////////////
void ps_main3(                                                                                   
    in float2 iTc0			  : TEXCOORD0,                                                                 
    in float3 iNrm			  : TEXCOORD1,                                                                 
    in float4 iWorldPos   : TEXCOORD2,
    
    out float4 oCol0		  : COLOR0 )                                                                 
{                                                                                               
    // Read texture
    float3 albedo = 1.0 - tex2D( g_albedo_samp, float2( -iTc0.x, iTc0.y ) ).rgb*0.8;
    float3 diffuse = texCUBE( g_diffuse_probe_samp, iNrm );
    
    // Compute reflection vector
    float3 eye = normalize( g_cam_pos - iWorldPos.xyz  );
    float3 n = normalize( iNrm );
    float3 r = reflect( -eye, n );
    float3 specular = texCUBE( g_specular_probe_samp, r ) * 5.0f;
    
    // Compute fresnel
    float fres = 1.0f - pow( saturate( dot( n, eye ) ), 2.0f );

    // Compute final color
    float3 raw_radiance = lerp( diffuse*g_color, specular, fres ) * albedo;	// Laquer
		
		// Done, output color!
    oCol0 = float4( lerp( raw_radiance, float3( 0.0f, 0.031f, 0.065f ), iWorldPos.w ), 1.0 );
}                                                                                               



////////////////////////////////////////////////////////////////////////////////////////////////////
void ps_main4(                                                                                   
    in float2 iTc0			  : TEXCOORD0,                                                                 
    in float3 iNrm			  : TEXCOORD1,                                                                 
    in float4 iWorldPos   : TEXCOORD2,
    
    out float4 oCol0		  : COLOR0 )                                                                 
{                                                                                               
    // Read texture
    float3 albedo = 1.0 - tex2D( g_albedo_samp, float2( -iTc0.x, iTc0.y ) ).rgb*0.8;
    float3 diffuse = texCUBE( g_diffuse_probe_samp, iNrm );
    
    // Compute reflection vector
    float3 eye = normalize( g_cam_pos - iWorldPos.xyz  );
    float3 n = normalize( iNrm );
    float3 r = reflect( -eye, n );
    float3 specular = texCUBE( g_specular_probe_samp, r ) * 3.0f;
    
    // Compute fresnel
    float fres = 1.0f - pow( saturate( dot( n, eye ) ), 2.0f );

    // Compute final color
    float3 raw_radiance = lerp( diffuse*g_color, specular, fres ) * albedo;	// Laquer
		
		// Done, output color!
    oCol0 = float4( lerp( raw_radiance, float3( 0.0f, 0.031f, 0.065f ), iWorldPos.w ), 1.0 );
}                                                                                               



// Techniques
////////////////////////////////////////////////////////////////////////////////////////////////////
technique main
{
   pass p0 
   {
				ZEnable = true;
        VertexShader = compile vs_3_0 vs_main();
        PixelShader  = compile ps_3_0 ps_main();
   }
}



////////////////////////////////////////////////////////////////////////////////////////////////////
technique main2
{
   pass p0 
   {
				ZEnable = true;
        VertexShader = compile vs_3_0 vs_main2();
        PixelShader  = compile ps_3_0 ps_main2();
   }
}



////////////////////////////////////////////////////////////////////////////////////////////////////
technique main3
{
   pass p0 
   {
				ZEnable = true;
        VertexShader = compile vs_3_0 vs_main2();
        PixelShader  = compile ps_3_0 ps_main3();
   }
}


////////////////////////////////////////////////////////////////////////////////////////////////////
technique main4
{
   pass p0 
   {
				ZEnable = true;
        VertexShader = compile vs_3_0 vs_main2();
        PixelShader  = compile ps_3_0 ps_main4();
   }
}

