#version 120

uniform vec2 fg_BufferSize;
uniform vec3 fg_Planes;

uniform sampler2D depth_tex;
uniform sampler2D normal_tex;
uniform sampler2D color_tex;
uniform sampler2D spec_emis_tex;
uniform vec4 LightPosition;
uniform vec4 LightDirection;
uniform vec4 Ambient;
uniform vec4 Diffuse;
uniform vec4 Specular;
uniform vec3 Attenuation;
uniform float Exponent;
uniform float Cutoff;
uniform float CosCutoff;
uniform float Near;
uniform float Far;

varying vec4 ecPosition;

vec3 position( vec3 viewDir, vec2 coords, sampler2D depth_tex );
vec3 normal_decode(vec2 enc);

void main() {
    vec3 ray = ecPosition.xyz / ecPosition.w;
    vec3 ecPos3 = ray;
    vec3 viewDir = normalize(ray);
    vec2 coords = gl_FragCoord.xy / fg_BufferSize;

    vec3 normal = normal_decode(texture2D( normal_tex, coords ).rg);
    vec4 spec_emis = texture2D( spec_emis_tex, coords );

    vec3 pos = position(viewDir, coords, depth_tex);

    if ( pos.z < ecPos3.z ) // Negative direction in z
        discard; // Don't light surface outside the light volume

    vec3 VP = LightPosition.xyz - pos;
    if ( dot( VP, VP ) > ( Far * Far ) )
        discard; // Don't light surface outside the light volume

    float d = length( VP );
    VP /= d;

    vec3 halfVector = normalize(VP - viewDir);

    float att = 1.0 / (Attenuation.x + Attenuation.y * d + Attenuation.z *d*d);
    float spotDot = dot(-VP, normalize(LightDirection.xyz));

    float spotAttenuation = 0.0;
    if (spotDot < CosCutoff)
        spotAttenuation = 0.0;
    else
        spotAttenuation = pow(spotDot, Exponent);
    att *= spotAttenuation;

    float cosAngIncidence = clamp(dot(normal, VP), 0.0, 1.0);

    float nDotVP = max(0.0, dot(normal, VP));
    float nDotHV = max(0.0, dot(normal, halfVector));

    vec4 color_material = texture2D( color_tex, coords );
    vec3 color = color_material.rgb;
    vec3 Iamb = Ambient.rgb * color * att;
    vec3 Idiff = Diffuse.rgb * color * att * nDotVP;

    float matID = color_material.a * 255.0;
    float spec_intensity = spec_emis.x;
    float spec_att = att;
    if (matID == 254.0) { // 254: water, 255: Ubershader
        spec_intensity = 1.0; // spec_color shouldn't depend on cloud cover when rendering spot light
        spec_att = min(10.0 * att, 1.0); // specular attenuation reduced on water
    }

    vec3 Ispec = vec3(0.0);
    if (cosAngIncidence > 0.0)
        Ispec = pow( nDotHV, spec_emis.y * 128.0 ) * spec_intensity * spec_att * Specular.rgb;

    if (matID >= 254.0)
        Idiff += Ispec * spec_emis.x;

    gl_FragColor = vec4(Iamb + Idiff + Ispec, 1.0);
}