#include "MasterEffect.h"
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// END OF TWEAKING VARIABLES      											     //
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//global vars
#define ScreenSize 	float4(BUFFER_WIDTH, BUFFER_RCP_WIDTH, float(BUFFER_WIDTH) / float(BUFFER_HEIGHT), float(BUFFER_HEIGHT) / float(BUFFER_WIDTH)) //x=Width, y=1/Width, z=ScreenScaleY, w=1/ScreenScaleY
#define PixelSize  	float2(BUFFER_RCP_WIDTH, BUFFER_RCP_HEIGHT)
#define PI 		3.1415972
#define PIOVER180 	0.017453292
#define AUTHOR 		MartyMcFly
#define FOV 		75
#define LumCoeff 	float3(0.212656, 0.715158, 0.072186)
#define zFarPlane 	1
#define zNearPlane 	0.001		//I know, weird values but ReShade's depthbuffer is ... odd
#define aspect          (BUFFER_RCP_HEIGHT/BUFFER_RCP_WIDTH)
#define InvFocalLen 	float2(tan(0.5f*radians(FOV)) / (float)BUFFER_RCP_HEIGHT * (float)BUFFER_RCP_WIDTH, tan(0.5f*radians(FOV)))
uniform float4 Timer < source = "timer"; >;

#pragma message "MasterEffect ReBorn 1.1.287 by Marty McFly"

// Global Settings
#include "MasterEffect\common.cfg"

#if RFX_Screenshot_Format != 2
	#pragma reshade screenshot_format bmp
#else
	#pragma reshade screenshot_format png
#endif

#if RFX_ShowFPS == 1
	#pragma reshade showfps
#endif
#if RFX_ShowClock == 1
	#pragma reshade showclock
#endif
#if RFX_ShowStatistics == 1
	#pragma reshade showstatistics
#endif

#if RFX_ShowToggleMessage == 1
	#pragma reshade showtogglemessage
#endif

//textures
texture   texBloom1 { Width = BUFFER_WIDTH; Height = BUFFER_HEIGHT; };
texture   texBloom2 { Width = BUFFER_WIDTH; Height = BUFFER_HEIGHT; };
texture   texBloom3 { Width = BUFFER_WIDTH/2; Height = BUFFER_HEIGHT/2; };
texture   texBloom4 { Width = BUFFER_WIDTH/4; Height = BUFFER_HEIGHT/4; };
texture   texBloom5 { Width = BUFFER_WIDTH/8; Height = BUFFER_HEIGHT/8; };

texture   texLens1 { Width = BUFFER_WIDTH/2; Height = BUFFER_HEIGHT/2; };
texture   texLens2 { Width = BUFFER_WIDTH/2; Height = BUFFER_HEIGHT/2; };

texture2D texLDR : COLOR;
texture   texHDR1 	{ Width = BUFFER_WIDTH; Height = BUFFER_HEIGHT; MipLevels = 5; };	
texture   texHDR2 	{ Width = BUFFER_WIDTH; Height = BUFFER_HEIGHT; MipLevels = 5; };

texture   texCoC	{ Width = BUFFER_WIDTH; Height = BUFFER_HEIGHT;  MipLevels = 5; Format = RGBA16F;};
texture2D texDepth : DEPTH;

texture   texNoise  < string source = "MasterEffect/internal/mcnoise.png";  	> {Width = BUFFER_WIDTH;Height = BUFFER_HEIGHT;Format = RGBA8;};
texture   texSprite < string source = "MasterEffect/mcsprite.png"; 	 	> {Width = BUFFER_WIDTH;Height = BUFFER_HEIGHT;Format = RGBA8;};
texture   texDirt   < string source = "MasterEffect/mcdirt.png";   		> {Width = BUFFER_WIDTH;Height = BUFFER_HEIGHT;Format = RGBA8;};
texture   texLUT    < string source = "MasterEffect/mclut.png";    		> {Width = 256; Height = 1;   Format = RGBA8;};
texture   texLUT3D  < string source = "MasterEffect/mclut3d.png";  		> {Width = 256; Height = 16;   Format = RGBA8;};
texture   texMask   < string source = "MasterEffect/mcmask.png";   		> {Width = BUFFER_WIDTH;Height = BUFFER_HEIGHT;Format = R8;};
texture   texHeat   < string source = "MasterEffect/internal/mcheat.png";   	> {Width = 512;Height = 512;Format = RGBA8;};

//samplers
sampler SamplerBloom1 { Texture = texBloom1; };
sampler SamplerBloom2 { Texture = texBloom2; };
sampler SamplerBloom3 { Texture = texBloom3; };
sampler SamplerBloom4 { Texture = texBloom4; };
sampler SamplerBloom5 { Texture = texBloom5; };

sampler SamplerLens1 { Texture = texLens1; };
sampler SamplerLens2 { Texture = texLens2; };

sampler2D SamplerLDR
{
	Texture = texLDR;
	MinFilter = LINEAR;
	MagFilter = LINEAR;
	MipFilter = LINEAR;
	AddressU = Clamp;
	AddressV = Clamp;
};

sampler2D SamplerHDR1
{
	Texture = texHDR1;
	MinFilter = LINEAR;
	MagFilter = LINEAR;
	MipFilter = LINEAR;
	AddressU = Clamp;
	AddressV = Clamp;
};

sampler2D SamplerHDR2
{
	Texture = texHDR2;
	MinFilter = LINEAR;
	MagFilter = LINEAR;
	MipFilter = LINEAR;
	AddressU = Clamp;
	AddressV = Clamp;
};

sampler2D SamplerCoC
{
	Texture = texCoC;
	MinFilter = LINEAR;
	MagFilter = LINEAR;
	MipFilter = LINEAR;
	AddressU = Clamp;
	AddressV = Clamp;
};

sampler2D SamplerDepth
{
	Texture = texDepth;
	MinFilter = LINEAR;
	MagFilter = LINEAR;
	MipFilter = LINEAR;
	AddressU = Clamp;
	AddressV = Clamp;
};

sampler2D SamplerNoise
{
	Texture = texNoise;
	MinFilter = LINEAR;
	MagFilter = LINEAR;
	MipFilter = NONE;
	AddressU = Wrap;
	AddressV = Wrap;
};

sampler2D SamplerSprite
{
	Texture = texSprite;
	MinFilter = LINEAR;
	MagFilter = LINEAR;
	MipFilter = NONE;
	AddressU = Clamp;
	AddressV = Clamp;
};

sampler2D SamplerDirt
{
	Texture = texDirt;
	MinFilter = LINEAR;
	MagFilter = LINEAR;
	MipFilter = LINEAR;
	AddressU = Clamp;
	AddressV = Clamp;
};

sampler2D SamplerLUT
{
	Texture = texLUT;
	MinFilter = LINEAR;
	MagFilter = LINEAR;
	MipFilter = LINEAR;
	AddressU = Clamp;
	AddressV = Clamp;
};

sampler2D SamplerLUT3D
{
	Texture = texLUT3D;
	MinFilter = LINEAR;
	MagFilter = LINEAR;
	MipFilter = LINEAR;
	AddressU = Clamp;
	AddressV = Clamp;
};

sampler2D SamplerMask
{
	Texture = texMask;
	MinFilter = LINEAR;
	MagFilter = LINEAR;
	MipFilter = LINEAR;
	AddressU = Clamp;
	AddressV = Clamp;
};

sampler2D SamplerHeat
{
	Texture = texHeat;
	MinFilter = LINEAR;
	MagFilter = LINEAR;
	MipFilter = LINEAR;
	AddressU = Repeat;
	AddressV = Repeat;
};

struct VS_OUTPUT_POST
{
	float4 vpos : SV_Position;
	float2 txcoord : TEXCOORD0;
};

struct VS_INPUT_POST
{
	uint id : SV_VertexID;
};

//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// Vertex Shaders													     //
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

VS_OUTPUT_POST VS_MasterEffect(VS_INPUT_POST IN)
{
	VS_OUTPUT_POST OUT;
	OUT.txcoord.x = (IN.id == 2) ? 2.0 : 0.0;
	OUT.txcoord.y = (IN.id == 1) ? 2.0 : 0.0;
	OUT.vpos = float4(OUT.txcoord * float2(2.0, -2.0) + float2(-1.0, 1.0), 0.0, 1.0);
	return OUT;
}

//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// SMAA													     		     //
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

#include "MasterEffect/internal/mcsmaa.hlsl"

//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// Functions														     //
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

float GetLinearDepth(float depth)
{
	return  1 / ((depth * ((zFarPlane - zNearPlane) / (-zFarPlane * zNearPlane)) + zFarPlane / (zFarPlane * zNearPlane)));
}

float3 GetNormalFromDepth(float fDepth, float2 vTexcoord) {
  
  	const float2 offset1 = float2(0.0,0.001);
  	const float2 offset2 = float2(0.001,0.0);
  
  	float depth1 = GetLinearDepth(tex2Dlod(SamplerDepth, float4(vTexcoord + offset1,0,0)).x);
  	float depth2 = GetLinearDepth(tex2Dlod(SamplerDepth, float4(vTexcoord + offset2,0,0)).x);
  
  	float3 p1 = float3(offset1, depth1 - fDepth);
  	float3 p2 = float3(offset2, depth2 - fDepth);
  
  	float3 normal = cross(p1, p2);
  	normal.z = -normal.z;
  
  	return normalize(normal);
}

float GetRandom(float2 co){
	return frac(sin(dot(co, float2(12.9898, 78.233))) * 43758.5453);
}

float3 GetRandomVector(float2 vTexCoord) {
  	return 2 * normalize(float3(GetRandom(vTexCoord - 0.5f),
				    GetRandom(vTexCoord + 0.5f),
				    GetRandom(vTexCoord))) - 1;
}

float4 GetAtlasTex(sampler tex, float2 coord, float spaltenzahl, float reihenzahl, float spalte, float reihe)
{
	return tex2Dlod(tex, float4(coord.xy/float2(spaltenzahl, reihenzahl)+float2((spalte-1)/spaltenzahl,(reihe-1)/reihenzahl),0,0));
}


float4 GaussBlur22(float2 coord, sampler tex, float mult, float lodlevel, bool isBlurVert) //texcoord, texture, blurmult in pixels, tex2dlod level, axis (0=horiz, 1=vert)
{
	float4 sum = 0;
	float2 axis = (isBlurVert) ? float2(0, 1) : float2(1, 0);
	float  weight[11] = {0.082607, 0.080977, 0.076276, 0.069041, 0.060049, 0.050187, 0.040306, 0.031105, 0.023066, 0.016436, 0.011254};

	for(int i=-10; i < 11; i++)
	{
		float currweight = weight[abs(i)];	
		sum	+= tex2Dlod(tex, float4(coord.xy + axis.xy * (float)i * PixelSize * mult,0,lodlevel)) * currweight;
	}

	return sum;
}

