#version 330 core

// inputz
in vec2 UV;
in vec2 ray;
uniform vec2 res;
uniform sampler2D inputtex;
uniform sampler2D overlay;
uniform sampler2D overlaygfx;
uniform float stetson;
uniform float brightness;
uniform float hueshift;
uniform float saturation;
uniform float iTime;
uniform float overlayVisibility;

const float PI = 3.141;

// outputz
out vec4 color;

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);
  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 rand(vec2 co) {
  return fract(sin(dot(co.xy ,vec2(12.9898,78.233))) * 43758.5453);
}

float hash(float f) {
  return fract(sin(f * 11.1753) * 192652.37862);
}

float noise(vec3 x) {
    vec3 p = floor(x);
    vec3 f = fract(x);
    f       = f*f*(3.0-2.0*f);
    float n = p.x + p.y*57.0 + 113.0*p.z;
    return mix(mix(mix( hash(n+0.0),   hash(n+1.0),  f.x),
                   mix( hash(n+57.0),  hash(n+58.0), f.x),f.y),
               mix(mix( hash(n+113.0), hash(n+114.0),f.x),
                   mix( hash(n+170.0), hash(n+171.0),f.x),f.y),f.z);
}

// for the lulz
float letterbox() {
	float w = res.x / res.y;
	float h = 1.0;

	float y = w / 2.39;
	float b = (h - y) / 2.0;

	return 1.0 - float((UV.y < b) || (UV.y > 1.0 - b));
}

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.49;
}

vec4 spacepochdist() {
  vec2 uv = 1.0 - 2.0 * UV;
  vec4 c = vec4(0.0);
  
  const int N = 12;
  float f = 1.0/float(N);
  for(int i = 0; i < N; ++i)
  {
    // sample texture
    c.x += f*texture(inputtex, co(0.991*uv) ).x;
    c.y += f*texture(inputtex, co(1.000*uv) ).y;
    c.z += f*texture(inputtex, co(1.011*uv) ).z;

    // distort radially
    uv /= 1.0 + ( f*(0.03+0.0005*sin(iTime*12.0)*rand(uv) ) );
  }
  // vignette and flicker
  float v  = 1.5 / pow(1.0 + 0.05*dot(uv, uv), 5.0); 
  float tv = 0.99+0.015*sin(60.0*iTime);
  return vec4( tv*c*v-0.1 );
}

vec4 hsvadjust(vec4 c) {
  float alpha = c.a;
  c *= brightness;

  vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);
  vec4 p = mix(vec4(c.bg, K.wz), vec4(c.gb, K.xy), step(c.b, c.g));
  vec4 q = mix(vec4(p.xyw, c.r), vec4(c.r, p.yzx), step(p.x, c.r));
  float d = q.x - min(q.w, q.y);
  float e = 1.0e-10;
  vec3 hsv = vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x);

  hsv.x *= hueshift;
  hsv.y *= saturation;

  K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);
  vec3 pp = abs(fract(hsv.xxx + K.xyz) * 6.0 - K.www);
  return vec4(hsv.z * mix(K.xxx, clamp(pp - K.xxx, 0.0, 1.0), hsv.y), alpha);
}

void main() {
	float row = res.y * UV.y;
    float hiha = 1.0;
    if (stetson > 0.5) {
        hiha = stetson * texture(overlay, UV).r;
    } else if (stetson < -0.5) {
        hiha = 1.0 + stetson * texture(overlay, UV).r;
    }
    // chromatic lens shit
    color =  vec4(spacepochdist() + 0.0001*vec4(hiha*texture(inputtex, UV).rgb, 1.0)); //vec3(mod(row,2.0)*0.1),1.0)
    // ...
    color  = hsvadjust(color);
    color = clamp(color, 0.0, 2.0);
    color += overlayVisibility * texture(overlaygfx, UV);
    // mild scanlines
    color *= 0.9+0.1*sin(UV.y*res.y*PI*0.5+PI/3.0);
    // thermal noise
    color += vec4( 0.015*vec3(rand(UV * vec2(iTime) )), 1.0 );
    // film grain
    color += vec4( 0.06*vec3(snoise(UV*400.0 + vec2(iTime*1000.0) )), 1.0 );
    // duh...
    color.xyz *= letterbox();
}
