#version 430

layout(binding=0) uniform sampler2D srcBg;
layout(binding=1) uniform sampler2D src;
layout(binding=2) uniform sampler2D texChromaPalette;

in vec2 uv;

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

uniform float g_time;

precision highp float;
in highp vec2 coord;

uniform float rayX=0.5;
uniform float rayY=0.5;

uniform float lightZ = 2.0;
uniform float g_intensity = 1.0;
uniform float g_specRounds = 2.0;
uniform float g_specOfs = 0.0;
uniform float g_specWeight = 1.5;
uniform float g_origWeight = 1.0;
uniform float g_length = 1.0;

uniform float g_rotateAmp = 1.0;
uniform float g_rotatePrim = 0.45;
uniform float g_rotateSinAmp = 3.2;
uniform float g_rotateSinFreq = 10.0;
uniform float g_rotateMove = 0.0;
uniform float g_rotateBrightMove = 0.0;
uniform float g_rotateBrightFreq = 0.0;
uniform float g_rotateDist = 0.0;
uniform float g_timeRot = 0.0;
uniform float g_timeBrightRot = 0.0;

uniform float g_rotCenterX = 0.0;
uniform float g_rotCenterY = 0.0;

uniform float g_loops = 64.0*1.5;
uniform float g_origAmount = 1.0;
uniform float g_baseFromCol = 1.0;

uniform float g_chromaPaletteEnabled = 0.0;
uniform float g_chromaPaletteY = 0.5;

vec4 spreadSpec(vec4 c, float sp) {
    vec4 res;
    sp = fract(sp);
    res.r = smoothstep(1.0, -0.0, (1.0-sp)*1.0)*c.r;
    res.g = smoothstep(1.0, -0.0, abs((sp-0.5)*2.0))*c.g;
    res.b = smoothstep(1.0, -0.0, sp*1.0)*c.b;

    res.a = c.a;
    return res;
}

vec4 spreadSpecTex(vec4 c, float sp) {
    vec4 res;
    sp = fract(sp);

    res.rgb = texture2D(texChromaPalette, vec2(sp, g_chromaPaletteY)).rgb;
    res.rgb *= c.rgb;

    // res.r = smoothstep(1.0, -0.0, (1.0-sp)*1.0)*c.r;
    //res.g = smoothstep(1.0, -0.0, abs((sp-0.5)*2.0))*c.g;
    // res.b = smoothstep(1.0, -0.0, sp*1.0)*c.b;

    res.a = c.a;
    return res;
}

vec3 tonemapUC2(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;
}


vec4 rotateXY(vec4 p, float a) {
    vec4 r = p;
    r.x = cos(a)*p.x - sin(a)*p.y;
    r.y = sin(a)*p.x + cos(a)*p.y;
    return r;
}

vec3 tonemap(vec3 color, float brightness) {
    color.xyz = pow(color.xyz, vec3(1.0))*brightness;
    color = color*(1.0+color/4.0)/(1.0+color);
    return color;
}
float aTanSafe(float y, float x) {
    float ret;
    if (x!=0.0) {
        if (x>0.0) {
            ret=atan(y/x);
        } else	{
            ret=atan(y/x)+3.141592;
        }
    } else	{
        if (y>=0.0) {
            ret=0.5*3.141592;
        } else {
            ret=-0.5*3.141592;
        }
    }
    return ret;
}

// google glsl rand gave this, thanks and credit flies to
// http://stackoverflow.com/questions/4200224/random-noise-functions-for-glsl
float rand(vec2 co){
    return fract(sin(dot(co.xy ,vec2(12.9898,78.233))) * 43758.5453);
}