float4 GaussBlurGeneric(float2 coord, sampler tex, float mult, float lodlevel, bool isBlurVert, float Radius, float Quality) //texcoord, texture, blurmult in pixels, tex2dlod level, axis (0=horiz, 1=vert), offset count, quality
{
	float2 axis = (isBlurVert) ? float2(0, 1) : float2(1, 0);

	float4 Sigma = 0;
	
	Sigma.x				= 1.0f / ( sqrt( 2.0f * PI ) * Radius );
	Sigma.y				= exp( -0.5f / ( Radius * Radius ));
	Sigma.z				= Sigma.y * Sigma.y;
	Sigma.w				= Sigma.x;
	Sigma.xy			*= Sigma.yz;

	float4 sum = tex2Dlod(tex, float4(coord.xy,0,lodlevel))*Sigma.x;

	for(int i = 1; i < 150 && Sigma.w < Quality; i++) 
	{
		sum 	+= tex2Dlod(tex, float4(coord.xy + axis.xy * (float)i * PixelSize * mult,0,lodlevel)) * Sigma.x;
		sum 	+= tex2Dlod(tex, float4(coord.xy - axis.xy * (float)i * PixelSize * mult,0,lodlevel)) * Sigma.x;
		Sigma.w += 2.0 * Sigma.x;
		Sigma.xy *= Sigma.yz;
	}

	sum /= Sigma.w;

	return sum;
}

float smootherstep(float edge0, float edge1, float x)
{
   	x = clamp((x - edge0)/(edge1 - edge0), 0.0, 1.0);
   	return x*x*x*(x*(x*6 - 15) + 10);
}

float3 Hue(in float3 RGB)
{
   	// Based on work by Sam Hocevar and Emil Persson
   	float Epsilon = 1e-10;
   	float4 P = (RGB.g < RGB.b) ? float4(RGB.bg, -1.0, 2.0/3.0) : float4(RGB.gb, 0.0, -1.0/3.0);
   	float4 Q = (RGB.r < P.x) ? float4(P.xyw, RGB.r) : float4(RGB.r, P.yzx);
   	float C = Q.x - min(Q.w, Q.y);
   	float H = abs((Q.w - Q.y) / (6 * C + Epsilon) + Q.z);
   	return float3(H, C, Q.x);
}

//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// Passes														     //
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

float4 BorderPass( float4 colorInput, float2 tex )
{
  	float3 fBorderColor_float = fBorderColor;
	float2 screen_size = float2(BUFFER_WIDTH, BUFFER_HEIGHT);
	float  screen_ratio = (BUFFER_WIDTH/BUFFER_HEIGHT);
  	float2 fBorderWidth_variable = fBorderWidth;

  	// -- calculate the right fBorderWidth for a given fBorderRatio --
  	//if (!any(fBorderWidth)) //if fBorderWidth is not used
  	if (fBorderWidth.x == -fBorderWidth.y) //if fBorderWidth is not used
    		if (screen_ratio < fBorderRatio)
      			fBorderWidth_variable = float2(0.0, (screen_size.y - (screen_size.x / fBorderRatio)) * 0.5);
    		else
      			fBorderWidth_variable = float2((screen_size.x - (screen_size.y * fBorderRatio)) * 0.5, 0.0);

  	float2 border = (PixelSize.xy * fBorderWidth_variable); //Translate integer pixel width to floating point

  	float2 within_border = saturate((-tex * tex + tex) - (-border * border + border)); //becomes positive when inside the border and 0 when outside

  	colorInput.rgb = all(within_border) ?  colorInput.rgb : fBorderColor_float ; //if the pixel is within the border use the original color, if not use the fBorderColor

  	return colorInput; //return the pixel
}

float3 CartoonPass( float3 colorInput, float2 tex, float2 pixelsize, sampler colorsampler )
{
 
  	float diff1 = dot(LumCoeff,tex2D(colorsampler, tex + pixelsize).rgb);
  	diff1 = dot(float4(LumCoeff,-1.0),float4(tex2D(colorsampler, tex - pixelsize).rgb , diff1));
  
  	float diff2 = dot(LumCoeff,tex2D(colorsampler, tex +float2(pixelsize.x,-pixelsize.y)).rgb);
  	diff2 = dot(float4(LumCoeff,-1.0),float4(tex2D(colorsampler, tex +float2(-pixelsize.x,pixelsize.y)).rgb , diff2));
    
  	float edge = dot(float2(diff1,diff2),float2(diff1,diff2));
  
  	colorInput.rgb =  pow(edge,CartoonEdgeSlope) * -CartoonPower + colorInput.rgb;
	
	return saturate(colorInput);
}

float3 LevelsPass( float3 colorInput )
{
	#define black_point_float ( Levels_black_point / 255.0 )
	#define white_point_float ( 255.0 / (Levels_white_point - Levels_black_point)) 

 	colorInput.rgb = colorInput.rgb * white_point_float - (black_point_float *  white_point_float);
  	return colorInput;
}

float3 TechniPass_prod80(float3 colorInput)
{

	float3 colStrength = float3(ColStrengthR,ColStrengthG,ColStrengthB);
	float3 tsource = saturate(colorInput.rgb);
	float3 ttemp = 1 - tsource;
	float3 ttarget = ttemp.grg;
	float3 ttarget2 = ttemp.bbr;
	float3 ttemp2 = tsource.rgb * ttarget.rgb;
	ttemp2.rgb *= ttarget2.rgb;

	ttemp.rgb = ttemp2.rgb * colStrength;
	ttemp2.rgb *= TechniBrightness;

	ttarget.rgb = ttemp.grg;
	ttarget2.rgb = ttemp.bbr;

	ttemp.rgb = tsource.rgb - ttarget.rgb;
	ttemp.rgb += ttemp2.rgb;
	ttemp2.rgb = ttemp.rgb - ttarget2.rgb;

	colorInput.rgb = lerp(tsource.rgb, ttemp2.rgb, TechniStrength);

	colorInput.rgb = lerp(dot(colorInput.rgb, 0.333), colorInput.rgb, TechniSat); 
	
	return colorInput.rgb;

}

float3 TechnicolorPass( float3 colorInput )
{

	#define cyanfilter float3(0.0, 1.30, 1.0)
	#define magentafilter float3(1.0, 0.0, 1.05) 
	#define yellowfilter float3(1.6, 1.6, 0.05)

	#define redorangefilter float2(1.05, 0.620) //RG_
	#define greenfilter float2(0.30, 1.0)       //RG_
	#define magentafilter2 magentafilter.rb     //R_B

	float3 tcol = colorInput.rgb;
	
  	float2 rednegative_mul   = tcol.rg * (1.0 / (redNegativeAmount * TechniPower));
	float2 greennegative_mul = tcol.rg * (1.0 / (greenNegativeAmount * TechniPower));
	float2 bluenegative_mul  = tcol.rb * (1.0 / (blueNegativeAmount * TechniPower));
	
  	float rednegative   = dot( redorangefilter, rednegative_mul );
	float greennegative = dot( greenfilter, greennegative_mul );
	float bluenegative  = dot( magentafilter2, bluenegative_mul );
	
	float3 redoutput   = rednegative.rrr + cyanfilter;
	float3 greenoutput = greennegative.rrr + magentafilter;
	float3 blueoutput  = bluenegative.rrr + yellowfilter;
	
	float3 result = redoutput * greenoutput * blueoutput;
	colorInput.rgb = lerp(tcol, result, TechniAmount);
	return colorInput;
}

float3 DPXPass(float3 InputColor){


	float3x3 RGB =
	float3x3(
	2.67147117265996,-1.26723605786241,-0.410995602172227,
	-1.02510702934664,1.98409116241089,0.0439502493584124,
	0.0610009456429445,-0.223670750812863,1.15902104167061
	);

	float3x3 XYZ =
	float3x3(
	0.500303383543316,0.338097573222739,0.164589779545857,
	0.257968894274758,0.676195259144706,0.0658358459823868,
	0.0234517888692628,0.1126992737203,0.866839673124201
	);

	float DPXContrast = 0.1;
	float DPXGamma = 1.0;

	float RedCurve = DPXRed;
	float GreenCurve = DPXGreen;
	float BlueCurve = DPXBlue;
	
	float3 RGB_Curve = float3(DPXRed,DPXGreen,DPXBlue);
	float3 RGB_C = float3(DPXRedC,DPXGreenC,DPXBlueC);

	float3 B = InputColor.rgb;
	B = pow(B, 1.0/DPXGamma);
 	B = B * (1.0 - DPXContrast) + (0.5 * DPXContrast);

	float3 Btemp = (1.0 / (1.0 + exp(RGB_Curve / 2.0)));	  
	B = ((1.0 / (1.0 + exp(-RGB_Curve * (B - RGB_C)))) / (-2.0 * Btemp + 1.0)) + (-Btemp / (-2.0 * Btemp + 1.0));

    	float value = max(max(B.r, B.g), B.b);
	float3 color = B / value;
	color = saturate(color);
	color = pow(color, 1.0/DPXColorGamma);
	
	float3 c0 = color * value;
        c0 = mul(XYZ, c0);

	float luma = dot(c0, float3(0.30, 0.59, 0.11)); //Use BT 709 instead?
        c0 = (1.0 - DPXSaturation) * luma + DPXSaturation * c0;
	c0 = mul(RGB, c0);
	
	InputColor.rgb = lerp(InputColor.rgb, c0, DPXBlend);

	return InputColor;
}

float3 LiftGammaGainPass( float3 colorInput )
{
	// -- Get input --
	float3 color = colorInput.rgb;
	
	// -- Lift --
	color = color * (1.5-0.5 * RGB_Lift) + 0.5 * RGB_Lift - 0.5;
	color = saturate(color); //isn't strictly necessary, but doesn't cost performance.
	
	// -- Gain --
	color *= RGB_Gain; 
	
	// -- Gamma --
	colorInput.rgb = pow(color, 1.0 / RGB_Gamma); //Gamma
	
	// -- Return output --
	//return (colorInput);
	return saturate(colorInput);
}

