////////////////////////////////////////////////////////////////////////////////////////////////////
// Includes
////////////////////////////////////////////////////////////////////////////////////////////////////

#include "../../../types.txt"

////////////////////////////////////////////////////////////////////////////////////////////////////
// Constant values
////////////////////////////////////////////////////////////////////////////////////////////////////

#define SAMPLING_COUNT 16

static float INV_SAMPLING_COUNT = 0.0625;

static float3 SAMPLING_TABLE[SAMPLING_COUNT] =
{
	float3( +0.53812504,  +0.18565957,   -0.43192      ),
	float3( +0.13790712,  +0.24864247,   +0.44301823   ),
	float3( +0.33715037,  +0.56794053,   -0.005789503  ),
	float3( -0.6999805,   -0.04511441,   -0.0019965635 ),
	float3( +0.06896307,  -0.15983082,   -0.85477847   ),
	float3( +0.056099437, +0.006954967,  -0.1843352    ),
	float3( -0.014653638, +0.14027752,   +0.0762037    ),
	float3( +0.010019933, -0.1924225,    -0.034443386  ),
	float3( -0.35775623,  -0.5301969,    -0.43581226   ),
	float3( -0.3169221,   +0.106360726,  +0.015860917  ),
	float3( +0.010350345, -0.58698344,   +0.0046293875 ),
	float3( -0.08972908,  -0.49408212,   +0.3287904    ),
	float3( +0.7119986,   -0.0154690035, -0.09183723   ),
	float3( -0.053382345, +0.059675813,  -0.5411899    ),
	float3( +0.035267662, -0.063188605,  +0.54602677   ),
	float3( -0.47761092,  +0.2847911,    -0.0271716    ),
};

////////////////////////////////////////////////////////////////////////////////////////////////////
// structuers
////////////////////////////////////////////////////////////////////////////////////////////////////

struct PS_INPUT
{
#if MIX_SM_HIGH
	float4 pos : SV_POSITION;
#endif //MIX_SM_HIGH
	float2 tex : TEXCOORD0;
};

////////////////////////////////////////////////////////////////////////////////////////////////////
// Global values
////////////////////////////////////////////////////////////////////////////////////////////////////

#if MIX_SM_HIGH

	cbuffer cbInput : register( b0 )
	{
		float4 g_Params0;
		float4 g_Params1;
		float4 g_Color;
	};

	Texture2D g_DepthTexture  : register( t0 );
	Texture2D g_DataTexture : register( t1 );
	Texture2D g_NoiseTexture   : register( t2 );

	SamplerState g_DepthSampler  : register( s0 );
	SamplerState g_DataSampler : register( s1 );
	SamplerState g_NoiseSampler  : register( s2 );
	
#else //MIX_SM_HIGH

	float4 g_Params0        : register( c0 );
	float4 g_Params1        : register( c1 );
	float4 g_Color          : register( c2 );

	sampler g_DepthSampler  : register( s0 );
	sampler g_DataSampler : register( s1 );
	sampler g_NoiseSampler  : register( s2 );

#endif //MIX_SM_HIGH

////////////////////////////////////////////////////////////////////////////////////////////////////
// Macros
////////////////////////////////////////////////////////////////////////////////////////////////////

#if MIX_SM_HIGH

	#define TEX_DEPTH( uv ) g_DepthTexture.Sample( g_DepthSampler, uv )
	#define TEX_DATA( uv ) g_DataTexture.Sample( g_DataSampler, uv )
	#define TEX_NOISE( uv ) g_NoiseTexture.Sample( g_NoiseSampler, uv )
	
#else //MIX_SM_HIGH

	#define TEX_DEPTH( uv ) tex2D( g_DepthSampler, uv )
	#define TEX_DATA( uv ) tex2D( g_DataSampler, uv )
	#define TEX_NOISE( uv ) tex2D( g_NoiseSampler, uv )

#endif //MIX_SM_HIGH

#define RADIUS      g_Params0.x
#define THRESHOLD   g_Params0.y
#define DEPTH       g_Params0.z
#define INTENSITY   g_Params0.w
#define NTEX_ASPECT g_Params1.xy

////////////////////////////////////////////////////////////////////////////////////////////////////
// Main function
////////////////////////////////////////////////////////////////////////////////////////////////////

float4 main( PS_INPUT input ) : MSV_TARGET0
{
#if USE_NOISE_TEX
	float3 noise = TEX_NOISE( input.tex * NTEX_ASPECT ).xyz * 2.0 - float3( 1.0, 1.0, 1.0 );
#endif //USE_NOISE_TEX

	float depth = TEX_DEPTH( input.tex ).x;
	float3 norm = TEX_DATA( input.tex ).xyz * 2.0 - 1.0;
//	float3 norm = TEX_DATA( input.tex ).xyz;

	float rd = RADIUS / depth;
	float occ = 0.0;
	
	for( uint i = 0; i < SAMPLING_COUNT; i++ )
	{
		float3 ray;
		float2 smpTex;
		float smpDepth;
		float3 smpNorm;
		float diffDepth;
		float diffNorm;

#if USE_NOISE_TEX
		ray = reflect( SAMPLING_TABLE[i].xyz, noise ) * rd;
#else //USE_NOISE_TEX
		ray = SAMPLING_TABLE[i].xyz * rd;
#endif //USE_NOISE_TEX

		smpTex.xy = input.tex.xy + sign( dot( ray, norm ) ) * ray.xy * float2( +1.0, -1.0 );
		
		smpDepth = TEX_DEPTH( smpTex.xy ).x;
		smpNorm = TEX_DATA( smpTex.xy ).xyz * 2.0 - 1.0;
//		smpNorm = TEX_DATA( smpTex.xy ).xyz;
		
		diffDepth = depth - smpDepth;
		diffNorm = 1.0 - dot( smpNorm, norm );
		
		occ += step( THRESHOLD, diffDepth ) * diffNorm * ( 1.0 - smoothstep( THRESHOLD, DEPTH, diffDepth ) );
	}
	
	occ = saturate( abs( occ * INV_SAMPLING_COUNT ) * INTENSITY );
	
	return float4( g_Color.rgb, occ );
}
