/*=============================================================================
	Fog.hlsl: Scene fogging pixel shaders.
	Copyright © 2004-2005 Epic Games, Inc. All Rights Reserved.
=============================================================================*/

#include "Common.hlsl"

static const float FLT_EPSILON = 0.001f;

/** calculate ratio of distance between world z height and relative fog height */
float4 linePlaneIntersection(float3 RelativeB,float4 RelativeZ)
{
	return RelativeZ / (abs(RelativeB.z) <= FLT_EPSILON ? FLT_EPSILON : RelativeB.z);
}

/** lighting contribution from fog */
const half3	FogInScattering[4];
/** distance at which fog will start */
const half4	FogStartDistance;
const half4 FogEndDistance;
const half4 FogStartDensity;
const half4 FogEndDensity;

// Propaganda Addition
const half FogHasVignette;
sampler FogVignetteTexture;

// FoxHasNoise.x is a flag for whether a noise texture exists or not.
// y is an intensity multiplier for the noise.
// z is a zoom value for the noise texture.
const half4 FogHasNoise;
sampler FogNoiseTexture;

// Use to animate the fog through time.
const half FogTime;

struct PSInput
{
	float2	TexCoord : TEXCOORD0;
	float4	ScreenVector : TEXCOORD1;
	float4	MinHeightRelativeZ : TEXCOORD2;
	float4	MaxHeightRelativeZ : TEXCOORD3;
	float4	Dummy : TEXCOORD4;
	// Propaganda Addition
	float2	ZeroToOneScreenPosition : TEXCOORD5;
};

float4 fogScene(PSInput Input) : COLOR0
{
	half3	SceneColor = tex2D(PreviousLightingTexture,Input.TexCoord).rgb;
	half	SceneDepth = calcSceneDepth(Input.TexCoord);
	half	ClampedSceneDepth = clamp(SceneDepth,1,65500);

	// vector into the screen of length SceneDepth
	float3	WorldPosition = Input.ScreenVector * ClampedSceneDepth;

			// maxfog - camera / z height
	half4	MinHeightPercent = linePlaneIntersection(WorldPosition,Input.MinHeightRelativeZ),
			// minfog - camera / z height
			MaxHeightPercent = linePlaneIntersection(WorldPosition,Input.MaxHeightRelativeZ),
			// swap Min/Max % when crossing over z==0 and clamp to [0,1]
			MinPercent = saturate(WorldPosition.z <= 0 ? MaxHeightPercent : MinHeightPercent),
			MaxPercent = saturate(WorldPosition.z <= 0 ? MinHeightPercent : MaxHeightPercent),
			// fog layer distance based on % over max/min fog heights
			LayerDistance = max(0,ClampedSceneDepth) * saturate(MaxPercent - MinPercent);

			// Interpolate the scattering
	half4	FogRange = FogEndDistance - FogStartDistance;
	half4	LerpFactor = (LayerDistance - FogStartDistance) / FogRange;
	half4	Scattering = LayerDistance < FogStartDistance ? lerp(half4(1,1,1,1), FogStartDensity, LayerDistance/FogStartDistance): (LayerDistance < FogEndDistance ? lerp(FogStartDensity, FogEndDensity, LerpFactor) : FogEndDensity);

	// Propaganda Addition
	half	FogNoise = 0;
			// Apply noise
			if (FogHasNoise.x > 0)
			{
				half2 NoiseOffset;

				// Use the time to offset the noise
				sincos(FogTime, NoiseOffset.x, NoiseOffset.y);
				FogNoise = tex2D(FogNoiseTexture, (Input.ZeroToOneScreenPosition + NoiseOffset) / FogHasNoise.z).r;

				// Apply the user-supplied scale factor
				FogNoise = (FogNoise - 0.5) * FogHasNoise.y;
			}

			// Modify the fog by the vignette
	half4	ScatteringDiff = half4(1, 1, 1, 1) - Scattering;
	half	VignetteBlend = 0;

			if (FogHasVignette > 0)
			{
				VignetteBlend = tex2D(FogVignetteTexture, Input.ZeroToOneScreenPosition).r;
			}
			Scattering = Scattering + VignetteBlend * ScatteringDiff;

	// ratio of the inscattering color to be used
	half4	InScattering = Scattering - 1;

	// handle up to 4 fog layers
	for(int LayerIndex = 0;LayerIndex < 4;LayerIndex++)
	{
		// Propaganda Modification
		SceneColor = SceneColor * Scattering[LayerIndex] + saturate(InScattering[LayerIndex] * (FogInScattering[LayerIndex] - FogNoise));
	}

	// return fog blended with scene as well as the depth for the alpha channel
	RETURN_COLOR( float4(SceneColor,SceneDepth) );
}

struct VSOutput
{
	float4	Position : POSITION;
	float2	TexCoord : TEXCOORD0;
	float4	ScreenVector : TEXCOORD1;
	float4	MinHeightRelativeZ : TEXCOORD2;
	float4	MaxHeightRelativeZ : TEXCOORD3;
	float4	Dummy : TEXCOORD4;
	// Propaganda Addition
	float2	ZeroToOneScreenPosition : TEXCOORD5;
};

// world space min z height
const float4	FogMinHeight;
// world space max z height
const float4	FogMaxHeight;
// transform from [-1,1] screen space to world
const float4x4	ScreenToWorld;
// world position of camera
const float3	CameraPosition;

VSOutput vertexShader(float4 Position : POSITION,float2 TexCoord : TEXCOORD0)
{
	VSOutput Result;
	
	// screenspace position from vb
	Result.Position = Position;
	// texture coord from vb
	Result.TexCoord = TexCoord;
	// remap texcoord inputs from [0,ScreenSize/BufferSize] to [-1,1] and deproject to world space
	Result.ScreenVector = normalize(mul(ScreenToWorld,float4((TexCoord - ScreenPositionScaleBias.wz) / ScreenPositionScaleBias.xy,1,0)));	
	Result.Dummy = mul(ScreenToWorld,float4((TexCoord - ScreenPositionScaleBias.wz) / ScreenPositionScaleBias.xy,1,1));
	// Propaganda Addition
	Result.ZeroToOneScreenPosition = ((((TexCoord - ScreenPositionScaleBias.wz) / ScreenPositionScaleBias.xy)+1)/2);
	Result.ZeroToOneScreenPosition.y = 1 - Result.ZeroToOneScreenPosition.y;
	// z distance from fog min to camera position
	Result.MinHeightRelativeZ = FogMinHeight - CameraPosition.z;
	// z distance from fog max to camera position
	Result.MaxHeightRelativeZ = FogMaxHeight - CameraPosition.z;

	return Result;
}
