#version 430

layout(binding=0) uniform sampler2D tex;
layout(binding=1) uniform sampler2D texNorm;
layout(binding=2) uniform sampler2D texEnv;
layout(binding=3) uniform sampler2D texPrevFrame;
layout(binding=4) uniform sampler2D texPrevBlurFrame;

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

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

layout(binding=0, offset=0) uniform atomic_uint ac;
layout(binding=0, rgba16f) uniform image2D emittedPartPos;
layout(binding=1, rgba16f) uniform image2D emittedPartNormal;
layout(binding=2, rgba16f) uniform image2D emittedPartVar;

//layout(binding=0, r32ui) uniform uimage2D headPointers;
//layout(binding=1, r32ui) uniform uimage2D nextPointers;
//layout(binding=2, rgba16f) uniform image2D pixelListColors;
//layout(binding=3, rgba32f) uniform image2D pixelListDepthNorm;


// layout(location = 0) out uvec4 uex_colour;
// layout(location = 1) out vec4 ex_colour;

uniform float g_time;

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

uniform float g_texBrightness = 1.0;
uniform float g_prevAmount = 0.0;
uniform float g_prevBlurAmount = 0.0;
uniform float g_prevNorm = 1.0;

uniform float g_cubesDiv = 16.0;
uniform float g_spread = 8.0;
uniform float g_worldPos = 1.0;

uniform float g_drawSurf = 0.0;

#define PI 3.1415926

vec2 latlong(vec3 v) {
  v = normalize(v);
  float theta = acos(v.z); // +z is up
  float phi = atan(v.y, v.x) + PI;
  return vec2(phi, theta)*vec2(.1591549, .6366198);
}

uniform mat4 modelMatrix;
uniform mat4 modelViewMatrix;
uniform mat4 modelViewInvMatrix;


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

uniform float g_genUvs = 0.0;

uniform float g_alpha = 1.0;