float3 TonemapPass( float3 colorInput )
{
	float3 color = colorInput.rgb;

	color = saturate(color - Defog * FogColor); // Defog
	
	color *= pow(2.0f, Exposure); // Exposure
	
	color = pow(color, Gamma);    // Gamma -- roll into the first gamma correction in main.h ?
	
	float lum = dot(LumCoeff, color.rgb);
	
	float3 blend = lum.rrr; //dont use float3
	
	float L = saturate( 10.0 * (lum - 0.45) );
  	
	float3 result1 = 2.0f * color.rgb * blend;
	float3 result2 = 1.0f - 2.0f * (1.0f - blend) * (1.0f - color.rgb);
	
	float3 newColor = lerp(result1, result2, L);
	float3 A2 = Bleach * color.rgb; //why use a float for A2 here and then multiply by color.rgb (a float3)?
	float3 mixRGB = A2 * newColor;
	
	color.rgb += ((1.0f - A2) * mixRGB);
	
	float3 middlegray = dot(color,(1.0/3.0)); //1fps slower than the original on nvidia, 2 fps faster on AMD
	
	float3 diffcolor = color - middlegray; //float 3 here
	colorInput.rgb = (color + diffcolor * Saturation)/(1+(diffcolor*Saturation)); //saturation
	
	return colorInput;
}

float3 VibrancePass( float3 colorInput )
{
   	#define Vibrance_coeff float3(Vibrance_RGB_balance * Vibrance)

	float3 color = colorInput; //original input color
  	float3 lumCoeff = float3(0.212656, 0.715158, 0.072186);  //Values to calculate luma with

	float luma = dot(LumCoeff, color.rgb); //calculate luma (grey)

	float max_color = max(colorInput.r, max(colorInput.g,colorInput.b)); //Find the strongest color
	float min_color = min(colorInput.r, min(colorInput.g,colorInput.b)); //Find the weakest color

  	float color_saturation = max_color - min_color; //The difference between the two is the saturation

   	color.rgb = lerp(luma, color.rgb, (1.0 + (Vibrance_coeff * (1.0 - (sign(Vibrance_coeff) * color_saturation))))); //extrapolate between luma and original by 1 + (1-saturation) - current

 	return color; //return the result
}

float3 CurvesPass( float3 colorInput )
{
  float Curves_contrast_blend = Curves_contrast;


   /*-----------------------------------------------------------.
  /               Separation of Luma and Chroma                 /
  '-----------------------------------------------------------*/

  	// -- Calculate Luma and Chroma if needed --
  	#if Curves_mode != 2

    	//calculate luma (grey)
    	float luma = dot(LumCoeff, colorInput.rgb);

    	//calculate chroma
	float3 chroma = colorInput.rgb - luma;
  	#endif

  	// -- Which value to put through the contrast formula? --
  	// I name it x because makes it easier to copy-paste to Graphtoy or Wolfram Alpha or another graphing program
  	#if Curves_mode == 2
	float3 x = colorInput.rgb; //if the curve should be applied to both Luma and Chroma
	#elif Curves_mode == 1
	float3 x = chroma; //if the curve should be applied to Chroma
	x = x * 0.5 + 0.5; //adjust range of Chroma from -1 -> 1 to 0 -> 1
  	#else // Curves_mode == 0
    	float x = luma; //if the curve should be applied to Luma
  	#endif

   /*-----------------------------------------------------------.
  /                     Contrast formulas                       /
  '-----------------------------------------------------------*/

  	// -- Curve 1 --
  	#if Curves_formula == 1
    	x = sin(PI * 0.5 * x); // Sin - 721 amd fps, +vign 536 nv
    	x *= x;
    
    	//x = 0.5 - 0.5*cos(PI*x);
    	//x = 0.5 * -sin(PI * -x + (PI*0.5)) + 0.5;
  	#endif

  	// -- Curve 2 --
  	#if Curves_formula == 2
    	x = x - 0.5;  
    	x = ( x / (0.5 + abs(x)) ) + 0.5;
    
    	//x = ( (x - 0.5) / (0.5 + abs(x-0.5)) ) + 0.5;
  	#endif

  	// -- Curve 3 --
  	#if Curves_formula == 3
    	//x = smoothstep(0.0,1.0,x); //smoothstep
    	x = x*x*(3.0-2.0*x); //faster smoothstep alternative - 776 amd fps, +vign 536 nv
    	//x = x - 2.0 * (x - 1.0) * x* (x- 0.5);  //2.0 is contrast. Range is 0.0 to 2.0
  	#endif

  	// -- Curve 4 --
  	#if Curves_formula == 4
    	x = (1.0524 * exp(6.0 * x) - 1.05248) / (20.0855 + exp(6.0 * x)); //exp formula
  	#endif

  	// -- Curve 5 --
  	#if Curves_formula == 5
    	//x = 0.5 * (x + 3.0 * x * x - 2.0 * x * x * x); //a simplified catmull-rom (0,0,1,1) - btw smoothstep can also be expressed as a simplified catmull-rom using (1,0,1,0)
    	//x = (0.5 * x) + (1.5 -x) * x*x; //estrin form - faster version
    	x = x * (x * (1.5-x) + 0.5); //horner form - fastest version

    	Curves_contrast_blend = Curves_contrast * 2.0; //I multiply by two to give it a strength closer to the other curves.
  	#endif

 	// -- Curve 6 --
  	#if Curves_formula == 6
    	x = x*x*x*(x*(x*6.0 - 15.0) + 10.0); //Perlins smootherstep
  	#endif

	// -- Curve 7 --
  	#if Curves_formula == 7
    	//x = ((x-0.5) / ((0.5/(4.0/3.0)) + abs((x-0.5)*1.25))) + 0.5;
	x = x - 0.5;
	x = x / ((abs(x)*1.25) + 0.375 ) + 0.5;
	//x = ( (x-0.5) / ((abs(x-0.5)*1.25) + (0.5/(4.0/3.0))) ) + 0.5;
  	#endif

  	// -- Curve 8 --
  	#if Curves_formula == 8
    	x = (x * (x * (x * (x * (x * (x * (1.6 * x - 7.2) + 10.8) - 4.2) - 3.6) + 2.7) - 1.8) + 2.7) * x * x; //Techicolor Cinestyle - almost identical to curve 1
  	#endif

  	// -- Curve 9 --
  	#if Curves_formula == 9
    	x =  -0.5 * (x*2.0-1.0) * (abs(x*2.0-1.0)-2.0) + 0.5; //parabola
  	#endif

  	// -- Curve 10 --
  	#if Curves_formula == 10 //Half-circles

    	#if Curves_mode == 0
      	float xstep = step(x,0.5);
	float xstep_shift = (xstep - 0.5);
	float shifted_x = x + xstep_shift;
   	#else
      	float3 xstep = step(x,0.5);
	float3 xstep_shift = (xstep - 0.5);
	float3 shifted_x = x + xstep_shift;
    	#endif

	x = abs(xstep - sqrt(-shifted_x * shifted_x + shifted_x) ) - xstep_shift;

  	//x = abs(step(x,0.5)-sqrt(-(x+step(x,0.5)-0.5)*(x+step(x,0.5)-0.5)+(x+step(x,0.5)-0.5)))-(step(x,0.5)-0.5); //single line version of the above
    
  	//x = 0.5 + (sign(x-0.5)) * sqrt(0.25-(x-trunc(x*2))*(x-trunc(x*2))); //worse
  
  	/* // if/else - even worse
  	if (x-0.5)
  	x = 0.5-sqrt(0.25-x*x);
  	else
  	x = 0.5+sqrt(0.25-(x-1)*(x-1));
	*/

  	//x = (abs(step(0.5,x)-clamp( 1-sqrt(1-abs(step(0.5,x)- frac(x*2%1)) * abs(step(0.5,x)- frac(x*2%1))),0 ,1))+ step(0.5,x) )*0.5; //worst so far
	
	//TODO: Check if I could use an abs split instead of step. It might be more efficient
	
	Curves_contrast_blend = Curves_contrast * 0.5; //I divide by two to give it a strength closer to the other curves.
  	#endif

  	// -- Curve 11 --
  	#if Curves_formula == 11 //Cubic catmull
    	float a = 1.00; //control point 1
    	float b = 0.00; //start point
    	float c = 1.00; //endpoint
    	float d = 0.20; //control point 2
    	x = 0.5 * ((-a + 3*b -3*c + d)*x*x*x + (2*a -5*b + 4*c - d)*x*x + (-a+c)*x + 2*b); //A customizable cubic catmull-rom spline
  	#endif

  	// -- Curve 12 --
  	#if Curves_formula == 12 //Cubic Bezier spline
    	float a = 0.00; //start point
    	float b = 0.00; //control point 1
    	float c = 1.00; //control point 2
    	float d = 1.00; //endpoint

    	float r  = (1-x);
	float r2 = r*r;
	float r3 = r2 * r;
	float x2 = x*x;
	float x3 = x2*x;
	//x = dot(float4(a,b,c,d),float4(r3,3*r2*x,3*r*x2,x3));

	//x = a * r*r*r + r * (3 * b * r * x + 3 * c * x*x) + d * x*x*x;
	//x = a*(1-x)*(1-x)*(1-x) +(1-x) * (3*b * (1-x) * x + 3 * c * x*x) + d * x*x*x;
	x = a*(1-x)*(1-x)*(1-x) + 3*b*(1-x)*(1-x)*x + 3*c*(1-x)*x*x + d*x*x*x;
  	#endif

  	// -- Curve 13 --
  	#if Curves_formula == 13 //Cubic Bezier spline - alternative implementation.
    	float3 a = float3(0.00,0.00,0.00); //start point
    	float3 b = float3(0.25,0.15,0.85); //control point 1
    	float3 c = float3(0.75,0.85,0.15); //control point 2
    	float3 d = float3(1.00,1.00,1.00); //endpoint

    	float3 ab = lerp(a,b,x);           // point between a and b
    	float3 bc = lerp(b,c,x);           // point between b and c
    	float3 cd = lerp(c,d,x);           // point between c and d
    	float3 abbc = lerp(ab,bc,x);       // point between ab and bc
    	float3 bccd = lerp(bc,cd,x);       // point between bc and cd
    	float3 dest = lerp(abbc,bccd,x);   // point on the bezier-curve
    	x = dest;
  	#endif

  	// -- Curve 14 --
  	#if Curves_formula == 14
    	x = 1.0 / (1.0 + exp(-(x * 10.0 - 5.0))); //alternative exp formula
  	#endif

   /*-----------------------------------------------------------.
  /                 Joining of Luma and Chroma                  /
  '-----------------------------------------------------------*/

  	#if Curves_mode == 2 //Both Luma and Chroma
	float3 color = x;  //if the curve should be applied to both Luma and Chroma
	colorInput.rgb = lerp(colorInput.rgb, color, Curves_contrast_blend); //Blend by Curves_contrast

  	#elif Curves_mode == 1 //Only Chroma
	x = x * 2.0 - 1.0; //adjust the Chroma range back to -1 -> 1
	float3 color = luma + x; //Luma + Chroma
	colorInput.rgb = lerp(colorInput.rgb, color, Curves_contrast_blend); //Blend by Curves_contrast

  	#else // Curves_mode == 0 //Only Luma
    	x = lerp(luma, x, Curves_contrast_blend); //Blend by Curves_contrast
    	colorInput.rgb = x + chroma; //Luma + Chroma

  	#endif

  	//Return the result
  	return colorInput;
}

