/*===============================================================================*\
|########################   [GLSL PSX FX SHADER V1.0]    #########################|
|########################	   [BY ASMODEAN@PCSX2]	     #########################|
||																				 ||
||			  		   ,---.  .---..-.   .-.  ,---..-.   .-.					 ||
||					   | .-.\( .-._)) \_/ /   | .-' ) \_/ / 					 ||
||					   | |-' )) \  (_)   /    | `-.(_)   /  					 ||
||					   | |--'_ \ \   / _ \    | .-'  / _ \  					 ||
||					   | | ( `-'  ) / / ) \   | |   / / ) \ 					 ||
||					   /(   `----' `-' (_)-'  )\|  `-' (_)-'					 ||
||					  (__)                   (__)           					 ||
||																				 ||
||		  This program is free software; you can redistribute it and/or			 ||
||		  modify it under the terms of the GNU General Public License			 ||
||		  as published by the Free Software Foundation; either version 2		 ||
||		  of the License, or (at your option) any later version.				 ||
||																				 ||
||		  This program is distributed in the hope that it will be useful,		 ||
||		  but WITHOUT ANY WARRANTY; without even the implied warranty of		 ||
||		  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the			 ||
||		  GNU General Public License for more details.							 ||
||																				 ||
|#################################################################################|
\*===============================================================================*/
#version 430 compatibility

/*------------------------------------------------------------------------------
								[EXTENSIONS]
------------------------------------------------------------------------------*/

#extension GL_NV_gpu_shader5 : enable
#extension GL_ARB_gpu_shader5 : enable
#extension GL_NV_draw_buffers : enable
#extension GL_ARB_draw_buffers : enable
#extension GL_ARB_sample_shading : enable
#extension GL_ARB_shader_precision : enable
#extension GL_ARB_conservative_depth : enable 
#extension GL_EXT_framebuffer_object : enable
#extension GL_ARB_uniform_buffer_object : enable
#extension GL_ARB_vertex_attrib_64bit : enable
#extension GL_NV_explicit_multisample : enable
#extension GL_ARB_shader_texture_lod : enable
#extension GL_ARB_texture_multisample : enable
#extension GL_ARB_texture_rectangle : enable

precision highp int;
precision highp float;

/*------------------------------------------------------------------------------
						[DEFINITIONS & ON/OFF OPTIONS]
------------------------------------------------------------------------------*/

//---------------------------#[CHOOSE EFFECTS]#--------------------------------\\

//-#[ANTIALIASING TECHNIQUES]  [1=ON/0=OFF]  *READ: For best results, only enable one type of AA at one time.
#define NFAA_ENABLED				0		//#Normal Filter Anti Aliasing (Subtle AA, with good edge detection, no blur (3D Only)).
#define SSAA_ENABLED				0		//#Shader-Based SuperSampling, Scales well with high resolutions. (Soft SS AA (2D & 3D)).
#define FXAA_ENABLED				1		//#HQ Fast Approximate Anti Aliasing (Heavy duty AA, more blur than the others, but also better jaggy removal. (2D & 3D)).
#define SPRITE_INTERPOLATION		0		//#2DAA Interpolation Smoothing, Nice for Sprite games(2D only). ||READ:**To enable this, you also need to set it to 1 in the Vertex shader (.slv)**||

//-#[LIGHTING & COLOUR] 	   [1=ON/0=OFF]  *READ: These can all be turned on & off independently of each other. || For HDR - the luma, tonemap, and bloom passes should be used together, for best results.
#define LUMA_SHARPEN				1		//#HQ Luma-Based Sharpen, looks similar to a negative mip LOD Bias, enhances texture fidelity. 
#define HDR_LUMA_PASS				1		//#Scene luma range correction pass of the HDR.
#define HDR_TONEMAP_PASS			1		//#Scene tonemapping pass of the HDR.
#define HDR_BLOOM_PASS				1 		//#Bloom high pass of the HDR.
#define DYNAMIC_CONTRAST			1		//#S-Curve Dynamic Scene Contrast Enhancement.
#define INTELLI_VIBRANCE			1		//Dynamic per pixel vibrance. It can also be used as color offset calibration, due to the HDR skewing the gamut.
#define POINT_LIGHT					1		//Point Light Attenuation, (lighting enhancement) doesn't work for all games, is why it's optional.
#define TOON_SHADER					0		//#A Cartoon-Style look, I'm still working on improving this, but it works fine for now.
#define DITHER_ENABLE				0		//#Finite Dithering, can help to reduce color banding.

//-#[TEXTURE FILTERING] 	   [1=ON/0=OFF]  *READ: The use of filters requires an AA technique to be turned on. For best results, only enable one type of Filter at one time.
#define TEXTURE_FILTER_ENABLED		1		//#<-**Don't turn this off, for now**. Enable or Disable The texture filtering from the two options below.
#define FILTER_TYPE_BICUBIC			0		//#CatMullRom BiCubic texture filter ||Choose one type of filter, don't enable both together.||
#define FILTER_TYPE_BILINEAR		1		//#BiLinear texture filter (recommended) ||Choose one type of filter, don't enable both together.||


/*------------------------------------------------------------------------------
							[GLOBAL VARIABLES]
------------------------------------------------------------------------------*/

uniform sampler2D colorSampler;
uniform sampler2D FXAASampler;
uniform sampler2D SSAASampler;
uniform sampler2D NFAASampler;
uniform sampler2D BloomSampler;
uniform sampler2D LumaSampler;
uniform sampler2D ImageSampler;
uniform sampler2D AvgLumSampler;
uniform sampler2D txLogLumSampler;
uniform sampler2D txRelLumAvgSampler;
uniform samplerBuffer lumCurveSampler;

const float TextureSize = 4096;
const float texelSize = (1.0 / TextureSize);
const ivec2 BufferSize = textureSize(colorSampler, 0);

precise vec2 texcoord = gl_TexCoord[0].st;
precise out vec4 gl_FragData[gl_MaxDrawBuffers];
vec4 texcolor = texture(colorSampler, texcoord);


/*------------------------------------------------------------------------------
					[SHADER FX CONFIG OPTIONS & LOCAL VARS]
------------------------------------------------------------------------------*/

#if (NFAA_ENABLED == 1)
	float NFWidth = 4096.0; 		//X res(density)
	float NFHeight = 2048.0;		//Y res(density)
	float filterStrength = 10.0;	//AA Strength 
	float filterSpread = 0.1;		//Filter Width
	
	bool debug = false;				//Shows the edge detection.
	bool useColor = false;			//Uses color detection, instead of luma edge detection (more coverage, less accuracy).
	
	precise vec2 rcpres = vec2(1.0/NFWidth, 1.0/NFHeight);
#endif

#if (SSAA_ENABLED == 1)
	float w = 1.0; //Filter Width
	float Width = 2560.0;
	float Height = 1440.0;

	precise vec2 inverse_buffer_size = vec2(1.0/Width, 1.0/Height);
#endif

#if (FXAA_ENABLED == 1)
	#define FXAA_REDUCE_MIN (1.0/32.0)
	#define FXAA_REDUCE_MUL (1.0/16.0)
	#define FXAA_SPAN_MAX (4.0)
	#define FXAA_GATHER4_ALPHA 1
	#define FXAA_QUALITY__SUBPIX 1
	#define FXAA_QUALITY__EDGE_THRESHOLD (1.0/32.0)
	#define FXAA_QUALITY__EDGE_THRESHOLD_MIN (1.0/32.0)

	#define FxaaInt2 ivec2
	#define FxaaFloat2 vec2
	#define FxaaFloat4 vec4
    #define FxaaSat(x) clamp(x, 0.0, 1.0)
    #define FxaaLerp(x,y,s) mix(x,y,s)
	#define FxaaTexLod0(t, p) textureLod(t, p, 0.0)
	#define FxaaTexOff(t, p, o, r) textureLodOffset(t, p, 0.0, o)
	#define FxaaTexAlpha4(t, p, r) textureGather(t, p, 3)
    #define FxaaTexOffAlpha4(t, p, o, r) textureGatherOffset(t, p, o, 3)
	
	precise in vec4 posPos;
	uniform float rt_w = 2560.0;
	uniform float rt_h = 1440.0;
#endif

#if (LUMA_SHARPEN == 1)
	#define Sharp_Strength 0.10   	//[0.10 to 3.00]
	#define Sharp_Clamp 0.020  		//[0.000 to 1.000]

	#define Pattern 5 				//1 = Normal, 2 = Wider, 3 = Pyramid shaped, 4 = 9-tap guassian, 5 = HQ 9-tap texture fetch.
	#define Offset_Bias 4.0 		//Offset Bias [0.0 to 6.0]
	#define Show_Sharpen 0
	
	#define BUFFER_RCP_WIDTH (1.0 / 2560)
	#define BUFFER_RCP_HEIGHT (1.0 / 1440)
	#define BUFFER_WIDTH 2560
	#define BUFFER_HEIGHT 1440
#endif

#if (HDR_BLOOM_PASS == 1)
	#define BloomThreshold 22.50	//[0.00 to 50.00] Threshold for what the bloom affects, in screen space.
	#define BloomStrength 1.500		//[0.000 to 8.000] Strength of the bloom
	#define BloomWidth 0.0142		//[0.0000 to 1.0000] Width of the bloom
#endif

#if (HDR_TONEMAP_PASS == 1)
	#define Gamma 1.00       //[0.000 to 2.000] Adjust midtones
	#define Exposure -0.05    //[-1.000 to 1.000] Adjust exposure
	#define Saturation -0.05  //[-1.000 to 1.000] Adjust white saturation
	#define Bleach 0.00      //[0.000 to 1.000] Brightens the shadows and fades the colors
#endif

#if (HDR_LUMA_PASS == 1)
	#define DO_TONEMAP
	#define DO_GLOBAL
	#define DO_LOCAL
	#define DO_CHROMINANCE
	#define DO_VARYING
	#define K 4

	const float Luminance = 1.000;		//Luma
	const float lumaFactor = 1.000;		//Luma Scale Factor
	const float lumaCorrection = 0.80;  //Percent of luma for correction

	uniform float key = 1.00;
	uniform float threshold = 1.00;
	uniform float phi = 1.00;
