//**************************************************************************/
// Copyright (c) 2007 Autodesk, Inc.
// All rights reserved.
// 
// These coded instructions, statements, and computer programs contain
// unpublished proprietary information written by Autodesk, Inc., and are
// protected by Federal copyright law. They may not be disclosed to third
// parties or copied or duplicated in any form, in whole or in part, without
// the prior written consent of Autodesk, Inc.
//**************************************************************************/
// DESCRIPTION: Shadow map utilities (D3D10).
// AUTHOR: Mauricio Vives
// CREATED: December 2007
//**************************************************************************/

#ifndef _SHADOWMAP_FXH_
#define _SHADOWMAP_FXH_

// Shadow map texture.
Texture2D gShadowMapTex : ShadowMap
<
    string UIName = "Shadow Map";
> = NULL;

// Shadow map sampler.
SamplerState gShadowMapSamp : ShadowMapSampler;

// Shadow map size.
int gShadowMapSize : ShadowMapSize
<
    string UIName = "Shadow Map Size";
>
= 512;

// Shadow map transformation, i.e. the view-projection transformation of the light.
float4x4 gShadowMapXf : ShadowMapXForm
<
    string UIName = "Shadow Map Transformation";
>;

// Precompute the size of a texel in texel space.
static float gTexelSize = 1.0f / gShadowMapSize;

// Shadow map bias.
float gShadowMapBias : ShadowMapBias
<
    string UIName = "Shadow Map Bias";
>
= 0.00005f;

// Shadow Density
float  gShadowDensity    : shadow_density
<
	string UIName = "Shadow Density";
>
= 0.8f;

// Function to sample the shadow map and return the effective shadow factor, where 0.0 is fully
// shadowed and 1.0 is fully lit.
float SampleShadowMap(float4 Pl)
{
    // Perform sampling for points inside the NDC box.  Percentage closest filtering is used to
    // smooth the result at shadow-light boundaries.  Points outside are treated as not in shadow.
    // The normalized version of the sample point is used for the rest of this function.
    float result = 1.0f;
    float3 Pndc = Pl / Pl.w;
    if (Pndc.x > -1.0f && Pndc.x < 1.0f && Pndc.y > -1.0f && Pndc.y < 1.0f &&
        Pndc.z >  0.0f && Pndc.z < 1.0f)
    {
        // Compute the texture coordinates for shadow map sampling based on the sample point.  Since
        // the point is in the light's space, the x and y components of the point map to the UV
        // texture coordinates.  They must be mapped from the range [-1.0, 1.0] to [0.0, 1.0], and
        // the v component must be flipped, i.e. v == 0.0 is at the top of the texture.
        float2 texCoords = 0.5f * float2(Pndc.x, Pndc.y) + float2(0.5f, 0.5f);
        texCoords.y = 1.0f - texCoords.y;
        
        // Sample the texture from computed location and three adjacent texels: down, right, and
        // diagonal.  Each texel's r component is the depth in the shadow map.  Record whether the
        // depth of the current sample point is greater than this depth (in shadow, 0.0) or less
        // (fully lit, 1.0).  Use the shadow bias to avoid a surface shadowing itself.
        float4 factors;
        factors.x = gShadowMapTex.Sample(gShadowMapSamp,
            texCoords                                 ).r + gShadowMapBias < Pndc.z ? 0.0f : 1.0f;
        factors.y = gShadowMapTex.Sample(gShadowMapSamp,
            texCoords + float2(gTexelSize, 0.0f)      ).r + gShadowMapBias < Pndc.z ? 0.0f : 1.0f;
        factors.z = gShadowMapTex.Sample(gShadowMapSamp,
            texCoords + float2(0.0f, gTexelSize)      ).r + gShadowMapBias < Pndc.z ? 0.0f : 1.0f;
        factors.w = gShadowMapTex.Sample(gShadowMapSamp,
            texCoords + float2(gTexelSize, gTexelSize)).r + gShadowMapBias < Pndc.z ? 0.0f : 1.0f;
        
        // Determine the 2D location of the sample point as a fraction of the current texel, e.g.
        // (0.5, 0.5) is the middle of the texel.
        float2 texPoint = frac(gShadowMapSize * texCoords);
        
        // Use the texel location of the sample point to linearly interpolate between the shadow
        // factors, and use that as the final shadow factor.  This performs bilinear interpolation
        // (four samples, three lerps).
        result = lerp(
            lerp(factors.x, factors.y, texPoint.x),
            lerp(factors.z, factors.w, texPoint.x),
            texPoint.y);
        
        // An alternative is to use the average of the four factors as the final shadow factor
        // result = dot(factors, factors) * 0.25;
    }

    return result;
}

#endif // _SHADOWMAP_FXH_