float3 SepiaPass( float3 colorInput )
{
	float3 sepia = colorInput.rgb;
	
	// calculating amounts of input, grey and sepia colors to blend and combine
	float grey = dot(sepia, LumCoeff);
	sepia *= ColorTone;
	
	float3 blend2 = (grey * GreyPower) + (colorInput.rgb / (GreyPower + 1));

	colorInput.rgb = lerp(blend2, sepia, SepiaPower);
	// returning the final color
	return colorInput;
}

float3 MoodPass( float3 colorInput )
{
	float3 colInput = colorInput;
	float3 colMood = 1.0f;
	colMood.r = moodR;
	colMood.g = moodG;
	colMood.b = moodB;
	float fLum = ( colInput.r + colInput.g + colInput.b ) / 3;
	colMood = lerp(0, colMood, saturate(fLum * 2.0));
	colMood = lerp(colMood, 1, saturate(fLum - 0.5) * 2.0);
	float3 colOutput = lerp(colInput, colMood, saturate(fLum * fRatio));
	colorInput=max(0, colOutput);
	return colorInput;
}

float3 CrossPass(float3 color)
{
	float2 CrossMatrix [3] = {
		float2 (1.03, 0.04),
		float2 (1.09, 0.01),
		float2 (0.78, 0.13),
 		};

	float3 image1 = color;
	float3 image2 = color;
	float gray = dot(float3(0.5,0.5,0.5), image1);  
	image1 = lerp (gray, image1,CrossSaturation);
	image1 = lerp (0.35, image1,CrossContrast);
	image1 +=CrossBrightness;
	image2.r = image1.r * CrossMatrix[0].x + CrossMatrix[0].y;
	image2.g = image1.g * CrossMatrix[1].x + CrossMatrix[1].y;
	image2.b = image1.b * CrossMatrix[2].x + CrossMatrix[2].y;
	color = lerp(image1, image2, CrossAmount);
	return color;
}

float3 FilmPass(float3 B)
{
	float3 G = B;
	float3 H = 0.01;
 
	B = saturate(B);
	B = pow(B, Linearization);
	B = lerp(H, B, Contrast);
 
	float A = dot(B.rgb, LumCoeff);
	float3 D = A;
 
	B = pow(B, 1.0 / BaseGamma);
 
	float a = FRedCurve;
	float b = FGreenCurve;
	float c = FBlueCurve;
	float d = BaseCurve;
 
	float y = 1.0 / (1.0 + exp(a / 2.0));
	float z = 1.0 / (1.0 + exp(b / 2.0));
	float w = 1.0 / (1.0 + exp(c / 2.0));
	float v = 1.0 / (1.0 + exp(d / 2.0));
 
	float3 C = B;
 
	D.r = (1.0 / (1.0 + exp(-a * (D.r - 0.5))) - y) / (1.0 - 2.0 * y);
	D.g = (1.0 / (1.0 + exp(-b * (D.g - 0.5))) - z) / (1.0 - 2.0 * z);
	D.b = (1.0 / (1.0 + exp(-c * (D.b - 0.5))) - w) / (1.0 - 2.0 * w);
 
	D = pow(D, 1.0 / EffectGamma);
 
	float3 Di = 1.0 - D;
 
	D = lerp(D, Di, FBleach);
 
	D.r = pow(abs(D.r), 1.0 / EffectGammaR);
	D.g = pow(abs(D.g), 1.0 / EffectGammaG);
	D.b = pow(abs(D.b), 1.0 / EffectGammaB);
 
	if (D.r < 0.5)
		C.r = (2.0 * D.r - 1.0) * (B.r - B.r * B.r) + B.r;
	else
		C.r = (2.0 * D.r - 1.0) * (sqrt(B.r) - B.r) + B.r;
 
	if (D.g < 0.5)
		C.g = (2.0 * D.g - 1.0) * (B.g - B.g * B.g) + B.g;
	else
		C.g = (2.0 * D.g - 1.0) * (sqrt(B.g) - B.g) + B.g;
 	//if (AgainstAllAutority) 
	if (D.b < 0.5)
		C.b = (2.0 * D.b - 1.0) * (B.b - B.b * B.b) + B.b;
	else
		C.b = (2.0 * D.b - 1.0) * (sqrt(B.b) - B.b) + B.b;
 
	float3 F = lerp(B, C, Strenght);
 
	F = (1.0 / (1.0 + exp(-d * (F - 0.5))) - v) / (1.0 - 2.0 * v);
 
	float r2R = 1.0 - FSaturation;
	float g2R = 0.0 + FSaturation;
	float b2R = 0.0 + FSaturation;
 
	float r2G = 0.0 + FSaturation;
	float g2G = (1.0 - Fade) - FSaturation;
	float b2G = (0.0 + Fade) + FSaturation;
 
	float r2B = 0.0 + FSaturation;
	float g2B = (0.0 + Fade) + FSaturation;
	float b2B = (1.0 - Fade) - FSaturation;
 
	float3 iF = F;
 
	F.r = (iF.r * r2R + iF.g * g2R + iF.b * b2R);
	F.g = (iF.r * r2G + iF.g * g2G + iF.b * b2G);
	F.b = (iF.r * r2B + iF.g * g2B + iF.b * b2B);
 
	float N = dot(F.rgb, LumCoeff);
	float3 Cn = F;
 
	if (N < 0.5)
		Cn = (2.0 * N - 1.0) * (F - F * F) + F;
	else
		Cn = (2.0 * N - 1.0) * (sqrt(F) - F) + F;
 
	Cn = pow(max(Cn,0), 1.0 / Linearization);
 
	float3 Fn = lerp(B, Cn, Strenght);
	return Fn;
}

float3 ReinhardToneMapping(in float3 x)
{
	const float W =  ReinhardWhitepoint;	// Linear White Point Value
    	const float K =  ReinhardScale;        // Scale

    	// gamma space or not?
    	return (1 + K * x / (W * W)) * x / (x + K);
}

float3 ReinhardLinearToneMapping(in float3 x)
{
    	const float W = ReinhardLinearWhitepoint;	        // Linear White Point Value
    	const float L = ReinhardLinearPoint;           // Linear point
    	const float C = ReinhardLinearSlope;           // Slope of the linear section
    	const float K = (1 - L * C) / C; // Scale (fixed so that the derivatives of the Reinhard and linear functions are the same at x = L)
    	float3 reinhard = L * C + (1 - L * C) * (1 + K * (x - L) / ((W - L) * (W - L))) * (x - L) / (x - L + K);

    	// gamma space or not?
    	return (x > L) ? reinhard : C * x;
}

float3 HaarmPeterDuikerFilmicToneMapping(in float3 x)
{
    	x = max( (float3)0.0f, x - 0.004f );
    	return pow( abs( ( x * ( 6.2f * x + 0.5f ) ) / ( x * ( 6.2f * x + 1.7f ) + 0.06 ) ), 2.2f );
}

float3 CustomToneMapping(in float3 x)
{
	const float A = 0.665f;
	const float B = 0.09f;
	const float C = 0.004f;
	const float D = 0.445f;
	const float E = 0.26f;
	const float F = 0.025f;
	const float G = 0.16f;//0.145f;
	const float H = 1.1844f;//1.15f;

    // gamma space or not?
	return (((x*(A*x+B)+C)/(x*(D*x+E)+F))-G) / H;
}

float3 ColorFilmicToneMapping(in float3 x)
{
	// Filmic tone mapping
	const float3 A = float3(0.55f, 0.50f, 0.45f);	// Shoulder strength
	const float3 B = float3(0.30f, 0.27f, 0.22f);	// Linear strength
	const float3 C = float3(0.10f, 0.10f, 0.10f);	// Linear angle
	const float3 D = float3(0.10f, 0.07f, 0.03f);	// Toe strength
	const float3 E = float3(0.01f, 0.01f, 0.01f);	// Toe Numerator
	const float3 F = float3(0.30f, 0.30f, 0.30f);	// Toe Denominator
	const float3 W = float3(2.80f, 2.90f, 3.10f);	// Linear White Point Value
	const float3 F_linearWhite = ((W*(A*W+C*B)+D*E)/(W*(A*W+B)+D*F))-(E/F);
	float3 F_linearColor = ((x*(A*x+C*B)+D*E)/(x*(A*x+B)+D*F))-(E/F);

    // gamma space or not?
	return pow(saturate(F_linearColor * 1.25 / F_linearWhite),1.25);
}

float3 ColormodPass( float3 color )
{
	color.xyz = (color.xyz - dot(color.xyz, 0.333)) * ColormodChroma + dot(color.xyz, 0.333);
	color.xyz = saturate(color.xyz);
	color.x = (pow(color.x, ColormodGammaR) - 0.5) * ColormodContrastR + 0.5 + ColormodBrightnessR;
	color.y = (pow(color.y, ColormodGammaG) - 0.5) * ColormodContrastG + 0.5 + ColormodBrightnessB;
	color.z = (pow(color.z, ColormodGammaB) - 0.5) * ColormodContrastB + 0.5 + ColormodBrightnessB;
	return color;	
}

float3 SphericalPass( float3 color )
{
	float3 signedColor = color.rgb * 2.0 - 1.0;
	float3 sphericalColor = sqrt(1.0 - signedColor.rgb * signedColor.rgb);
	sphericalColor = sphericalColor * 0.5 + 0.5;
	sphericalColor *= color.rgb;
	color.rgb += sphericalColor.rgb * sphericalAmount;
	color.rgb *= 0.95;
	return color;
}

float3 SincityPass(float3 color)
{
	float sinlumi = dot(color.rgb, float3(0.30f,0.59f,0.11f));
	if(color.r > (color.g + 0.2f) && color.r > (color.b + 0.025f))
	{
		color.rgb = float3(sinlumi, 0, 0)*1.5;
	}
	else
	{
		color.rgb = sinlumi;
	}
	return color;
}