#endif

#if (DYNAMIC_CONTRAST == 1)
	#define Curves_Contrast 0.20  //[-1.00 to 1.00] Minus(-)values increase contrast when using Formula 8 only, .
	#define Curves_Formula 5      	//[1|2|3|4|5|6|7|8] The constrast s-curve you want to use.
#endif

#if (INTELLI_VIBRANCE == 1)
	#define Vibrance -0.05 //[-1.00 to 1.00] Intelligently saturates (or desaturates if you use negative values) the pixels depending on their original saturation.
#endif

#if (POINT_LIGHT == 1)
smooth out vec3 normal, lightDir, eyeVec;
smooth out float att;
#endif

#if (TOON_SHADER == 1)
	#define BUFFER_RCP_WIDTH (1.0 / 4096)
	#define BUFFER_RCP_HEIGHT (1.0 / 2048)
	
	uniform float ToonVibrance = 0.25;		//Toon DynaVibrance
	uniform float Outline_Thickness = 2.5;	//Edge Detect Width
#endif

/*------------------------------------------------------------------------------
                       [TEXTURE FILTER FUNCTIONS]
------------------------------------------------------------------------------*/

#if (TEXTURE_FILTER_ENABLED == 1)
uniform float fWidth = 4096.0;	 //Filter X res
uniform float fHeight = 2048.0;	 //Filter Y res

vec4 cubic(float x)
{
    float x2 = x * x;
    float x3 = x2 * x;
    vec4 w;
    w.x =   -x3 + 3*x2 - 3*x + 1;
    w.y =  3*x3 - 6*x2       + 4;
    w.z = -3*x3 + 3*x2 + 3*x + 1;
    w.w =  x3;
    return w / 6.f;
}

float CatMullRom(float x)
{
    float B = 0.0;
    float C = 0.5;
    float f = x;
	
    if(f < 0.0)
    {
        f = -f;
    }
    if(f < 1.0)
    {
        return ((12.0 - 9.0 * B - 6.0 * C) * (f * f * f) + 
		(-18.0f + 12.0f * B + 6.0f * C) * (f * f) + 
		(6.0f - 2.0f * B)) / 6.0f;
    }
    else if(f >= 1.0 && f < 2.0)
    {
        return (( -B - 6 * C) * (f * f * f) + 
		(6 * B + 30 * C) * (f *f) + 
		(-(12 * B) - 48 * C) * f + 8 * B + 24 * C)/ 6.0;
    }
    else
    {
        return 0.0;
    }
}

vec4 texture2DBilinear(sampler2D textureSampler, vec2 uv)
{
    for (int i=0; i<32; i++)
	{
		vec4 tl = texture(textureSampler, texcoord);
		vec4 tr = texture(textureSampler, texcoord + vec2(texelSize, 0));
		vec4 bl = texture(textureSampler, texcoord + vec2(0, texelSize));
		vec4 br = texture(textureSampler, texcoord + vec2(texelSize , texelSize));
		vec2 f = fract( texcoord.xy * BufferSize );
		vec4 tA = mix( tl, tr, f.x );
		vec4 tB = mix( bl, br, f.x );
		
		return mix( tA, tB, f.y );
	}   
}

#if (FILTER_TYPE_BICUBIC == 1)
vec4 BiCubic(sampler2D textureSampler, vec2 TexCoord)
{
	float texelSizeX = (1.0 / fWidth); //size of one texel 
	float texelSizeY = (1.0 / fHeight); //size of one texel
	
    vec4 nSum = vec4( 0.0, 0.0, 0.0, 0.0 );
    vec4 nDenom = vec4( 0.0, 0.0, 0.0, 0.0 );
	
    float a = fract( TexCoord.x * fWidth ); // get the decimal part
    float b = fract( TexCoord.y * fHeight ); // get the decimal part

	int nX = int(TexCoord.x * fWidth);
	int nY = int(TexCoord.y * fHeight);
	
	vec2 TexCoord1 = vec2( float(nX) / fWidth + 0.5 / fWidth,
					       float(nY) / fHeight + 0.5 / fHeight );

    for(int m = -1; m <=2; m++)
    {
        for(int n =-1; n<= 2; n++)
        {
			vec4 vecData = texture(textureSampler, TexCoord1 + vec2(texelSizeX * float( m ), texelSizeY * float( n )));
			float f  = CatMullRom( float( m ) - a );
			vec4 vecCooef1 = vec4( f,f,f,f );
			float f1 = CatMullRom( -( float( n ) - b ) );
			vec4 vecCoeef2 = vec4( f1, f1, f1, f1 );
            nSum = nSum + ( vecData * vecCoeef2 * vecCooef1  );
            nDenom = nDenom + (( vecCoeef2 * vecCooef1 ));
        }
    }
    return nSum / nDenom;
}
#endif
#if (FILTER_TYPE_BILINEAR == 1)
vec4 tex2DBiLinear(sampler2D textureSampler_i, vec2 texCoord_i)
{	
	float texelSizeX = (1.0 / fWidth); //size of one texel 
	float texelSizeY = (1.0 / fHeight); //size of one texel 

	int nX = int( texCoord_i.x * fWidth );
	int nY = int( texCoord_i.y * fHeight );
	
	vec2 texCoord_New = vec2( ( float( nX ) + 0.5 ) / fWidth,
							  ( float( nY ) + 0.5 ) / fHeight );
	// Take nearest two data in current row.
    vec4 p0q0 = texture(textureSampler_i, texCoord_New);
    vec4 p1q0 = texture(textureSampler_i, texCoord_New + vec2(texelSizeX, 0));

	// Take nearest two data in bottom row.
    vec4 p0q1 = texture(textureSampler_i, texCoord_New + vec2(0, texelSizeY));
    vec4 p1q1 = texture(textureSampler_i, texCoord_New + vec2(texelSizeX , texelSizeY));

    float a = fract(texCoord_i.x * fWidth); // Get Interpolation factor for X direction.
											 // Fraction near to valid data.
	// Interpolation in X direction.
    vec4 pInterp_q0 = mix( p0q0, p1q0, a ); // Interpolates top row in X direction.
    vec4 pInterp_q1 = mix( p0q1, p1q1, a ); // Interpolates bottom row in X direction.

    float b = fract(texCoord_i.y * fHeight); // Get Interpolation factor for Y direction.
	
    return mix(pInterp_q0, pInterp_q1, b); // Interpolate in Y direction.
}
#endif
#endif

/*------------------------------------------------------------------------------
                       [COLOR CORRECTION FUNCTIONS]
------------------------------------------------------------------------------*/

#define GammaCorrection(color, gamma) pow(color, 1.0 / gamma)

vec4 ExpandRGBE(vec4 RGBE)
{
	return vec4(ldexp(RGBE.xyz, ivec3(255.0 * RGBE.w - 128.0 )), 1.0);
}

float LinearToSRGB(float c)
{
	#define EXP (1.0 / 2.4)
	#define A (0.055)
	#define B (1.0 + A)

	float v = c;
	if (v < 0.0031308)
		v = 12.92 * v;
	else
		v = B * pow (v , EXP) - A;

	return v;
}

vec4 Desaturate(vec3 color, float Desaturation)
{
	vec3 grayXfer = vec3(0.3, 0.59, 0.11);
	vec3 gray = vec3(dot(grayXfer, color));
	return vec4(mix(color, gray, Desaturation), 1.0);
}

vec3 RGBToHSL(vec3 color)
{
	vec3 hsl; // init to 0 to avoid warnings ? (and reverse if + remove first part)
	
	float fmin = min(min(color.r, color.g), color.b);    //Min. value of RGB
	float fmax = max(max(color.r, color.g), color.b);    //Max. value of RGB
	float delta = fmax - fmin;             //Delta RGB value

	hsl.z = (fmax + fmin) / 2.0; // Luminance

	if (delta == 0.0)		//This is a gray, no chroma...
	{
		hsl.x = 0.0;	// Hue
		hsl.y = 0.0;	// Saturation
	}
	else                                    //Chromatic data...
	{
		if (hsl.z < 0.5)
			hsl.y = delta / (fmax + fmin); // Saturation
		else
			hsl.y = delta / (2.0 - fmax - fmin); // Saturation
		
		float deltaR = (((fmax - color.r) / 6.0) + (delta / 2.0)) / delta;
		float deltaG = (((fmax - color.g) / 6.0) + (delta / 2.0)) / delta;
		float deltaB = (((fmax - color.b) / 6.0) + (delta / 2.0)) / delta;

		if (color.r == fmax )
			hsl.x = deltaB - deltaG; // Hue
		else if (color.g == fmax)
			hsl.x = (1.0 / 3.0) + deltaR - deltaB; // Hue
		else if (color.b == fmax)
			hsl.x = (2.0 / 3.0) + deltaG - deltaR; // Hue

		if (hsl.x < 0.0)
			hsl.x += 1.0; // Hue
		else if (hsl.x > 1.0)
			hsl.x -= 1.0; // Hue
	}

	return hsl;
}

float HueToRGB(float f1, float f2, float hue)
{
	if (hue < 0.0)
		hue += 1.0;
	else if (hue > 1.0)
		hue -= 1.0;
	float res;
	if ((6.0 * hue) < 1.0)
		res = f1 + (f2 - f1) * 6.0 * hue;
	else if ((2.0 * hue) < 1.0)
		res = f2;
	else if ((3.0 * hue) < 2.0)
		res = f1 + (f2 - f1) * ((2.0 / 3.0) - hue) * 6.0;
	else
		res = f1;
	return res;
}

