#version 430

layout(binding=0) uniform sampler2D tex;
layout(binding=1) uniform sampler2D tex2;
layout(binding=2) uniform sampler2D tex3;
layout(binding=3) uniform sampler2D tex4;
layout(binding=4) uniform sampler2D texPrevBlurFrame;
layout(binding=5) uniform sampler2D texPrevNorm;



in vec4 posG;
in vec4 posOrigG;
in vec3 normalG;
in vec3 normalWSG;
in vec2 uvG;
in vec3 tangentG;
in vec3 colorG;
in vec4 posW;
in float brightG;

in float triangleIdG;

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


#define PI 3.1415926

uniform float g_time;

uniform float g_uvOfsX = 0.0;
uniform float g_uvScale = 1.0;
uniform float g_uvScaleY = 1.0;
uniform float g_uvOfsY = 0.0;

uniform float g_texBrightness = 1.0;
uniform float g_texAmbient = 0.0;
uniform float g_prevAmount = 0.0;
uniform float g_prevBlurAmount = 0.0;
uniform float g_bump = 0.0;

uniform vec4 g_color = vec4(1.0);

uniform float g_reset;

uniform mat4 modelViewMatrix;
uniform mat4 modelViewInvMatrix;
uniform mat4 viewInvMatrix;
uniform mat4 viewMatrix;
uniform mat4 projectionMatrix;
uniform mat4 projectionInvMatrix;

uniform float g_windowWidth = 1280.0;
uniform float g_windowHeight = 720.0;

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 rotateXY3(vec3 p, float a) {
  return rotateXY(vec4(p, 0.0), a).xyz;
}

// 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);
}

const float zFar = 1.0;
const float zNear = 0.0;

float getPointDist(float z) {
    float clipA = zFar / (zFar - zNear);
    float clipB = zFar*zNear / (zNear - zFar);
    return clipB/(z-clipA);
}
float getPointZ(float d) {
    float clipA = zFar / (zFar - zNear);
    float clipB = zFar*zNear / (zNear - zFar);
    return (clipB + d*clipA)/d;
}

vec4 CalcEyeFromWindow(in vec3 windowSpace) {
    vec3 ndcPos;
    vec4 viewport = vec4(0.0, 0.0, g_windowWidth, g_windowHeight);
    ndcPos.xy = ((2.0 * windowSpace.xy) - (2.0 * viewport.xy)) / (viewport.zw) - 1;
//    ndcPos.z = (2.0 * windowSpace.z - zNear - zFar) / (zFar - zNear);
    ndcPos.z = (2.0 * windowSpace.z - zNear - zFar) / (zFar - zNear);
    vec4 clipPos;
    clipPos.w = projectionMatrix[3][2]/(ndcPos.z-(projectionMatrix[2][2]/projectionMatrix[2][3]));
    clipPos.xyz = ndcPos * clipPos.w;
    return projectionInvMatrix * clipPos;
}

vec2 getBump(vec2 uv) {
    vec2 d = vec2(0.01, 0.0);
    return vec2(texture2D(tex, uv+d.xy).g-texture2D(tex, uv-d.xy).g,
                texture2D(tex, uv+d.yx).g-texture2D(tex, uv-d.yx).g);
}


float atanSafe(float y, float x) {
    float ret=0.0;
    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;
}

// 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<8;i++) {
                //if (i<2) continue;
                r+=s*(perlin(c)*1.0+0.0);
                c*=3.0;
                s*=0.55;
        }
        return r;
}

vec3 texStripes(vec3 p) {
    float sw = 0.20;
    float sf = 40.0;
    float res = clamp((sin(p.z*sf+p.x*sf)-1.0+sw)/sw, -1.0, 1.0)+clamp((sin((p.z*sf+p.x*sf)*0.1)-1.0+sw)/sw, 0.0, 1.0);
    return -vec3(res*1.25, res*1.1, res*1.05)+vec3(2.0);
}

vec3 spreadSpec3(vec3 c, float sp) {
    sp = fract(sp);
    c.r *= smoothstep(1.0, 0.0, (1.0-sp)*1.0);
    c.g *= smoothstep(1.0, 0.0, abs((sp-0.5)*2.0));
    c.b *= smoothstep(1.0, 0.0, sp*1.0);
    return c;
}

vec3 texStripesRad(vec3 p) {
    float sw = 2.0;
    float sf = 32.0;
    float pk = sqrt(dot(p.xy, p.xy))+atanSafe(p.y, p.x)/sf;
    float res = clamp((sin(pk*sf)-1.30+sw)/sw, -1.0, 1.0);
    vec3 r = (vec3(res*1.3, res*1.1, res*1.0)*20.0+vec3(0.0));
    vec3 rr = vec3(0.0);
    for (int i=0; i<32; i++) {
        rr += spreadSpec3(r, pk*i*0.1+i/16.0);
    }
    return rr/32.0;
}


