-- glslfx version 0.1

//
// Copyright 2017 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/terminals.glslfx

--- --------------------------------------------------------------------------
-- glsl Geometry.CustomDisplacement

FORWARD_DECL(
    vec4 displacementShader(int index, vec4 Peye, vec3 Neye, vec4 patchCoord));

vec4 DisplacementTerminal(int index, vec4 Peye, vec3 Neye, vec4 patchCoord)
{
    return displacementShader(index, Peye, Neye, patchCoord);
}

--- --------------------------------------------------------------------------
-- glsl Geometry.NoCustomDisplacement

vec4 DisplacementTerminal(int index, vec4 Peye, vec3 Neye, vec4 patchCoord)
{
    return Peye;
}

--- --------------------------------------------------------------------------
-- glsl Fragment.CommonTerminals

struct ReprStyle
{
    vec4  color;
    bool  usePrimvarColor;
    bool  usePrimvarAlpha;
    bool  applyColorOverride;
    bool  useSurfaceShaderColor;
    bool  useSurfaceShaderAlpha;
};

struct ScalarOverride
{
    bool enabled;
    vec3 color;
};

FORWARD_DECL(ReprStyle GetReprStyle());
FORWARD_DECL(ScalarOverride GetScalarOverride());
FORWARD_DECL(
    vec4 surfaceShader(vec4 Peye, vec3 Neye, vec4 color, vec4 patchCoord));
FORWARD_DECL(vec4 postSurfaceShader(vec4 Peye, vec3 Neye, vec4 color));

vec4 ShadingTerminal(vec4 Peye, vec3 Neye, vec4 color, vec4 patchCoord)
{
    ReprStyle reprStyle = GetReprStyle();
    
    // Apply scalar override.
    ScalarOverride scalarOverride = GetScalarOverride();
    if (scalarOverride.enabled) {
        vec4 result;
        
        result.rgb = scalarOverride.color;
        result.a   = reprStyle.usePrimvarAlpha ? color.a: reprStyle.color.a;

        vec4 colorOverride = ApplyColorOverrides(result);
        result = reprStyle.applyColorOverride ? colorOverride : result;

        return result;
    }

    // Draw mode can override face color
    vec4 reprColor;
    
    reprColor.rgb = reprStyle.usePrimvarColor ? color.rgb : reprStyle.color.rgb;
    reprColor.a   = reprStyle.usePrimvarAlpha ? color.a   : reprStyle.color.a; 

    // Compute color overrides
    vec4 colorOverride = ApplyColorOverrides(reprColor);
    reprColor = reprStyle.applyColorOverride ? colorOverride : reprColor;
    

    // Surface shading can be expensive and also can contain undesirable
    // side effects (like discards).  So only run it for reprs that require it.

    if (reprStyle.useSurfaceShaderColor ||
        reprStyle.useSurfaceShaderAlpha) {
        vec4 shadingColor;

        shadingColor = surfaceShader(Peye,
                                     Neye,
                                     reprColor,
                                     patchCoord);

#ifdef HD_HAS_postSurfaceShader
        shadingColor = postSurfaceShader(Peye,
                                         Neye,
                                         shadingColor);
#endif
    
        reprColor.rgb = reprStyle.useSurfaceShaderColor ? 
                        shadingColor.rgb :
                        reprColor.rgb;
                        
        reprColor.a   = reprStyle.useSurfaceShaderAlpha ? 
                        shadingColor.a :
                        reprColor.a;
    }

    vec4 baseColor = color;
    baseColor = ApplyColorOverrides(baseColor);
    
    vec4 litColor = mix(baseColor,
                        reprColor,
                        GetLightingBlendAmount());

    // Final overrides.

    return ApplyColorOverridesPostLighting(litColor); 
}

--- --------------------------------------------------------------------------
-- glsl Fragment.Surface

#ifdef HD_HAS_integrateLights
#ifndef HD_HAS_definedIntegrateLights
#define HD_HAS_definedIntegrateLights

LightingContribution
integrateLights(vec4 Peye, vec3 Neye, LightingInterfaceProperties props)
{
    return integrateLightsDefault(Peye, Neye, props);
}

#endif // HD_HAS_definedIntegrateLights
#endif

ReprStyle GetReprStyle()
{
    ReprStyle reprStyle;
    
    reprStyle.color                    = vec4(0.0, 0.0, 0.0, 1.0);
    reprStyle.usePrimvarColor          = true;
    reprStyle.usePrimvarAlpha          = true;
    reprStyle.applyColorOverride       = true;
    reprStyle.useSurfaceShaderColor    = true;
    reprStyle.useSurfaceShaderAlpha    = true;
    
    return reprStyle; 
}

--- --------------------------------------------------------------------------
-- glsl Fragment.SurfaceUnlit

#ifdef HD_HAS_integrateLights
#ifndef HD_HAS_definedIntegrateLights
#define HD_HAS_definedIntegrateLights

