#include "Post.fxh"
#include "PackUtils.fxh"

float4x4 worldViewPorj;
float4x4 invProj;
float farPlane;

float sample_rad;
float intensity;
float scale;
float bias;
float selfOcclusion;

//float gi_sample_rad;
//float gi_intensity;
//float gi_scale;
//float gi_bias;
//float gi_selfOcclusion;

float2 invScreenSize;

texture2D texDepth;
texture2D texNrmPos;
texture2D texRandom;
texture2D texGILight;

sampler2D samGILight = sampler_state
{
	Texture = texGILight;
	MinFilter = LINEAR;
    MagFilter = LINEAR;    
    MipFilter = NONE;
	AddressU = WRAP;
	AddressV = WRAP;
};
sampler2D samNrmPos = sampler_state
{
	Texture = texNrmPos;
	MinFilter = POINT;
    MagFilter = POINT;    
    MipFilter = NONE;
	AddressU = WRAP;
	AddressV = WRAP;
};
sampler2D samDepth = sampler_state
{
    Texture = texDepth;
    MinFilter = POINT;
    MagFilter = POINT;    
    MipFilter = NONE;
	AddressU = WRAP;
	AddressV = WRAP;
};
sampler2D grandom = sampler_state
{
    Texture = texRandom;
    MinFilter = POINT;
    MagFilter = POINT;    
    MipFilter = NONE;
	AddressU = WRAP;
	AddressV = WRAP;
};


float3 getPosition(in float2 uv)
{
	float3 p;
	p.xy = tex2D(samNrmPos, uv).xy;
	p.z = tex2D(samDepth, uv).r;
    return p;
}
float3 getNormal(in float2 uv)
{
	float2 sample = tex2D(samNrmPos, uv).ba;

    float3 nrm;
	nrm.xy = unpackVec( sample.x);//tex2D(samNrmPos, uv).ba;// //
	nrm.z = sample.y;
	nrm = nrm*2-1;

	// -sqrt(1-dot(nrm.xy, nrm.xy));
	return nrm;
}

float getRandom(in float2 uv)
{
    return tex2D(grandom, screenSize * uv / 2.0f).x;
}



float doAo(in float2 tcoord, in float2 uv, in float3 p, in float3 cnorm)
{
  float3 diff = getPosition(tcoord + uv) - p;
  const float3 v = normalize(diff);
  const float  d = length(diff) * scale;
  return max(0.0-selfOcclusion, dot(cnorm,v)-bias)*(1.0/(1.0+d*d)) * intensity;
}

//Ambient Occlusion form factor:
float aoFF(float3 vv, float rd, float3 cnorm, float3 nrm)
{
    return (1.0- saturate(dot( nrm,  -vv ))) *
                 saturate(dot( cnorm, vv )) * 
                 (1.0 - 1.0/sqrt(1.0/(rd*rd) + 1.0));
}

//GI form factor:
float giFF(float3 vv, float rd, float3 cnorm, float3 nrm)
{
    return 1.0 * saturate(dot( nrm,  -vv ))*
                 saturate(dot( cnorm, vv ))/
                    (rd*rd+1.0);  
}

float4 SSAOPost(float2 uv : TEXCOORD0, float3 ray : TEXCOORD1) : COLOR
{
    const float3 vec[14] = 
	{
	    float3( 1, 1,-1),  float3( 1,-1,-1),
        float3( 1, 1, 1),  float3( 1,-1, 1),
        float3(-1, 1,-1),  float3(-1,-1,-1),
        float3(-1, 1, 1),  float3(-1,-1, 1),
                         
        float3( 1, 0, 0),  float3(-1, 0, 0),
        float3( 0, 1, 0),  float3( 0,-1, 0),
        float3( 0, 0, 1),  float3( 0, 0,-1),
    };

    float3 p = getPosition(uv);
	if (p.z<3)
		return 0;

    float3 n = getNormal(uv);

    float rand = getRandom(uv);

    float ao = 0.0;
    float rad = sample_rad / p.z;
	float3 gi = 0;
    //**SSAO Calculation**//
  
    for (int j = 0; j < 14; ++j)
    {
        float2 coord = mul(float4(vec[j] * rad * rand, 0), worldViewPorj).xy;
        coord.y = screenSize.y - coord.y; 
		coord.xy *= invScreenSize * 1000.0;

        float val = doAo(uv, coord, p, n );

		ao += val;
		gi += val * tex2D(samGILight, uv + coord).rgb;
    }

	gi/=14;
    ao/=8;
    ao+=selfOcclusion;

    //**END**//

    return float4(gi,ao);
}

technique SSAO
{
	pass p0
	{
		VertexShader = compile vs_3_0 PostQuad();
		PixelShader = compile ps_3_0 SSAOPost();
	}
}