float3 colorhuefx_prod80( float3 color )
{
	
	float3 fxcolor = saturate( color.xyz );
	float greyVal = dot( fxcolor.xyz, LumCoeff.xyz );
	float3 HueSat = Hue( fxcolor.xyz );
	float colorHue = HueSat.x;
	float colorInt = HueSat.z - HueSat.y * 0.5;
	float colorSat = HueSat.y / ( 1.0 - abs( colorInt * 2.0 - 1.0 ) * 1e-10 );

	//When color intensity not based on original saturation level
   	if ( USE_COLORSAT == 0 )   colorSat = 1.0f;

	float hueMin_1 = hueMid - hueRange;
	float hueMax_1 = hueMid + hueRange;
	float hueMin_2 = 0.0f;
	float hueMax_2 = 0.0f;


   	if ( hueMin_1 < 0.0 )
   	{
   		hueMin_2 = 1.0f + hueMin_1;
   		hueMax_2 = 1.0f + hueMid;
   
      		if ( colorHue >= hueMin_1 && colorHue <= hueMid )
         		fxcolor.xyz = lerp( greyVal.xxx, fxcolor.xyz, smootherstep( hueMin_1, hueMid, colorHue ) * ( colorSat * satLimit ));
      		else if ( colorHue >= hueMid && colorHue <= hueMax_1 )
        		fxcolor.xyz = lerp( greyVal.xxx, fxcolor.xyz, ( 1.0f - smootherstep( hueMid, hueMax_1, colorHue )) * ( colorSat * satLimit ));
      		else if ( colorHue >= hueMin_2 && colorHue <= hueMax_2 )
         		fxcolor.xyz = lerp( greyVal.xxx, fxcolor.xyz, smootherstep( hueMin_2, hueMax_2, colorHue ) * ( colorSat * satLimit ));
      		else
         		fxcolor.xyz = greyVal.xxx;
   	}

   	else if ( hueMax_1 > 1.0 )
   	{
   		hueMin_2 = 0.0f - ( 1.0f - hueMid );
   		hueMax_2 = hueMax_1 - 1.0f;

      		if ( colorHue >= hueMin_1 && colorHue <= hueMid )
         		fxcolor.xyz = lerp( greyVal.xxx, fxcolor.xyz, smootherstep( hueMin_1, hueMid, colorHue ) * ( colorSat * satLimit ));
      		else if ( colorHue >= hueMid && colorHue <= hueMax_1 )
         		fxcolor.xyz = lerp( greyVal.xxx, fxcolor.xyz, ( 1.0f - smootherstep( hueMid, hueMax_1, colorHue )) * ( colorSat * satLimit ));
      		else if ( colorHue >= hueMin_2 && colorHue <= hueMax_2 )
         		fxcolor.xyz = lerp( greyVal.xxx, fxcolor.xyz, ( 1.0f - smootherstep( hueMin_2, hueMax_2, colorHue )) * ( colorSat * satLimit ));
      		else
         		fxcolor.xyz = greyVal.xxx;
   	}	
   
	else
   	{
      		if ( colorHue >= hueMin_1 && colorHue <= hueMid )
        		fxcolor.xyz = lerp( greyVal.xxx, fxcolor.xyz, smootherstep( hueMin_1, hueMid, colorHue ) * ( colorSat * satLimit ));
      		else if ( colorHue > hueMid && colorHue <= hueMax_1 )
         		fxcolor.xyz = lerp( greyVal.xxx, fxcolor.xyz, ( 1.0f - smootherstep( hueMid, hueMax_1, colorHue )) * ( colorSat * satLimit ));
      		else
         		fxcolor.xyz = greyVal.xxx;
   	}

   	color.xyz = lerp( color.xyz, fxcolor.xyz, fxcolorMix );

	return color.xyz;

}

float3 SharpPass( float3 colorInput, float2 tex, sampler colorsampler)
{
     	float3 blur_ori = tex2D(colorsampler, tex + float2(0.5 * PixelSize.x,-PixelSize.y * fSharpBias)).rgb*0.25;  	// South South East
    	blur_ori += tex2D(colorsampler, tex + float2(fSharpBias * -PixelSize.x,0.5 * -PixelSize.y)).rgb*0.25; 		// West South West
   	blur_ori += tex2D(colorsampler, tex + float2(fSharpBias * PixelSize.x,0.5 * PixelSize.y)).rgb*0.25; 		// East North East
    	blur_ori += tex2D(colorsampler, tex + float2(0.5 * -PixelSize.x,PixelSize.y * fSharpBias)).rgb*0.25;		// North North West

	float3 sharp = colorInput - blur_ori;
	float sharp_luma = dot(sharp, fSharpStrength);
	
	sharp_luma = clamp(sharp_luma, -fSharpClamp, fSharpClamp);
	
	float3 done = tex2D(colorsampler, tex).rgb + sharp_luma; 

	colorInput = done;

	return colorInput;
}

float3 ExplosionPass( float3 colorInput, float2 tex, sampler colorsampler )
{

  	// -- pseudo random number generator --
  	float2 sine_cosine;
  	sincos(dot(tex, float2(12.9898,78.233)),sine_cosine.x,sine_cosine.y);
  	sine_cosine = sine_cosine * 43758.5453 + tex;
  	float2 noise = frac(sine_cosine);

  	tex = (-fExplosionRadius * PixelSize) + tex; //Slightly faster this way because it can be calculated while we calculate noise.
  
  	colorInput.rgb = tex2D(colorsampler, (2.0 * fExplosionRadius * PixelSize) * noise + tex).rgb;
  
 
  	return colorInput;
}

//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// Initializing pass which converts LDR image to HDR space														     //
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

float4 PS_ME_Init(VS_OUTPUT_POST IN) : COLOR 
{
	float mask = 1.0f;
#if(USE_HUD_MASKING==1)
	mask = tex2D(SamplerMask, IN.txcoord.xy).x;
#endif
	return tex2D(SamplerLDR, IN.txcoord.xy)*mask;
}

//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// Bloom 													     	     //
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

float4 PS_ME_BloomPrePass(VS_OUTPUT_POST IN) : COLOR
{
	
	float4 bloom=0.0;
	float2 bloomuv;

	float2 offset[4]=
	{
		float2(1.0, 1.0),
		float2(1.0, 1.0),
		float2(-1.0, 1.0),
		float2(-1.0, -1.0)
	};

	for (int i=0; i<4; i++)
	{
		bloomuv.xy=offset[i]*PixelSize.xy*2;
		bloomuv.xy=IN.txcoord.xy + bloomuv.xy;
		float4 tempbloom=tex2Dlod(SamplerLDR, float4(bloomuv.xy, 0, 0));
		tempbloom.w = max(0,dot(tempbloom.xyz,0.333)-fAnamFlareThreshold);
		tempbloom.xyz = max(0, tempbloom.xyz-fBloomThreshold); 

#if(USE_HUD_MASKING == 1)
		float mask = tex2Dlod(SamplerMask, float4(bloomuv.xy, 0, 0)).x;
		tempbloom *= mask;
#endif

		bloom+=tempbloom;
	}

	bloom *= 0.25;
	return bloom;
}

float4 PS_ME_BloomPass1(VS_OUTPUT_POST IN) : COLOR
{

	float4 bloom=0.0;
	float2 bloomuv;

	float2 offset[8]=
	{
		float2(1.0, 1.0),
		float2(0.0, -1.0),
		float2(-1.0, 1.0),
		float2(-1.0, -1.0),
		float2(0.0, 1.0),
		float2(0.0, -1.0),
		float2(1.0, 0.0),
		float2(-1.0, 0.0)
	};

	for (int i=0; i<8; i++)
	{
		bloomuv.xy=offset[i]*PixelSize.xy*4;
		bloomuv.xy=IN.txcoord.xy + bloomuv.xy;
		float4 tempbloom=tex2Dlod(SamplerBloom1, float4(bloomuv.xy, 0, 0));
		bloom+=tempbloom;
	}

	bloom *= 0.125;
	return bloom;
}

float4 PS_ME_BloomPass2(VS_OUTPUT_POST IN) : COLOR
{

	float4 bloom=0.0;
	float2 bloomuv;

	float2 offset[8]=
	{
		float2(0.707, 0.707),
		float2(0.707, -0.707),
		float2(-0.707, 0.707),
		float2(-0.707, -0.707),
		float2(0.0, 1.0),
		float2(0.0, -1.0),
		float2(1.0, 0.0),
		float2(-1.0, 0.0)
	};

	for (int i=0; i<8; i++)
	{
		bloomuv.xy=offset[i]*PixelSize.xy*8;
		bloomuv.xy=IN.txcoord.xy + bloomuv.xy;
		float4 tempbloom=tex2Dlod(SamplerBloom2, float4(bloomuv.xy, 0, 0));
		bloom+=tempbloom;
	}

	bloom *= 0.5; //to brighten up the sample, it will lose brightness in H/V gaussian blur 
	return bloom;
}


float4 PS_ME_BloomPass3(VS_OUTPUT_POST IN) : COLOR
{
	float4 bloom;
	bloom = GaussBlur22(IN.txcoord.xy, SamplerBloom3, 16, 0, 0);
	bloom.a *= fAnamFlareAmount;
	bloom.xyz *= fBloomAmount;
	return bloom;
}

float4 PS_ME_BloomPass4(VS_OUTPUT_POST IN) : COLOR
{
	float4 bloom;
	bloom.xyz = GaussBlur22(IN.txcoord.xy, SamplerBloom4, 16, 0, 1).xyz*2.5;	
	bloom.w   = GaussBlur22(IN.txcoord.xy, SamplerBloom4, 32*fAnamFlareWideness, 0, 0).w*2.5; //to have anamflare texture (bloom.w) avoid vertical blur
	return bloom;
}

//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// Lensflares 													     	     //
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

float3 GetDnB (sampler2D tex, float2 coords)
{
	float3 Color = max(0,dot(tex2Dlod(tex,float4(coords.xy,0,4)).rgb,0.333) - ChapFlareTreshold)*ChapFlareIntensity;
	#if(CHAPMANDEPTHCHECK == 1)
	if(tex2Dlod(SamplerDepth,float4(coords.xy,0,3)).x<0.99999) Color = 0;
	#endif
	return Color;
}

float2 GetFlippedTC(float2 texcoords) 
{
	return -texcoords + 1.0;
}

float3 GetDistortedTex(
	sampler2D tex,
	float2 sample_center, // where we'd normally sample
	float2 sample_vector,
	float3 distortion // per-channel distortion coeffs
) {

	float2 final_vector = sample_center + sample_vector * min(min(distortion.r, distortion.g),distortion.b); 

	if(final_vector.x > 1.0 
	|| final_vector.y > 1.0 
	|| final_vector.x < -1.0 
	|| final_vector.y < -1.0)
	return 0;

	else return float3(
		GetDnB(tex,sample_center + sample_vector * distortion.r).r,
		GetDnB(tex,sample_center + sample_vector * distortion.g).g,
		GetDnB(tex,sample_center + sample_vector * distortion.b).b
	);
}