LightingContribution
integrateLights(vec4 Peye, vec3 Neye, LightingInterfaceProperties props)
{
    return integrateLightsConstant(Peye, Neye, props);
}

#endif // HD_HAS_definedIntegrateLights
#endif

ReprStyle GetReprStyle()
{
    ReprStyle reprStyle;
    
    reprStyle.color                    = vec4(0.0, 0.0, 0.0, 1.0);
    reprStyle.usePrimvarColor          = true;
    reprStyle.usePrimvarAlpha          = true;
    reprStyle.applyColorOverride       = true;
    reprStyle.useSurfaceShaderColor    = true;
    reprStyle.useSurfaceShaderAlpha    = true;
    
    return reprStyle; 
}

--- --------------------------------------------------------------------------
-- glsl Fragment.SurfaceSheer

#ifdef HD_HAS_integrateLights
#ifndef HD_HAS_definedIntegrateLights
#define HD_HAS_definedIntegrateLights

LightingContribution
integrateLights(vec4 Peye, vec3 Neye, LightingInterfaceProperties props)
{
    return integrateLightsConstant(Peye, Neye, props);
}

#endif // HD_HAS_definedIntegrateLights
#endif

ReprStyle GetReprStyle()
{
    // shade only every 2nd pixel in x and y
    // creating a thin stippled mesh grid 
    float factor = step(0.5, fract((gl_FragCoord.x + 1.0) * 0.5))
                 * step(0.5, fract((gl_FragCoord.y + 0.0) * 0.5));
    
    // make the surface translucent so that the lines of
    // the mesh edges are visible even from the back faces.
    float alpha = 0.2 * (1.0 - factor);


    ReprStyle reprStyle;
    
    reprStyle.color                    = vec4(0.0, 0.0, 0.0, alpha);
    reprStyle.usePrimvarColor          = true;
    reprStyle.usePrimvarAlpha          = false;
    reprStyle.applyColorOverride       = true;
    reprStyle.useSurfaceShaderColor    = true;
    reprStyle.useSurfaceShaderAlpha    = false;
    
    return reprStyle; 
}

--- --------------------------------------------------------------------------
-- glsl Fragment.SurfaceOutline

#ifdef HD_HAS_integrateLights
#ifndef HD_HAS_definedIntegrateLights
#define HD_HAS_definedIntegrateLights

LightingContribution
integrateLights(vec4 Peye, vec3 Neye, LightingInterfaceProperties props)
{
    return integrateLightsConstant(Peye, Neye, props);
}

#endif // HD_HAS_definedIntegrateLights
#endif

ReprStyle GetReprStyle()
{
    ReprStyle reprStyle;
    
    reprStyle.color                    = vec4(0.0, 0.0, 0.0, 1.0);
    reprStyle.usePrimvarColor          = false;
    reprStyle.usePrimvarAlpha          = false;
    reprStyle.applyColorOverride       = false;
    reprStyle.useSurfaceShaderColor    = false;
    reprStyle.useSurfaceShaderAlpha    = false;
    
    return reprStyle; 
}

--- --------------------------------------------------------------------------
-- glsl Fragment.ConstantColor

#ifdef HD_HAS_integrateLights
#ifndef HD_HAS_definedIntegrateLights
#define HD_HAS_definedIntegrateLights

LightingContribution
integrateLights(vec4 Peye, vec3 Neye, LightingInterfaceProperties props)
{
    return integrateLightsConstant(Peye, Neye, props);
}

#endif // HD_HAS_definedIntegrateLights
#endif

ReprStyle GetReprStyle()
{
    ReprStyle reprStyle;
    
    reprStyle.color                    = vec4(0.0, 0.0, 0.0, 1.0);
    reprStyle.usePrimvarColor          = true;
    reprStyle.usePrimvarAlpha          = true;
    reprStyle.applyColorOverride       = true;
    reprStyle.useSurfaceShaderColor    = false;
    reprStyle.useSurfaceShaderAlpha    = false;

    return reprStyle; 
}

--- --------------------------------------------------------------------------
-- glsl Fragment.HullColor

#ifdef HD_HAS_integrateLights
#ifndef HD_HAS_definedIntegrateLights
#define HD_HAS_definedIntegrateLights

LightingContribution
integrateLights(vec4 Peye, vec3 Neye, LightingInterfaceProperties props)
{
    return integrateLightsConstant(Peye, Neye, props);
}

#endif // HD_HAS_definedIntegrateLights
#endif