vec2 rotateXY2(vec2 p, float a) {
  return rotateXY(vec4(p, 0.0, 0.0), a).xy;
}

float getRot(int oted, int closestEdge) {
    float rot = 1.0*3.141592;

    if (oted == 0 && closestEdge == 0) {
        rot = -3.141592;
    }
    if (oted == 0 && closestEdge == 1) {
        rot = -0.25*3.141592;
    }
    if (oted == 0 && closestEdge == 2) {
        rot = 0.5*3.141592;
    }

    if (oted == 1 && closestEdge == 0) {
        rot = 0.25*3.141592;
    }
    if (oted == 1 && closestEdge == 1) {
        rot = -3.141592;
    }
    if (oted == 1 && closestEdge == 2) {
        rot = -0.25*3.141592;
    }

    if (oted == 2 && closestEdge == 0) {
        rot = -0.5*3.141592;
    }
    if (oted == 2 && closestEdge == 1) {
        rot = 0.50*3.141592;
    }
    if (oted == 2 && closestEdge == 2) {
        rot = 3.141592;
    }

    return rot;
}




vec4 getCol(float freq, vec2 ofs) {
    vec4 d;
    vec4 diffuse;
    float kalkutta, kalkuttas, kf;
    float pi = 3.141592;
    vec2 uv;


    float overlaps = g_uvScale;
    float dots = dot(vec3(0.0, 1.0, 0.0),normalize(posW.xyz));
    float dotter = (0.50+0.45*dots)*g_uvScaleY+g_uvOfsY*freq;
    kalkutta = (atanSafe(posW.x, posW.z)+0.5*pi)/(2.0*pi)*overlaps*2.0;
    overlaps = fract((overlaps-0.01)*2.0)*0.5;
    kf = fract(kalkutta);
    uv = vec2(kalkutta, dotter)*1.0;
    d = texture2D(tex, uv*freq+ofs);
    d *= d;
    diffuse = d*(smoothstep(0.0, overlaps, kf))*(1.0-smoothstep(overlaps, overlaps*2.0, kf));

    overlaps = g_uvScale*1.5;
    kalkutta = ((atanSafe(posW.z, posW.x)+0.50*pi)/(2.0*pi)+0.0)*overlaps*2.0;
    overlaps = fract((overlaps-0.01)*2.0)*0.5;
    kf = fract(kalkutta);
    uv = vec2(kalkutta, dotter)*1.0;
    d = texture2D(tex, uv*freq+ofs);
    d *= d;
    diffuse += d*(smoothstep(0.0, overlaps, kf))*(1.0-smoothstep(overlaps, overlaps*2.0, kf));

    return diffuse*brightG;
}

vec3 tonemapUC2(vec3 x) {
    x = clamp(x, 0.0, 10000.0);
    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;
}



layout(binding=0, rgba32f) uniform image2D triangleInfo;
layout(binding=1, r32f) uniform image2D texSpaceWaveIn;
layout(binding=2, r32f) uniform image2D texSpaceWaveOut;
layout(binding=3, r32f) uniform image2D texWaveFeed;
layout(binding=5, rgba32f) uniform image2D texSpaceDirX;
layout(binding=6, rgba32f) uniform image2D texSpaceDirY;
layout(binding=7, rgba32f) uniform image2D texSpace;


uniform float g_texW = 1280;
uniform float g_texH = 720;
uniform float g_quadsPerRow = 128;

uniform float g_waveBlur = 0.01; // keep this quite low
uniform float g_hitHeight = 0.05; // do not explode this too high
uniform float g_waveDamp = 0.999;
uniform float g_waveSpeed = 0.99; // not a real speed but somehow damps too...