void main() {
    vec4 tex = texture2D(src, coord);
    vec4 texBg = texture2D(srcBg, coord);
    vec3 bright = vec3(dot(tex.rgb, vec3(0.344, 0.5, 0.156)));
    vec4 color = pow(tex,vec4(1.0))*0.0;
    //lowp vec2 center = vec2(0.5, 0.5);
    vec2 center = vec2(rayX*1.0+0.5, rayY*1.0+0.5);
    float loops=g_loops;


//    loops = loops*(1.0+16.0*g_length+16.0*g_rotateSinAmp*g_rotateAmp);
//    loops = min(100.0, loops);

    //raymarch version
    float eyeZ = 0.02;
    vec2 coordCen = coord-vec2(0.5, 0.5);
    vec3 eyeDir = vec3((coord-vec2(0.5, 0.5))*eyeZ*1.0, eyeZ);
    vec3 ray=eyeDir;
    vec3 image=vec3(coord-vec2(0.5, 0.5), 1.0);
    vec3 lightPos=vec3((center-vec2(0.5, 0.5)), image.z+lightZ);

    //float radial=tan(lightPosC.y/lightPosC.x);
    float radial=1.0;
    float staticOfs = 1.0*(rand(coord+vec2(0.3,0.476)*(0.0)+vec2(0.123,0.172)*g_time*0.0)-0.5);
    vec4 colorNow = vec4(0.0);
    vec4 colorPrev = vec4(0.0);
    vec4 colorPrev2 = vec4(0.0);
    vec3 eyeToLight;
    vec3 eyeAtImage;
    vec2 imagePos;
    float distCen = sqrt(dot(coordCen-center+vec2(0.5,0.5), coordCen-center+vec2(0.5,0.5)));


    if (g_chromaPaletteEnabled < 0.5) { // maybe consider completely own shader file TBD later ...
        for (float i=0.0; i<loops; i++) {
            lowp float sp = i/(loops-1.0);
            eyeToLight = lightPos-ray;
            eyeAtImage = ray+vec3(eyeToLight.xy*(image.z-ray.z)/(lightPos.z-ray.z), image.z);
            imagePos = vec2(eyeAtImage.xy+vec2(0.50,0.50));
            vec4 piste = clamp(texture2D(src, imagePos).r, 0.0, 10.0)*vec4(texture2D(srcBg, imagePos).rgb, 1.0)*radial;
            //vec4 piste = vec4(texture2D(srcBg, imagePos).rgb, 1.0)*radial;

            piste = piste*g_baseFromCol+(piste.r+piste.g+piste.b)*0.5*vec4(1.0-g_baseFromCol);
            piste = clamp(piste*g_intensity, 0.0, 100.0);

            colorNow = spreadSpec(piste, sp*g_specRounds+g_specOfs)*g_specWeight+piste*g_origWeight;
            color += colorNow; //*(radial2*0.05+0.95);

            float len = g_length; // *(piste.r*1.0+0.0);

            ray = eyeDir+(image-eyeDir)*(sp*len+1.0-g_length+1.0/loops*staticOfs);

            vec4 k = vec4(ray, 0.0);
            k.x*=16.0/9.0;

            vec2 rotCen = vec2(g_rotCenterX*(1.0+g_rotateDist*sin(sp*4.1)), g_rotCenterY);


            k.xy -= rotCen;
            // k = rotateXY(k, sp*0.45+0.2*sin(2.0*sp));
            // k = rotateXY(k, sp*0.45+3.2*sin(2.0*sp));
            //k.xzyw = rotateXY(k.xzyw, (sp*g_rotatePrim+g_rotateSinAmp*sin(g_rotateSinFreq*sp))*g_rotateAmp);
            k = rotateXY(k, ((1.0-sp)*g_rotatePrim+g_rotateSinAmp*sin((g_rotateSinFreq+g_rotateBrightFreq*(piste.r+1.0))*(1.0-sp)-g_time*g_timeRot-(piste.r+1.0)*g_timeBrightRot*g_time+g_rotateBrightMove*(piste.r+1.0)+(ray.x*0.0+(1.0-sp)*10.0)*g_rotateMove))*g_rotateAmp);
            k.xy += rotCen;
            //k.xzyw = rotateXY(k.xzyw, sp*0.0+0.010*tan(2.0*sp));
            //k.zyxw = rotateXY(k.zyxw, sp*0.20+0.110*cos(2.0*sp));
            k.x*=9.0/16.0;
            ray.xyz = k.xyz;
        }
    } else {
        for (float i=0.0; i<loops; i++) {
            lowp float sp = i/(loops-1.0);
            eyeToLight = lightPos-ray;
            eyeAtImage = ray+vec3(eyeToLight.xy*(image.z-ray.z)/(lightPos.z-ray.z), image.z);
            imagePos = vec2(eyeAtImage.xy+vec2(0.50,0.50));
            vec4 piste = clamp(texture2D(src, imagePos).r, 0.0, 10.0)*vec4(texture2D(srcBg, imagePos).rgb, 1.0)*radial;
            //vec4 piste = vec4(texture2D(srcBg, imagePos).rgb, 1.0)*radial;

            piste = piste*g_baseFromCol+(piste.r+piste.g+piste.b)*0.5*vec4(1.0-g_baseFromCol);
            piste = clamp(piste*g_intensity, 0.0, 100.0);

            colorNow = spreadSpecTex(piste, sp*g_specRounds+g_specOfs)*g_specWeight+piste*g_origWeight;
            color += colorNow; //*(radial2*0.05+0.95);

            float len = g_length; // *(piste.r*1.0+0.0);

            ray = eyeDir+(image-eyeDir)*(sp*len+1.0-g_length+1.0/loops*staticOfs);

            vec4 k = vec4(ray, 0.0);
            k.x*=16.0/9.0;

            vec2 rotCen = vec2(g_rotCenterX*(1.0+g_rotateDist*sin(sp*4.1)), g_rotCenterY);


            k.xy -= rotCen;
            // k = rotateXY(k, sp*0.45+0.2*sin(2.0*sp));
            // k = rotateXY(k, sp*0.45+3.2*sin(2.0*sp));
            //k.xzyw = rotateXY(k.xzyw, (sp*g_rotatePrim+g_rotateSinAmp*sin(g_rotateSinFreq*sp))*g_rotateAmp);
            k = rotateXY(k, ((1.0-sp)*g_rotatePrim+g_rotateSinAmp*sin((g_rotateSinFreq+g_rotateBrightFreq*(piste.r+1.0))*(1.0-sp)-g_time*g_timeRot-(piste.r+1.0)*g_timeBrightRot*g_time+g_rotateBrightMove*(piste.r+1.0)+(ray.x*0.0+(1.0-sp)*10.0)*g_rotateMove))*g_rotateAmp);
            k.xy += rotCen;
            //k.xzyw = rotateXY(k.xzyw, sp*0.0+0.010*tan(2.0*sp));
            //k.zyxw = rotateXY(k.zyxw, sp*0.20+0.110*cos(2.0*sp));
            k.x*=9.0/16.0;
            ray.xyz = k.xyz;
        }
    }

    //color = spreadSpec(color, color.a*0.2);
    color *= 1.0/(loops-1.0);
    color *= color;

    color.rgb = clamp(color.rgb, 0.0, 100.0);

   // color.rgb += texBg.rgb*texBg.rgb*g_origAmount;

   // color.rgb = pow(color.rgb, vec3(0.5));


    gl_FragColor = vec4(color.rgb, 1.0);
}