float3 GetBrightPass(float2 tex)
{
	float3 c = tex2D(SamplerHDR1, tex).rgb;
    	float3 bC = max(c - float3(fFlareLuminance, fFlareLuminance, fFlareLuminance), 0.0);
    	float bright = dot(bC, 1.0);
    	bright = smoothstep(0.0f, 0.5, bright);
	float3 result = lerp(0.0, c, bright);
#if (bFlareDepthCheckEnable == 1)
	float checkdepth = tex2D(SamplerDepth, tex).x;
	if(checkdepth < 0.99999) result = 0;
#endif
	return result;

}

float3 GetAnamorphicSample(int axis, float2 tex, float blur)
{
	tex = 2.0 * tex - 1.0;
	tex.x /= -blur;
	tex = 0.5 * tex + 0.5;
	return GetBrightPass(tex);
}

float4 PS_ME_LensPrepass(VS_OUTPUT_POST IN) : COLOR
{
	float4 lens=0;

#if (USE_LENZFLARE == 1)

	float3 lfoffset[19]={
		float3(0.9, 0.01, 4),
		float3(0.7, 0.25, 25),
		float3(0.3, 0.25, 15),
		float3(1, 1.0, 5),
		float3(-0.15, 20, 1),
		float3(-0.3, 20, 1),
		float3(6, 6, 6),
		float3(7, 7, 7),
		float3(8, 8, 8),
		float3(9, 9, 9),
		float3(0.24, 1, 10),
		float3(0.32, 1, 10),
		float3(0.4, 1, 10),
		float3(0.5, -0.5, 2),
		float3(2, 2, -5),
		float3(-5, 0.2, 0.2),
		float3(20, 0.5, 0),
		float3(0.4, 1, 10),
		float3(0.00001, 10, 20)
	};

	float3 lffactors[19]={
		float3(1.5, 1.5, 0),
		float3(0, 1.5, 0),
		float3(0, 0, 1.5),
		float3(0.2, 0.25, 0),
		float3(0.15, 0, 0),
		float3(0, 0, 0.15),
		float3(1.4, 0, 0),
		float3(1, 1, 0),
		float3(0, 1, 0),
		float3(0, 0, 1.4),
		float3(1, 0.3, 0),
		float3(1, 1, 0),
		float3(0, 2, 4),
		float3(0.2, 0.1, 0),
		float3(0, 0, 1),
		float3(1, 1, 0),
		float3(1, 1, 0),
		float3(0, 0, 0.2),
 	       	float3(0.012,0.313,0.588)
	};

	float3 lenstemp = 0;

	float2 lfcoord = float2(0,0);
	float2 distfact=(IN.txcoord.xy-0.5);
	distfact.x *= ScreenSize.z;

	for (int i=0; i<19; i++)
	{
		lfcoord.xy=lfoffset[i].x*distfact;
		lfcoord.xy*=pow(2.0*length(float2(distfact.x,distfact.y)), lfoffset[i].y*3.5);
		lfcoord.xy*=lfoffset[i].z;
		lfcoord.xy=0.5-lfcoord.xy;
		float2 tempfact = (lfcoord.xy-0.5)*2;
		float templensmult = clamp(1.0-dot(tempfact,tempfact),0,1);
		float3 lenstemp1 = dot(tex2Dlod(SamplerHDR1, float4(lfcoord.xy,0,1)).xyz,0.333);

		#if (LENZDEPTHCHECK == 1)
		float templensdepth = tex2D(SamplerDepth, lfcoord.xy).x;
		if(templensdepth < 0.99999) lenstemp1 = 0;
		#endif	
	
		lenstemp1 = max(0,lenstemp1.xyz - fLenzThreshold);
		lenstemp1 *= lffactors[i].xyz*templensmult;

		lenstemp += lenstemp1;
	}

	lens.xyz += lenstemp.xyz*fLenzIntensity;
#endif

#if(USE_CHAPMAN_LENS == 1)
	float2 sample_vector = (float2(0.5,0.5) - IN.txcoord.xy) * ChapFlareDispersal;
	float2 halo_vector = normalize(sample_vector) * ChapFlareSize;

	float3 chaplens = GetDistortedTex(SamplerHDR1, IN.txcoord.xy + halo_vector,halo_vector,ChapFlareCA*2.5f).rgb;

	for (int i = 0; i < ChapFlareCount; ++i) 
	{
		float2 foffset = sample_vector * float(i);
		chaplens += GetDistortedTex(SamplerHDR1, IN.txcoord.xy + foffset,foffset,ChapFlareCA).rgb;

	}
	chaplens *= 1/float(ChapFlareCount);
	lens.xyz += chaplens;
#endif

#if( USE_GODRAYS == 1)
	float2 ScreenLightPos = float2(0.5, 0.5);
	float2 texCoord = IN.txcoord.xy;
	float2 deltaTexCoord = (texCoord.xy - ScreenLightPos.xy);
	deltaTexCoord *= 1.0 / (float)iGodraySamples * fGodrayDensity;


	float illuminationDecay = 1.0;

	for(int g = 0; g < iGodraySamples; g++) {
	
		texCoord -= deltaTexCoord;;
		float4 sample2 = tex2D(SamplerHDR1, texCoord.xy);
		float sampledepth = tex2D(SamplerDepth, texCoord.xy).x;
		sample2.w = saturate(dot(sample2.xyz, 0.3333) - fGodrayThreshold);
		sample2.r *= 1.0;
		sample2.g *= 0.95;
		sample2.b *= 0.85;
		sample2 *= illuminationDecay * fGodrayWeight;
	#if (bGodrayDepthCheck == 1)
		if(sampledepth>0.99999) lens.xyz += sample2.xyz*sample2.w;
	#else
		lens.xyz += sample2;
	#endif
		illuminationDecay *= fGodrayDecay;
	}
#endif

#if(USE_ANAMFLARE == 1)
	float3 anamFlare=0;
	float gaussweight[5] = {0.2270270270, 0.1945945946, 0.1216216216, 0.0540540541, 0.0162162162};
	for(int z=-4; z < 5; z++)
	{
		anamFlare+=GetAnamorphicSample(0, IN.txcoord.xy + float2(0, z * PixelSize.y * 2), fFlareBlur) * fFlareTint* gaussweight[abs(z)];
	}
	lens.xyz += anamFlare * fFlareIntensity;
#endif

	return lens;
}

float4 PS_ME_LensPass1(VS_OUTPUT_POST IN) : COLOR
{
	return GaussBlur22(IN.txcoord.xy, SamplerLens1, 2, 0, 1);	
}

float4 PS_ME_LensPass2(VS_OUTPUT_POST IN) : COLOR
{
	return GaussBlur22(IN.txcoord.xy, SamplerLens2, 2, 0, 0);	
}

//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// Lighting combine													     //
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

float4 PS_ME_LightingCombine(VS_OUTPUT_POST IN) : COLOR 
{
 
	float4 color = tex2D(SamplerHDR2, IN.txcoord.xy);

#if (USE_BLOOM == 1)
	float3 colorbloom=0;

	colorbloom.xyz += tex2D(SamplerBloom3, IN.txcoord.xy).xyz*1.0;
	colorbloom.xyz += tex2D(SamplerBloom5, IN.txcoord.xy).xyz*9.0;
	colorbloom.xyz *= 0.1;

	colorbloom.xyz = saturate(colorbloom.xyz);
	float colorbloomgray = dot(colorbloom.xyz, 0.333);
	colorbloom.xyz = lerp(colorbloomgray, colorbloom.xyz, fBloomSaturation);
	colorbloom.xyz *= fBloomTint;
	float colorgray = dot(color.xyz, 0.333);

	if(iBloomMixmode == 1) color.xyz = color.xyz + colorbloom.xyz;
	if(iBloomMixmode == 2) color.xyz = 1-(1-color.xyz)*(1-colorbloom.xyz);
	if(iBloomMixmode == 3) color.xyz = max(0.0f,max(color.xyz,lerp(color.xyz,(1.0f - (1.0f - saturate(colorbloom.xyz)) *(1.0f - saturate(colorbloom.xyz * 1.0))),1.0)));
	if(iBloomMixmode == 4) color.xyz = max(color.xyz, colorbloom.xyz);
#endif

#if(USE_GAUSSIAN_ANAMFLARE == 1)
	float3 anamflare = tex2D(SamplerBloom5, IN.txcoord.xy).w*2*fAnamFlareColor;
	anamflare.xyz = max(anamflare.xyz,0);
	color.xyz += pow(anamflare.xyz,1/fAnamFlareCurve);
#endif

#if(USE_LENSDIRT == 1)
	float lensdirtmult = dot(tex2D(SamplerBloom5, IN.txcoord.xy).xyz,0.333);
	float3 dirttex = tex2D(SamplerDirt, IN.txcoord.xy).xyz;

	float3 lensdirt = dirttex.xyz*lensdirtmult*fLensdirtIntensity*fLensdirtTint;
	lensdirt = lerp(dot(lensdirt.xyz,0.333), lensdirt.xyz, fLensdirtSaturation);

	if(iLensdirtMixmode == 1) color.xyz = color.xyz + lensdirt.xyz;
	if(iLensdirtMixmode == 2) color.xyz = 1-(1-color.xyz)*(1-lensdirt.xyz);
	if(iLensdirtMixmode == 3) color.xyz = max(0.0f,max(color.xyz,lerp(color.xyz,(1.0f - (1.0f - saturate(lensdirt.xyz)) *(1.0f - saturate(lensdirt.xyz * 1.0))),1.0)));
	if(iLensdirtMixmode == 4) color.xyz = max(color.xyz, lensdirt.xyz);
#endif

	float3 LensflareSample = tex2D(SamplerLens1, IN.txcoord.xy).xyz;
	float3 LensflareMask   = tex2D(SamplerSprite, IN.txcoord.xy+float2(0.5,0.5)*PixelSize.xy).xyz;
	LensflareMask   += tex2D(SamplerSprite, IN.txcoord.xy+float2(-0.5,0.5)*PixelSize.xy).xyz;
	LensflareMask   += tex2D(SamplerSprite, IN.txcoord.xy+float2(0.5,-0.5)*PixelSize.xy).xyz;
	LensflareMask   += tex2D(SamplerSprite, IN.txcoord.xy+float2(-0.5,-0.5)*PixelSize.xy).xyz;

	color.xyz += LensflareMask*0.25*LensflareSample;

	return color;

}

