#version 330 core

in vec2 UV;
in vec2 ray;
uniform sampler2D currentScene;
uniform sampler2D previousFrame;
uniform sampler2D depthMap;
uniform float fba;
uniform float time;
uniform bool renderTime;
uniform int type;

uniform float wet;
uniform float dry;
uniform float zoom;
uniform float na;
uniform float nf;
uniform float macroSize;
uniform float smudgeamount;
uniform float smudgestep;
uniform float blender;

uniform float w;
uniform float h;

const float ar = 1.77777778;

vec2 co(vec2 uv)
{
	// return sampler-compatible uv coords
    //uv.y = -uv.y; // Remove this if image is upside down (tends to happen with video)
	return 0.5+uv*0.5;
}

mat2 rot2d(float angle){
	return mat2(cos( angle ), -sin( angle ), 
			    sin( angle ),  cos( angle ));
}
vec3 mod289(vec3 x) {
  return x - floor(x * (1.0 / 289.0)) * 289.0;
}
vec2 mod289(vec2 x) {
  return x - floor(x * (1.0 / 289.0)) * 289.0;
}
vec3 permute(vec3 x) {
  return mod289(((x*34.0)+1.0)*x);
}
float snoise(vec2 v){
  const vec4 C = vec4(0.211324865405187,  // (3.0-sqrt(3.0))/6.0
                      0.366025403784439,  // 0.5*(sqrt(3.0)-1.0)
                     -0.577350269189626,  // -1.0 + 2.0 * C.x
                      0.024390243902439); // 1.0 / 41.0
  vec2 i  = floor(v + dot(v, C.yy) );
  vec2 x0 = v -   i + dot(i, C.xx);
  vec2 i1;
  i1 = (x0.x > x0.y) ? vec2(1.0, 0.0) : vec2(0.0, 1.0);
  vec4 x12 = x0.xyxy + C.xxzz;
  x12.xy -= i1;
  i = mod289(i); // Avoid truncation effects in permutation
  vec3 p = permute( permute( i.y + vec3(0.0, i1.y, 1.0 )) + i.x + vec3(0.0, i1.x, 1.0 ));
  vec3 m = max(0.5 - vec3(dot(x0,x0), dot(x12.xy,x12.xy), dot(x12.zw,x12.zw)), 0.0);
  m = m*m ;
  m = m*m ;
  vec3 x = 2.0 * fract(p * C.www) - 1.0;
  vec3 h = abs(x) - 0.5;
  vec3 ox = floor(x + 0.5);
  vec3 a0 = x - ox;
  m *= 1.79284291400159 - 0.85373472095314 * ( a0*a0 + h*h );
  vec3 g;
  g.x  = a0.x  * x0.x  + h.x  * x0.y;
  g.yz = a0.yz * x12.xz + h.yz * x12.yw;
  return 130.0 * dot(m, g);
}

float lumadiff(sampler2D frame,  vec2 uv)
{
	//vec2 uv = UV;
    vec4 sc = texture(frame, uv);
    uv.x -= 0.001*smudgestep;
    vec4 sp = texture(frame, uv);
 	return (sc.x+sc.y+sc.z)/3.0-(sp.x+sp.y+sp.z)/3.0;
}

vec2 transform(vec2 uv) {
	//float rotation = 0.003*sin(0.1666*time)-0.00125*cos(0.28*time);
	//return co(rot2d(rotation)*0.99*uv);
	//uv *= rot2d(rotation); // 0.0075 for video
	return uv-0.002*vec2( snoise(vec2(uv.x*ar*4.0, 0.29*time)), snoise(vec2(uv.y*4.0, -0.41*time)));
}

vec2 transform2(vec2  uv) {
	float rotation = 0.003*sin(0.1666*time)-0.00125*cos(0.28*time);
	//return co(rot2d(rotation)*0.99*uv);
	uv *= rot2d(rotation);
	return uv-0.004*vec2( snoise(vec2(uv.x*64.0*macroSize, 3.59*time)), ar*snoise(vec2(uv.y*64.0*macroSize, -2.71*time)));
}