void main() {

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

 // color.rgb = vec3(1.0);

  vec2 myUv;

  myUv = posW.xy*g_uvScale*1.0+vec2(0.5, 0.5);
  myUv.y *= -1.0;
  if (g_genUvs < 0.5) {
    myUv = uv*g_uvScale;
    myUv.y *= -1.0;
  }
  myUv.x += g_uvOfsX;


 vec4 diffuse = texture2D(tex, myUv.xy);
 float alfe = sin(posW.x*3.0)*0.5+0.5;
// alfe = clamp(abs(normalWSG.x), 0.0, 1.0);
// diffuse = alfe*diffuse+(1.0-alfe)*texture2D(texEnv, myUv.xy);
 diffuse *= 1.0;
 //diffuse.rgb *= diffuse.rgb;
 diffuse.rgb *= g_texBrightness;
 //diffuse.rgb += vec3(1.0)*0.0;


 normal = normalize(normal);
 //
// vec4 diffuse = 10.1*vec4(1.0);




 //diffuse += 4.0*texture2D(tex, myUv.xy*10.0)+0.1*vec4(1.0);


 // diffuse.r = pow(diffuse.r, 2.5);
 // diffuse.g = pow(diffuse.g, 1.10);
 // diffuse.b = pow(diffuse.b, 0.70);

  vec3 lightPos = vec3(0.0*cos(g_time*2.0), 0.0, 5.0);
  vec3 surfPos = vec3(0.0f, 0.0f, 0.0f);
  vec3 lightDir = lightPos-surfPos;

  float lightDist = sqrt(dot(lightDir, lightDir));

  vec3 myNormal = normal;
  vec3 biTangent = cross(myNormal, tangent);

//  float bumpX = 0.0*(texture2D(tex, myUv.xy+vec2(1.0/512.0, 0.0)).g-texture2D(tex, myUv.xy+vec2(-1.0/512.0, 0.0)).g);
//  float bumpY = 0.0*(texture2D(tex, myUv.xy+vec2(0.0, 1.0/512.0)).g-texture2D(tex, myUv.xy+vec2(0.0, -1.0/512.0)).g);


  vec4 normFromTex = texture2D(texNorm, myUv*10.0);
  float bumpStrength = 0.1;
  float bumpX = -(normFromTex.x-0.5)*bumpStrength;
  float bumpY = -(normFromTex.y-0.5)*bumpStrength;

//  bumpX = 0.0;
//  bumpY = 0.0;

 // myNormal += tangent*bumpX + biTangent*bumpY;

  myNormal = normalize(myNormal)*1.0;

  float normalLen = sqrt(dot(myNormal, myNormal));

  float d = dot(lightDir, myNormal)/(lightDist*normalLen);
  d = clamp(d, 0.0, 1.0)*1.0;

  //d = d*0.35+pow(d, 128.0f);
  //frag = vec4(d, d, d, d);

 // frag = (diffuse+0.4)*d*0.35 + pow(d, 128.0f)+0.03;

  float specPow = 120.0;

 // frag = diffuse*(d*1.10+0.10)+vec4(0.00)+1.0*vec4(pow(d, specPow));
  frag = diffuse;
//  frag.rgb = vec3(d); //vec3(1.0*pow(d*1.0, specPow));

  vec4 c = frag;


//  c.r = pow(c.r, 0.85);
//  c.g = pow(c.g, 0.55);
//  c.b = pow(c.b, 0.45);

//  c.r = pow(c.r, 1.20);
//  c.g = pow(c.g, 0.80);
//  c.b = pow(c.b, 1.10);


  vec2 ssPos = gl_FragCoord.xy*vec2(1.0/1280.0, 1.0/720.0)*1.0;
  ssPos.y = ssPos.y;

  ssPos -= vec2(0.5, 0.5);
  ssPos *= 1.05;
  ssPos += vec2(0.5, 0.5);

  vec3 eyeRay = vec3(ssPos.xy, posG.z);

  eyeRay = normalize(eyeRay);
  vec3 ref = reflect(eyeRay, -normal);

  ref = (modelViewInvMatrix * vec4(ref, 0.0)).xyz;

  //ref = normalize(ref);
   ref.xzy = rotateXY3(ref.xzy, -3.141592*0.50);
   ref.yzx = rotateXY3(ref.yzx, -3.141592*0.5);
 // ref = rotateXY3(ref, 3.141592*0.5);

  vec2 uvLatLong = latlong(ref.xyz);
 // uvLatLong.y *= 0.50;
  c.rgb *= 0.40+vec3(clamp(normal.x, 0.0, 1.0))*0.0;
  //vec3 envColor = texture2D(texEnv, uvLatLong).rgb;
  //c.rgb += envColor*envColor;

  vec2 uvLatLongPrev = uvLatLong;
  uvLatLongPrev.x *= -1.0;
  //c.rgb += 1.0*pow(texture2D(texPrevFrame, uvLatLongPrev).rgb,vec3(1.0));
  vec2 norkor = posG.xy/posG.z;
  norkor.xy *= 0.8;
  //norkor.y *= 1.1;
  norkor.xy = norkor.xy*0.5+0.5;
  //norkor.x *= 9.0/16.0;


//  norkor.y *= -1.0;
  vec3 prev = texture2D(texPrevFrame, (norkor.xy)+0.2*normal.xy).rgb;
  prev = pow(prev, vec3(2.0));
  c.rgb += g_prevAmount*pow(clamp(prev, 0.0, 2.0),vec3(1.0));
  vec2 paske = (norkor.xy)+g_prevNorm*0.1*normal.xy;
  paske = clamp(paske, 0.0, 1.0);
  vec3 prevb = texture2D(texPrevBlurFrame, paske).rgb;
  prevb = pow(prevb, vec3(2.0));
  c.rgb += 3.0*g_prevBlurAmount*pow(clamp(prevb, 0.0, 8.0),vec3(1.0));

//  vec2 uvLatLongPrev = uvLatLong;
//  uvLatLongPrev.x *= -1.0;
//  c.rgb = 1.0*pow(texture2D(texPrevFrame, uvLatLongPrev).rgb,vec3(1.0));

  c.a = diffuse.a*1.0;

 // c.a = 1.0;

  // c.rgb = vec3((posG.z/posG.w-0.9)*10.0);
  //c.rgb = vec3(gl_FragDepth*10000.0);
  // c.rgb = vec3((gl_FragCoord.z*gl_FragCoord.w-0.0)*10.0);

  frag = vec4(c.r, c.g, c.b, c.a);
  frag = pow(frag, vec4(0.5));

//  uint counter = atomicCounterIncrement(ac);
//  frag.rgb = vec3(fract(float(counter)/(1280.0*720.0)));
 // frag.a = clamp((pow(frag.r-0.1,2.0))*4.0, 0.0, 1.0);
 // frag.a = clamp(0.60-diffuse.a*0.3, 0.0, 1.0);
  frag.a = g_alpha;

  //float depthi = clamp(1.0-(gl_FragCoord.z*gl_FragCoord.w)*0.50, 0.0, 1.0);
  // frag2.rgb = vec3(depthi*depthi);

  float depthi = posG.z/posG.w;
  frag2.r = depthi;
  frag2.gb = normalize(normalWSG).xy;
  frag2.a = g_alpha;

  vec4 pospos = modelViewMatrix*posW;
//  pospos /= pospos.w;

  fragPos = vec4(pospos.xyz, 1.0);

  pospos = modelMatrix*posW;

//  ivec3 fc = ivec3(pospos.xyz*(pospos.z*4.0+1.0)*1.0);
//  int dd = 16*4;

    vec4 poske = posW;
    vec3 pkz = ((pospos.xyz*g_worldPos+poske.xyz*(1.0-g_worldPos))*(1.0));
    vec3 fc = vec3((pkz*1.0));
//    pkz.x += gl_FragCoord.x;
    pkz = fract(pkz);
    float dd = float(g_cubesDiv);

//    fc.x += int(gl_FragCoord.x*0.0)%dd;
//    fc.y += int(gl_FragCoord.y*0.0)%dd;
//    int kx = fc.x % dd;
//    int ky = fc.y % dd;
//    int kz = fc.z % dd;

 //   int kcx=kx;
 //   int kcy=ky;

    float kcx = fract(float(gl_FragCoord.x*0.10/dd+fc.x*0.0+(g_spread*8.0)));
    float kcy = fract(float(gl_FragCoord.y*0.10/dd+fc.y*0.0+0.0*(g_spread*8.0)));

//    vec3 an = abs(normalG);

//    if (an.z > an.x && an.z > an.y) {
//        kcx = kx;
//        kcy = ky;
//    } else if (an.y > an.x && an.y > an.z) {
//        kcx = kx;
//        kcy = kz;
//    } else  {
//        kcx = ky;
//        kcy = kz;
//    }


 //   kx = kp.x%dd;
 //   ky = kp.y%dd;

//    int kkx = kp.x % 2;
//    int kky = kp.y % 2;

    vec4 vars = vec4(0.0);

    vec3 kn = normalize(normalG);

    float dn = dot(vec3(0.0, 0.0, 1.0), kn);

 //   dn = 0.9;

    vars.x = clamp(pow(dn, 3.0)*1.0-0.20+0.0, 0.0, 1.0)*30.0; // *abs(0.50-pkz.x);
//    vars.x = clamp(abs(kn.z*1.0+0.0)*1.0-0.20+0.0, 0.0, 10.0)*120.0*abs((0.50-pkz.x)); // *abs((0.50-pkz.y)); // *(1.0-pkz.y);
 //  vars.x = clamp(abs(kn.z*0.0+1.0)*1.0-0.20+0.0, 0.0, 10.0)*120.0*abs((0.50-pkz.x))*abs((0.50-pkz.y)); // *(1.0-pkz.y);

//    if (abs(kcy-(kcx+1.0))<0.1 && vars.x > 0.0) { // && kkx==0 && kky==0) {

    float pkx = 1.0; // clamp(1.0-abs(kcx-0.07)*30.0, 0.0, 1.0)*clamp(1.0-abs(kcy-0.07)*30.0, 0.0, 1.0);

    kcx *= 2.0;
    kcy *= 2.0;

    pkx *= 1.0-clamp((kcx-0.4)*10.0, 0.0, 1.0);
    pkx *= clamp((kcx)*10.0, 0.0, 1.0);
    pkx *= 1.0-clamp((kcy-0.4)*10.0, 0.0, 1.0);
    pkx *= clamp((kcy)*10.0, 0.0, 1.0);

    vars.x *= pkx*1.0;


    if (kcx < 0.5 && kcy < 0.5) { //  && vars.x > 0.0) {
        uint counter = atomicCounterIncrement(ac);
        uint cy = counter/(1280);
        uint cx = counter-uint(cy*1280);
        ivec2 listCoord = ivec2(cx,cy);
        imageStore(emittedPartPos, listCoord, modelMatrix*posW);
        imageStore(emittedPartNormal, listCoord, vec4(normalWSG, 1.0));
        imageStore(emittedPartVar, listCoord, vars);
    }

    if (g_drawSurf < 0.5) {
        discard;
    }

//  ivec3 fc = ivec3(posW.xyz*50.0);
//  int dd = 16;
//  int kx = fc.x % dd;
//  int ky = fc.y % dd;
//  int kz = fc.z % dd;
//  if (kx == 0 && ky == 0 && kz == 0) {
//      uint counter = atomicCounterIncrement(ac);
//      uint cy = counter/(1280);
//      uint cx = counter-uint(cy*1280);
//      ivec2 listCoord = ivec2(cx,cy);
//      imageStore(emittedPartPos, listCoord, modelMatrix*vec4(posW));
//  }

//  ivec2 fc = ivec2(uv*200.0);
//  int dd = 128;
//  int kx = fc.x % dd;
//  int ky = fc.y % dd;
//  //int kz = fc.z % dd;
//  if (kx == 0 && ky == 0) {
//      uint counter = atomicCounterIncrement(ac);
//      uint cy = counter/(1280);
//      uint cx = counter-uint(cy*1280);
//      ivec2 listCoord = ivec2(cx,cy);
//      imageStore(emittedPartPos, listCoord, modelMatrix*vec4(posW));
//  }

  // uint kk = imageAtomicExchange(headPointers, ivec2(gl_FragCoord.xy), 123);

  // uint kk = imageAtomicExchange(headPointers, ivec2(gl_FragCoord.xy), 123);
 //  imageAtomicAdd(headPointers, ivec2(gl_FragCoord.xy), 1);
 //  imageAtomicAdd(headPointers, ivec2(gl_FragCoord.x+1, gl_FragCoord.y), 1);
 //  imageAtomicAdd(headPointers, ivec2(gl_FragCoord.x-1, gl_FragCoord.y), 1);
 //  imageAtomicAdd(headPointers, ivec2(gl_FragCoord.x, gl_FragCoord.y+1), 1);
 //  imageAtomicAdd(headPointers, ivec2(gl_FragCoord.x, gl_FragCoord.y-1), 1);


//   float r = rand(ivec2(gl_FragCoord.x, gl_FragCoord.y));
//   float rm = 8.0;
   // imageAtomicAdd(headPointers, ivec2(gl_FragCoord.x, gl_FragCoord.y), (1));

//    uint counter = atomicCounterIncrement(ac)+1;
//    uint cy = counter/(1280*4);
//    uint cx = counter-uint(cy*1280*4);
//    ivec2 listCoord = ivec2(cx,cy);
//    uint prevCounter = imageAtomicExchange(headPointers, ivec2(gl_FragCoord.xy), counter);
//    imageStore(nextPointers, listCoord, uvec4(prevCounter));
//    imageStore(pixelListColors, listCoord, frag);
//    imageStore(pixelListDepthNorm, listCoord, frag2);

//    discard;


 //  r = rand(ivec2(gl_FragCoord.x+12, gl_FragCoord.y))*rm;
 //  imageAtomicAdd(headPointers, ivec2(gl_FragCoord.x+1, gl_FragCoord.y+r), (1));
 //  r = rand(ivec2(gl_FragCoord.x+3, gl_FragCoord.y-2))*rm;
 //  imageAtomicAdd(headPointers, ivec2(gl_FragCoord.x+1+r, gl_FragCoord.y+1-r), (1));

 //  r = rand(ivec2(gl_FragCoord.x+2, gl_FragCoord.y+4))*rm;
 //  imageAtomicAdd(headPointers, ivec2(gl_FragCoord.x-1, gl_FragCoord.y-r), (1));
 //  r = rand(ivec2(gl_FragCoord.x-2, gl_FragCoord.y+8))*rm;
 //  imageAtomicAdd(headPointers, ivec2(gl_FragCoord.x-1+r, gl_FragCoord.y-1+r), (1));

 //  r = rand(ivec2(gl_FragCoord.x-4, gl_FragCoord.y))*rm;
 //  imageAtomicAdd(headPointers, ivec2(gl_FragCoord.x-r, gl_FragCoord.y+1), (1));
 //  r = rand(ivec2(gl_FragCoord.x+4, gl_FragCoord.y))*rm;
 //  imageAtomicAdd(headPointers, ivec2(gl_FragCoord.x-1-r, gl_FragCoord.y-r+1), (1));

 //  r = rand(ivec2(gl_FragCoord.x-6, gl_FragCoord.y+7))*rm;
 //  imageAtomicAdd(headPointers, ivec2(gl_FragCoord.x+r, gl_FragCoord.y-1), (1));
 //  r = rand(ivec2(gl_FragCoord.x+6, gl_FragCoord.y+7))*rm;
 //  imageAtomicAdd(headPointers, ivec2(gl_FragCoord.x+1-r, gl_FragCoord.y+r-1), (1));

  // imageStore(headPointers, ivec2(gl_FragCoord.xy), uvec4(123, 2, 2, 2));

   //  discard;



// preview the normal...
//  frag.rg = normal.xy;
//  frag.b = normal.z;


 // frag2.rgba = vec4(0.0, 0.0, 0.0, 1.0);

  // frag.rgb = vec3(1.0);


}

