//--------------------------------------------------------------------------------------
// File: Effects.fx
//
//--------------------------------------------------------------------------------------

#include "EffectPool.fxh"
#include "LightHelper.fxh"


float4 Fresnel(float4 aSubstance, float3 aDirectionToLight, float3 aNormalVector)
{
	float4 fresnel = aSubstance+(1.0-aSubstance)*pow(1.0-saturate(dot(aDirectionToLight,aNormalVector)),5.0);
	return fresnel;
}

//--------------------------------------------------------------------------------------
// Input
//--------------------------------------------------------------------------------------
struct VS_INPUT
{
    float4 Pos  : POSITION;
    float3 Norm : NORMAL;
	float2 Tex  : TEXCOORD;
};

struct PS_INPUT
{
    float4 Pos  : SV_POSITION;
    float3 Norm : NORMAL;
	float2 Tex  : TEXCOORD;
};

struct VS_OUTPUT
{
    float4 Pos : SV_POSITION;
    float4 WorldPos : TEXCOORD1;
    float3 Norm : NORMAL;
    float2 Tex : TEXCOORD;
};

Texture2D DiffuseTexture;
Texture2D AOTexture;
Texture2D SubstanceTexture;
Texture2D RoughnessTexture;
Texture2D NormalTexture;
TextureCube CubeMap; 

//--------------------------------------------------------------------------------------
// Vertex Shader
//--------------------------------------------------------------------------------------
VS_OUTPUT VS( VS_INPUT input )
{
    VS_OUTPUT output = (VS_OUTPUT)0;
    output.Pos = mul( input.Pos, World );
	output.Norm = mul( input.Norm, World );
	output.WorldPos = output.Pos;
	
    output.Pos = mul( output.Pos, View );
    output.Pos = mul( output.Pos, Projection );
    
    output.Tex = input.Tex;
    
    return output;
}


//--------------------------------------------------------------------------------------
// Pixel Shader
//--------------------------------------------------------------------------------------
float4 PS( VS_OUTPUT input) : SV_Target
{
	float3 normal = normalize(input.Norm);
	
	float3 norm = NormalTexture.Sample(sampleLinear, input.Tex ).xyz*2-1;

	float4 diffuseAmbient = 0;
	float4 speculareAmbient = 0;
	float4 speculareLight = 0;
	float4 finalColor  = 0;
	
	float4 substance = SubstanceTexture.Sample( sampleLinear, input.Tex );
	float roughness = RoughnessTexture.Sample( sampleLinear, input.Tex ).r;
	float4 albedo = DiffuseTexture.Sample( sampleLinear, input.Tex );
	float ao = AOTexture.Sample( sampleLinear, input.Tex ).r;
	float3 viewDirection = normalize(CameraPosition - input.WorldPos);
	float4 refSchlick = Fresnel(substance, viewDirection, norm);
	
	float ap = pow(MaxGloss,roughness);
	float normalization = (8.0+ap) / 8.0;
	
	diffuseAmbient += CubeMap.SampleLevel( sampleLinear, norm, AmbientMipMapLevel) * albedo * (1-refSchlick) * ao;
	speculareAmbient += CubeMap.SampleLevel( sampleLinear, reflect(norm, viewDirection), (SpecularMipMapLevel - (SpecularMipMapLevel * roughness + 0.5))) * refSchlick * ao;
	
	for(int i=0; i<NumberOfDirectionalLights; i++)
	{
		float lightDotNormal = saturate(dot(norm, normalize(DirectionalLightDirection[i])));
		float3 VplusL=(normalize(DirectionalLightDirection[i])+normalize(viewDirection));
		float3 halfVector = normalize(VplusL);
		float kelemen = 4 / (dot(VplusL, VplusL));
		speculareLight += ((ao*normalization*Fresnel(substance, normalize(DirectionalLightDirection[i]), halfVector)*pow(saturate(dot(halfVector,norm)),ap)*lightDotNormal*kelemen)+(1-substance)*lightDotNormal*albedo)*DirectionalLightColor[i];
	}
	
	for(int i=0; i<NumberOfPointLights; i++)
	{
		float4 lightvec = (PointLightPos[i] - input.WorldPos);
		float lightdist = length(lightvec);
	
		float4 lightIntence = PointLightColor[i] * (1/(pow(lightdist/PointLightFallOff[i],2)));

		float lightDotNormal = saturate(dot(norm, normalize(lightvec)));
		float3 VplusL=(normalize(lightvec)+normalize(viewDirection));
		float3 halfVector = normalize(VplusL);
		float kelemen = 4 / (dot(VplusL, VplusL));
		speculareLight += ((ao*normalization*Fresnel(substance, normalize(lightvec), halfVector)*pow(saturate(dot(halfVector,norm)),ap)*lightDotNormal*kelemen)+(1-substance)*lightDotNormal*albedo)*lightIntence;
	}
	
	finalColor += diffuseAmbient + speculareLight + speculareAmbient;
	return finalColor;
}

RasterizerState rs
{
	cullMode = None;
	FillMode = Solid;
};

//--------------------------------------------------------------------------------------
technique11 Render
{
    pass P0
    {
        SetVertexShader( CompileShader( vs_5_0, VS() ) );
		SetGeometryShader(NULL);
		SetHullShader( NULL );
		SetDomainShader( NULL );
        SetPixelShader( CompileShader( ps_5_0, PS() ) );
		SetBlendState( NULL, float4( 0.0f, 0.0f, 0.0f, 0.0f ), 0xFFFFFFFF );
		SetRasterizerState(rs);
		SetDepthStencilState(EnableAllDSS, 0);
		SetComputeShader(NULL);
    }
}


