#version 330

in vec2 UV;

out vec3 color;

uniform sampler2D tex;
uniform sampler2D texAlbedo;
uniform sampler2D tex3D;
uniform sampler2D texReproj;
uniform sampler2D prevTex;
//uniform sampler2D velTex;
//uniform sampler2D varTex;
uniform vec2 res;
uniform float time;
uniform int showAlbedo;
uniform float leaveProb;
uniform int rejectNow;

uniform float avgLuminance;
uniform float whitePoint;
uniform float keyValue;

const float texCoeff = 0.05;
const float valOff = 3.0/256;
const float extraOff = 0.0/256;

float rand(vec2 co, float he){
    return fract((dot(co.xy*he ,vec2(12.9898,78.233))) * 43758.5453);
}

vec3 rgbC = vec3(0.2989, 0.5870, 0.1140);

// Reinhard's tone mapping.
// https://www.cs.utah.edu/~reinhard/cdrom/tonemap.pdf
// https://www.gamedev.net/topic/407348-reinhards-tone-mapping-operator/
vec3 ToneMapReinhard(in vec3 color)
{
	// RGB -> XYZ conversion
	//const mat3 RGB2XYZ = mat3(0.5141364, 0.3238786,  0.16036376,
	//						  0.265068,  0.67023428, 0.06409157,
	//						  0.0241188, 0.1228178,  0.84442666); 
	const mat3 RGB2XYZ = mat3(0.5141364,  0.265068,   0.0241188,
							  0.3238786,  0.67023428, 0.1228178,
							  0.16036376, 0.06409157, 0.84442666); 
	vec3 XYZ = RGB2XYZ * color;

	// XYZ -> Yxy conversion
	vec3 Yxy;
	Yxy.r = XYZ.g;                            // copy luminance Y
	Yxy.g = XYZ.r / (XYZ.r + XYZ.g + XYZ.b); // x = X / (X + Y + Z)
	Yxy.b = XYZ.g / (XYZ.r + XYZ.g + XYZ.b); // y = Y / (X + Y + Z)

	// (Lp) Map average luminance to the middlegrey zone by scaling pixel luminance
	float Lp = Yxy.r * keyValue / avgLuminance;                       
	// (Ld) Scale all luminance within a displayable range of 0 to 1
	Yxy.r = (Lp * (1.0f + Lp/(whitePoint * whitePoint)))/(1.0f + Lp);

	// Yxy -> XYZ conversion
	XYZ.r = Yxy.r * Yxy.g / Yxy. b;               // X = Y * x / y
	XYZ.g = Yxy.r;                                // copy luminance Y
	XYZ.b = Yxy.r * (1 - Yxy.g - Yxy.b) / Yxy.b;  // Z = Y * (1-x-y) / y

	// XYZ -> RGB conversion
	//const mat3 XYZ2RGB  = mat3(2.5651,-1.1665,-0.3986,
	//						  -1.0217, 1.9777, 0.0439, 
	//						   0.0753, -0.2543, 1.1892);
	const mat3 XYZ2RGB  = mat3(2.5651, -1.0217,  0.0753, 
							  -1.1665,  1.9777, -0.2543,
							  -0.3986,  0.0439,  1.1892);
	color = XYZ2RGB * XYZ;
	return color;
}

void main(){
	vec2 pixel = 1/res;
	vec3 nowTexM = texture( tex, UV ).rgb;
	vec3 texAlbedoSample = texture( texAlbedo, UV ).rgb;

	if (showAlbedo != 0)
		nowTexM *= texAlbedoSample;
	nowTexM = ToneMapReinhard(nowTexM);

	//return;

	//vec3 nowTexNW = texture( tex, UV + vec2(-pixel.x,-pixel.y) ).rgb;
	//vec3 nowTexNE = texture( tex, UV + vec2(pixel.x,-pixel.y) ).rgb;
	//vec3 nowTexSE = texture( tex, UV + vec2(pixel.x,pixel.y) ).rgb;
	//vec3 nowTexSW = texture( tex, UV + vec2(-pixel.x,pixel.y) ).rgb;

	vec3 nowTexN = texture( tex, UV + vec2(0,-pixel.y) ).rgb;
	vec3 nowTexS = texture( tex, UV + vec2(0,pixel.y) ).rgb;
	vec3 nowTexE = texture( tex, UV + vec2(pixel.x,0) ).rgb;
	vec3 nowTexW = texture( tex, UV + vec2(-pixel.x,0) ).rgb;

	//TODO?: lot of samples, another pass?
	if (showAlbedo != 0) {
		nowTexN *= texture( texAlbedo, UV + vec2(0,-pixel.y) ).rgb;
		nowTexS *= texture( texAlbedo, UV + vec2(0,pixel.y) ).rgb;
		nowTexE *= texture( texAlbedo, UV + vec2(pixel.x,0) ).rgb;
		nowTexW *= texture( texAlbedo, UV + vec2(-pixel.x,0) ).rgb;
	}
	nowTexN = ToneMapReinhard(nowTexN);
	nowTexS = ToneMapReinhard(nowTexS);
	nowTexE = ToneMapReinhard(nowTexE);
	nowTexW = ToneMapReinhard(nowTexW);

	//vec3 velTex = texture( velTex, UV ).rgb;
	//vec2 velocity = vec2(0);//velTex.rg;
	vec2 velocity = vec2(texture(tex3D, UV ).a,texture(texReproj, UV ).a)*res;
	velocity = UV;

	vec3 prevTexx = texture( prevTex, 0*UV + velocity).rgb;
	//vec3 prevTexx2 = texture( prevTex, UV ).rgb;

	//vec3 minRange = min(min(nowTexNW,nowTexNE),min(nowTexSE,nowTexSW)) - valOff;
	//vec3 maxRange = max(max(nowTexNW,nowTexNE),max(nowTexSE,nowTexSW)) + valOff;

	//float reject = min(1,texture( varTex, UV ).a*2);
	//if (isnan(reject))
	//	reject = 1;

	float valOffN = 0*valOff;//(1-leaveProb)*valOff + (1-reject)*extraOff;
	vec3 minRange = min(min(nowTexN,nowTexS),min(nowTexE,nowTexW)) - valOffN;
	vec3 maxRange = max(max(nowTexN,nowTexS),max(nowTexE,nowTexW)) + valOffN;

	//minRange = min(minRange,min(min(nowTexNW,nowTexNE),min(nowTexSE,nowTexSW))) - valOff;
	//maxRange = max(maxRange,max(max(nowTexNW,nowTexNE),max(nowTexSE,nowTexSW))) + valOff;

	prevTexx = clamp(prevTexx,minRange,maxRange);

	float texCoeff2 = texCoeff;
	if (rejectNow == 1)
		texCoeff2 = 1;

	color = texCoeff2*nowTexM + (1-texCoeff2)*prevTexx;

	vec3 noisePlus = vec3(rand(UV,time),rand(UV,time*3),rand(UV,time*7))*2-1;
	color += noisePlus*0.001;

	//color = 2*color*texAlbedo;

	//color = vec3(nowTexM.r,prevTexx.r,prevTexx2.r);
}