float4 PS_ME_Colors(VS_OUTPUT_POST IN) : COLOR 
{
	float4 color = tex2D(SamplerHDR1, IN.txcoord.xy);

#if(USE_LED_SHADER == 1 )
	float LEDradius = fLEDCircleSize * 0.375;
	float2 quadPos = floor(IN.txcoord.xy * float2(BUFFER_WIDTH,BUFFER_HEIGHT) / fLEDCircleSize) * fLEDCircleSize;
	float2 quad = quadPos/float2(BUFFER_WIDTH,BUFFER_HEIGHT);
	float2 quadCenter = (quadPos + fLEDCircleSize/2.0);
	float quaddist = length(quadCenter - IN.txcoord.xy * float2(BUFFER_WIDTH,BUFFER_HEIGHT));
	float4 LEDtexel = tex2D(SamplerHDR1, quad);
	float LEDtexellum = saturate(dot(LEDtexel.xyz,0.333)-0.75)*fLEDCircleSize*0.33;
	color.xyz = lerp(fLEDBackgroundColor, LEDtexel.xyz, smoothstep(1.5*(1.0+LEDtexellum),-1.5*(1.0+LEDtexellum), quaddist-LEDradius));
#endif	

#if(USE_LUT == 1)
	float3 LUTcolor = 0.0;	
 #if(iLookupTableMode == 1)  
	LUTcolor.x = tex2D(SamplerLUT, float2(saturate(color.x),0)).x;
	LUTcolor.y = tex2D(SamplerLUT, float2(saturate(color.y),0)).y;
	LUTcolor.z = tex2D(SamplerLUT, float2(saturate(color.z),0)).z;
 #elif (iLookupTableMode == 2)
	float2 GridSize = float2(0.00390625, 0.0625);
	float3 coord3D = saturate(color.xyz);
	coord3D.z  *= 15;
	float shift = floor(coord3D.z);
	coord3D.xy =  coord3D.xy * 15 * GridSize + 0.5 * GridSize;
	coord3D.x += shift * 0.0625;
	LUTcolor.xyz = lerp( tex2D(SamplerLUT3D, coord3D.xy).xyz, tex2D(SamplerLUT3D, coord3D.xy + float2(GridSize.y, 0)).xyz, coord3D.z - shift);
 #endif
	color.xyz = lerp(color.xyz, LUTcolor.xyz, fLookupTableMix);
#endif

#if (USE_CARTOON == 1)
	color.xyz = CartoonPass(color.xyz, IN.txcoord.xy, PixelSize.xy, SamplerHDR1);
#endif

#if (USE_LEVELS== 1)
	color.xyz = LevelsPass(color.xyz);
#endif

#if (USE_TECHNICOLOR == 1)
	color.xyz = TechniPass_prod80(color.xyz);
#endif

#if (USE_SWFX_TECHNICOLOR == 1)
	color.xyz = TechnicolorPass(color.xyz);
#endif

#if (USE_DPX == 1)
	color.xyz = DPXPass(color.xyz);
#endif

#if (USE_MONOCHROME == 1)
	color.xyz = dot(color.xyz, 0.333);
#endif

#if (USE_LIFTGAMMAGAIN == 1)
	color.xyz = LiftGammaGainPass(color.xyz);
#endif
	
#if (USE_TONEMAP == 1)
	color.xyz = TonemapPass(color.xyz);
#endif
	
#if (USE_VIBRANCE == 1)
	color.xyz = VibrancePass(color.xyz);
#endif
	
#if (USE_CURVES == 1)
	color.xyz = CurvesPass(color.xyz);
#endif

#if (USE_SEPIA == 1)
	color.xyz = SepiaPass(color.xyz);
#endif

#if (USE_COLORMOOD == 1)
	color.xyz = MoodPass(color.xyz);
#endif
 
#if (USE_CROSSPROCESS == 1)
	color.xyz = CrossPass(color.xyz);
#endif
	
#if (USE_FILMICPASS == 1)
	color.xyz = FilmPass(color.xyz);
#endif

#if (USE_REINHARD == 1)
	color.xyz = ReinhardToneMapping(color.xyz);
#endif

#if (USE_REINHARDLINEAR == 1)
	color.xyz = ReinhardLinearToneMapping(color.xyz);
#endif

#if (USE_HPD == 1)
	color.xyz = HaarmPeterDuikerFilmicToneMapping(color.xyz);
#endif
	
#if (USE_FILMICCURVE == 1)
	color.xyz = CustomToneMapping(color.xyz);
#endif

#if(USE_WATCHDOG_TONEMAP == 1)
	color.xyz = ColorFilmicToneMapping(color.xyz);
#endif

#if (USE_COLORMOD == 1)
	color.xyz = ColormodPass(color.xyz);
#endif

#if (USE_SPHERICALTONEMAP == 1)
	color.xyz = SphericalPass(color.xyz);
#endif

#if (USE_SINCITY == 1)
	color.xyz = SincityPass(color.xyz);
#endif

#if (USE_COLORHUEFX == 1)
	color.xyz = colorhuefx_prod80(color.xyz);
#endif

	return color;

}

float4 PS_ME_PostFX(VS_OUTPUT_POST IN) : COLOR 
{

#if (USE_SMAA == 1)
 #define SamplerCurrent SamplerHDR1
#else
 #define SamplerCurrent SamplerHDR2
#endif

	float4 color = tex2D(SamplerCurrent, IN.txcoord.xy);

#if(USE_FISHEYE_CA == 1)
	float4 coord=0.0;
	coord.xy=IN.txcoord.xy;
	coord.w=0.0;  
	float3 eta = float3(1.0+fFisheyeColorshift*0.9,1.0+fFisheyeColorshift*0.6,1.0+fFisheyeColorshift*0.3);
	float2 center;
	center.x = coord.x-0.5;
	center.y = coord.y-0.5;
	float LensZoom = 1.0/fFisheyeZoom;

	float r2 = (IN.txcoord.x-0.5) * (IN.txcoord.x-0.5) + (IN.txcoord.y-0.5) * (IN.txcoord.y-0.5);     
	float f = 0;

	if( fFisheyeDistortionCubic == 0.0){
		f = 1 + r2 * fFisheyeDistortion;
	}else{
                f = 1 + r2 * (fFisheyeDistortion + fFisheyeDistortionCubic * sqrt(r2));
	};

	float x = f*LensZoom*(coord.x-0.5)+0.5;
	float y = f*LensZoom*(coord.y-0.5)+0.5;
	float2 rCoords = (f*eta.r)*LensZoom*(center.xy*0.5)+0.5;
	float2 gCoords = (f*eta.g)*LensZoom*(center.xy*0.5)+0.5;
	float2 bCoords = (f*eta.b)*LensZoom*(center.xy*0.5)+0.5;
	
	color.x = tex2D(SamplerCurrent,rCoords).r;
	color.y = tex2D(SamplerCurrent,gCoords).g;
	color.z = tex2D(SamplerCurrent,bCoords).b;	
#endif

#undef SamplerCurrent

	return color;
}

