#version 430

layout(location = 0) out vec4 frag;
// layout(location = 1) out vec4 frag2;


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


// from pouet raymarching thread by las of mercury
float perlin(vec3 p) {
    vec3 i = floor(p);
    vec4 a = dot(i, vec3(1., 57., 21.)) + vec4(0., 57., 21., 78.);
    vec3 f = cos((p-i)*3.14159265)*(-.5)+.5;
    a = mix(sin(cos(a)*a),sin(cos(1.+a)*(1.+a)), f.x);
    a.xy = mix(a.xz, a.yw, f.y);
    return mix(a.x, a.y, f.z);
}

float turb(vec3 c) {
        float r=0.0;
        float s=0.5;
        c*=1.0;
        for (int i=0;i<6;i++) {
                //if (i<2) continue;
                r+=s*(perlin(c)*1.0+0.0);
                c*=3.0;
                s*=0.75;
        }
        return r;
}


layout(binding=0) uniform sampler2D tex;
layout(binding=1) uniform sampler2D texPalaFlow;
layout(binding=2) uniform sampler2D texEmitBuf;

layout(binding=4) uniform sampler2D texDepth;

uniform float g_windowWidth;
uniform float g_windowHeight;
uniform float g_time;
uniform float g_timeStep;

uniform mat4 viewInvMatrix;
uniform mat4 viewMatrix;


uniform float freq = 3.0;
uniform float amp = 5.0;
uniform float prev = 0.95;
uniform float dirX = 0.0;
uniform float dirY = -0.25;
uniform float phase = 0.0; // = g_time*freq;

uniform float g_randNoise = 0.0;

uniform float g_feedThr = 0.0;
uniform float g_feedPow = 1.0;

uniform float g_feedAmp = 0.0;
uniform float g_feedZoom = 1.0;

uniform vec4 g_feedColor = vec4(0.0, 0.0, 0.0, 0.0);

uniform float cenX2D = 0.5;
uniform float cenY2D = 0.5;

uniform float useEmitBuf = 0.0;


float timeStepper = 1.0;

float tsCorrExp(float t) {
    float tsScale = (timeStepper)/0.01667;
    if (timeStepper < 0.001) {
   //     return t;
    }
    if (t<0.0) {
        return -pow(-t, 1.0+tsScale);
    }
    return pow(t, 1.0+tsScale);
}

float tsCorrLin(float t) {
    float tsScale = (timeStepper)/0.01667;
    return t*tsScale;
}

uniform float effectWidth = 1280.0;
uniform float effectHeight = 720.0;

void main() {

    vec2 uvs = gl_FragCoord.xy/vec2(effectWidth, effectHeight);

    timeStepper = g_timeStep;

    // timeStepper = 0.0167;
  //  if (timeStepper > 0.0167) timeStepper= 0.0167;

    if (timeStepper < 0.0001) {
        frag.rgb = texture2D(texPalaFlow, uvs).rgb;
        frag.a = 1.0;
        return;
    }

    uvs -= vec2(cenX2D*0.5+0.5, cenY2D*0.5+0.5);
    uvs *= tsCorrExp(g_feedZoom);
    uvs += vec2(cenX2D*0.5+0.5, cenY2D*0.5+0.5);

    vec4 screen = texture2D(tex, uvs, 0);
    screen.rgb = pow(screen.rgb, vec3(2.0));

    vec4 dep = texture2D(texDepth, uvs);

    vec4 d = texelFetch(texDepth, ivec2(gl_FragCoord.xy), 0);

// distance based check, could be used but do with proper 3D coords
    //  if (d.x > 0.998) screen.rgb *= 0.0;


  //  uvs.y += 10.0/g_windowHeight;

    vec2 uvss = uvs;

  //  uvss.x += g_randNoise/g_windowWidth*rand(uvs+vec2(g_time, g_time*0.3));
  //  uvss.y += g_randNoise/g_windowHeight*rand(uvs*0.723+vec2(g_time*0.56, g_time*1.3));


    vec3 ray = vec3(uvss*1.0-0.50, -1.0);
    ray.x *= 16.0/9.0;

//    ray.xyz = ray.xzy;

    vec3 orig = vec3(0.0, 0.0, -0.0);
    vec3 norm = vec3(0.0, 0.0, -1.0);


//    orig = (viewInvMatrix*vec4(orig, 0.0)).xyz;
//    norm = (viewInvMatrix*vec4(norm, 0.0)).xyz;
    vec4 ray4 = (viewInvMatrix*vec4(ray, 0.0));
    ray = ray4.xyz; // /ray4.w;
    vec3 rayN = normalize(ray);

    float den = dot(norm, rayN);

    vec3 rayHit = vec3(0.50);

//    if (den > 0.0001) {
        vec4 vmp = 1.0*(viewInvMatrix*vec4(0.0, 0.0, 0.0, 1.0));
        float ts = dot(orig-vmp.xyz, norm) / den;
        vec3 kba = 1.0*(viewInvMatrix*vec4(0.0, 0.0, 0.0, 1.0)).xyz;
      //  kba.x *= 0.7;
        kba.x *= 1.23;
        kba.y *= 1.23;
        rayHit = ts*rayN+kba;
//    }
    uvss = rayHit.xy*0.25;


    float ampRand = 1.0*amp*rand(uvs*1.0+vec2(g_time, g_time*0.3));
    vec4 g_freqAmp = vec4(freq, freq, (amp+ampRand)/g_windowWidth, (amp+ampRand)/g_windowHeight);
    vec2 g_dir = vec2(dirX, dirY);

 //   uvss.y -= 0.0*g_time;

    vec2 ufo;

    ufo.x = (turb(vec3(uvss*g_freqAmp.x+vec2(phase*0.32, phase*0.47), phase))+g_dir.x)*g_freqAmp.z;
    ufo.y = (turb(vec3(uvss*g_freqAmp.y+vec2(phase*0.12, phase*0.53), phase+3.0))+g_dir.y)*g_freqAmp.w;


    uvs.x += tsCorrLin(ufo.x);
    uvs.y += tsCorrLin(ufo.y);

    vec4 palaFlow = texture2D(texPalaFlow, uvs);
    palaFlow.rgb = pow(palaFlow.rgb, vec3(2.0));

    vec4 result = vec4(0.0);

    palaFlow.rgb = pow(clamp(palaFlow.rgb, 0.0, 1.0), vec3(1.0));

    float emitBufValue = 1.0;
    if (useEmitBuf > 0.5) {
        emitBufValue = texture2D(texEmitBuf, uvs).x;
    }


    screen.rgb = clamp(pow((screen.rgb-vec3(g_feedThr)), vec3(g_feedPow))*emitBufValue*g_feedAmp*(vec3(1.0)+g_feedColor.rgb), 0.0, 1.0);

    result.rgb = screen.rgb*(1.0-tsCorrExp(prev))+palaFlow.rgb*tsCorrExp(prev);

    //result.rgb *= result.rgb;
    result.rgb = pow(result.rgb, vec3(0.50));

    result.rgb = clamp(result.rgb, 0.0, 20.0);

   // if (abs(rayHit.x) < 1.0 && abs(rayHit.y) < 1.0)
   // result.rgb = rayHit.xyz;

  //  result.rgb = vec3(perlin(vec3(uvs*64.0, 0.0)))*0.1+0.1;

//    result.rgb = vec3(cenX2D, cenY2D, 0.0);

//    result.rgb = vec3(0.0, 0.0, 0.0);

    result.a = 1.0;


    frag = result;
}

