uniform sampler2D tex;

uniform float KEY;
const float FUDGE = 0.001;
uniform float L_WHITE;
//const float L_WHITE_SQUARED = L_WHITE * L_WHITE;
const float PI = 3.14159265358979323846264;
const float RECOVERY_SATURATION = 1.0;
const float gamma = 2.2;

uniform float luminance;
uniform float averageLuminance;
/*
vec3 pow(vec3 color, float power)
{
	color.r = pow(color.r, power);
	color.g = pow(color.g, power);
	color.b = pow(color.b, power);

	return color; 
}

vec4 pow(vec4 color, float power)
{
	color.r = pow(color.r, power);
	color.g = pow(color.g, power);
	color.b = pow(color.b, power);
	color.a = pow(color.a, power);

	return color; 
}
*/

// from: http://www.koders.com/noncode/fidB134383CDA66ACFDDE1E2BB70579CB362DC28D24.aspx
vec3 reinhardTonemap(in vec3 inColour, in float averageLuminance)
{
	// From Reinhard et al
	// "Photographic Tone Reproduction for Digital Images"
	//compute luminance of current color (http://www.cs.bris.ac.uk/~reinhard/papers/jgt_reinhard.pdf)
	float worldLuminance = 0.27 * inColour.r + 0.67 * inColour.g + 0.06 * inColour.b;
	// Initial luminence scaling (equation 2)
	float scaledLuminance = KEY / averageLuminance  * worldLuminance;
	
	//bring ALL luminance into displayable range (equation 3)...
	// float displayLuminance = scaledLuminance / (1 + scaledLuminance);
	
	// ...or allow some burning or white out. controlled by L_WHITE (equation 4 nom)
	float displayLuminance = scaledLuminance * (1.0 + scaledLuminance / (L_WHITE*L_WHITE));
	// Final mapping (equation 4 denom)
	displayLuminance /= (1.0 + scaledLuminance);
	
	//recover RGB values (http://www.cs.virginia.edu/~gfx/pubs/tonemapGPU/itm.pdf)
	inColour.r = pow((inColour.r/worldLuminance),RECOVERY_SATURATION) * displayLuminance;
	inColour.g = pow((inColour.g/worldLuminance),RECOVERY_SATURATION) * displayLuminance;
	inColour.b = pow((inColour.b/worldLuminance),RECOVERY_SATURATION) * displayLuminance;
	
	return inColour;
}

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

	//make sure we don't have any 0s ('singularities at black')
	color.rgb += 0.001;	

	color = pow(color, vec4(2.2));
	
	color.rgb *= luminance;
//	color.r *=1.5;
//	color.b *= 0.7;
	color.rgb = reinhardTonemap(color.rgb, averageLuminance);

	color = pow(color, vec4(1.0/2.2));

	gl_FragColor = color;
}
