#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;
layout(binding=5) uniform sampler2D texPrevNorm;

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

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

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(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;

#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 modelViewMatrix;
uniform mat4 modelViewInvMatrix;
uniform mat4 viewInvMatrix;
uniform mat4 viewMatrix;
uniform mat4 projectionMatrix;
uniform mat4 projectionInvMatrix;


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, 1280.0, 720.0);
    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;
}


void main() {

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

 // color.rgb = vec3(1.0);

  vec2 myUv = vec2(posW.x*1.1+posW.z*0.05, posW.x*0.1+posW.z*1.07+posW.y*0.23)*g_uvScale*1.0+vec2(0.5, 0.5);
  myUv.y *= -1.0;
  myUv.x += g_uvOfsX;

  vec2 myUv2 = vec2(posW.z*1.4+posW.y*2.2, posW.x+posW.y*2.3)*g_uvScale*1.0+vec2(0.5, 0.5);
  myUv2.y *= -1.0;
  myUv2.x += g_uvOfsX;

  //vec2 myUv = uv*1;


 vec4 diffuse = texture2D(tex, myUv.xy*0.4)*(1.0+1.2*texture2D(tex, myUv2.xy*1.1));
 diffuse.rgb *= 0.20*diffuse.rgb;
// diffuse.rgb *= 0.0; // *g_texBrightness;
 diffuse.rgb += vec3(0.50);


 //diffuse.rgb *= diffuse.rgb;
// 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));

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

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


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

//float bumpX = 0.0;
// float  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*0.0+1.0)+vec4(0.00)+0.0*vec4(0.05*pow(d*1.0, specPow));
//  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);
  ssPos.y = ssPos.y;

  ssPos -= vec2(0.5, 0.5);
  ssPos *= 2.0;
 // ssPos += vec2(0.5, 0.5);

  vec3 eyeRay = vec3(ssPos.xy, 1.0); // /gl_FragCoord.w;

  eyeRay = normalize(eyeRay);


  normal+=tangent*bumpX + biTangent*bumpY;
  normal = normalize(normal);

  vec3 ref = reflect(eyeRay, -normal);

 // vec3 sp = (modelViewInvMatrix * vec4(eyeRay, 0.0)).xyz*4.0;
 // vec3 sp = eyeRay*posG.z;
 // sp = (modelViewInvMatrix * vec4(sp, 1.0)).xyz*1.0;

  vec3 sp = posW.xyz;

  // world space from gl_FragCoord.xyz
//  vec4 ndcPos;
//  vec4 viewport = vec4(0.0, 0.0, 1280.0, 720.0);
//  ndcPos.xy = ((2.0 * gl_FragCoord.xy) - (2.0 * viewport.xy)) / (viewport.zw) - 1.0;
//  ndcPos.z = (2.0 * gl_FragCoord.z - zNear - zFar) / (zFar - zNear);
//  ndcPos.w = 1.0;
//  vec4 clipPos = ndcPos / gl_FragCoord.w;
//  vec4 eyePos = projectionInvMatrix * clipPos;
//  vec3 sz = (viewInvMatrix*vec4(eyePos.xyz, 1.0)).xyz;
//  sp = vec3(sz.x, sz.y, sz.z*1.0);

//  vec3 jorge = texture2D(texPrevNorm, gl_FragCoord.xy/viewport.zw).rgb;
//  vec4 efe = CalcEyeFromWindow(vec3(gl_FragCoord.xy, jorge.r));
//  vec3 seze = (viewInvMatrix*vec4(efe.xyz, 1.0)).xyz;
//  sp = seze.xyz;


//  sp = sz;

  // sp = vec3(z_eye)*0.1;

  // sp = vec3(pow(gl_FragCoord.z, 5.0))*2.0;

 // 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 = norkor.xy*0.5+0.5;
  vec3 refNormal = reflect(eyeRay, -normal);
  vec3 normalB = (viewMatrix * vec4(normal, 0.0)).xyz;
  vec2 paske = (norkor.xy)+0.25*(normalB.xy);
  paske = clamp(paske, 0.0, 1.0);
  vec3 jorge = texture2D(texPrevNorm, paske).rgb*0.0;
  vec4 efe = CalcEyeFromWindow(vec3(gl_FragCoord.xy, jorge.r));
  vec3 seze = (viewInvMatrix*vec4(efe.xyz, 1.0)).xyz;

  sp = seze-sp;
  float dok = 200.0/((dot(sp, sp))*20.0+100.0);
  dok = clamp(dok, 0.0, 100.0);

  float dok2 = dot(sp, normal)-0.0;
  dok2 = clamp(dok2*1.0, 0.0, 1.0);

  float dok2a = 0.85;
  dok *= (dok2*dok2a+1.0-dok2a);

  float kk = 0.5;
  if (paske.x < 0.01 || paske.y < 0.01 || paske.x > 0.99 || paske.y > 0.99) kk = 0.0;
  vec3 prevb = 0.5*texture2D(texPrevBlurFrame, paske).rgb*clamp(dok*kk, 0.0, 1.0);
// c.rgb *= g_prevBlurAmount*4.0*pow(clamp(prevb, 0.0, 8.0),vec3(0.50));

 // c.rgb *= 0.0; // brightG;
//  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.rgb = eyeRay.xyz*50.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.rgb *= colorG.rgb;
  frag = pow(frag, vec4(0.5));

  //frag.rgb = seze.rgb;

 // frag.rgb = jorge.rgb*10.0;
//  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 = 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 = gl_FragCoord.z; //depthi;
  frag2.rgb = normalize(normalWSG).xyz;
  frag2.a = 1.0;


}

