#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, 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(binding=0, rgba16f) uniform image2D emittedPartPos;

// 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_writeCollisionDepth = 1.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);
}


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;
//  myUv = uv*g_uvScale;
//  myUv.y *= -1.0;
  myUv.x += g_uvOfsX;


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

 diffuse.rgb = clamp((diffuse.rgb-0.0)*2.2+0.0, 0.0, 10.0);

 myUv = posW.xz*g_uvScale*1.0+vec2(0.5, 0.5);
 vec4 d2 = texture2D(texNorm, myUv.xy*88.8);

 d2.rgb *= d2.rgb;


 diffuse.rgb += clamp((d2.rgb-0.0)*1.0, 0.0, 100.0)*12.0;
 diffuse.rgb = clamp(diffuse.rgb, 0.0, 1000.0);

 diffuse.rgb *= g_texBrightness;
 //diffuse.rgb += vec3(1.0)*0.0;


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

  normal = normalize(normal);


 //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 = 1.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 = 1.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)+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 += 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 = 1.0;

  float depthi = (posG.z/posG.w);
  if (depthi > 0.999) {
      //discard;
      frag.a = clamp((1.0-depthi)*1000.0, 0.0, 1.0);
  }

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

  frag2.r = depthi*g_writeCollisionDepth+(1.0-g_writeCollisionDepth)*1.0;
  frag2.gb = normalize(normalWSG).xy;
  frag2.a = 1.0;

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

  fragPos = vec4(pospos.xyz, 1.0);

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


}

