-- 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.
//

--- This is what an import might look like.
--- #import $TOOLS/hdSt/shaders/meshNormal.glslfx


--- --------------------------------------------------------------------------
-- glsl MeshNormal.Scene

vec3 GetNormal(vec3 Neye, int index)
{
    vec3 normal = vec3(0);
#if defined(HD_HAS_normals)
    normal = vec3(HdGet_normals(index).xyz);
#endif

    MAT4 transformInv = ApplyInstanceTransformInverse(HdGet_transformInverse());
    normal = vec4(transpose(transformInv * GetWorldToViewInverseMatrix()) *
                  vec4(normal,0)).xyz;

    if (length(normal) > 0.0)
        normal = normalize(normal);
    return normal;
}

vec3 GetNormal(vec3 Neye, int index, vec2 localST)
{
    return GetNormal(Neye, index);
}

--- --------------------------------------------------------------------------
-- glsl MeshNormal.Scene.Patches

vec3 GetNormal(vec3 Neye, int index, vec2 localST)
{
    vec3 normal = vec3(0);
#if defined(HD_HAS_normals)
    normal = vec3(HdGet_normals(index, localST).xyz);
#endif

    MAT4 transformInv = ApplyInstanceTransformInverse(HdGet_transformInverse());
    normal = vec4(transpose(transformInv * GetWorldToViewInverseMatrix()) *
                  vec4(normal,0)).xyz;

    if (length(normal) > 0.0)
        normal = normalize(normal);
    return normal;
}

--- --------------------------------------------------------------------------
-- glsl MeshNormal.Smooth

vec3 GetNormal(vec3 Neye, int index)
{
    vec3 normal = vec3(0);
#if defined(HD_HAS_smoothNormals)
    normal = vec3(HdGet_smoothNormals(index).xyz);
#elif defined(HD_HAS_packedSmoothNormals)
    normal = vec3(HdGet_packedSmoothNormals(index).xyz);
#endif

    MAT4 transformInv = ApplyInstanceTransformInverse(HdGet_transformInverse());
    normal = vec4(transpose(transformInv * GetWorldToViewInverseMatrix()) *
                  vec4(normal,0)).xyz;

    if (length(normal) > 0.0)
        normal = normalize(normal);
    return normal;
}

vec3 GetNormal(vec3 Neye, int index, vec2 localST)
{
    return GetNormal(Neye, index);
}

--- --------------------------------------------------------------------------
-- glsl MeshNormal.Flat

vec3 GetNormal(vec3 Neye, int index)
{
    vec3 normal = vec3(0);
#if defined(HD_HAS_flatNormals)
    normal = vec3(HdGet_flatNormals(index).xyz);
#elif defined(HD_HAS_packedFlatNormals)
    normal = vec3(HdGet_packedFlatNormals(index).xyz);
#endif

    MAT4 transformInv = ApplyInstanceTransformInverse(HdGet_transformInverse());
    normal = vec4(transpose(transformInv * GetWorldToViewInverseMatrix()) *
                  vec4(normal,0)).xyz;

    if (length(normal) > 0.0)
        normal = normalize(normal);
    return normal;
}

vec3 GetNormal(vec3 Neye, int index, vec2 localST)
{
    return GetNormal(Neye, index);
}

--- --------------------------------------------------------------------------
-- glsl MeshNormal.Fragment.ScreenSpace

FORWARD_DECL(vec3 ComputeScreenSpaceNeye());

vec3 GetNormal(vec3 Neye, int index)
{
    return ComputeScreenSpaceNeye();
}

vec3 GetNormal(vec3 Neye, int index, vec2 localST)
{
    return GetNormal(Neye, index);
}

--- --------------------------------------------------------------------------
-- glsl MeshNormal.Pass

vec3 GetNormal(vec3 Neye, int index)
{
    return Neye;
}

vec3 GetNormal(vec3 Neye, int index, vec2 localST)
{
    return GetNormal(Neye, index);
}

--- --------------------------------------------------------------------------
-- glsl MeshNormal.Geometry.Flat

vec3 GetTriGeometryNormal(vec3 Neye, vec4 Peye0, vec4 Peye1, vec4 Peye2,
                          bool isFlipped)
{
    // ignore vertex normal and compute flat facing normal
    vec3 n = normalize(cross(Peye1.xyz - Peye0.xyz, Peye2.xyz - Peye0.xyz));
    return isFlipped ? -n : n;
}

vec3 GetQuadGeometryNormal(vec3 Neye,
                           vec4 Peye0, vec4 Peye1, vec4 Peye2, vec4 Peye3,
                           bool isFlipped)
{
    //  0---3
    //  |.  |
    //  | . |
    //  |  .|
    //  1---2
    // ignore vertex normal and compute flat facing normal
    // average diagonal cross products to deal with co-linear edges
    vec3 A0 = Peye2.xyz - Peye3.xyz;
    vec3 B0 = Peye0.xyz - Peye3.xyz;
    vec3 A1 = Peye0.xyz - Peye1.xyz;
    vec3 B1 = Peye2.xyz - Peye1.xyz;
    vec3 n = normalize(cross(B0, A0) + cross(B1, A1));
    return isFlipped ? -n : n;
}

--- --------------------------------------------------------------------------
-- glsl MeshNormal.Geometry.NoFlat

vec3 GetTriGeometryNormal(vec3 Neye, vec4 Peye0, vec4 Peye1, vec4 Peye2,
                          bool isFlipped)
{
    return Neye;
}

vec3 GetQuadGeometryNormal(vec3 Neye,
                           vec4 Peye0, vec4 Peye1, vec4 Peye2, vec4 Peye3,
                           bool isFlipped)
{
    return Neye;
}

--- --------------------------------------------------------------------------
-- glsl MeshNormal.Fragment.SingleSided

vec3 GetShadingNormal(vec3 N, bool isFlipped)
{
    // the fragment shader takes already-flipped-normals.
    // no need to flip here.
    return N;
}

--- --------------------------------------------------------------------------
-- glsl MeshNormal.Fragment.DoubleSided

vec3 GetShadingNormal(vec3 N, bool isFlipped)
{
    // note that negative scaling isn't taken into account in gl_FrontFacing
    // so we have to consider isFlipped here too.
    return (isFlipped != gl_FrontFacing) ? N : -N;
}
