-- glslfx version 0.1

//
// Copyright 2016 Pixar
//
// Licensed under the Apache License, Version 2.0 (the "Apache License")
// with the following modification; you may not use this file except in
// compliance with the Apache License and the following modification to it:
// Section 6. Trademarks. is deleted and replaced with:
//
// 6. Trademarks. This License does not grant permission to use the trade
//    names, trademarks, service marks, or product names of the Licensor
//    and its affiliates, except as required to comply with Section 4(c) of
//    the License and to reproduce the content of the NOTICE file.
//
// You may obtain a copy of the Apache License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the Apache License with the above modification is
// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the Apache License for the specific
// language governing permissions and limitations under the Apache License.
//

-- configuration
{
    "techniques": {
        "default": {
            "vertexShader": {
                "source": [ "SimpleShadowMap.Vertex"]
            },
            "fragmentShader": {
                "source": [ "SimpleShadowMap.Fragment"]
            }
        }
    }
}

-- glsl SimpleShadowMap.Shadowing

#if NUM_LIGHTS > 0

#define SHADOW_SHADOWING

uniform bool useShadows;

uniform sampler2DArray shadowTexture;
uniform sampler2DArrayShadow shadowCompareTexture;

struct Shadow {
    mat4 eyeToShadowMatrix;
    vec4 basis[3];
    float bias;
};

uniform Shadow shadow[NUM_LIGHTS];

// shadowSample() returns depth value.
float
shadowSample(int index, vec4 coord)
{
    return texture(shadowTexture, vec3(coord.x/coord.w, coord.y/coord.w, index)).z;
}

// shadowCompare() returns filtered result of comparing shadow depth and coord.z
float
shadowCompare(int index, vec4 coord)
{
    return texture(shadowCompareTexture, vec4(coord.x/coord.w, coord.y/coord.w, index, coord.z));
}

#ifndef SHADOW_FILTER
float
shadowFilter(int index, vec4 coord, vec4 Peye)
{
    return shadowCompare(index, coord);
}
#endif

float
shadowing(int index, vec4 Peye)
{
    float result = 1.0;
    vec4 coord = shadow[index].eyeToShadowMatrix * Peye;

    // coord.xy : homogenius shadow uv coordinate
    // coord.z : cartisian receiver depth
    // coord.w : shadow projection w

    float dReceiver = coord.z/coord.w;
    coord.z = min(1, dReceiver + shadow[index].bias);
    return shadowFilter(index, coord, Peye);
}

#ifdef REQUIRE_SHADOW_FILTER_WIDTH
out vec2 FshadowFilterWidth[NUM_LIGHTS];
#define COMPUTE_SHADOW_FILTER_WIDTH(x) computeShadowFilterWidth(x)

void
computeShadowFilterWidth(vec4 Pworld)
{
    // interpolate filter width
    for (int i = 0; i < NUM_LIGHTS; ++i) {
        vec4 cx = shadow[i].basis[0];
        vec4 cy = shadow[i].basis[1];
        vec4 cz = shadow[i].basis[2];
        
        // compare homogeneous vector length
        vec3 x = cx.xyz - cx.w * Pworld.xyz;
        vec3 y = cy.xyz - cy.w * Pworld.xyz;
        vec3 z = cz.xyz - cz.w * Pworld.xyz;
        FshadowFilterWidth[i] = vec2(sqrt (1.0 / dot (x,x)), sqrt(1.0 / dot (y,y)));
//        FshadowFilterWidth[i] = vec2(sqrt (dot(z, z) / dot (x,x)), sqrt(dot(z,z) / dot (y,y)));
    }
}
#endif // REQUIRE_SHADOW_FILTER_WIDTH

#endif // NUM_LIGHTS > 0

-- glsl SimpleShadowMap.Vertex

in vec4 Pobj;
in vec3 Nobj;
in vec4 Cobj;

uniform mat4 objectToClipMatrix;

out vec4 Cout;

void
main()
{
    gl_Position = objectToClipMatrix * Pobj;
    Cout = Cobj;
}

-- glsl SimpleShadowMap.Fragment

in vec4 Cout;

void
main()
{
    gl_FragDepth = gl_FragCoord.z;
}