ReprStyle GetReprStyle()
{
    vec4 hullColor = vec4(vec3(0.18), 1.0);

#if defined(HD_HAS_selectedWeight)
    float weight = clamp(HdGet_selectedWeight(), 0.0, 1.0);

    if (weight <= 0.0) {
        discard;
    }

    // The three control points of the quadratic curve for the selection color
    // with the binomial coefficient premultiplied in.
    // constant  :      1
    // linear    :    1   1
    // quadratic :  1   2   1
    vec3 c0 = vec3(0.0, 0.0, 0.0); // 1.0 * Black
    vec3 c1 = vec3(2.0, 0.0, 0.0); // 2.0 * Red
    vec3 c2 = vec3(1.0, 1.0, 0.0); // 1.0 * Yellow
    
    // de Casteljau quadratic curve interpolation
    // A recursive application of lerp ('mix' in glsl) reducing the order each
    // step of the recursion. 
    //  at weight = 0.0  we get c0
    //  at weight = 0.5  we get c0 * .25 + c1 * 0.5 + c2 *.25
    //  at weight = 1.0  we get c2
    // Thus it is a smooth curve going from c0 to c2 bending towards c1
    hullColor.rgb = mix(mix(c0, c1, weight),
                        mix(c1, c2, weight), weight);

#else
#if defined(HD_HAS_hullColor)
    hullColor.rgb = HdGet_hullColor();
#endif
#if defined(HD_HAS_hullOpacity)
    hullColor.a = HdGet_hullOpacity();
#endif
#endif

    ReprStyle reprStyle;
    
    reprStyle.color                    = hullColor;
    reprStyle.usePrimvarColor          = false;
    reprStyle.usePrimvarAlpha          = false;
    reprStyle.applyColorOverride       = true;
    reprStyle.useSurfaceShaderColor    = false;
    reprStyle.useSurfaceShaderAlpha    = false;
    
    return reprStyle;
}

--- --------------------------------------------------------------------------
-- glsl Fragment.PointColor

#ifdef HD_HAS_integrateLights
#ifndef HD_HAS_definedIntegrateLights
#define HD_HAS_definedIntegrateLights

LightingContribution
integrateLights(vec4 Peye, vec3 Neye, LightingInterfaceProperties props)
{
    return integrateLightsConstant(Peye, Neye, props);
}

#endif // HD_HAS_definedIntegrateLights
#endif

ReprStyle GetReprStyle()
{
    vec4 pointColor = vec4(vec3(0.18), 1.0);
#if defined(HD_HAS_pointColor)
    pointColor = HdGet_pointColor();
#endif

    ReprStyle reprStyle;
    
    reprStyle.color                    = pointColor;
    reprStyle.usePrimvarColor          = false;
    reprStyle.usePrimvarAlpha          = false;
    reprStyle.applyColorOverride       = true;
    reprStyle.useSurfaceShaderColor    = false;
    reprStyle.useSurfaceShaderAlpha    = false;
    
    return reprStyle; 
}

--- --------------------------------------------------------------------------
-- glsl Fragment.PointShaded

ReprStyle GetReprStyle()
{
    vec4 pointColor = vec4(vec3(0.18), 1.0);
#if defined(HD_HAS_pointColor)
    pointColor = HdGet_pointColor();
#endif

    ReprStyle reprStyle;
    
    reprStyle.color                    = pointColor;
    reprStyle.usePrimvarColor          = false;
    reprStyle.usePrimvarAlpha          = false;
    reprStyle.applyColorOverride       = true;
    reprStyle.useSurfaceShaderColor    = true;
    reprStyle.useSurfaceShaderAlpha    = true;
    
    return reprStyle; 
}

--- --------------------------------------------------------------------------
-- glsl Fragment.ScalarOverride

ScalarOverride GetScalarOverride()
{
    ScalarOverride result;

#if defined(HD_HAS_scalarOverride)
    result.enabled = true;

    // Allow a scalar value to override the color from the surface
    // for previewing heatmaps. This is useful for editing workflows.
#if defined(HD_HAS_scalarOverrideColorRamp)
    int rampCount = constantPrimvars[GetDrawingCoord().constantCoord].
                scalarOverrideColorRamp.length();
    float scalar = HdGet_scalarOverride() * float(rampCount - 1);
    float baseIndex = floor(scalar);
    float nextIndex = min(float(rampCount - 1), baseIndex + 1.0);
    float interp = scalar - baseIndex;
    result.color = mix(HdGet_scalarOverrideColorRamp(int(baseIndex)).rgb,
                       HdGet_scalarOverrideColorRamp(int(nextIndex)).rgb,
                       interp);
#else
    // If no ramp is given just gamma correct the scalar as greyscale.
    result.color = vec3(pow(HdGet_scalarOverride(), 2.2));
#endif // HD_HAS_scalarOverrideColorRamp

#else // HD_HAS_scalarOverride
    result.enabled = false;
    result.color   = vec3(0.0, 0.0, 0.0); 
#endif

    return result;
}

--- --------------------------------------------------------------------------
-- glsl Fragment.NoScalarOverride

ScalarOverride GetScalarOverride()
{
    ScalarOverride result;
    
    result.enabled = false;
    result.color   = vec3(0.0, 0.0, 0.0); 

    return result;    
}
