
void SSAO_vp(	float4 position : POSITION,
		float3 farCorner : NORMAL,
		float2 uv1	: TEXCOORD0,

		out float4 oPosition    : POSITION,
		//out float2 oUv1		: TEXCOORD0,
		//out float3 oCamDir      : TEXCOORD1,
		uniform float4 viewportSize )
{
	//oUv1 = uv1;
	oPosition = position;
	oPosition.z = 1.f;
	//oCamDir = -farCorner;
	//oPosition.x -= viewportSize.z;
	//oPosition.y += viewportSize.w;
}

float3 decodeNormal(float2 enc)
{
	float2 fenc = enc * 2 - 1;
	float3 n = float3( 0.f, 0.f, -( dot( fenc, fenc ) * 2 - 1 ) );
	n.xy = normalize( fenc ) * sqrt( 1 - n.z * n.z );
	return n;
}

float decodeDepth(float2 enc)
{
	return dot( enc, float2( 1.f, 1.f / 255.f ) );
}



//sampler g_buffer;
//sampler g_buffer_pos;
//sampler g_random;

//float4x4 g_screen_to_camera;
//float4x4 g_mat;

#define g_sample_rad 0.55f
#define g_intensity 0.8f
#define g_scale 0.32f
#define g_bias 0.045f
#define g_self_occlusion 0.12f

float getRandom( float2 uv, float2 viewportSize )
{
  return ( frac( uv.x * ( viewportSize.x / 2.0 ) ) * 0.25 ) + ( frac( uv.y * ( viewportSize.y / 2.0 ) ) * 0.5 );
}


float doAmbientOcclusion(in float3 diff, in float3 cnorm )
{		
	const float3 v = normalize(diff);
	const float  d = length(diff)*g_scale;
	return max(0.0-g_self_occlusion,dot(cnorm,v)-g_bias)*(1.0/(1.0+d*d))*g_intensity;
	//return length(diff) * 0.3f;
}


float3 camPosFromCorners( float4x4 frustumCorners, float2 uv )
{
	return float3( lerp( frustumCorners[0].x, frustumCorners[1].x, uv.x ), lerp( frustumCorners[0].y, frustumCorners[2].y, uv.y ), frustumCorners[0].z );
}


void SSAO_fp( 	float2 screenPos : SV_POSITION,
		//float3 camVec : TEXCOORD1,
		out float4 color : COLOR0,
		//uniform float4x4 worldViewProj,
		uniform float4 viewportSize,
		uniform sampler2D depthAndNormalBuffer : register(s0),
		//uniform sampler2D depthBuffer : register(s0),
		//uniform sampler2D normalBuffer : register(s1),
		uniform float4x4 frustumCorners,
		uniform float4x4 projection,
		uniform float4x4 inverseProjection )
{
	const float2 vec[] = {  
	float2(1, 0),
	float2(-0.5, 0.866025),
	float2(-0.5, -0.866025),
	float2(2, 0),
	float2(1, 1.73205),
	float2(-1, 1.73205),
	float2(-2, -1.74846e-007),
	float2(-1, -1.73205),
	float2(1, -1.73205),
	float2(3, 0),
	float2(2.29813, 1.92836),
	float2(0.520944, 2.95442),
	float2(-1.5, 2.59808),
	float2(-2.81908, 1.02606),
	float2(-2.81908, -1.02606),
	float2(-1.5, -2.59808),
	float2(0.520946, -2.95442),
	float2(2.29813, -1.92836) };
	
	float2 uv = ( screenPos + 0.5 ) * viewportSize.zw;
	//float depth = tex2D( depthBuffer, uv ).r;
	float depth = decodeDepth( tex2D( depthAndNormalBuffer, uv ).xy );
	float3 p = camPosFromCorners( frustumCorners, uv ) * depth;
	//float3 n = decodeNormal( tex2D( normalBuffer, uv ).xy );
	float3 n = decodeNormal( tex2D( depthAndNormalBuffer, uv).zw );
	float rand = getRandom( uv, viewportSize.xy ) * g_sample_rad;

	float ao = 0.0;
	//**SSAO Calculation**//
	
	//float2 scaledMultiple = ( g_sample_rad * ( 1.f - depth ) ) * rand * viewportSize.zw;

	for( int i = 0; i < 9; i += 1 )
	{
		//float len = length( vec[i] );
		//float4 tmp = float4( p, 1.f );
		float4 screenSpace = mul( projection, float4( p.xy + ( vec[i] * rand ), p.z, 1.f ) );
		screenSpace /= screenSpace.w;
		screenSpace.y = -screenSpace.y;
		screenSpace.xy += 1.f;
		screenSpace.xy *= 0.5f;

		//ao += doAmbientOcclusion( ( camPosFromCorners( frustumCorners, screenSpace.xy ) * tex2D( depthBuffer, screenSpace.xy ).r ) - p, n );// * ( 1.f / len ) );
		float pixelDepth = decodeDepth( tex2D( depthAndNormalBuffer, screenSpace.xy ).xy );
		ao += doAmbientOcclusion( ( camPosFromCorners( frustumCorners, screenSpace.xy ) * pixelDepth ) - p, n );// * ( 1.f / len ) );
	} 
	ao/=8;
	ao = 1.f - ao;
	ao+=g_self_occlusion;
	//float2 newUv = uv + ( invSize * ( vec[5] * rad ) );
	//**END**//
	//color.xyzw = saturate( length( ( camPosFromCorners( frustumCorners, uv + float2( viewportSize.z * 1.f, 0.f ) ) * tex2D( depthBuffer, uv + float2( viewportSize.z * 1.f, 0.f ) ).r ) - p ) );
	color.xyzw = ao;
}

void SSAOOut_fp(float2 screenPos : SV_POSITION,
		out float4 color : COLOR0,
		uniform float4 viewportSize,
		uniform sampler2D AOBuffer : register(s0) )
{
	color.w = 1.f;
	float2 uv = ( screenPos + 0.5 ) * viewportSize.zw;
	const float2 vec[3] = {
		float2(1,1),
		float2(1,0),
		float2(0,1) };

	float3 ao = tex2D( AOBuffer, uv ).xyz;
	for( int i=0; i < 3; i += 1 )
	{
		float2 tcoord = uv + float2( vec[i].x * viewportSize.z, vec[i].y * viewportSize.w );
		ao += tex2D( AOBuffer, tcoord ).xyz;
	}
	ao /= 4;
	color.xyz = ao;
}