vec3 HSLToRGB(vec3 hsl)
{
	vec3 rgb;
	
	if (hsl.y == 0.0)
		rgb = vec3(hsl.z); // Luminance
	else
	{
		float f2;
		
		if (hsl.z < 0.5)
			f2 = hsl.z * (1.0 + hsl.y);
		else
			f2 = (hsl.z + hsl.y) - (hsl.y * hsl.z);
			
		float f1 = 2.0 * hsl.z - f2;
		
		rgb.r = HueToRGB(f1, f2, hsl.x + (1.0/3.0));
		rgb.g = HueToRGB(f1, f2, hsl.x);
		rgb.b= HueToRGB(f1, f2, hsl.x - (1.0/3.0));
	}
	
	return rgb;
}

// For all settings: 1.0 = 100% 0.5=50% 1.5 = 150%
vec3 ContrastSaturationBrightness(vec3 color, float brt, float sat, float con)
{
	// Increase or decrease theese values to adjust r, g and b color channels seperately
	const float AvgLumR = 0.5;
	const float AvgLumG = 0.5;
	const float AvgLumB = 0.5;
	
	const vec3 LumCoeff = vec3(0.2125, 0.7154, 0.0721);
	
	vec3 AvgLumin = vec3(AvgLumR, AvgLumG, AvgLumB);
	vec3 brtColor = color * brt;
	vec3 intensity = vec3(dot(brtColor, LumCoeff));
	vec3 satColor = mix(intensity, brtColor, sat);
	vec3 conColor = mix(AvgLumin, satColor, con);
	return conColor;
}

vec3 BlendHue(vec3 base, vec3 blend)
{
	vec3 baseHSL = RGBToHSL(base);
	return HSLToRGB(vec3(RGBToHSL(blend).r, baseHSL.g, baseHSL.b));
}

vec3 BlendColor(vec3 base, vec3 blend)
{
	vec3 blendHSL = RGBToHSL(blend);
	return HSLToRGB(vec3(blendHSL.r, blendHSL.g, RGBToHSL(base).b));
}

/*------------------------------------------------------------------------------
                             [NFAA CODE SECTION]
------------------------------------------------------------------------------*/

#if (NFAA_ENABLED == 1)
	float GetColorLuminance(vec3 i_vColor)
	{
		return dot(i_vColor, vec3(0.2126f, 0.7152f, 0.0722f));
	}

	vec2 findContrastByLuminance(vec2 XYCoord) 
	{
		// Normal offsets, scale by filter spread
		vec2 upOffset = vec2( 0, rcpres.y ) * filterSpread;
		vec2 rightOffset = vec2( rcpres.x, 0 ) * filterSpread;

		float topHeight         = GetColorLuminance( texture( NFAASampler, XYCoord + upOffset              ).rgb );
		float bottomHeight      = GetColorLuminance( texture( NFAASampler, XYCoord - upOffset              ).rgb );
		float rightHeight       = GetColorLuminance( texture( NFAASampler, XYCoord + rightOffset           ).rgb );
		float leftHeight        = GetColorLuminance( texture( NFAASampler, XYCoord - rightOffset           ).rgb );
		float leftTopHeight     = GetColorLuminance( texture( NFAASampler, XYCoord - rightOffset + upOffset).rgb );
		float leftBottomHeight  = GetColorLuminance( texture( NFAASampler, XYCoord - rightOffset - upOffset).rgb );
		float rightBottomHeight = GetColorLuminance( texture( NFAASampler, XYCoord + rightOffset + upOffset).rgb );
		float rightTopHeight    = GetColorLuminance( texture( NFAASampler, XYCoord + rightOffset - upOffset).rgb );

		// Normal map creation
		float sum0 = rightTopHeight    + bottomHeight + leftTopHeight;
		float sum1 = leftBottomHeight  + topHeight    + rightBottomHeight;
		float sum2 = leftTopHeight     + rightHeight  + leftBottomHeight;
		float sum3 = rightBottomHeight + leftHeight   + rightTopHeight;

		// Subtract the opposite sample set for final vectors
		float vector1 = (sum0 - sum1) * filterStrength;
		float vector2 = (sum3 - sum2) * filterStrength;

		vec2 Vectors = vec2(vector1, vector2);

		return Vectors;
	}

	vec2 findContrastByColor(vec2 XYCoord)
	{
		// Normal offsets, scale by filter spread
		vec2 upOffset = vec2( 0, rcpres.y ) * filterSpread;
		vec2 rightOffset = vec2( rcpres.x, 0 ) * filterSpread;

		vec3 topHeight         = texture( NFAASampler, XYCoord + upOffset              ).rgb;
		vec3 bottomHeight      = texture( NFAASampler, XYCoord - upOffset              ).rgb;
		vec3 rightHeight       = texture( NFAASampler, XYCoord + rightOffset           ).rgb;
		vec3 leftHeight        = texture( NFAASampler, XYCoord - rightOffset           ).rgb;
		vec3 leftTopHeight     = texture( NFAASampler, XYCoord - rightOffset + upOffset).rgb;
		vec3 leftBottomHeight  = texture( NFAASampler, XYCoord - rightOffset - upOffset).rgb;
		vec3 rightBottomHeight = texture( NFAASampler, XYCoord + rightOffset + upOffset).rgb;
		vec3 rightTopHeight    = texture( NFAASampler, XYCoord + rightOffset - upOffset).rgb;

		// Normal map creation
		vec3 sum0 = rightTopHeight    + bottomHeight + leftTopHeight;
		vec3 sum1 = leftBottomHeight  + topHeight    + rightBottomHeight;
		vec3 sum2 = leftTopHeight     + rightHeight  + leftBottomHeight;
		vec3 sum3 = rightBottomHeight + leftHeight   + rightTopHeight;

		// Subtract the opposite sample set for final vectors
		float vector1 = length(sum0 - sum1) * filterStrength;
		float vector2 = length(sum3 - sum2) * filterStrength;

		vec2 Vectors = vec2(vector1, vector2);

		return Vectors;
	}

	vec4 getNFAA(vec4 o_Color, vec2 Vectors) 
	{
		
		filterStrength += (filterSpread/2);
		
		if (useColor)
		{ 
			Vectors = findContrastByColor(texcoord.xy);
		}
		else
		{
			Vectors = findContrastByLuminance(texcoord.xy);
		}

		float filterClamp = filterStrength/filterSpread;

		Vectors.xy = clamp(Vectors, -vec2(filterClamp,filterClamp), vec2(filterClamp,filterClamp));

		vec2 Normal = vec2(Vectors.x, Vectors.y) * rcpres;
		
		#if (TEXTURE_FILTER_ENABLED == 1 && FILTER_TYPE_BICUBIC == 1)
			vec4 Scene0 = BiCubic(NFAASampler, texcoord.xy);
			vec4 Scene1 = texture(NFAASampler, texcoord.xy + Normal.xy, 0.0);
			vec4 Scene2 = texture(NFAASampler, texcoord.xy - Normal.xy, 0.0);
			vec4 Scene3 = texture(NFAASampler, texcoord.xy + vec2(Normal.x, -Normal.y), 0.0);
			vec4 Scene4 = texture(NFAASampler, texcoord.xy - vec2(Normal.x, -Normal.y), 0.0);
		#elif (TEXTURE_FILTER_ENABLED == 1 && FILTER_TYPE_BILINEAR == 1)
			vec4 Scene0 = tex2DBiLinear(NFAASampler, texcoord.xy);
			vec4 Scene1 = texture(NFAASampler, texcoord.xy + Normal.xy, 0.0);
			vec4 Scene2 = texture(NFAASampler, texcoord.xy - Normal.xy, 0.0);
			vec4 Scene3 = texture(NFAASampler, texcoord.xy + vec2(Normal.x, -Normal.y), 0.0);
			vec4 Scene4 = texture(NFAASampler, texcoord.xy - vec2(Normal.x, -Normal.y), 0.0);
		#else
			vec4 Scene0 = texture(NFAASampler, texcoord.xy, 0.0);
			vec4 Scene1 = texture(NFAASampler, texcoord.xy + Normal.xy, 0.0);
			vec4 Scene2 = texture(NFAASampler, texcoord.xy - Normal.xy, 0.0);
			vec4 Scene3 = texture(NFAASampler, texcoord.xy + vec2(Normal.x, -Normal.y), 0.0);
			vec4 Scene4 = texture(NFAASampler, texcoord.xy - vec2(Normal.x, -Normal.y), 0.0);
		#endif

		// Final color
		o_Color = (Scene0 + Scene1 + Scene2 + Scene3 + Scene4) * 0.2;

		// Debug Output
		if (debug) 
		{
			o_Color .xyz = normalize(vec3(Vectors.x, Vectors.y, 1.0) * 0.5 + 0.5);
		}

		return o_Color;
	}
#endif

/*------------------------------------------------------------------------------
                             [SSAA CODE SECTION]
------------------------------------------------------------------------------*/

