/**
 * Copyright (C) 2014 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 fragshadow.glsl
 * @date 04/23/14
 */
#ifndef FRAGSHADOW_GLSL
#define FRAGSHADOW_GLSL

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

/**
 * @brief Determines the visibility of a fragment.
 *
 * @param coord A coordinate along the fragment-light ray.
 *              The x,y are in texture coordinates.
 *              The z is in normalized depth map values.
 * @param thickness The heuristic thickness of the potential occulder.
 * @param depthMap The depth buffer of the scene.
 * @param normalMap The normal buffer of the scene.
 * @return 1 is fully unocculded. 0 is completely occulded.
 */
float Visibility(in vec3 coord, in float thickness, in sampler2D depthMap, in sampler2D normalMap)
{
    const float NORMAL_EPSILON = 0.1;
    const float OCCULSION_EPSILON = 1.0 / 65536.0;

    float occulder = texture2D(depthMap, coord.xy).r;
    vec3 n = ColorToNormal(texture2D(normalMap, coord.xy).rgb);
    thickness *= step(NORMAL_EPSILON, n.z);

    float back = occulder + thickness;
    float behind = step(coord.z, occulder + OCCULSION_EPSILON);
    float ignore = step(back, coord.z);

    return behind + ignore;
}

/**
 * @brief Performs a shadow occulsion check.
 *
 * @param offsetDir The direction from the fragment toward the light.
 * @param fragCoord The current fragment texture coordinates (x,y) and depth value (z).
 * @param thickness The heuristic thickness of the potential occulder.
 * @param weights x: offsetDir factor. y: thickness factor. z: shadow strength (0 for lighter)
 * @param depthMap The depth buffer of the scene.
 * @param normalMap The normal buffer of the scene.
 * @return 1 is fully unocculded. 0 is completely occulded.
 */
float ShadowCheck(in vec3 offsetDir,
                  in vec3 fragCoord,
                  in float thickness,
                  in vec3 weights,
                  in sampler2D depthMap,
                  in sampler2D normalMap)
{
    vec3 tapLocation = offsetDir * weights.x + fragCoord;
    float visibility = Visibility(tapLocation, thickness * weights.y, depthMap, normalMap);

    return mix(1.0, visibility, weights.z);
}

#endif // FRAGSHADOW_GLSL
