#ifndef SSAO_1231242112
#define SSAO_1231242112
#include "common.hlsli"

#define SSAO_RADIUS 0.8

Texture2D jitter0;
sampler smp_jitter;

float4 scaled_screen_res;

float3 uv_to_eye(float2 uv, float eye_z)
{
    uv = uv * float2(2.0f, 2.0f) - float2(1.0f, 1.0f);
    return float3(uv * pos_decompression_params.xy, 1.0f) * eye_z;
}

/* 
	SSAO Нагло украдено у Sir Lancevrot (с его разрешения)
*/

float3 GetViewPos(float2 uv)
{
	float depth = s_position.SampleLevel(smp_nofilter, uv, 0).x;
    return uv_to_eye(uv, depth_unpack.x * rcp(depth - depth_unpack.y));
}

float doPBAO(float2 uv, float3 pos, float3 n, float invRad, float bias, float selfOcc)
{
	float3 p = GbufferGetPointRealUnjitter(uv);
	float3 dist	= p - pos;
	
	float len = length(dist);
	float3 v = dist * rcp(len);
	
	float atten	= len * invRad;
	return max(-selfOcc, dot(n, v) - bias) * rcp(atten * atten + 1.0f);
}

float calc_ssao(float depth, float3 normal, float2 tc0)
{
	// define kernel
	float n = 0.0f;
	const float step = 0.875f;
	const float fScale = 0.57735f * 0.025f; 

	const float inv2 = 0.5f;
	const float inv5_3 = 0.188679245283f;
	const float inv8 = 0.125f;
	const float inv16 = 0.0625f;
	const float selfOcc = 0.0f; // range: 0.0f to 1.0f
	const float2 focalLen = rcp(pos_decompression_params.xy);

	const float3 arrKernel[8] =
	{
		float3( 1.0,  1.0,  1.0) * fScale * (n += step),
		float3(-1.0, -1.0, -1.0) * fScale * (n += step),
		float3(-1.0, -1.0,  1.0) * fScale * (n += step),
		float3(-1.0,  1.0, -1.0) * fScale * (n += step),
		float3(-1.0,  1.0,  1.0) * fScale * (n += step),
		float3( 1.0, -1.0, -1.0) * fScale * (n += step),
		float3( 1.0, -1.0,  1.0) * fScale * (n += step),
		float3( 1.0,  1.0, -1.0) * fScale * (n += step),
	};
	
	float2 tc1 = (tc0 * scaled_screen_res.xy) * 0.015625f;
	float3 rotSample = jitter0.Sample(smp_jitter, tc1).xyz;
	
	rotSample = frac(m_taa_jitter.z + rotSample);
	rotSample = normalize(rotSample - 0.5f);

	float3 pos = GbufferGetPointRealUnjitter(tc0, depth) * 0.99f;
	
	// calculate angle bias
	float bias = 0.0;
	
	// calculate contrast
	float contrast = inv16 * rcp(1.0f - saturate(bias));

	// calculate radius
	float radius = SSAO_RADIUS * saturate(pos.z * inv5_3) * (1.0f + pos.z * inv8);
	float invRad = rcp(radius);
	
	float2 radius2D	= radius * focalLen * rcp(pos.z);
	float ao = 0.0f;

	// calculate ao
 	[unroll]
	for (int i = 0; i < 8; ++i) {
		float2 deltaUV = reflect(arrKernel[i], rotSample).xy * radius2D;		
		ao += doPBAO(tc0 + deltaUV, pos, normal, invRad, bias, selfOcc);
		ao += doPBAO(tc0 + deltaUV * inv2, pos, normal, invRad, bias, selfOcc);
	}

	ao = 1.0f - (ao * contrast + selfOcc);
	return ao * ao;
}
#endif