vec2 transform3(vec2 uv) {
	float rotation = 0.003*sin(0.1666*time)-0.00125*cos(0.28*time);
	//return co(rot2d(rotation)*0.99*uv);
	uv *= rot2d(rotation); // 0.0075 for video
	return uv-0.003*vec2( snoise(vec2(uv.x*ar*4.0, 0.29*time)), snoise(vec2(uv.y*4.0, -0.41*time)));
}

vec4 sharpen(sampler2D frame, vec2 coords){
	float kernel[9];
	vec2 offset[9];

	float step_w = 1.0/w;
	float step_h = 1.0/h;

	offset[0] = vec2(-step_w, -step_h);
    offset[1] = vec2(0.0, -step_h);
	offset[2] = vec2(step_w, -step_h);
	offset[3] = vec2(-step_w, 0.0);
	offset[4] = vec2(0.0, 0.0);
	offset[5] = vec2(step_w, 0.0);
	offset[6] = vec2(-step_w, step_h);
	offset[7] = vec2(0.0, step_h);
	offset[8] = vec2(step_w, step_h);

	kernel[0] = 0.;
	kernel[1] = -1.;
	kernel[2] = 0.;
	kernel[3] = -1.;
	kernel[4] = 5.;
	kernel[5] = -1.;
	kernel[6] = 0.;
	kernel[7] = -1.;
	kernel[8] = 0.;

	vec4 sum = vec4(0.0);
    for (int i = 0; i < 9; i++) {
        vec4 color = texture(frame, transform2(coords)+offset[i]);
        sum += color * kernel[i];
    }

    return sum;
}

vec4 gauss(sampler2D tex, vec2 uv, vec2 pOff){
    vec4 cout = vec4(0.0);
    const int stepCount = 2;
    const float weights[stepCount] = float[stepCount](
    	0.44908,
    	0.05092
    );
    const float offsets[stepCount] = float[stepCount](
    	0.53805,
    	2.06278
    );

    uv = transform(uv);

    for(int i = 0; i < stepCount; i++) {
    	vec2 tOff = offsets[i] * pOff;
    	vec4 col = texture( tex, uv + tOff) + texture( tex, uv - tOff) - na*snoise(nf*uv+vec2(620.0*time));
    	cout += weights[i] * col;
    }

    return cout;
}

vec4 blurtest() {
	vec4 color = vec4(0.0);
	color = wet*gauss(previousFrame, co(zoom*ray), vec2(1.0/w, 1.0/h));
	return color;
}

vec4 fakevideo() {
	vec4 color = vec4(0.0);
	//if(renderTime) {
		color = (0.8+0.2*(1.0-fba))*texture(currentScene, UV) + fba*0.2*texture(previousFrame, transform(UV)) + fba*0.4*sharpen(previousFrame, UV);
	//} else {
	//	color = texture(previousFrame, UV);
	//}
	// This balances the luminance differences when boosting the amount of feedback
	return color*(1.1 - 0.333*smoothstep(0.0, 1.0, fba) + 0.333*smoothstep(0.0, -1.0, fba));
}

vec4 smudge() {
	vec4 color = vec4(0.0);
	if(renderTime) {
		vec2 uv = co(transform3(zoom*ray));
 		float d = lumadiff(previousFrame, uv);
 		color = 0.5*texture(currentScene, UV)+fba*texture(previousFrame, uv+smudgeamount*d);
	} else {
		color = texture(previousFrame, UV);
	}
	
    /*float shift = 0.05*sin(5.0*time);
    float shaft = 0.05*cos(4.31*time);
    uv.x += d*shift;
    uv.y -= d*shaft;*/
    
    // radial coordinates: uv-length(smudgeamount*d)*(ray/3.0) (or something...)
    return color;//*(1.2 - 0.7*smoothstep(0.0, 1.3, fba) + 0.0*smoothstep(0.0, -1.0, fba));
}

out vec4 color;
void main() {
	// video-artifact fakes
	if     (type == 1){
		color = fakevideo();
	}
	// noisy particle-like cloud
	else if(type == 2){ // 2
		color = mix(texture(currentScene, UV), blurtest() + dry*gauss(currentScene, UV, vec2(1.0/w, 1.0/h)), blender);
	}
	// analoggish edge patterns
	else if(type == 3){ // 3
		color = smudge();
	}
	// default, no feedback
	else {
		color = texture(currentScene, UV);
	}
}
