#version 120
//#extension GL_EXT_gpu_shader4 : require

#pragma optimize(on)

uniform sampler2D map_albedo;
uniform sampler2D map_normal;
uniform sampler2D map_aux;
uniform sampler2D map_depth;
uniform sampler2DShadow map_shadow;

uniform float contextWidth;
uniform float contextHeight;
uniform float contextX;
uniform float contextY;

uniform bool has_shadow;
uniform bool lightType;

uniform vec2 cameraClip;

//uniform mat4 projectionMatrix;
uniform mat4 modelViewMatrix;

varying vec4 positionView;
//varying vec4 shadowCoord;
varying mat4 lightViewMatrix;

void main(void) {

  //gl_FragData[0] = vec4(0);
  //gl_FragData[1] = vec4(0);
  //discard;

  vec2 texCoord = gl_FragCoord.xy;
  texCoord.x -= contextX;
  texCoord.y -= contextY;
  texCoord.x /= contextWidth;
  texCoord.y /= contextHeight;
  //ivec2 texCoordi = ivec2(texCoord);

  float depth = texture2D(map_depth, texCoord).x;
  //float depth = texelFetch(map_depth, texCoordi, 2).x;

  // convert from non-linear to linear
  float fragDepth = -cameraClip.y / (depth - cameraClip.x);

  vec3 lightPos = gl_LightSource[0].position.xyz;
  float radius = gl_LightSource[0].diffuse.w;

  //if (fragDepth < lightPos.z - radius) discard;
  //if (fragDepth > lightPos.z + radius) discard;

  vec3 position = vec3(positionView.xy * fragDepth / positionView.z, fragDepth);
  // calculate fragments location in view-space
  vec2 positionClip = (positionView * gl_ProjectionMatrix).xy / (positionView * gl_ProjectionMatrix).z;

  float dist = distance(lightPos.xyz, position);
  if (dist > radius) discard;
  
  vec3 lightDir = normalize(lightPos.xyz - position);

  vec4 normalshine = texture2D(map_normal, texCoord);
  //float xyLength = length(normalspec.xy);
  vec3 normal = normalize(normalshine.xyz);

  float nDotLD = dot(lightDir, normal) * 1.1 - 0.1;// * 0.9 + 0.1;
    
  // todo
  //float nDotLD;
  //if (lightType == 0)
  //  nDotLD = dot(lightDir, normal);
  //else

  // allow for some neg ndotl to allow for smooth normals
  if (nDotLD < -0.3) discard;
  //nDotLD *= 0.8;
  //nDotLD += 0.2;
  //nDotLD = sqrt(nDotLD);
  if (nDotLD < 0.0) nDotLD = 0.0;
  //if (nDotLD < 0.0) discard;
  
  nDotLD = pow(nDotLD, 0.8); // 1.2
  
  //fragColor = clamp(fragColor, 0, 1);
  
  // photoshop's 'curves' in a sinewave fashion
  //nDotLD = nDotLD * 0.2 + (-cos(nDotLD * 3.14159265) * 0.5 + 0.5) * 0.8;

  float shininess = normalshine.w;

  // linear
  float falloff = max(0.0, radius - dist) / radius;
  // exp
  //falloff *= falloff * falloff;
  falloff = falloff * falloff;

  vec3 lighted = nDotLD * falloff * gl_LightSource[0].diffuse.xyz;

  vec3 refl = reflect(normalize(position), normal);
  vec4 base = texture2D(map_albedo, texCoord);

  // blur
  //base = base + texture2D(map_albedo, texCoord + vec2(0, 1 / contextHeight));
  //base = base + texture2D(map_albedo, texCoord + vec2( 1 / contextHeight, 0));
  //base = base + texture2D(map_albedo, texCoord + vec2(0, -1 / contextHeight));
  //base = base + texture2D(map_albedo, texCoord + vec2(-1 / contextHeight, 0));
  //base = base / 5.0;


  float spec = base.w;
  //spec *= 10.0;
  vec3 specular = pow(max(0.0, dot(refl, lightDir)), shininess) * spec * falloff * gl_LightSource[0].diffuse.xyz;// * vec3(1.3, 1.2, 0.9);

  lighted = clamp(lighted, 0.0, 1.0);

  float shaded = 1.0;
  if (has_shadow) {


//    vec4 coord = lightViewMatrix * modelViewMatrix * vec4(position, 1.0);
//    float A = shadow2DProj(map_shadow, coord).r;
//    float R = coord.p / coord.q;
//    float shadowColor = (R <= A + 0.0002) ? 1.0 : 0.4;

    mat4 lightModelMatrix = lightViewMatrix * modelViewMatrix;

    float shift = 0.1;

    vec3 offset = vec3(0, 0, 0);
    vec4 coord = lightModelMatrix * vec4(position + offset, 1.0);
    float A = shadow2DProj(map_shadow, coord).r;
    float R = coord.p / coord.q;
    float shadowColor = (R <= A + 0.0002) ? 1.0 : 0.0;

    offset = vec3(shift, 0, 0);
    coord = lightModelMatrix * vec4(position + offset, 1.0);
    A = shadow2DProj(map_shadow, coord).r;
    R = coord.p / coord.q;
    shadowColor += (R <= A + 0.0002) ? 1.0 : 0.0;

    offset = vec3(0, shift, 0);
    coord = lightModelMatrix * vec4(position + offset, 1.0);
    A = shadow2DProj(map_shadow, coord).r;
    R = coord.p / coord.q;
    shadowColor += (R <= A + 0.0002) ? 1.0 : 0.0;

    offset = vec3(-shift, 0, 0);
    coord = lightModelMatrix * vec4(position + offset, 1.0);
    A = shadow2DProj(map_shadow, coord).r;
    R = coord.p / coord.q;
    shadowColor += (R <= A + 0.0002) ? 1.0 : 0.0;

    offset = vec3(0, -shift, 0);
    coord = lightModelMatrix * vec4(position + offset, 1.0);
    A = shadow2DProj(map_shadow, coord).r;
    R = coord.p / coord.q;
    shadowColor += (R <= A + 0.0002) ? 1.0 : 0.0;

    shaded = shadowColor / 5.0;

    //shaded *= 0.25;
    //shaded += 0.75;
    //shaded *= 0.5;
    //shaded += 0.5;
    //shaded *= 0.75;
    //shaded += 0.25;
    shaded *= 0.8;
    shaded += 0.2;
  }
  //gl_FragColor = vec4(brightness);

  vec3 fragColor = (base.rgb * lighted + specular) * shaded;
  
  float brightness = 0.9;
  
  fragColor.r *= 1.1;
  fragColor.g *= 1.03;
  fragColor.b *= 1.0;

  gl_FragData[0] = vec4(clamp(fragColor * brightness, 0.0, 1.0), 0.0);
  gl_FragData[1] = vec4(0);
}