#if (SSAA_ENABLED == 1)
	float lumRGB(vec3 v)
	{   
		return dot(v, vec3(0.2126f, 0.7152f, 0.0722f));
	}
	
	vec4 getSSAA(vec4 oColor, vec2 txCoord) 
	{
	 
		float   t = lumRGB(texture(SSAASampler, texcoord + vec2(0.0, -1.0) * w * inverse_buffer_size, 0.0).xyz),
				l = lumRGB(texture(SSAASampler, texcoord + vec2(-1.0, 0.0) * w * inverse_buffer_size, 0.0).xyz),
				r = lumRGB(texture(SSAASampler, texcoord + vec2(1.0, 0.0) * w * inverse_buffer_size, 0.0).xyz),
				b = lumRGB(texture(SSAASampler, texcoord + vec2(0.0, 1.0) * w * inverse_buffer_size, 0.0).xyz);
	 
		vec2    n = vec2(-(t - b), r - l);

		float   nl = length(n);
		
		if	(nl < (1.0 / 16.0))
			return texture(SSAASampler, texcoord, 0.0);
	 
		else
		{
			n *= inverse_buffer_size / nl;
			
			#if (TEXTURE_FILTER_ENABLED == 1 && FILTER_TYPE_BICUBIC == 1)
				vec4	o = BiCubic(SSAASampler, texcoord),
						t0 = texture(SSAASampler, texcoord + n * 0.5, 0.0) * 0.9,
						t1 = texture(SSAASampler, texcoord - n * 0.5, 0.0) * 0.9,
						t2 = texture(SSAASampler, texcoord + n, 0.0) * 0.75,
						t3 = texture(SSAASampler, texcoord - n, 0.0) * 0.75; 
			#elif (TEXTURE_FILTER_ENABLED == 1 && FILTER_TYPE_BILINEAR == 1)
				vec4	o = tex2DBiLinear(SSAASampler, texcoord),
						t0 = tex2DBiLinear(SSAASampler, texcoord + n * 0.5) * 0.9,
						t1 = texture(SSAASampler, texcoord - n * 0.5, 0.0) * 0.9,
						t2 = texture(SSAASampler, texcoord + n, 0.0) * 0.75,
						t3 = texture(SSAASampler, texcoord - n, 0.0) * 0.75; 
			#else
				vec4	o = texture(SSAASampler, texcoord, 0.0),
						t0 = texture(SSAASampler, texcoord + n * 0.5, 0.0) * 0.9,
						t1 = texture(SSAASampler, texcoord - n * 0.5, 0.0) * 0.9,
						t2 = texture(SSAASampler, texcoord + n, 0.0) * 0.75,
						t3 = texture(SSAASampler, texcoord - n, 0.0) * 0.75; 
			#endif						
					
			oColor = (o + t0 + t1 + t2 + t3) / 4.3;
			
			return oColor;
	}
	}
#endif

/*------------------------------------------------------------------------------
                             [FXAA CODE SECTION]
------------------------------------------------------------------------------*/

#if (FXAA_ENABLED == 1)
	vec3 FxaaPixelShader(vec4 posPos, sampler2D tex, vec2 rcpFrame)
	{	
		vec2 posM;
		posM.x = posPos.x;
		posM.y = posPos.y;
		
		#define FXAA_QUALITY__P0 	1.0
		#define FXAA_QUALITY__P1 	1.0
		#define FXAA_QUALITY__P2 	1.0
		#define FXAA_QUALITY__P11	8.0
		
		#if (GL_NV_gpu_shader5)
		vec4 luma4A = FxaaTexAlpha4(tex, posM, rcpFrame.xy);
		vec4 luma4B = FxaaTexOffAlpha4(tex, posM, FxaaInt2(-1, -1), rcpFrame.xy);
		#endif
		
		vec4 rgbyM = FxaaTexLod0(tex, posM);
 
        float lumaS = FxaaTexOff(tex, posM, FxaaInt2( 0, 1), rcpFrame.xy).w;
        float lumaE = FxaaTexOff(tex, posM, FxaaInt2( 1, 0), rcpFrame.xy).w;
        float lumaN = FxaaTexOff(tex, posM, FxaaInt2( 0,-1), rcpFrame.xy).w;
        float lumaW = FxaaTexOff(tex, posM, FxaaInt2(-1, 0), rcpFrame.xy).w;
		
		vec3 rgbNW = FxaaTexLod0(tex, posPos.zw).xyz;
		vec3 rgbNE = FxaaTexOff(tex, posPos.zw, FxaaInt2(1,0), rcpFrame.xy).xyz;
		vec3 rgbSW = FxaaTexOff(tex, posPos.zw, FxaaInt2(0,1), rcpFrame.xy).xyz;
		vec3 rgbSE = FxaaTexOff(tex, posPos.zw, FxaaInt2(1,1), rcpFrame.xy).xyz;
		vec3 rgbM  = FxaaTexLod0(tex, posPos.xy).xyz;

		vec3 luma = vec3(0.2125, 0.7154, 0.0721);
		float lumaNW = dot(rgbNW, luma);
		float lumaNE = dot(rgbNE, luma);
		float lumaSW = dot(rgbSW, luma);
		float lumaSE = dot(rgbSE, luma);
		float lumaM  = dot(rgbM,  luma);
		
		float maxSM = max(lumaS, lumaM);
		float minSM = min(lumaS, lumaM);
		float maxESM = max(lumaE, maxSM);
		float minESM = min(lumaE, minSM);
		float maxWN = max(lumaN, lumaW);
		float minWN = min(lumaN, lumaW);
		float rangeMax = max(maxWN, maxESM);
		float rangeMin = min(minWN, minESM);
		float rangeMaxScaled = rangeMax * FXAA_QUALITY__EDGE_THRESHOLD;
		float range = rangeMax - rangeMin;
		float rangeMaxClamped = max(FXAA_QUALITY__EDGE_THRESHOLD_MIN, rangeMaxScaled);
		bool earlyExit = range < rangeMaxClamped;
		
		float lumaNS = lumaN + lumaS;
		float lumaWE = lumaW + lumaE;
		float subpixRcpRange = 1.0/range;
		float subpixNSWE = lumaNS + lumaWE;
		float edgeHorz1 = (-2.0 * lumaM) + lumaNS;
		float edgeVert1 = (-2.0 * lumaM) + lumaWE;

		float lumaNESE = lumaNE + lumaSE;
		float lumaNWNE = lumaNW + lumaNE;
		float edgeHorz2 = (-2.0 * lumaE) + lumaNESE;
		float edgeVert2 = (-2.0 * lumaN) + lumaNWNE;

		float lumaNWSW = lumaNW + lumaSW;
		float lumaSWSE = lumaSW + lumaSE;
		float edgeHorz4 = (abs(edgeHorz1) * 2.0) + abs(edgeHorz2);
		float edgeVert4 = (abs(edgeVert1) * 2.0) + abs(edgeVert2);
		float edgeHorz3 = (-2.0 * lumaW) + lumaNWSW;
		float edgeVert3 = (-2.0 * lumaS) + lumaSWSE;
		float edgeHorz = abs(edgeHorz3) + edgeHorz4;
		float edgeVert = abs(edgeVert3) + edgeVert4;
		
		float subpixNWSWNESE = lumaNWSW + lumaNESE;
		float lengthSign = rcpFrame.x;
		bool horzSpan = edgeHorz >= edgeVert;
		float subpixA = subpixNSWE * 2.0 + subpixNWSWNESE;
		
		if(!horzSpan) lumaN = lumaW;
		if(!horzSpan) lumaS = lumaE;
		if(horzSpan) lengthSign = rcpFrame.y;
		float subpixB = (subpixA * (1.0/12.0)) - lumaM;
		
		float gradientN = lumaN - lumaM;
		float gradientS = lumaS - lumaM;
		float lumaNN = lumaN + lumaM;
		float lumaSS = lumaS + lumaM;
		bool pairN = abs(gradientN) >= abs(gradientS);
		float gradient = max(abs(gradientN), abs(gradientS));
		if(pairN) lengthSign = -lengthSign;
		float subpixC = FxaaSat(abs(subpixB) * subpixRcpRange);
		
		vec2 posB;
		posB.x = posM.x;
		posB.y = posM.y;
		vec2 offNP;
		offNP.x = (!horzSpan) ? 0.0 : rcpFrame.x;
		offNP.y = ( horzSpan) ? 0.0 : rcpFrame.y;
		if(!horzSpan) posB.x += lengthSign * 0.5;
		if( horzSpan) posB.y += lengthSign * 0.5;
		
		vec2 posN;
		posN.x = posB.x - offNP.x * FXAA_QUALITY__P0;
		posN.y = posB.y - offNP.y * FXAA_QUALITY__P0;
		vec2 posP;
		posP.x = posB.x + offNP.x * FXAA_QUALITY__P0;
		posP.y = posB.y + offNP.y * FXAA_QUALITY__P0;
		float subpixD = ((-2.0)*subpixC) + 3.0;
		float lumaEndN = FxaaTexLod0(tex, posN).w;
		float subpixE = subpixC * subpixC;
		float lumaEndP = FxaaTexLod0(tex, posP).w;
		
		if(!pairN) lumaNN = lumaSS;
		float gradientScaled = gradient * 1.0/4.0;
		float lumaMM = lumaM - lumaNN * 0.5;
		float subpixF = subpixD * subpixE;
		bool lumaMLTZero = lumaMM < 0.0;
		
		lumaEndN -= lumaNN * 0.5;
		lumaEndP -= lumaNN * 0.5;
		bool doneN = abs(lumaEndN) >= gradientScaled;
		bool doneP = abs(lumaEndP) >= gradientScaled;
		if(!doneN) posN.x -= offNP.x * FXAA_QUALITY__P1;
		if(!doneN) posN.y -= offNP.y * FXAA_QUALITY__P1;
		bool doneNP = (!doneN) || (!doneP);
		if(!doneP) posP.x += offNP.x * FXAA_QUALITY__P1;
		if(!doneP) posP.y += offNP.y * FXAA_QUALITY__P1;
		
		if(doneNP)
		{
			if(!doneN) lumaEndN = FxaaTexLod0(tex, posN.xy).w;
			if(!doneP) lumaEndP = FxaaTexLod0(tex, posP.xy).w;
			if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5;
			if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5;
			doneN = abs(lumaEndN) >= gradientScaled;
			doneP = abs(lumaEndP) >= gradientScaled;
			if(!doneN) posN.x -= offNP.x * FXAA_QUALITY__P11;
			if(!doneN) posN.y -= offNP.y * FXAA_QUALITY__P11;
			doneNP = (!doneN) || (!doneP);
			if(!doneP) posP.x += offNP.x * FXAA_QUALITY__P11;
			if(!doneP) posP.y += offNP.y * FXAA_QUALITY__P11;
		}
		
		float dstN = posM.x - posN.x;
		float dstP = posP.x - posM.x;
		if(!horzSpan) dstN = posM.y - posN.y;
		if(!horzSpan) dstP = posP.y - posM.y;
		
		bool goodSpanN = (lumaEndN < 0.0) != lumaMLTZero;
		float spanLength = (dstP + dstN);
		bool goodSpanP = (lumaEndP < 0.0) != lumaMLTZero;
		float spanLengthRcp = 1.0/spanLength;

		bool directionN = dstN < dstP;
		float dst = min(dstN, dstP);
		bool goodSpan = directionN ? goodSpanN : goodSpanP;
		float subpixG = subpixF * subpixF;
		float pixelOffset = (dst * (-spanLengthRcp)) + 0.5;
		float subpixH = subpixG * FXAA_QUALITY__SUBPIX;

		float pixelOffsetGood = goodSpan ? pixelOffset : 0.0;
		float pixelOffsetSubpix = max(pixelOffsetGood, subpixH);
		if(!horzSpan) posM.x += pixelOffsetSubpix * lengthSign;
		if( horzSpan) posM.y += pixelOffsetSubpix * lengthSign;

		float lumaMin = min(lumaM, min(min(lumaNW, lumaNE), min(lumaSW, lumaSE)));
		float lumaMax = max(lumaM, max(max(lumaNW, lumaNE), max(lumaSW, lumaSE)));

		vec2 dir; 
		dir.x = -((lumaNW + lumaNE) - (lumaSW + lumaSE));
		dir.y =  ((lumaNW + lumaSW) - (lumaNE + lumaSE));

		float dirReduce = max(
			(lumaNW + lumaNE + lumaSW + lumaSE) * (0.25 * 
			FXAA_REDUCE_MUL), FXAA_REDUCE_MIN);
		float rcpDirMin = 1.0/(min(abs(dir.x), abs(dir.y)) + dirReduce);
		dir = min(FxaaFloat2( FXAA_SPAN_MAX,  FXAA_SPAN_MAX), 
			  max(FxaaFloat2(-FXAA_SPAN_MAX, -FXAA_SPAN_MAX), 
			  dir * rcpDirMin)) * rcpFrame.xy;

		vec3 rgbA = (1.0/2.0) * (
			FxaaTexLod0(tex, posPos.xy + dir * (1.0/3.0 - 0.5)).xyz +
			FxaaTexLod0(tex, posPos.xy + dir * (2.0/3.0 - 0.5)).xyz);
		vec3 rgbB = rgbA * (1.0/2.0) + (1.0/4.0) * (
			FxaaTexLod0(tex, posPos.xy + dir * (0.0/3.0 - 0.5)).xyz +
			FxaaTexLod0(tex, posPos.xy + dir * (3.0/3.0 - 0.5)).xyz);
		float lumaB = dot(rgbB, luma);
		
		if((lumaB < lumaMin) || (lumaB > lumaMax)) return rgbA;
		return rgbB;
	}

	vec4 PostFX(sampler2D tex, vec2 uv)
	{
		#if (TEXTURE_FILTER_ENABLED == 1 && FILTER_TYPE_BILINEAR == 1)
		vec4 FxaaOutput = tex2DBiLinear(FXAASampler, texcoord);
		#elif (TEXTURE_FILTER_ENABLED == 1 && FILTER_TYPE_BICUBIC == 1)
		vec4 FxaaOutput = BiCubic(FXAASampler, texcoord);
		#else
		vec4 FxaaOutput = texture(FXAASampler, texcoord, 0.0);
		#endif
		vec2 rcpFrame = vec2(1.0/rt_w, 1.0/rt_h);
		FxaaOutput.rgb = FxaaPixelShader(posPos, tex, rcpFrame);
		FxaaOutput.a = 1.0;
		return FxaaOutput;
	}

	vec4 getFXAA(vec4 FxaaColor, vec2 Tex) 
	{
		return PostFX(FXAASampler, texcoord);
	}
