<jittershader name="default">
	<description>Default Slab </description>
	<param name="tex0" type="int" default="0" />
	<param name="MVP" type="mat4" state="MODELVIEW_PROJECTION_MATRIX" />
	<param name="textureMatrix0" type="mat4" state="TEXTURE0_MATRIX" />
	<param name="pos" type="vec3" state="POSITION" />
	<param name="uv" type="vec2" state="TEXCOORD" />
	<param name="tonemapping" type="int" default="1" />
	<param name="gamma_correction" type="int" default="1" />
	<param name="dithering" type="int" default="0" />
	<param name="exposure" type="float" default="1." />
	<param name="max_white" type="float" default="3." />
	<param name="color_levels" type="int" default="256" />
	<param name="show_clipped" type="int" default="0" />

	<language name="glsl" version="1.5">
		<bind param="tex0" program="fp" />
		<bind param="MVP" program="vp" />
		<bind param="textureMatrix0" program="vp" />
		<bind param="pos" program="vp" />
		<bind param="uv" program="vp" />
		<bind param="gamma_correction" program="fp" />
		<bind param="tonemapping" program="fp" />
		<bind param="dithering" program="fp" />
		<bind param="exposure" program="fp" />
		<bind param="max_white" program="fp" />
		<bind param="color_levels" program="fp" />
		<bind param="show_clipped" program="fp" />
		<program name="vp" type="vertex"  >
<![CDATA[
	#version 330 core
	
	in vec3 pos;
	in vec2 uv;
	out jit_PerVertex {
		smooth vec2 uv;
		smooth vec2 uvNorm;
	} jit_out;
	uniform mat4 MVP;
	uniform mat4 textureMatrix0;
	
	void main(void) {
		gl_Position = MVP*vec4(pos, 1.);
		jit_out.uv = vec2(textureMatrix0*vec4(uv, 0., 1.));
		jit_out.uvNorm = uv;
	}
]]>
</program>

