#version 330 core

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

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 G1V ( float dotNV, float k ) {
    return 1.0 / (dotNV*(1.0 - k) + k);
}

vec3 computePBRLighting ( in vec3 lightpos, in vec3 lightcolor, in vec3 position, in vec3 N, in vec3 V, in vec3 albedo, in float roughness, in vec3 F0 ) {
// https://www.shadertoy.com/view/MlB3DV
    float alpha = roughness*roughness;
    vec3 L = normalize(lightpos - position);
    vec3 H = normalize (V + L);

    float dotNL = clamp (dot (N, L), 0.0, 1.0);
    float dotNV = clamp (dot (N, V), 0.0, 1.0);
    float dotNH = clamp (dot (N, H), 0.0, 1.0);
    float dotLH = clamp (dot (L, H), 0.0, 1.0);

    float D, vis;
    vec3 F;

    // NDF : GGX
    float alphaSqr = alpha*alpha;
    float pi = 3.1415926535;
    float denom = dotNH * dotNH *(alphaSqr - 1.0) + 1.0;
    D = alphaSqr / (pi * denom * denom);

    // Fresnel (Schlick)
    float dotLH5 = pow (1.0 - dotLH, 5.0);
    F = F0 + (1.0 - F0)*(dotLH5);

    // Visibility term (G) : Smith with Schlick's approximation
    float k = alpha / 2.0;
    vis = G1V (dotNL, k) * G1V (dotNV, k);

    vec3 specular = /*dotNL **/ D * F * vis;

    vec3 ambient = albedo; // was vec3(0.1) or something like that

    float invPi = 0.31830988618;
    vec3 diffuse = (albedo * invPi);


    return ambient + (diffuse + specular) * lightcolor * dotNL ;
}

void main() {
    // Extract data from helper buffers
    vec4 cAmbient = vec4(texture(ssao, UV).rgb * texture(colors, UV).rgb, 1.0);  // Ambient color
    vec4 normalData = texture(normals, UV);                                      // Surface normal

    // Lambertian light stuff
    vec3 normal = normalize(texture(normals, UV).xyz);
    vec3 pixpos = getPos(UV);
    vec3 lightdir = normalize(pixpos - lightpos);
    float lambertTerm = max(0.0, dot(normal, lightdir));
    vec4 cLambert = vec4(lambertTerm * vec3(0.9, 1.0, 1.0), 1.0);

    // Specular term
    vec4 cSpecular = vec4(0.0);

    // Visibility calculation
    vec4 lightCoord = depthMVP * vec4(pixpos, 1.0);
    vec2 pixUV = lightCoord.xy / lightCoord.w;
    float visib = texture(volushadows, UV).x;

    // Light fusion
    color = visib * (ambientCoeff * cAmbient
          + visib * (
              diffuCoeff * cLambert
            + specuCoeff * cSpecular
            ));
    float metalMask = 0.5;
    vec3 baseColor = cAmbient.xyz;
    vec4 rd = texture(refls, UV);
    color.xyz = visib * computePBRLighting(lightpos, vec3(1), pixpos, normal, normalize(eyepos - pixpos), baseColor, 0.7, baseColor*metalMask );
    //color.xyz += visib * texture(colors, rd.xy).xyz * exp(-0.5 * rd.z);
    color.a = 1.0;
}