#endif

/*------------------------------------------------------------------------------
						[DYNAMIC CONTRAST CODE SECTION]
						[Adapted from CeeJay's SweetFX]
    [http://www.guru3d.com/files_details/sweetfx_shader_suite_download.html]
------------------------------------------------------------------------------*/

#if (DYNAMIC_CONTRAST == 1)
	vec4 CurvesPass(vec4 colorInput)
	{
		vec3 color = colorInput.rgb;
		vec3 lumCoeff = vec3(0.2126, 0.7152, 0.0722);
		
		float Curves_contrast_blend = Curves_Contrast;
		float PI = acos(-1); //3.14159265

		//calculate luma (grey)
		float luma = dot(lumCoeff, color);
		
		//calculate chroma
		vec3 chroma = color - luma;

		//Apply curve to luma

		// -- Curve 1 -- sin algo
		#if (Curves_Formula == 1)
		luma = sin(PI * 0.5 * luma);
		luma *= luma;  
		#endif

		// -- Curve 2 -- abs split
		#if (Curves_Formula == 2)
		luma = ( (luma - 0.5) / (0.5 + abs(luma-0.5)) ) + 0.5;
		#endif

		// -- Curve 3 -- smoothstep
		#if (Curves_Formula == 3)
		luma = luma*luma*(3.0-2.0*luma);
		#endif

		// -- Curve 4 -- exp formula
		#if (Curves_Formula == 4)
		luma = 1.1048 / (1.0 + exp(-3.0 * (luma * 2.0 - 1.0))) - (0.1048 / 2.0);
		#endif

		// -- Curve 5 -- a simple catmull-rom
		#if (Curves_Formula == 5)
		luma = 0.5 * (luma + 3.0 * luma * luma - 2.0 * luma * luma * luma);
		Curves_contrast_blend = Curves_Contrast * 2.0;
		#endif

		// -- Curve 6 -- Perlins smootherstep
		#if (Curves_Formula == 6)
		luma = luma*luma*luma*(luma*(luma*6.0 - 15.0) + 10.0);
		#endif
		
		// -- Curve 7 -- abs add
		#if (Curves_Formula == 7)
		luma = ((luma-0.5) / ((0.5/(4.0/3.0)) + abs((luma-0.5)*1.25))) + 0.5;
		#endif
		
		// -- Curve 8 -- an experimental catmull-rom.
		#if (Curves_Formula == 8)
		luma = CatMullRom(luma + 3.0 * luma * luma - 6.0 * luma * luma * luma);
		#endif

		//Add back the chroma
		color = luma + chroma;

		//Blend by Curves_contrast
		colorInput.rgb = mix(colorInput.rgb, color, Curves_contrast_blend);

		return colorInput;
	}
#endif

/*------------------------------------------------------------------------------
                          [LUMA SHARPEN CODE SECTION]
						[Adapted from CeeJay's SweetFX]
	[http://www.guru3d.com/files_details/sweetfx_shader_suite_download.html]
------------------------------------------------------------------------------*/

#if (LUMA_SHARPEN == 1)
	#define CoefLuma vec3(0.2126, 0.7152, 0.0722)
	#define sharp_strength_luma (CoefLuma * Sharp_Strength)
	#define px BUFFER_RCP_WIDTH
	#define py BUFFER_RCP_HEIGHT
	#define screen_size vec2(BUFFER_WIDTH, BUFFER_HEIGHT)
	#define pixel vec2(px,py)
	
	vec4 LumaSharpen(vec4 inputcolor, vec2 tex) 
	{
		vec3 ori = texture(colorSampler, tex).rgb; 

		// -- Pattern 1 -- A 9 tap gaussian using 4+1 texture fetches.
		#if (Pattern == 1)
			vec3 blur_ori = texture(colorSampler, tex + vec2(px,-py) * 0.5 * Offset_Bias).rgb;
			blur_ori += texture(colorSampler, tex + vec2(-px,-py) * 0.5 * Offset_Bias).rgb;   
			blur_ori += texture(colorSampler, tex + vec2(px,py) * 0.5 * Offset_Bias).rgb;
			blur_ori += texture(colorSampler, tex + vec2(-px,py) * 0.5 * Offset_Bias).rgb;

			blur_ori *= 0.25;
		#endif 

		// -- Pattern 2 -- An experimental 17 tap gaussian using 4+1 texture fetches.
		#if (Pattern == 2)
			vec3 blur_ori = texture(colorSampler, tex + vec2(0.4*px,-1.2*py)* Offset_Bias).rgb;
			blur_ori += texture(colorSampler, tex + vec2(-1.2*px,-0.4*py) * Offset_Bias).rgb;
			blur_ori += texture(colorSampler, tex + vec2(1.2*px,0.4*py) * Offset_Bias).rgb;
			blur_ori += texture(colorSampler, tex + vec2(-0.4*px,1.2*py) * Offset_Bias).rgb;
			blur_ori *= 0.25;

			sharp_strength_luma *= 0.51;
		#endif

		// -- Pattern 3 -- A 9 tap high pass (pyramid filter) using 4+1 texture fetches.
		#if (Pattern == 3)
			vec3 blur_ori = texture(colorSampler, tex + vec2(0.5 * px,-py * Offset_Bias)).rgb;
			blur_ori += texture(colorSampler, tex + vec2(Offset_Bias * -px,0.5 * -py)).rgb;
			blur_ori += texture(colorSampler, tex + vec2(Offset_Bias * px,0.5 * py)).rgb;
			blur_ori += texture(colorSampler, tex + vec2(0.5 * -px,py * Offset_Bias)).rgb;	
			blur_ori /= 4.0;

			sharp_strength_luma *= 0.666;
		#endif

		// -- Pattern 4 -- A (slower) 9 tap gaussian using 9 texture fetches.
		#if (Pattern == 4)
			half3 blur_ori = texture(colorSampler, tex + vec2(-px,py) * Offset_Bias).rgb;
			blur_ori += texture(colorSampler, tex + vec2(px,-py) * Offset_Bias).rgb;
			blur_ori += texture(colorSampler, tex + vec2(-px,-py)  * Offset_Bias).rgb;
			blur_ori += texture(colorSampler, tex + vec2(px,py) * Offset_Bias).rgb;

			half3 blur_ori2 = texture(colorSampler, tex + vec2(0,py) * Offset_Bias).rgb;
			blur_ori2 += texture(colorSampler, tex + vec2(0,-py) * Offset_Bias).rgb;
			blur_ori2 += texture(colorSampler, tex + vec2(-px,0) * Offset_Bias).rgb;
			blur_ori2 += texture(colorSampler, tex + vec2(px,0) * Offset_Bias).rgb;
			blur_ori2 *= 2.0;

			blur_ori += blur_ori2;
			blur_ori += (ori * 4);
			blur_ori /= 16.0;
		#endif

		// -- Pattern 5 -- A (slower) 9 tap high pass using 9 texture fetches.
		#if (Pattern == 5)
			vec3 blur_ori = texture(colorSampler, tex + vec2(-px,py) * Offset_Bias).rgb;
			blur_ori += texture(colorSampler, tex + vec2(px,-py) * Offset_Bias).rgb;
			blur_ori += texture(colorSampler, tex + vec2(-px,-py)  * Offset_Bias).rgb;
			blur_ori += texture(colorSampler, tex + vec2(px,py) * Offset_Bias).rgb;

			blur_ori += ori.rgb;

			blur_ori += texture(colorSampler, tex + vec2(0,py) * Offset_Bias).rgb;
			blur_ori += texture(colorSampler, tex + vec2(0,-py) * Offset_Bias).rgb;
			blur_ori += texture(colorSampler, tex + vec2(-px,0) * Offset_Bias).rgb;
			blur_ori += texture(colorSampler, tex + vec2(px,0) * Offset_Bias).rgb;

			blur_ori /= 9;
		#endif

		vec3 sharp = ori - blur_ori;  
		float sharp_luma = dot(sharp, sharp_strength_luma);
		sharp_luma = clamp(sharp_luma, -Sharp_Clamp, Sharp_Clamp);

		vec4 done = inputcolor + sharp_luma; 

		#if Show_Sharpen == 1
		done = clamp(0.5 + (sharp_luma * 4), 0.0, 1.0).rrrr;
		#endif

		return done;
	}