void main() {

  vec3 normal = normalG;
  vec2 uv = uvG;
  vec3 tangent = tangentG;
  vec3 color = colorG;
  float sk = 0.2;


  vec4 diffuse = vec4(1.0);
 vec4 pb = vec4(gl_FragCoord.xy, gl_FragCoord.xy);
 ivec2 ct = ivec2(gl_FragCoord.xy);

 vec4 win = imageLoad(texSpaceWaveIn, ct);
 vec4 wout = imageLoad(texSpaceWaveOut, ct);
// vec4 woutPrev = imageLoad(texSpaceWaveOutPrev, ct);

 vec4 dirx = imageLoad(texSpaceDirX, ct);
 vec4 diry = imageLoad(texSpaceDirY, ct);

 vec4 res = vec4(0.0);

 float w = 0.0;

 float vRight=0.0;
 float vLeft=0.0;
 float vUp=0.0;
 float vDown=0.0;
 // simple blur with four neighbors
 if (dirx.x > 0.0 || dirx.y > 0.0) {
    vLeft = imageLoad(texSpaceWaveIn, ivec2(dirx.xy)).r;
    res += vLeft;
    w += 1.0;
 }
 if (dirx.z > 0.0 || dirx.w > 0.0) {
     vRight = imageLoad(texSpaceWaveIn, ivec2(dirx.zw)).r;
     res += vRight;
     w += 1.0;
 }
 if (diry.x > 0.0 || diry.y > 0.0) {
     vUp = imageLoad(texSpaceWaveIn, ivec2(diry.xy)).r;
     res += vUp;
     w += 1.0;
 }
 if (diry.z > 0.0 || diry.w > 0.0) {
     vDown = imageLoad(texSpaceWaveIn, ivec2(diry.zw)).r;
     res += vDown;
     w += 1.0;
 }

 // and add these for blur with eight neighbors
 vec4 dirxy1 = imageLoad(texSpaceDirY, ivec2(dirx.xy));
 vec4 dirxy2 = imageLoad(texSpaceDirY, ivec2(dirx.zw));
 //vec4 diry = imageLoad(texSpaceDirY, ct);

 float vv;
 float pa = 0.5;
 if (dirxy1.x > 0.0 || dirxy1.y > 0.0) {
    vv = pa*imageLoad(texSpaceWaveIn, ivec2(dirxy1.xy)).r;
    res += vv;
    w += pa;
 }
 if (dirxy1.z > 0.0 || dirxy1.w > 0.0) {
    vv = pa*imageLoad(texSpaceWaveIn, ivec2(dirxy1.zw)).r;
    res += vv;
    w += pa;
 }
 if (dirxy2.x > 0.0 || dirxy2.y > 0.0) {
    vv = pa*imageLoad(texSpaceWaveIn, ivec2(dirxy2.xy)).r;
    res += vv;
    w += pa;
 }
 if (dirxy2.z > 0.0 || dirxy2.w > 0.0) {
    vv = pa*imageLoad(texSpaceWaveIn, ivec2(dirxy2.zw)).r;
    res += vv;
    w += pa;
 }

 vec4 kb = imageLoad(texSpace, ct);


 if (w > 0.0) {
     res.r /= w;
 }

 float bias = 0.0;

 res.r -= bias;


 float blur = g_waveBlur;

 // res.r *= 0.9;

 vec4 reso = res;
 res.r *= blur;
 res.r += (1.0-blur)*(reso.r*2.0-(wout.r-bias))*g_waveDamp;

 res.r += bias;

 res.r = clamp(res.r, -128.0, 128.0);

 float speed = g_waveSpeed;
 res.r = speed*res.r+(1.0-speed)*win.r;

// float tim = g_time*0.150;
//  vec3 pallo = vec3(sin(tim*12.6)*4.0+0.0, cos(tim*7.6)+0.0, sin(cos(tim*3.4)+sin(tim*2.1)))*0.750;
//  vec3 dis = pallo-posOrigG.xyz;
//  float disto = 1.0-(sqrt(dot(dis,dis))*4.0+0.0);

  //disto = sin(disto*32.0);

 //// feed new wave
  //res.r += clamp(smoothstep(0.0, 0.10, disto), 0.0, 1.0)*4.0;
//  if (clamp(smoothstep(0.0, 0.10, disto), 0.0, 1.0)*16.0 > 0.2) res.r = 10.0;
//  res.r += kb.r*0.01-0.001;

//  if (w < 3.5) {
//      res.rgb = vec3(0.0, 0.0, 0.0);
//  }

  vec4 feed = imageLoad(texWaveFeed, ct);
  if (feed.r > 0.1) {
      float feedLeft = feed.r;
      if (feed.r < 3.0) {
        res.r += g_hitHeight; // feedLeft*0.3; // feedLeft*5.0;
        //feedLeft = 0.0;
      }
      feedLeft *= 0.50;
      imageStore(texWaveFeed, ct, vec4(feedLeft));
    //  imageStore(texSpaceWaveIn, ct, vec4(res.r));
  }



 // reset
  if (g_reset > 0.5) {
    res.r = 0.0;
  }
// float damp = 0.99;

//  res.r = feed.r*2.0;

// res.r = posOrigG.z;

  if (abs(res.r-win.r) > 1.0) {
//      res.r *= 0.5; // (1.0-clamp(abs(res.r-win.r)-0.5, 0.0, 1.0));
  }

// res.r *= damp;
 imageStore(texSpaceWaveOut, ct, vec4(res.r));


 discard;

 return;


}

