/**
 * Copyright (C) 2013 Stellar Jockeys.
 * All Rights Reserved.
 *
 * NOTICE: All information contained herein is, and remains the property of
 * Stellar Jockeys and its suppliers, if any.  The intellectual and technical
 * concepts contained herein are proprietary to Stellar Jockeys and its suppliers.
 * Dissemination of this information or reproduction of this material is
 * strictly forbidden unless prior written permission is obtained from
 * Stellar Jockeys.
 *
 * @file fraglightdirectional.glsl
 * @date 07/25/13
 */
#ifndef FRAGLIGHTDIRECTIONAL_GLSL
#define FRAGLIGHTDIRECTIONAL_GLSL

#ifndef FRAGNORMAL_GLSL
#error fragnormal.glsl should be included
#endif

#ifndef FRAGMATERIAL_GLSL
#error fragmaterial.glsl should be included
#endif

#ifdef FRAGSHADOW_GLSL
float Shadowing(in float depth)
{
    const int SAMPLES = 10;
    vec3 WEIGHTS[SAMPLES] = vec3[](vec3(0.25, 0.7, 1.0),
                                   vec3(0.50, 0.8, 1.0),
                                   vec3(0.75, 0.8, 1.0),
                                   vec3(1.00, 0.8, 1.0),
                                   vec3(1.25, 0.8, 1.0),
                                   vec3(1.50, 0.8, 1.0),
                                   vec3(1.75, 0.8, 1.0),
                                   vec3(2.00, 2.0, 0.9),
                                   vec3(2.25, 2.0, 0.8),
                                   vec3(2.50, 0.8, 0.7));

    vec3 offsetDir = uLightDirection * uProjectionScale * 0.5;
    vec3 fragCoord = vec3(vTextureCoord, depth);
    float thickness = -uProjectionScale.z;
    float shadowing = 1.0;

    for (int index = 0; index < SAMPLES; ++index)
    {
        float check = ShadowCheck(offsetDir, fragCoord, thickness, WEIGHTS[index], uDepth, uNormals);
        shadowing = min(shadowing, check);
    }

    return shadowing;
}
#endif // FRAGSHADOW_GLSL

void main()
{
    vec4 albedo = texture2D(uDiffuse, vTextureCoord);

    if (albedo.a < (1.0 / 255.0))
    {
        discard;
    }

    vec4 material = texture2D(uMaterial, vTextureCoord);
    float fresnel = UnpackFresnel(material);
    float specExp = UnpackSpecularExponent(material);

    gl_FragDepth = texture2D(uDepth, vTextureCoord).r;
    vec3 n = ColorToNormal(texture2D(uNormals, vTextureCoord).rgb);

    float shading = max(dot(uLightDirection, n), 0.0) * uLightColor.a;
    float specular = Specularity(n, uHalfVector, specExp, fresnel);

    // EXPERIMENTAL: auto dim light at it approaches the horizon
    float attenuation = max(dot(uLightDirection, vec3(0.0, 0.866, 0.5)), 0.0);
    shading *= attenuation * AUTO_DIM + (1.0 - AUTO_DIM);

#ifdef FRAGSHADOW_GLSL
    shading *= Shadowing(gl_FragDepth);
#endif

    vec3 directionalLighting = (albedo.rgb * uDiffuseAmount + specular);
    directionalLighting *= (shading * uLightIntensity) * uLightColor.rgb;

    albedo.rgb = albedo.rgb * (uAmbient.rgb * uAmbient.a) + directionalLighting;
    gl_FragData[0] = vec4(albedo.rgb * albedo.a, dot(albedo.rgb, DESATURATE));
}

#endif // FRAGLIGHTDIRECTIONAL_GLSL