#endif

/*------------------------------------------------------------------------------
                             [DITHER CODE SECTION]
						[Adapted from CeeJay's SweetFX]
    [http://www.guru3d.com/files_details/sweetfx_shader_suite_download.html]
------------------------------------------------------------------------------*/

#if (DITHER_ENABLE == 1)
	vec4 Dither(vec4 colorInput, vec2 tex)
	{
		#define screen_size vec2(1.0/1920, 1.0/1080)
		
		vec4 color = colorInput;
		
		float dither_size = 2.0;
		float dither_bit  = 8.0;
		
		float grid_position = fract(dot(tex,(screen_size / dither_size)) + (0.5 / dither_size));
		float dither_shift = (0.25) * (1.0 / (pow(2,dither_bit) - 1.0));
		
		vec3 dither_shift_RGB = vec3(dither_shift, dither_shift, dither_shift);
  
		color.rgb += mix(2.0 * dither_shift_RGB, -2.0 * dither_shift_RGB, grid_position); 

		return color;
		
	}
#endif

/*------------------------------------------------------------------------------
                           [TOON SHADER CODE SECTION]
------------------------------------------------------------------------------*/

#if (TOON_SHADER == 1)
	vec4 Cartoon(vec4 colorInput, vec2 Tex)
	{	
	
		#define px BUFFER_RCP_WIDTH
		#define py BUFFER_RCP_HEIGHT
		#define pixel vec2(px,py)
		
		vec3 ToonLumaCoef = vec3(0.2126, 0.7152, 0.0722);
		float Tluma = dot(colorInput.rgb, ToonLumaCoef);
		
		float Tmax_color = max(colorInput.r, max(colorInput.g,colorInput.b));
		float Tmin_color = min(colorInput.r, min(colorInput.g,colorInput.b));

		float Tcolor_saturation = Tmax_color - Tmin_color;

		colorInput.rgb = mix(vec3(Tluma), colorInput.rgb, (1.0 + (ToonVibrance * (1.0-(sign(ToonVibrance) * Tcolor_saturation)))));

		float diff1 = dot(ToonLumaCoef, texture(colorSampler, Tex + pixel).rgb);
		diff1 -= dot(ToonLumaCoef, texture(colorSampler, Tex - pixel).rgb);
		float diff2 = dot(ToonLumaCoef, texture(colorSampler, Tex +vec2(pixel.x,-pixel.y)).rgb);
		diff2 -= dot(ToonLumaCoef, texture(colorSampler, Tex +vec2(-pixel.x,pixel.y)).rgb);

		float edge = dot(vec2(diff1, diff2), vec2(diff1, diff2));

		colorInput.rgb = clamp((colorInput.rgb) - edge * Outline_Thickness, 0.0, 1.0);

		return colorInput;
	}
#endif

/*------------------------------------------------------------------------------
                    [SPRITE INTERPOLATION AA CODE SECTION]
------------------------------------------------------------------------------*/

#if (SPRITE_INTERPOLATION == 1)
	vec4 getSpI(vec4 SpriteColor, vec2 txCoord)
	{	
		/*This code is courtesy of guest.r*/
		
		vec3 c11 = texture(colorSampler, gl_TexCoord[0].xy).xyz;
		vec3 s00 = texture(colorSampler, gl_TexCoord[1].xy).xyz; 
		vec3 s20 = texture(colorSampler, gl_TexCoord[2].xy).xyz; 
		vec3 s22 = texture(colorSampler, gl_TexCoord[3].xy).xyz; 
		vec3 s02 = texture(colorSampler, gl_TexCoord[4].xy).xyz; 
		vec3 c00 = texture(colorSampler, gl_TexCoord[5].xy).xyz; 
		vec3 c22 = texture(colorSampler, gl_TexCoord[6].xy).xyz; 
		vec3 c20 = texture(colorSampler, gl_TexCoord[5].zw).xyz;
		vec3 c02 = texture(colorSampler, gl_TexCoord[6].zw).xyz;
		vec3 c10 = texture(colorSampler, gl_TexCoord[1].zw).xyz; 
		vec3 c21 = texture(colorSampler, gl_TexCoord[2].zw).xyz; 
		vec3 c12 = texture(colorSampler, gl_TexCoord[3].zw).xyz; 
		vec3 c01 = texture(colorSampler, gl_TexCoord[4].zw).xyz;     
		vec3 dt = vec3(1.0,1.0,1.0);
	 
		float d1=dot(abs(c00-c22),dt)+0.001;
		float d2=dot(abs(c20-c02),dt)+0.001;
		float hl=dot(abs(c01-c21),dt)+0.001;
		float vl=dot(abs(c10-c12),dt)+0.001;
		float m1=dot(abs(s00-s22),dt)+0.001;
		float m2=dot(abs(s02-s20),dt)+0.001;
	 
		c11 =.5*(m2*(s00+s22)+m1*(s02+s20))/(m1+m2);

		float k1 = max(dot(abs(c00-c11),dt),dot(abs(c22-c11),dt))+0.01;k1=1.0/k1;
		float k2 = max(dot(abs(c20-c11),dt),dot(abs(c02-c11),dt))+0.01;k2=1.0/k2;
		float k3 = max(dot(abs(c01-c11),dt),dot(abs(c21-c11),dt))+0.01;k3=1.0/k3;
		float k4 = max(dot(abs(c01-c11),dt),dot(abs(c12-c11),dt))+0.01;k4=1.0/k4;
	 
		c11 = 0.5*(k1*(c00+c22)+k2*(c20+c02)+k3*(c01+c21)+k4*(c10+c12))/(k1+k2+k3+k4);
	 
		vec3 mn1 = min(min(c00,c01),c02);
		vec3 mn2 = min(min(c10,c11),c12);
		vec3 mn3 = min(min(c20,c21),c22);
		vec3 mx1 = max(max(c00,c01),c02);
		vec3 mx2 = max(max(c10,c11),c12);
		vec3 mx3 = max(max(c20,c21),c22);
	 
		mn1 = min(min(mn1,mn2),mn3);
		mx1 = max(max(mx1,mx2),mx3);
	 
		float filterparam = 10.0; 
	 
		vec3 dif1 = abs(c11-mn1) + 0.001*dt;
		vec3 dif2 = abs(c11-mx1) + 0.001*dt;
	 
		dif1=vec3(pow(dif1.x,filterparam),pow(dif1.y,filterparam),pow(dif1.z,filterparam));
		dif2=vec3(pow(dif2.x,filterparam),pow(dif2.y,filterparam),pow(dif2.z,filterparam));
	 
		c11.r = (dif1.x*mx1.x + dif2.x*mn1.x)/(dif1.x + dif2.x);
		c11.g = (dif1.y*mx1.y + dif2.y*mn1.y)/(dif1.y + dif2.y);
		c11.b = (dif1.z*mx1.z + dif2.z*mn1.z)/(dif1.z + dif2.z);
		
		SpriteColor = vec4(c11, 1.0);
	 
		return SpriteColor;
	} 
#endif

/*------------------------------------------------------------------------------
					[HDR LUMA CORRECTION PASS CODE SECTION]
------------------------------------------------------------------------------*/

