uniform sampler2D tex;
//uniform sampler2D colorTempTex;

uniform float colorTemperature;

uniform vec4 u_blendcolor;
varying vec2 v_texcoord;

uniform float filmicTMShoulderStrength;
uniform float filmicTMLinearStrength ;
uniform float filmicTMLinearAngle;
uniform float filmicTMToeStrength;
uniform float filmicTMToeNumerator;
uniform float filmicTMToeDenominator;
uniform float filmicTMLinearWhitePoint;
uniform float tonemap;

const float screenGamma = 2.2;

uniform float exposure;
uniform float offset;
uniform float gamma;

uniform float userExposure;
uniform float userOffset;
uniform float userGamma;

uniform float saturation;
uniform float ligthness;
uniform float hue;
uniform float applyHSL;

uniform float luminanceY;
uniform float chromaBlue;
uniform float chromaRed;
uniform float saturationYCbCr;

uniform vec3 shiftColor;

uniform float noiseFactor;
uniform float noiseStrength;
uniform float time;

uniform float gammaCorrect;

//mat3 toYCbCrCoeff = mat3(	65.481, -37.797 , 112.0, 
//						128.553, -74.203, -93.786,
//						24.966, 112.0, -18.214 );

mat3 toYCbCrCoeff = mat3(	65.481, 128.553 , 24.966, 
						-37.797, -74.203, 112.0,
						112.0, -93.786, -18.214 );

//mat3 fromYCbCrCoeff = mat3(	0.00456621, 0.00456621 , 0.00456621, 
//							0.0, -0.00153632, 0.00791071,
//							0.00625893, -0.00318811, 0.0 );

mat3 fromYCbCrCoeff = mat3(		0.00456621, 0.0 , 0.00625893, 
							0.00456621, -0.00153632, -0.00318811,
							0.00456621, 0.00791071, 0.0 );

vec3 YCbCrOffset = vec3(16, 128, 128);

/*
** Hue, saturation, luminance
* code taken from http://mouaif.wordpress.com/2009/01/05/photoshop-math-with-glsl-shaders/
*/
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;
}

/* 
taken from http://www.poynton.com/PDFs/ColorFAQ.pdf
*/
vec3 RGBToYCbCr(vec3 rgb)
{
	vec3 ycbcr = YCbCrOffset + toYCbCrCoeff*rgb;

	ycbcr = clamp(ycbcr, vec3(1), vec3(254));

	return ycbcr;
}

vec3 YCbCrToRGB(vec3 ycbcr)
{
	return fromYCbCrCoeff*(ycbcr-YCbCrOffset);
}

float filmicTonemap(float x)
{
	//from http://filmicgames.com/Downloads/GDC_2010/Uncharted2-Hdr-Lighting.pptx
	float mappedX = ((x*(filmicTMShoulderStrength*x+filmicTMLinearAngle*filmicTMLinearStrength)+filmicTMToeStrength*filmicTMToeNumerator));
	mappedX /= (x*(filmicTMShoulderStrength*x+filmicTMLinearStrength)+filmicTMToeStrength*filmicTMToeDenominator);
	mappedX -= filmicTMToeNumerator/filmicTMToeDenominator;
	
	return mappedX;
}

vec3 filmicTonemap(vec3 x)
{
	vec3 mappedColor = x;
	mappedColor.r = filmicTonemap(mappedColor.r);
	mappedColor.g = filmicTonemap(mappedColor.g);
	mappedColor.b = filmicTonemap(mappedColor.b);
	
	return mappedColor;
}

float rand(vec2 co){
    return fract(sin(dot(co.xy ,vec2(1.29898,.78233))) * 43758.5453);
}

void main()
{
	vec4 color = texture2D(tex, v_texcoord);// * u_blendcolor;
	// vec4 color = texture2D(tex, gl_TexCoord[0].xy);

	color.rgb += 0.001;	
	
	color = mix(color, pow(color, vec4(screenGamma)), gammaCorrect);
	
	//Hue, Saturation, Lightness
	if(applyHSL > 0.0 && (saturation != 1.0 || ligthness != 1.0))
	{
		vec3 hsl = RGBToHSL(color.rgb);
	//	hsl.r *= radians(hue);
		hsl.g *= saturation;
		hsl.b *= ligthness;
		color.rgb = mix(color.rgb, HSLToRGB(hsl), applyHSL);
	}

	//saturation and ligthness via YCbCr
	// vec3 ycbcr = RGBToYCbCr(color.rgb);
	// ycbcr.r *= luminanceY;
	// ycbcr.g *= chromaBlue;
	// ycbcr.b *= chromaRed;
	// ycbcr.g *= saturationYCbCr;
	// ycbcr.b *= saturationYCbCr;
	// ycbcr = clamp(ycbcr, vec3(1), vec3(254));
	// color.rgb = YCbCrToRGB(ycbcr);

	//Exposure, Offset and Gamma 
	color.rgb = pow((color.rgb * exposure) + offset, vec3(1.0/gamma));
	color.rgb = pow((color.rgb * userExposure) + userOffset, vec3(1.0/userGamma));

	color.rgb *= shiftColor.rgb;

	color.rgb = mix(color.rgb, filmicTonemap(color.rgb)/filmicTonemap(filmicTMLinearWhitePoint), tonemap);

	color.rgb += color.rgb * rand(v_texcoord.xy*time) * noiseFactor * noiseStrength;
	// color.rgb += color.rgb * rand(gl_TexCoord[0].xy*time) * noiseFactor * noiseStrength;
	
	color.rgb = mix(color.rgb, pow(color.rgb, vec3(1.0/screenGamma)), gammaCorrect);	

	//fxaa needs luma in alpha
	color.a = sqrt(dot(color.rgb, vec3(0.299, 0.587, 0.114))); // compute luma

	gl_FragColor = color;
}
