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

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

////////////////////////////////////////////////////////////////////////////////////////////////////
// Structures
////////////////////////////////////////////////////////////////////////////////////////////////////

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

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

static const float3 LUMINANCE = float3( 0.2125, 0.7154, 0.0721 ); //RGB to LUM

#define EPSILON 0.0001

////////////////////////////////////////////////////////////////////////////////////////////////////
// Grobal values
////////////////////////////////////////////////////////////////////////////////////////////////////

#if MIX_SM_HIGH

	cbuffer cbInput : register( b0 )
	{
		float4 g_Params;
	};

	Texture2D g_Texture : register( t0 );
	SamplerState g_Sampler : register( s0 );
	
#else //MIX_SM_HIGH

	float4 g_Params : register( c0 );

	sampler g_Sampler  : register( s0 );

#endif //MIX_SM_HIGH

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

#if MIX_SM_HIGH

	#define TEX_LUM( uv ) g_Texture.Sample( g_Sampler, uv )

#else //MIX_SM_HIGH

	#define TEX_LUM( uv ) tex2D( g_Sampler, uv )

#endif //MIX_SM_HIGH

#define TU g_Params.x
#define TV g_Params.y
#define TEX_OFFSET( a ) ( g_Params.xy * SAMPLE4X_TABLE[a] )

#define MIN_LUM g_Params.z
#define MAX_LUM g_Params.w

////////////////////////////////////////////////////////////////////////////////////////////////////
// Main function : 1/2
////////////////////////////////////////////////////////////////////////////////////////////////////

//PHASE1 : _ETvOȂuϋPx(ΐ)vo
float4 mainInital_2x( PS_INPUT input ) : MSV_TARGET0
{
	float4 output;

	float lum0 = dot( LUMINANCE, TEX_LUM( input.tex + float2( -TU, -TV ) ).rgb );
	float lum1 = dot( LUMINANCE, TEX_LUM( input.tex + float2(  TU, -TV ) ).rgb );
	float lum2 = dot( LUMINANCE, TEX_LUM( input.tex + float2(  TU,  TV ) ).rgb );
	float lum3 = dot( LUMINANCE, TEX_LUM( input.tex + float2( -TU,  TV ) ).rgb );

	// { log( lum_n ) } / 4
	output.rgb = ( log( max( EPSILON, lum0 ) ) + log( max( EPSILON, lum1 ) ) + log( max( EPSILON, lum2 ) ) + log( max( EPSILON, lum3 ) ) ) * 0.25;
	output.a = 1.0;

	return output;
}

//PHASE2 : _ETvOȂuϋPxvo
float4 mainIterate_2x( PS_INPUT input ) : MSV_TARGET0
{
	float4 output = 0.0;

	output.r += TEX_LUM( input.tex + float2( -TU, -TV ) ).r;
	output.r += TEX_LUM( input.tex + float2(  TU, -TV ) ).r;
	output.r += TEX_LUM( input.tex + float2(  TU,  TV ) ).r;
	output.r += TEX_LUM( input.tex + float2( -TU,  TV ) ).r;

	output.rgb = output.r * 0.25;
	output.a = 1.0;

	return output;
}

//PHASE3 : _ETvOȂuϋPx(w)vo
float4 mainFinal_2x( PS_INPUT input ) : MSV_TARGET0
{
	float4 output = 0.0;

	output.r += TEX_LUM( input.tex + float2( -TU, -TV ) ).r;
	output.r += TEX_LUM( input.tex + float2(  TU, -TV ) ).r;
	output.r += TEX_LUM( input.tex + float2(  TU,  TV ) ).r;
	output.r += TEX_LUM( input.tex + float2( -TU,  TV ) ).r;

	output.rgb = clamp( exp( output.r * 0.25 ), MIN_LUM, MAX_LUM );
	output.a = 1.0;

	return output;
}

////////////////////////////////////////////////////////////////////////////////////////////////////
// Main function : 1/4
////////////////////////////////////////////////////////////////////////////////////////////////////

//PHASE1 : _ETvOȂuϋPx(ΐ)vo
float4 mainInital_4x( PS_INPUT input ) : MSV_TARGET0
{
	float4 output = 0;

	for( int i = 0; i < SAMPLE4X_MAX; i++ )
	{
		float lum = dot( LUMINANCE, TEX_LUM( input.tex + TEX_OFFSET( i ) ).rgb );
		output.r += log( max( EPSILON, lum ) );
	}

	output.rgb = output.r * 0.0625;
	output.a = 1.0;

	return output;
}

//PHASE2 : _ETvOȂuϋPxvo
float4 mainIterate_4x( PS_INPUT input ) : MSV_TARGET0
{
	float4 output = 0.0;

	for( int i = 0; i < SAMPLE4X_MAX; i++ )
	{
		output.r += TEX_LUM( input.tex + TEX_OFFSET( i ) ).r;
	}

	output.rgb = output.r * 0.0625;
	output.a = 1.0;

	return output;
}

//PHASE3 : _ETvOȂuϋPx(w)vo
float4 mainFinal_4x( PS_INPUT input ) : MSV_TARGET0
{
	float4 output = 0.0;

	for( int i = 0; i < SAMPLE4X_MAX; i++ )
	{
		output.r += TEX_LUM( input.tex + TEX_OFFSET( i ) ).r;
	}

	output.rgb = clamp( exp( output.r * 0.0625 ), MIN_LUM, MAX_LUM );
	output.a = 1.0;

	return output;
}