#if (HDR_LUMA_PASS == 1)
	vec3 RGB2XYZ(const vec3 RGB)
	{
	  const mat3 mRGB2XYZ = mat3
	  (
		vec3(0.51413640, 0.26506800, 0.02411880),
		vec3(0.32387860, 0.67023428, 0.12281780),
		vec3(0.16036376, 0.06409157, 0.84442666)
	  );
	  vec3 XYZ = mRGB2XYZ * RGB;
	  return(XYZ);
	}
	
	vec3 XYZ2RGB(const vec3 XYZ)
	{
	  const mat3 mXYZ2RGB = mat3
	  (
		vec3( 2.5651, -1.0217,  0.0753),
		vec3(-1.1665,  1.9777, -0.2543),
		vec3(-0.3986,  0.0439,  1.1892)
	  );
	  vec3 RGB = mXYZ2RGB * XYZ;
	  return(RGB);
	}
	
	struct Yxy_t
	{
	  float Y;
	  float x;
	  float y;
	};

	Yxy_t XYZ2Yxy(const vec3 XYZ)
	{
	  Yxy_t Yxy;
	  float W = XYZ.x + XYZ.y + XYZ.z;
	  Yxy.Y = XYZ.y;
	  Yxy.x = XYZ.x / W;
	  Yxy.y = XYZ.y / W;
	  return(Yxy);
	}

	Yxy_t RGB2Yxy(const vec3 RGB)
	{
	  vec3 XYZ = RGB2XYZ(RGB);
	  Yxy_t Yxy = XYZ2Yxy(XYZ);
	  return(Yxy);
	}

	vec3 Yxy2XYZ(const Yxy_t Yxy)
	{
	  vec3 XYZ;
	  XYZ.x = Yxy.Y * (Yxy.x / Yxy.y);
	  XYZ.y = Yxy.Y;
	  XYZ.z = (XYZ.x / Yxy.x) - XYZ.x - XYZ.y;
	  return(XYZ);
	}

	vec3 Yxy2RGB(const Yxy_t Yxy)
	{
	  vec3 XYZ = Yxy2XYZ(Yxy);
	  vec3 RGB = XYZ2RGB(XYZ);
	  return(RGB);
	}

	struct Lab_t
	{
	  float L;
	  float a;
	  float b;
	};

	const vec3 D50 = vec3( 96.4212, 100.0, 82.51880 );
	const vec3 D55 = vec3( 95.6797, 100.0, 92.14810 );
	const vec3 D65 = vec3( 95.0429, 100.0, 108.8900 );
	const vec3 D75 = vec3( 94.9722, 100.0, 122.6394 );

	const float e = 216.0 / 24389.0;
	const float k = 24389.0 / 27.0;
	
	Lab_t XYZ2Lab(const vec3 XYZ)
	{
	  const vec3 W = D65;

	  const vec3 r = XYZ / W;

	  vec3 f;
	  f.x = (r.x > e) ? pow(r.x, 1.0/3.0) : (k*r.x + 16.0)/116.0;
	  f.y = (r.y > e) ? pow(r.y, 1.0/3.0) : (k*r.y + 16.0)/116.0;
	  f.z = (r.z > e) ? pow(r.z, 1.0/3.0) : (k*r.z + 16.0)/116.0;

	  Lab_t Lab;
	  Lab.L = 116.0*f.y - 16.0;
	  Lab.a = 500.0*(f.x - f.y);
	  Lab.b = 200.0*(f.y - f.z);

	  return(Lab);
	}

	vec3 Lab2XYZ(const Lab_t Lab)
	{
	  const vec3 W = D65;

	  vec3 f;
	  f.y = (Lab.L + 16.0) / 116.0;
	  f.x = (Lab.a/500.0) + f.y;
	  f.z = f.y - (Lab.b/200.0);

	  vec3 r;
	  r.x = (pow(f.x, 3.0) > e) ? pow(f.x, 3.0) : (116.0*f.x - 16.0)/k;
	  r.y = (pow(f.y, 3.0) > e) ? pow(f.y, 3.0) : Lab.L / k;
	  r.z = (pow(f.z, 3.0) > e) ? pow(f.z, 3.0) : (116.0*f.z - 16.0)/k;

	  vec3 XYZ;
	  XYZ = r * W;

	  return(XYZ);
	}

	Lab_t RGB2Lab(const vec3 RGB)
	{
	  vec3 XYZ = RGB2XYZ(RGB);
	  Lab_t Lab = XYZ2Lab(XYZ);
	  return(Lab);
	}

	vec3 Lab2RGB(const Lab_t Lab)
	{
	  vec3 XYZ = Lab2XYZ(Lab);
	  vec3 RGB = XYZ2RGB(XYZ);
	  return(RGB);
	}

	Lab_t Yxy2Lab(const Yxy_t Yxy)
	{
	  vec3 XYZ = Yxy2XYZ(Yxy);
	  Lab_t Lab = XYZ2Lab(XYZ);
	  return(Lab);
	}

	Yxy_t Lab2Yxy(const Lab_t Lab)
	{
	  vec3 XYZ = Lab2XYZ(Lab);
	  Yxy_t Yxy = XYZ2Yxy(XYZ);
	  return(Yxy);
	}

	float E(const float I)
	{
	  return( ((70.0)/(1.0 + pow(10.0/I, 0.383))) + 22.0 );
	}

	void ChrominanceAdaption(inout vec3 XYZ, const float lambda)
	{
	  Lab_t Lab = XYZ2Lab(XYZ);
	  float rho = min(E(lambda)/E(10.0), 1.0);
	  if (Lab.a > 0.0)
		Lab.a *= rho;
	  XYZ = Lab2XYZ(Lab);
	}

	float RelativeLuminance(const float lum, const float key, const float logavglum)
	{
	  float rLum = (lum*key) / logavglum;
	  return(rLum);
	}

	float Global(const float lum, const float rLum)
	{
	  float dLum = rLum / (1.0+rLum);
	  return(dLum);
	}
	
	#define vec float
	#define EXT r
	#define sampler sampler2DRect
	#define texFetch texture2DRect

	uniform sampler txSATLum;
	uniform vec2 SATSIZE;

	vec texSATArea(const sampler SAT, vec2 amin, vec2 amax, out vec2 area)
	{
	  amax = min(amax, SATSIZE-vec2(0.5));
	  vec accum = texFetch(SAT, amax).EXT;
	  amin = max(amin, vec2(0.5));
	  amin -= vec2(1);
	  accum -= texFetch(SAT, vec2(amin.x,amax.y)).EXT;
	  accum -= texFetch(SAT, vec2(amax.x,amin.y)).EXT;
	  accum += texFetch(SAT, amin).EXT;
	  area = vec2(amax.x-amin.x, amax.y-amin.y);
	  return(accum);
	}

	vec texSATDiff(const sampler SAT, vec2 center, vec2 diff, out vec2 area)
	{
	  vec2 amin = center-diff;
	  vec2 amax = center+diff;
	  vec sum = texSATArea(SAT, amin, amax, area);
	  return(sum);
	}
	
	float Activity(const float Aa, const float Bb, const float ii, const float kkey, const float pphi)
	{
	  float scale = pow(1.6, ii);
	  float num = (Aa - Bb);
	  float sharp = pow(2.0, pphi)*kkey;
	  float denum = (sharp/(scale*scale))+Aa;
	  float activity = abs(num/denum);
	  return(activity);
	}
	
	float LumScale(const sampler SAT, vec2 coord, const int i)
	{
	  //const int sizes [8] = { 1, 3, 5, 7, 11, 17, 27, 43 };
	  const int radii [8] = int[]( 0, 1, 2, 3, 5, 8, 13, 21 );
	  vec2 area;
	  float lum = texSATDiff(SAT, coord, vec2(radii[i]), area);
	  lum /= (area.x*area.y);
	  return(lum);
	}

	#define SCALES 8
	vec3 MaxScaleLuminance(const sampler SAT, vec2 coord, const float rLum)
	{
	  float lums [8];
	  lums[0] = rLum;

	  float add_back = texture(txRelLumAvgSampler, vec2(0.0)).r;

	  for (int i=SCALES-1; i>0; --i)
		lums[i] = LumScale(SAT, coord, i) + add_back;

	  vec3 lummax = vec3(lums[SCALES-1], SCALES-1, 1.0);
	  for (int i=0; i<SCALES-1; ++i)
	  {
		float activity = Activity(lums[i], lums[i+1], i, key, phi);
		if (activity > threshold)
		{
		  #if (GL_NV_gpu_shader5)
			lummax = vec3(lums[i], i, float(i)/float(SCALES-1)); //intelligent method (works on NVIDIA)
			break;
		  #else
		  if (lummax.x == lums[SCALES-1])
			lummax = vec3(lums[i], i, float(i)/float(SCALES-1)); //Radeon-friendly.
		  #endif
		}
	  }

	  return(lummax);
	}

	float Local(const float lum, const float rLum, const float maxlum)
	{
	  float dLum = rLum / (1.0+maxlum);
	  return(dLum);
	}
	
	vec4 LumCorrectPass(vec4 HDRColor, vec2 Tex)
	{		
		//HDRColor *= pow(Luminance, (1.0/lumaFactor));
		
		Yxy_t Yxy = RGB2Yxy(HDRColor.rgb);
		float rLum = vec3(0.2126, 0.7152, 0.0722);
		float dLum = Yxy.Y;
		vec3 maxLum = vec3(0.0);

		#ifdef DO_TONEMAP
			vec2 avgs = texture(AvgLumSampler, vec2(0.5)).ra;
			float chromaLum = avgs.x;
			rLum = RelativeLuminance(Yxy.Y, key, avgs.y);

		#ifdef DO_GLOBAL
			dLum = Global(Yxy.Y, rLum);
		#endif

		#ifdef DO_LOCAL
			maxLum = MaxScaleLuminance(txSATLum, gl_TexCoord[1].xy, rLum);
			dLum = Local(Yxy.Y, rLum, maxLum.x);

		#ifdef DO_VARYING
			chromaLum = maxLum.x*(avgs.x/key);
		#endif
		#endif

		Yxy.Y = dLum;
		vec3 XYZ = Yxy2XYZ(Yxy);

		#ifdef DO_CHROMINANCE
		  ChrominanceAdaption(XYZ, chromaLum);
		#endif

		HDRColor.rgb + XYZ2RGB(XYZ);
		HDRColor = pow(HDRColor, vec4(1.0/lumaCorrection));
		HDRColor = clamp(HDRColor, 0.001, 1.0);
		#endif

		return HDRColor;
	}
#endif

/*------------------------------------------------------------------------------
                        [HDR BLOOM PASS CODE SECTION]
------------------------------------------------------------------------------*/