<program name="fp" type="fragment"  >
<![CDATA[
	#version 330 core
	
	in jit_PerVertex {
		smooth vec2 uv;
		smooth vec2 uvNorm;
	} jit_in;
	layout (location = 0) out vec4 outCol;
	
	uniform sampler2DRect tex0;
	uniform int gamma_correction, tonemapping, dithering, color_levels, show_clipped;
	uniform float exposure, max_white;


//====================TONE-MAPPING====================//
vec3 aces(vec3 x){
	//from: https://knarkowicz.wordpress.com/2016/01/06/aces-filmic-tone-mapping-curve/
	
    float a = 2.51;
    float b = 0.03;
    float c = 2.43;
    float d = 0.59;
    float e = 0.14;
    return clamp((x*(a*x+b))/(x*(c*x+d)+e), vec3(0.), vec3(1.));
}

vec3 reinhard(vec3 v){
    vec3 numerator = v * (1.0f + (v / vec3(max_white * max_white)));
    return numerator / (1.0f + v);
}

vec3 reinhard_jodie(vec3 v){
	// from: https://www.shadertoy.com/view/4dBcD1
    float l = dot(v, vec3(0.2126, 0.7152, 0.0722));
    float max_white_squared = max_white*max_white;
    vec3 tv = v / (1. + v);
    return mix(v / (1. + l), tv, tv);
}

vec3 uncharted2_tonemap_partial(vec3 x){
    float A = 0.15;
    float B = 0.50;
    float C = 0.10;
    float D = 0.20;
    float E = 0.02;
    float F = 0.30;
    return ((x*(A*x+C*B)+D*E)/(x*(A*x+B)+D*F))-E/F;
}

vec3 uncharted2(vec3 v){
	//from: https://64.github.io/tonemapping/
    float exposure_bias = 2.0;
    vec3 curr = uncharted2_tonemap_partial(v * exposure_bias);

    vec3 W = vec3(11.2);
    vec3 white_scale = vec3(1.0) / uncharted2_tonemap_partial(W);
    return curr * white_scale;
}

//====================GAMMA-CORRECTION====================//
vec3 lin2sRGB(vec3 x){
	return pow(x, vec3(0.454545454545));
}
vec3 lin2sRGB_exact(vec3 x){
	//accurate gamma correction taken from:
	//http://renderwonk.com/blog/index.php/archive/adventures-with-gamma-correct-rendering/
 	return vec3( 	x.x <= 0.00031308 ? x.x*12.92 : pow(x.x*1.055, 0.416666666666) - 0.055,
 					x.y <= 0.00031308 ? x.y*12.92 : pow(x.y*1.055, 0.416666666666) - 0.055,
 					x.z <= 0.00031308 ? x.z*12.92 : pow(x.z*1.055, 0.416666666666) - 0.055
 				);
}


//====================DITHERING====================//
float uniformNoise(vec2 n){
    // uniformly distribued, normalized in [0..1[
    return fract(sin(dot(n, vec2(12.9898, 78.233))) * 43758.5453);
}

float interleavedGradientNoise(vec2 n) {
    float f = 0.06711056 * n.x + 0.00583715 * n.y;
    return fract(52.9829189 * fract(f));
}

float triangleNoise(vec2 n) {
    // triangle noise, in [-0.5..1.5[ range
    vec2 p = fract(n * vec2(5.3987, 5.4421));
    p += dot(p.yx, p.xy + vec2(21.5351, 14.3137));

    float xy = p.x * p.y;
    // compute in [0..2[ and remap to [-1.0..1.0[
    float noise = (fract(xy * 95.4307) + fract(xy * 75.04961) - 1.0);
	return noise;
}

float triangleRemap(float n) {
    float origin = n * 2.0 - 1.0;
    float v = origin / sqrt(abs(origin));
    v = max(-1.0, v);
    v -= sign(origin);
    return v;
}

vec3 triangleRemap(vec3 n) {
    return vec3(
        triangleRemap(n.x),
        triangleRemap(n.y),
        triangleRemap(n.z)
    );
}

vec3 Dither_Uniform(vec3 col) {
    float noise = uniformNoise(jit_in.uvNorm);
    noise = noise - 0.5;
    return col + noise / (color_levels - 1.0);
}

vec3 Dither_Interleaved(vec3 col) {
    // Jimenez 2014, "Next Generation Post-Processing in Call of Duty"
    float noise = interleavedGradientNoise(jit_in.uv);
    noise = noise - 0.5;
    return col + noise / (color_levels - 1.0);
}

vec3 Dither_Vlachos(vec3 col) {
    // Vlachos 2016, "Advanced VR Rendering"
    vec3 noise = vec3(dot(vec2(171.0, 231.0), jit_in.uv));
    noise = fract(noise / vec3(103.0, 71.0, 97.0));
    noise = noise - 0.5;
    return col.rgb + (noise / (color_levels - 1.0));
}

vec3 Dither_Vlachos_TrianglePDF(vec3 col) {
    // Vlachos 2016, "Advanced VR Rendering"
    vec3 noise = vec3(dot(vec2(171.0, 231.0), jit_in.uv));
    noise = fract(noise / vec3(103.0, 71.0, 97.0));
    noise = triangleRemap(noise);
    return col + (noise / (color_levels - 1.0));
}

vec3 Dither_TriangleNoise(vec3 col) {
    // Gjøl 2016, "Banding in Games: A Noisy Rant"
    vec3 noise = vec3(
        triangleNoise(jit_in.uvNorm         ) / (color_levels - 1.0),
        triangleNoise(jit_in.uvNorm + 0.1337) / (color_levels - 1.0),
        triangleNoise(jit_in.uvNorm + 0.3141) / (color_levels - 1.0)
    );
    return col.rgb + noise;
}

void main(void) {

 	vec3 	col = 	texture(tex0, jit_in.uv).rgb;

			col *= 	exposure;
			col = 	tonemapping == 1 ? 	reinhard(col) 		: col;
			col = 	tonemapping == 2 ? 	reinhard_jodie(col) : col;
			col = 	tonemapping == 3 ? 	aces(col) 			: col;
			col =  	tonemapping == 4 ?  uncharted2(col) 	: col;

			col =  	gamma_correction == 1 ? lin2sRGB(col) 		: col;
			col =  	gamma_correction == 2 ? lin2sRGB_exact(col) : col;


			col =  	dithering == 1 ? Dither_Uniform(col) 				: col;
			col =  	dithering == 2 ? Dither_Interleaved(col) 			: col;
			col =  	dithering == 3 ? Dither_Vlachos(col) 				: col;
			col =  	dithering == 4 ? Dither_Vlachos_TrianglePDF(col) 	: col;
			col =  	dithering == 5 ? Dither_TriangleNoise(col) 			: col;
			col = 	floor(col * color_levels + vec3(0.5)) / color_levels;

			col = 	show_clipped == 1 ? 
							(col.r >= 1. || col.g >= 1. || col.b >= 1.) ? vec3(1., 0., 0.) : col
					: col;

			outCol = vec4(col, 1.);


}
]]>
		</program>
	</language>
</jittershader>
