#version 330 core

in vec2 UV;
uniform sampler2D colors;
uniform sampler2D normals;
uniform sampler2D ssao;
uniform sampler2D depth;
uniform mat4 projection; // should be viewprojection
uniform mat4 depthMVP;
uniform vec3 lightpos;
uniform vec3 lightdir;
uniform float lightAngle;
uniform float lightIntensity;
uniform float volubias;
uniform float time;
uniform float SHADOWVAL;
uniform vec3 eyepos;
uniform sampler2D shadowMap;

const float ambientCoeff = 1.0;
const float diffuCoeff = 0.5;
const float specuCoeff = 1.4;

// outputz
out vec4 color;


// Transform UV from location texture to (x, y, z) world coordinates
vec3 getPos(vec2 uv) {
  float z = 2.0 * texture(depth, uv).x - 1.0;
  vec4 clipSpace = vec4(2.0*UV-1.0, z, 1.0);
  vec4 homogLoc = inverse(projection) * clipSpace;
  return homogLoc.xyz / homogLoc.w;
}

float rand(vec2 co){
  return fract(sin(dot(co.xy ,vec2(12.9898,78.233))) * 43758.5453);
}

float visibility(vec4 lightCoord, vec3 pixpos) {
    //const float SHADOWVAL = 0.1;

    // Shadowed crap
    if (texture(shadowMap, lightCoord.xy / lightCoord.w).z < (lightCoord.z - 1e-4) / lightCoord.w) {
        return SHADOWVAL;
    }

    // Out of spot light
    vec3 lp = pixpos - lightpos;
    float angle = acos(dot(lp, lightdir) / (length(lp) * length(lightdir))) * 180.0 / 3.141;
    if (angle >= lightAngle) {
        return SHADOWVAL;
    }
    return 1.0;
}

float volumetricVisibility(vec3 pixpos) {
    const float NSAMPLES = 64.0;
    float v = 0.0;
    for (float idx = 0.0; idx < NSAMPLES; idx += 1.0) {
        // Generate random point
        float rnd = max(volubias, rand(UV + vec2(idx, time) + pixpos.yx));
        vec3 pos = eyepos + rnd * (pixpos - eyepos);

        // Compute visibility & cumulate
        v += visibility(depthMVP * vec4(pos, 1.0), pos);
    }
    return v / NSAMPLES;
}

void main() {
    vec3 pixpos = getPos(UV);
    color.xyz = vec3(volumetricVisibility(pixpos));
    color.a = 1.0;
}
