/*=============================================================================
	FilterPixelShader.usf: Filter pixel shader source.
	Copyright 1998-2010 Epic Games, Inc. All Rights Reserved.
=============================================================================*/

#include "Common.usf"

// needed for CompressDeviceZIntoHalfResTextureChannel()
#include "DepthOfFieldCommon.usf"

sampler2D FilterTexture;
half4 SampleWeights[NUM_SAMPLES];
// minv, minv, maxu,maxv
float4 SampleMaskRect;

// UV.y and UV.wz are the input UV coordinates
half ComputeMask(float2 UV)
{
	// actual masking costs performance and might be not really needed
	// (only required with spitscreen or not using full screen resolution)
	// can be a shader combination but when measured it wasn't faster
	// also the implementation can be changed to
	//    float4 Mask = saturate(UV.xyxy*MulConst+AddConst);
	//    return Mask2.x * Mask2.y * Mask2.y * Mask2.w;
	// which is softer and might be even faster
	half2 Mask = (UV > SampleMaskRect.xy) * (UV < SampleMaskRect.zw);

	return Mask.x * Mask.y;
}

void Main(
	float4 InOffsetUVs[(NUM_SAMPLES + 1) / 2] : TEXCOORD0,
	out float4 OutColor : COLOR0
	)
{
	int SampleIndex;
	half4 Sum = 0;
	for(SampleIndex = 0;SampleIndex < NUM_SAMPLES - 1;SampleIndex += 2)
	{
		half Mask; 
		float4 UVUV = InOffsetUVs[SampleIndex / 2];
		
		Mask = ComputeMask(UVUV.xy);
		Sum += tex2D(FilterTexture,UVUV.xy) * Mask * SampleWeights[SampleIndex + 0];

		Mask = ComputeMask(UVUV.wz);
		Sum += tex2D(FilterTexture,UVUV.wz) * Mask * SampleWeights[SampleIndex + 1];
	}
	if(SampleIndex < NUM_SAMPLES)
	{
		float4 UVUV = InOffsetUVs[SampleIndex / 2];

		half Mask = ComputeMask(UVUV.xy);
		Sum += tex2D(FilterTexture,UVUV.xy) * Mask * SampleWeights[SampleIndex + 0];
	}

	// RETURN_COLOR not needed unless writing to SceneColor;
	OutColor = Sum;
}

// currently only used for downsampling, doesn't need to be masked as it doesn't read outside bounds
void MainDepthInAlpha(
	float4 InOffsetUVs[(NUM_SAMPLES + 1) / 2] : TEXCOORD0,
	out float4 OutColor : COLOR0
	)
{
	int SampleIndex;
	half4 Sum = 0;

	for(SampleIndex = 0;SampleIndex < NUM_SAMPLES - 1;SampleIndex += 2)
	{
		{
			float2 UV = InOffsetUVs[SampleIndex / 2].xy;
			half Weight = SampleWeights[SampleIndex + 0].r;

			Sum.rgb += tex2D(FilterTexture, UV).rgb * Weight;
		}
		{
			float2 UV = InOffsetUVs[SampleIndex / 2].wz;
			half Weight = SampleWeights[SampleIndex + 1].r;

			Sum.rgb += tex2D(FilterTexture, UV).rgb * Weight;
		}
	}
	if(SampleIndex < NUM_SAMPLES)
	{
		float2 UV = InOffsetUVs[SampleIndex / 2].xy;
		half Weight = SampleWeights[SampleIndex + 0].r;

		Sum.rgb += tex2D(FilterTexture, UV).rgb * Weight;
	}
// currently the depth in alpha feature is only used with 4 samples
#if NUM_SAMPLES == 4
	// to avoid leaking between far and near blur we don't do average on depth
	// we take the sample that is nearest to the average
	{
		float4 Samples;
		
		Samples.x = CompressDeviceZIntoHalfResTextureChannel(GetSceneDeviceZ(InOffsetUVs[0].xy));
		Samples.y = CompressDeviceZIntoHalfResTextureChannel(GetSceneDeviceZ(InOffsetUVs[0].wz));
		Samples.z = CompressDeviceZIntoHalfResTextureChannel(GetSceneDeviceZ(InOffsetUVs[1].xy));
		Samples.w = CompressDeviceZIntoHalfResTextureChannel(GetSceneDeviceZ(InOffsetUVs[1].wz));

		float Avg = dot(Samples, 0.25f);

		Samples -= Avg;

		float Chosen = Samples.x;
		Chosen = (abs(Samples.y) < abs(Chosen)) ? Samples.y : Chosen;
		Chosen = (abs(Samples.z) < abs(Chosen)) ? Samples.z : Chosen;
		Chosen = (abs(Samples.w) < abs(Chosen)) ? Samples.w : Chosen;
		Sum.a = Chosen + Avg;
	}
#endif

	// RETURN_COLOR not needed unless writing to SceneColor;
	OutColor = Sum;
}

// --------------------

// to visualize the content of a texture to the screen, useful for debugging
// use "VisualizeTexture" in the console to activate
sampler2D VisualizeTexture;
// [0]: RGBAdd, AMul, Add, FracScale
// [1]: BlinkState=0/1, Frac when 0, saturate when 1, unused, unused
float4 VisualizeParam[2];

void VisualizeTexturePS(
	float4 InOffsetUVs[1] : TEXCOORD0,
	out float4 OutColor : COLOR0)
{
	float2 UV = InOffsetUVs[0].xy;

	float4 TexLookup = tex2D(VisualizeTexture, UV);

	float Add = TexLookup.a * VisualizeParam[0].y + VisualizeParam[0].z;
	OutColor.rgb = TexLookup.rgb * VisualizeParam[0].xxx + Add.xxx;

	float3 ScaledColor = OutColor.rgb * VisualizeParam[0].w;
	float3 FracOutColor = lerp(frac(ScaledColor), saturate(ScaledColor), VisualizeParam[1].y);

	float3 AlternateColor = FracOutColor;

	// blink green if >1
	if(OutColor.r > 1.0f || OutColor.g > 1.0f || OutColor.b > 1.0f)
	{
		AlternateColor = float3(0,1,0);
	}
	
	// blink red if <0
	if(OutColor.r < 0.0f || OutColor.g < 0.0f || OutColor.b < 0.0f)
	{
		AlternateColor = float3(1,0,0);
	}
	
	// blink blue if not finite
	if (isfinite(OutColor.rgb).x == false)
	{
		AlternateColor = float3(0,0,1);
	}

	OutColor.rgb = lerp(FracOutColor, AlternateColor, VisualizeParam[1].x);
	OutColor.a = 0;
}