#if (HDR_BLOOM_PASS == 1)	
	//Cross Processing
	vec4 bloomGradient(vec4 coo)
	{
		vec4 stripes = coo;
		stripes.r = stripes.r*1.1;
		stripes.g = stripes.g*1.1;
		stripes.b = stripes.b*1.1;
		stripes.a = texcolor.a;
		return stripes;
	}
	
	vec4 BloomPass(vec4 bloomColor, vec2 Tex)
	{	
		#define BUFFER_RCP_WIDTH (1.0 / 2560)
		#define BUFFER_RCP_HEIGHT (1.0 / 1440)
		#define px BUFFER_RCP_WIDTH
		#define py BUFFER_RCP_HEIGHT
		#define pixel vec2(px,py)
		
		vec3 Blurtemp;
		vec3 BlurColor2;
		float CurDistance;
		float MaxDistance = sqrt(8.0*BloomWidth);
		
		float Samplecount = 16.0;
		
		vec2 blurtempvalue = Tex * pixel * BloomWidth;
		
		vec2 BloomSample = vec2(2.5, -2.5);
		vec2 BloomSampleValue;
		
		for(BloomSample.x = (2.5); BloomSample.x > -2.0; BloomSample.x = BloomSample.x - 1.0) // runs 5 times
		{
			BloomSampleValue.x = BloomSample.x * blurtempvalue.x;
			vec2 distancetemp = vec2(BloomSample.x) * vec2(BloomSample.x) * BloomWidth;
			
			for(BloomSample.y = (- 2.5); BloomSample.y < 2.0; BloomSample.y = BloomSample.y + 1.0) // runs 5 ( * 5) times
			{
				distancetemp.y = BloomSample.y * BloomSample.y;
				CurDistance = sqrt( (distancetemp.y * BloomWidth) + distancetemp.x);
				
				BloomSampleValue.y = BloomSample.y * blurtempvalue.y;
				Blurtemp.rgb = texture(BloomSampler, vec2(Tex + BloomSampleValue)).rgb;
				
				BlurColor2.rgb += mix(Blurtemp.rgb,bloomColor.rgb, 1.0 - ((MaxDistance - CurDistance) / MaxDistance)); //convert vec4 to vec3 and check if it's possible to use a MAD
			}
		}
		BlurColor2.rgb = (BlurColor2.rgb / (Samplecount - (BloomStrength - BloomThreshold*5))); //check if using MAD
		float Bloomamount = (dot(bloomColor.rgb,vec3(0.2126, 0.7152, 0.0722))) ;
		vec3 BlurColor = BlurColor2.rgb * (BloomStrength + 4.0); //check if calculated offline and combine with line 24 (the blurcolor2 calculation)

		bloomColor.rgb = mix(bloomColor.rgb, BlurColor.rgb, Bloomamount);	

		return bloomGradient(bloomColor);
	}
#endif

/*------------------------------------------------------------------------------
                        [HDR TONEMAP PASS CODE SECTION]
						[Adapted from CeeJay's SweetFX]
	[http://www.guru3d.com/files_details/sweetfx_shader_suite_download.html]
------------------------------------------------------------------------------*/

#if (HDR_TONEMAP_PASS == 1)
	vec4 ContrastSCurves(vec4 colorInput)
	{
		vec3 color = colorInput.rgb;
		vec3 TonelumCoeff = vec3(0.2126, 0.7152, 0.0722);
		float ToneCurves_contrast = -0.015;
		float ToneCurves_contrast_blend = ToneCurves_contrast;
		float PI = acos(-1);
		float luma = dot(TonelumCoeff, color);
		vec3 chroma = color - luma;

		luma = CatMullRom(luma + 3.0 * luma * luma - 6.0 * luma * luma * luma);

		color = luma + chroma;

		colorInput.rgb = mix(colorInput.rgb, color, ToneCurves_contrast_blend);

		return colorInput;
	}

	vec4 TonemapPass(vec4 tonemapColor)
	{
		vec3 color = tonemapColor.rgb;

		//color = clamp((color - Defog * FogColor), 0.0, 1.0); // Defog
		
		color *= pow(2.0f, Exposure);

		color = pow(color, vec3(Gamma));

		vec3 lumCoeff = vec3(0.2126, 0.7152, 0.0722);
		float lum = dot(lumCoeff, color.rgb);

		vec3 blend = lum.rrr;

		float L = clamp( 10.0 * (lum - 0.45), 0.0, 1.0 );

		vec3 result1 = 2.0f * color.rgb * blend;
		vec3 result2 = 1.0f - 2.0f * (1.0f - blend) * (1.0f - color.rgb);

		vec3 newColor = mix(result1, result2, L);

		vec3 A2 = Bleach * color.rgb;
		vec3 mixRGB = A2 * newColor;

		color.rgb += ((1.0f - A2) * mixRGB);

		vec3 middlegray = vec3(color.r, color.g, color.b) / 3;

		vec3 diffcolor = color - middlegray;
		tonemapColor.rgb = (color + diffcolor * Saturation)/(1.0+(diffcolor*Saturation)); //saturation

		return ContrastSCurves(tonemapColor);
	}
#endif

/*------------------------------------------------------------------------------
						[DYNAMIC VIBRANCE CODE SECTION]
						[Adapted from CeeJay's SweetFX]
	[http://www.guru3d.com/files_details/sweetfx_shader_suite_download.html]
------------------------------------------------------------------------------*/

#if (INTELLI_VIBRANCE == 1)
	vec4 VibrancePass( vec4 vibranceColor )
	{
		vec4 color = vibranceColor; //original input color
		vec3 lumCoeff = vec3(0.2126, 0.7152, 0.0722);  //Values to calculate luma with

		float luma = dot(lumCoeff, color.rgb); //calculate luma (grey)
		
		float max_color = max(vibranceColor.r, max(vibranceColor.g,vibranceColor.b)); //Find the strongest color
		float min_color = min(vibranceColor.r, min(vibranceColor.g,vibranceColor.b)); //Find the weakest color
		
		float color_saturation = max_color - min_color; //The difference between the two is the saturation
	  
		color.rgb = mix(vec3(luma), color.rgb, (1.0 + (Vibrance * (1.0 - (sign(Vibrance) * color_saturation))))); //extrapolate between luma and original by 1 + (1-saturation) - current
	  
		//color.rgb = lerp(luma, color.rgb, 1.0 + (1.0-pow(color_saturation, 1.0 - (1.0-Vibrance))) ); //pow version
	  
		return color; //return the result
	}
#endif

#if (POINT_LIGHT == 1)
	vec4 pointLights(vec4 pointColor)
	{
		pointColor = (gl_FrontLightModelProduct.sceneColor * gl_FrontMaterial.ambient) + 
		(gl_LightSource[0].ambient * gl_FrontMaterial.ambient * att);

								
		vec3 N = normalize(normal);
		vec3 L = normalize(lightDir);

		float lambertTerm = dot(N,L);

		if(lambertTerm > 0.0)
		{
			pointColor += gl_LightSource[0].diffuse * gl_FrontMaterial.diffuse * lambertTerm * att;	
			
			vec3 E = normalize(eyeVec);
			vec3 R = reflect(-L, N);
			float specular = pow( max(dot(R, E), 0.0), gl_FrontMaterial.shininess );
			pointColor += gl_LightSource[0].specular * gl_FrontMaterial.specular * specular * att;	
		}

		return pointColor;
	}
#endif

/*------------------------------------------------------------------------------
                      [MAIN() & COMBINE PASS CODE SECTION]
------------------------------------------------------------------------------*/

void main()
{
	vec4 baseColor;
	vec4 lumFactor = texture(LumaSampler, texcoord, 0.0);

	#if (NFAA_ENABLED == 1)
		baseColor = getNFAA(baseColor, texcoord);
	#else
		baseColor = texture(colorSampler, texcoord);
	#endif
	
	#if (SSAA_ENABLED == 1)
		baseColor = getSSAA(baseColor, texcoord);
	#endif
	
	#if (FXAA_ENABLED == 1)
		baseColor = getFXAA(baseColor, texcoord);
	#endif
	
	#if (SPRITE_INTERPOLATION == 1)
		baseColor = getSpI(baseColor, texcoord);
	#endif
	
	#if (LUMA_SHARPEN == 1)
		baseColor = LumaSharpen(baseColor, texcoord);
	#endif
	
	#if (POINT_LIGHT == 1)
		baseColor += pointLights(baseColor);
	#endif
	
	#if (HDR_LUMA_PASS == 1)
		baseColor = LumCorrectPass(baseColor, texcoord);
	#endif
	
	#if (HDR_BLOOM_PASS == 1)
		baseColor = BloomPass(baseColor, texcoord);
	#endif
	
	#if (HDR_TONEMAP_PASS == 1)
		baseColor = TonemapPass(baseColor);
	#endif
	
	#if (INTELLI_VIBRANCE == 1)
		baseColor = VibrancePass(baseColor);
	#endif
	
	#if (DYNAMIC_CONTRAST == 1)
		baseColor = CurvesPass(baseColor);
	#endif
	
	#if (TOON_SHADER == 1)
		baseColor = Cartoon(baseColor, texcoord);
	#endif
	
	#if (DITHER_ENABLE == 1)
		baseColor = Dither(baseColor, texcoord);
	#endif
	
	float greyPoint = dot(baseColor.rgb, vec3(0.2126, 0.7152, 0.0722));
	
	int rOffset = int(baseColor.r * 1024); 
	lumFactor.r = texelFetchBuffer(lumCurveSampler, rOffset).r;
	
	int gOffset = int(baseColor.g * 1024); 
	lumFactor.g = texelFetchBuffer(lumCurveSampler, gOffset).r;

	int bOffset = int(baseColor.b * 1024); 
	lumFactor.b = texelFetchBuffer(lumCurveSampler, bOffset).r;
		
	lumFactor.a = 1.0f;
	
	lumFactor = clamp(lumFactor, 0.0f, 1.0f);
	baseColor = clamp(baseColor, 0.0f, 1.0f);
	
	gl_FragData[0] = baseColor;
	gl_FragData[1] = vec4(greyPoint, greyPoint, greyPoint, 1.0f);
	gl_FragData[2] = lumFactor;	
}