float4 PS_ME_Overlay(VS_OUTPUT_POST IN) : COLOR 
{

#if (USE_SMAA == 1)
 #define SamplerCurrent SamplerHDR2
#else
 #define SamplerCurrent SamplerHDR1
#endif

	float4 color = tex2D(SamplerCurrent, IN.txcoord.xy);

#if( USE_HEATHAZE == 1)
	float3 heatnormal = tex2Dlod(SamplerHeat, float4(IN.txcoord.xy*fHeatHazeTextureScale+float2(0.0,Timer.x*0.0001*fHeatHazeSpeed),0,0)).rgb - 0.5;
    	float2 heatoffset = normalize(heatnormal.xy) * pow(length(heatnormal.xy), 0.5);
	float3 heathazecolor = 0;
	heathazecolor.y = tex2D(SamplerCurrent, IN.txcoord.xy + heatoffset.xy * 0.001 * fHeatHazeOffset).y;
	heathazecolor.x = tex2D(SamplerCurrent, IN.txcoord.xy + heatoffset.xy * 0.001 * fHeatHazeOffset * (1.0+fHeatHazeChromaAmount)).x;
	heathazecolor.z = tex2D(SamplerCurrent, IN.txcoord.xy + heatoffset.xy * 0.001 * fHeatHazeOffset * (1.0-fHeatHazeChromaAmount)).z;
	color.xyz = heathazecolor;
 #if(bHeatHazeDebug == 1)
	color.xyz = heatnormal.xyz+0.5;
 #endif
#endif


/*   xyz

Must be moved elsewhere in order to be used correctly.
Reminder to me: Enable CoC for FOG, too.


#define USE_FOG 1

#define fFogStart 	 0.1
#define	fFogEnd 	 0.7
#define	fFogAmount   	 1.0
#define fFogColor	float3(0.67,0.67,0.67)

#if( USE_FOG == 1)

	float lineardepth = tex2Dlod(SamplerCoC, float4(IN.txcoord.xy,0,0)).y;
	float fogdepth=0;
	fogdepth += tex2Dlod(SamplerCoC, float4(IN.txcoord.xy,0,2)).y;
	fogdepth += tex2Dlod(SamplerCoC, float4(IN.txcoord.xy,0,3)).y;
	fogdepth += tex2Dlod(SamplerCoC, float4(IN.txcoord.xy,0,4)).y;
	fogdepth /= 3;

	fogdepth = lerp(lineardepth, fogdepth, saturate(lineardepth*3));

	float fogamount = saturate(smoothstep(fFogStart, fFogEnd, fogdepth)*fFogAmount);

	float3 fogblur=0;
	fogblur += tex2Dlod(SamplerCurrent, float4(IN.txcoord.xy,0,2)).xyz;
	fogblur += tex2Dlod(SamplerCurrent, float4(IN.txcoord.xy,0,3)).xyz;
	fogblur += tex2Dlod(SamplerCurrent, float4(IN.txcoord.xy,0,4)).xyz;
	fogblur /= 3;

	float3 fogcolor = fFogColor;

	fogblur = (fogblur - fogcolor) * 0.75 + fogcolor;
	color.xyz = lerp(color.xyz, fogblur, saturate(fogamount*2));
	color.xyz = lerp(color.xyz, fogcolor, fogamount);
#endif
*/

#if(USE_SHARPENING == 1)
	color.xyz = SharpPass(color.xyz, IN.txcoord.xy, SamplerCurrent);
#endif

#if (USE_EXPLOSION == 1)
	color.xyz = ExplosionPass(color.xyz, IN.txcoord.xy, SamplerCurrent);
#endif

#if(USE_GRAIN == 1)
	float3 noisesample = tex2D(SamplerNoise, IN.txcoord.xy).xyz;
	float noisegray = dot(noisesample, 0.333);
	noisesample.xyz = lerp(noisegray.xxx, noisesample.xyz, fGrainSaturation);
	float colorgray = dot(color.xyz, 0.333);
	float fGrainAmount = fGrainIntensityMid;

	if(colorgray > 0.5) fGrainAmount = lerp(fGrainIntensityMid, fGrainIntensityBright, saturate(colorgray-0.5)*2);
	if(colorgray < 0.5) fGrainAmount = lerp(fGrainIntensityDark, fGrainIntensityMid, colorgray*2);

	noisesample.xyz = (noisesample.xyz-0.5)*fGrainAmount;
	color.xyz = max(0, color.xyz + noisesample.xyz);
#endif

#if (USE_COLORVIGNETTE==1)
        float2	uv=(IN.txcoord-0.5)*fVignetteRadius;
	float	vignetteold=saturate(dot(uv.xy, uv.xy));
	vignetteold=pow(vignetteold, fVignetteCurve);
	float3	EVignetteColor=fVignetteColor;
	color.xyz=lerp(color.xyz, EVignetteColor, vignetteold*fVignetteAmount);
#endif

#if (USE_HD6_VIGNETTE==1)
	float rovigpwr = fHD6VignetteRoundness; //for a circular vignette
	float2 sqvigpwr = float2( fHD6VignetteTop, fHD6VignetteBottom ); // for the top and bottom of the screen
	float vsatstrength = fHD6VignetteColorDistort; // color distortion
	float vignettepow = fHD6VignetteContrast; // increases the contrast and sharpness
	float vstrengthatnight = fHD6VignetteBorder;
 
 	float2 inTex = IN.txcoord;
 	float vhnd = 0.5;
 	float4 voriginal = color;
 	float4 vcolor = voriginal;
 	vcolor.xyz=1;
 	inTex -= 0.5; // center
 	inTex.y += 0.01; // offset from the center
 	float vignette = saturate(1.0 - dot( inTex, inTex ));
 	vcolor *= pow( vignette, vignettepow );
 
 	float4 rvigtex = vcolor;
 	rvigtex.xyz = pow( vcolor.xyz, 1 );
 	rvigtex.xyz = lerp(float3(0.5, 0.5, 0.5), rvigtex.xyz, 2.25); // contrast
 	rvigtex.xyz = lerp(float3(1,1,1),rvigtex.xyz,rovigpwr); // strength of the circular vinetty
 
	//darken the top and bottom
 	float4 vigtex = vcolor;
 	vcolor.xyz = float3(1,1,1);
 #if (fHD6VignetteMode==1)
 	float3 topv = min((inTex.x+0.5)*2,1.5) * 2; // top
 	float3 botv = min(((0-inTex.x)+0.5)*2,1.5) * 2; // botton
	topv= lerp(float3(1,1,1), topv, sqvigpwr.x);
 	botv= lerp(float3(1,1,1), botv, sqvigpwr.y);
	vigtex.xyz = (topv)*(botv);
 #endif
 #if (fHD6VignetteMode==2)
        float3 topv = min((inTex.y+0.5)*2,1.5) * 2; // top
 	float3 botv = min(((0-inTex.y)+0.5)*2,1.5) * 2; // botton
	topv= lerp(float3(1,1,1), topv, sqvigpwr.x);
 	botv= lerp(float3(1,1,1), botv, sqvigpwr.y);
	vigtex.xyz = (topv)*(botv);
 #endif
 #if (fHD6VignetteMode==3)
	float3 rightv = min((inTex.x+0.5)*2,1.5) * 2;
 	float3 leftv = min(((0-inTex.x)+0.5)*2,1.5) * 2; 
        float3 topv = min((inTex.y+0.5)*2,1.5) * 2; 
 	float3 botv = min(((0-inTex.y)+0.5)*2,1.5) * 2; 
 	rightv= lerp(float3(1,1,1), rightv, sqvigpwr.y);
 	leftv= lerp(float3(1,1,1), leftv, sqvigpwr.x);
        topv= lerp(float3(1,1,1), topv, sqvigpwr.x);
 	botv= lerp(float3(1,1,1), botv, sqvigpwr.y);
 	vigtex.xyz = (topv)*(botv)*(rightv)*(leftv);
 #endif
 	// mix the two types of vignettes
 	vigtex.xyz*=rvigtex.xyz;
	vigtex.xyz = lerp(vigtex.xyz,float3(1,1,1),(vhnd-vstrengthatnight*vhnd)); //for a dark screen
 	vigtex.xyz = min(vigtex.xyz,1);
 	vigtex.xyz = max(vigtex.xyz,0);
 	float3 vtintensity = dot(voriginal.xyz, float3(0.2125, 0.7154, 0.0721));
 	color.xyz = lerp(vtintensity, voriginal.xyz, ((((1-(vigtex.xyz*2))+2)-1)*vsatstrength)+1 );
  	color.xyz *= (vigtex.xyz);
#endif

#if (USE_BORDER==1)
	color.xyz = BorderPass(color, IN.txcoord.xy).xyz;
#endif

#if (USE_MOVIEBARS == 1)
	color.xyz = IN.txcoord.y > 0.12 && IN.txcoord.y < 0.88 ? color.xyz : 0.0;
#endif

#if(USE_SPLITSCREEN == 1)
	if(IN.txcoord.x > 0.5) color.xyz = tex2D(SamplerLDR, IN.txcoord.xy).xyz;
#endif

#if(USE_HUD_MASKING == 1)
	float HUDMaskSample = tex2D(SamplerMask, IN.txcoord.xy).x;
	float3 origcolor = tex2D(SamplerLDR, IN.txcoord.xy).xyz;
	color.xyz = lerp(origcolor.xyz, color.xyz, saturate(HUDMaskSample));
#endif

	return color;
}

//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

technique MasterEffect < bool enabled = 1; toggle = MASTEREFFECT_TOGGLEKEY; >
{
	pass ME_Init
	{
		VertexShader = VS_MasterEffect;
		PixelShader = PS_ME_Init;
		RenderTarget = texHDR1;
	}
								//so both HDR1 and HDR2 textures are filled with input color
	pass ME_Init						//later, numerous DOF shaders have different passnumber but later passes depend
	{							//on fixed HDR1 HDR2 HDR1 HDR2... sequence so a 2 pass DOF outputs HDR1 in pass 1 and 	
		VertexShader = VS_MasterEffect;			//HDR2 in second pass, a 3 pass DOF outputs HDR2, HDR1, HDR2 so last pass outputs always HDR2
		PixelShader = PS_ME_Init;
		RenderTarget = texHDR2;
	}

#if (USE_BLOOM == 1 || USE_GAUSSIAN_ANAMFLARE == 1 || USE_LENSDIRT == 1)
	pass BloomPrePass
	{
		VertexShader = VS_MasterEffect;
		PixelShader = PS_ME_BloomPrePass;
		RenderTarget = texBloom1;
	}
	
	pass BloomPass1
	{
		VertexShader = VS_MasterEffect;
		PixelShader = PS_ME_BloomPass1;
		RenderTarget = texBloom2;
	}

	pass BloomPass2
	{
		VertexShader = VS_MasterEffect;
		PixelShader = PS_ME_BloomPass2;
		RenderTarget = texBloom3;
	}

	pass BloomPass3
	{
		VertexShader = VS_MasterEffect;
		PixelShader = PS_ME_BloomPass3;
		RenderTarget = texBloom4;
	}

	pass BloomPass4
	{
		VertexShader = VS_MasterEffect;
		PixelShader = PS_ME_BloomPass4;
		RenderTarget = texBloom5;
	}
#endif

#if (USE_LENZFLARE == 1 || USE_CHAPMAN_LENS == 1 || USE_GODRAYS == 1 || USE_ANAMFLARE == 1)
	pass ME_LensPrepass
	{
		VertexShader = VS_MasterEffect;
		PixelShader = PS_ME_LensPrepass;
		RenderTarget = texLens1;
	}
	
	pass ME_LensPass1
	{
		VertexShader = VS_MasterEffect;
		PixelShader = PS_ME_LensPass1;
		RenderTarget = texLens2;
	}

	pass ME_LensPass2
	{
		VertexShader = VS_MasterEffect;
		PixelShader = PS_ME_LensPass2;
		RenderTarget = texLens1;
	}
#endif

	pass ME_LightingCombine
	{
		VertexShader = VS_MasterEffect;
		PixelShader = PS_ME_LightingCombine;
		RenderTarget = texHDR1;
	}

	pass ME_Colors
	{
		VertexShader = VS_MasterEffect;
		PixelShader = PS_ME_Colors;
		RenderTarget = texHDR2;
	}

#if (USE_SMAA == 1)
	pass SMAA_EdgeDetection //First SMAA Pass
	{
		VertexShader = SMAAEdgeDetectionVSWrap;
 #if (iSMAAEdgeDetectionMode == 1)
		PixelShader = SMAALumaEdgeDetectionPSWrap;
 #elif (iSMAAEdgeDetectionMode == 3)
		PixelShader = SMAADepthEdgeDetectionPSWrap;
 #else
		PixelShader = SMAAColorEdgeDetectionPSWrap; //Probably the best in most cases so I default to this.
 #endif
		StencilEnable = true;
		StencilPass = REPLACE;
		StencilRef = 1;
		RenderTarget = texEdges;
	}
	
	pass SMAA_BlendWeightCalculation //Second SMAA Pass
	{
		VertexShader = SMAABlendingWeightCalculationVSWrap;
		PixelShader = SMAABlendingWeightCalculationPSWrap;
     		StencilEnable = true;
		StencilPass = KEEP;
		StencilFunc = EQUAL;
		StencilRef = 1;
		RenderTarget = texBlend;
	}
	
	pass SMAA_NeighborhoodBlending //Third SMAA Pass
	{
		VertexShader = SMAANeighborhoodBlendingVSWrap;
		PixelShader  = SMAANeighborhoodBlendingPSWrap;
		
 #if (iSMAADebugOutput == 5)
		// Use the stencil so we can show it.
		StencilEnable = true;
		StencilPass = KEEP;
		StencilFunc = EQUAL;
		StencilRef = 1;
 #else
		// Process all the pixels.
		StencilEnable = false;
 #endif
		RenderTarget = texHDR1;	
	}
#endif
	pass ME_PostFX
	{
		VertexShader = VS_MasterEffect;
		PixelShader = PS_ME_PostFX;
#if (USE_SMAA == 1)					//exactly what I wanted to prevent with new system :(
		RenderTarget = texHDR2;			//but I see now, first AA and then chromatic abberation gives smoother result...
#else							//this of course eliminates the option to use 2 AA's together because with each count 
		RenderTarget = texHDR1;			//this here would get more and more complicated...damn
#endif							//Noone will ever read this so I'm basically talking to a text file. Hello text file.
	}						

	pass ME_Overlay
	{
		VertexShader = VS_MasterEffect;
		PixelShader = PS_ME_Overlay;
	}
}
