/*=============================================================================
	DepthOfFieldAndBloom.hlsl: Combined depth of field and bloom shaders.
	Copyright © 2006 Epic Games, Inc. All Rights Reserved.
=============================================================================*/

#include "Common.hlsl"

/**
 * R = FocusDistance
 * G = 1 / FocusRadius
 * B = FocusExponent
 */
half3 FocusParameters;

/** clamp for min/max blur amount values - default would be [1,1] */
float2 MinMaxBlurClamp;

half CalcUnfocusedPercent(float SceneDepth)
{
	// Blur amount based on ratio of distance to focus plane to the focus radius
	// it is clamped to [-1,1]. Note that FocusDistance can be negative if it 
	// falls behind the near plane.
	half RelativeDistanceSign = sign(SceneDepth - FocusParameters.r);
	half MaxUnfocusedPercent = RelativeDistanceSign < 0 ? MinMaxBlurClamp.x : MinMaxBlurClamp.y;
	return min(
		MaxUnfocusedPercent,
		pow(
			saturate(abs(SceneDepth - FocusParameters.r) * FocusParameters.g),
			FocusParameters.b
			)
		);
}

#if NUM_SAMPLES

float BloomScale;

half4 ComputeWeightedSample(float2 UV)
{
	half UnfocusedPercent = CalcUnfocusedPercent(calcSceneDepth(UV));
	half3 SceneColor = CalcSceneColor(UV);
	half3 BloomColor = any(SceneColor < 0 || SceneColor > 1) ? (SceneColor * BloomScale) : 0;
	return float4(
		UnfocusedPercent * SceneColor + BloomColor,
		UnfocusedPercent
		) / NUM_SAMPLES;
}

void GatherPixelShader(
	in float4 OffsetUVs[(NUM_SAMPLES + 1) / 2] : TEXCOORD0,
	out float4 OutColor : COLOR0
	)
{
	half4 Result = 0;
	for(int SampleIndex = 0;SampleIndex < NUM_SAMPLES;SampleIndex += 2)
	{
		Result += ComputeWeightedSample(OffsetUVs[SampleIndex / 2].xy);
		if(SampleIndex + 1 < NUM_SAMPLES)
		{
			Result += ComputeWeightedSample(OffsetUVs[SampleIndex / 2].wz);
		}
	}
	OutColor = Result;
}

float4 SampleOffsets[(NUM_SAMPLES + 1) / 2];

void GatherVertexShader(
	in float4 InPosition : POSITION,
	in float2 InUV : TEXCOORD0,
	out float4 OutPosition : POSITION,
	out float4 OutOffsetUVs[(NUM_SAMPLES + 1) / 2] : TEXCOORD0
	)
{
	OutPosition = InPosition;
	for(int OffsetIndex = 0;OffsetIndex < (NUM_SAMPLES + 1) / 2;OffsetIndex++)
	{
		OutOffsetUVs[OffsetIndex] = InUV.xyyx + SampleOffsets[OffsetIndex];
	}
}

#else

sampler2D LinearImage;

half4 BlendPixelShader(float2 UV : TEXCOORD0,float2 SceneUV : TEXCOORD1) : COLOR0
{
	float SceneDepth = calcSceneDepth(SceneUV);

	half3 FocusedSceneColor = CalcSceneColor(SceneUV);
	half FocusedWeight = saturate(1 - CalcUnfocusedPercent(SceneDepth));

	half3 UnfocusedSceneColor = tex2D(LinearImage,UV).rgb;
	half UnfocusedWeight = tex2D(LinearImage,UV).a;

	half WeightSum = max(FocusedWeight + UnfocusedWeight,0.001);

	RETURN_COLOR( 
//PGMOD_BEGIN(MJP)
// There was an issue with banding around highly bloomed objects due to the colour wrapping.  So, we clamp.
		saturate
//PGMOD_END(MJP)
		(float4((FocusedSceneColor * FocusedWeight + UnfocusedSceneColor) / WeightSum, SceneDepth )) );
}

half4 SceneCoordinateScaleBias;

void BlendVertexShader(
	in float4 InPosition : POSITION,
	in float3 InTexCoord : TEXCOORD0,
	out float4 OutPosition : POSITION,
	out float2 OutTexCoord : TEXCOORD0,
	out float2 OutSceneUV : TEXCOORD1
	)
{
	OutPosition = InPosition;
	OutTexCoord = InTexCoord;
	OutSceneUV = InPosition.xy / InPosition.w * SceneCoordinateScaleBias.xy + SceneCoordinateScaleBias.wz;
}

#endif