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

-- glsl RenderPass.Camera

// ---------------------------------------------------------------------------
// global defines
// ---------------------------------------------------------------------------
// codeGen can override this range (currently not).
// quadro 4000's max is 189.
#ifndef HD_GL_POINT_SIZE_MAX
#define HD_GL_POINT_SIZE_MAX  100.0
#endif
#ifndef HD_GL_POINT_SIZE_MIN
#define HD_GL_POINT_SIZE_MIN  .45
#endif

// ---------------------------------------------------------------------------
// render pass states
// ---------------------------------------------------------------------------

MAT4  GetWorldToViewMatrix() {
#if defined(HD_HAS_worldToViewMatrix)
    return MAT4(HdGet_worldToViewMatrix());
#else
    return MAT4(1);
#endif
}
MAT4  GetWorldToViewInverseMatrix() {
#if defined(HD_HAS_worldToViewInverseMatrix)
    return MAT4(HdGet_worldToViewInverseMatrix());
#else
    return MAT4(1);
#endif
}
MAT4  GetProjectionMatrix() {
#if defined(HD_HAS_projectionMatrix)
    return MAT4(HdGet_projectionMatrix());
#else
    return MAT4(1);
#endif
}
vec3 GetPositionInWorldSpace(vec3 windowRelativeCoord)
{
#if defined(HD_HAS_imageToWorldMatrix)
    vec4 pImage = vec4(windowRelativeCoord, 1.0);
    vec4 pWorld = vec4(HdGet_imageToWorldMatrix() * pImage);
    return (pWorld / pWorld.w).xyz;
#else
    return windowRelativeCoord;
#endif
}
float GetLightingBlendAmount() {
#if defined(HD_HAS_lightingBlendAmount)
    return HdGet_lightingBlendAmount();
#else
    return 1;
#endif
}
vec4  GetViewport() {
#if defined(HD_HAS_viewport)
    return HdGet_viewport();
#else
    return vec4(0,0,1,1);
#endif
}
float GetTessLevel() {
#if defined(HD_HAS_tessLevel)
    return HdGet_tessLevel();
#else
    return 1;
#endif
}
float GetPointSize() {
#if defined(HD_HAS_pointSize)
    return HdGet_pointSize();
#else
    return 3.0;
#endif
}
float GetPointSelectedSize() {
#if defined(HD_HAS_pointSelectedSize)
    return HdGet_pointSelectedSize();
#else
    return 5.0;
#endif
}
vec4  GetWireframeColor() {
// Individual prims can specify an alternative wireframe color
// to one specified in the render pass.  This is used in cases were
// there is not enough contrast with the normal one. 
#if defined(HD_HAS_overrideWireframeColor)
    return HdGet_overrideWireframeColor();
#elif defined(HD_HAS_wireframeColor)
    return HdGet_wireframeColor();
#else
    return vec4(0,0,0,0);
#endif
}
vec4  GetMaskColor() {
#if defined(HD_HAS_maskColor)
    return HdGet_maskColor();
#else
    return vec4(0.5,0,0,1);
#endif
}
vec4  GetIndicatorColor() {
#if defined(HD_HAS_indicatorColor)
    return HdGet_indicatorColor();
#else
    return vec4(0,0.5,0,1);
#endif
}

bool ShouldDiscardByAlpha(vec4 color)
{
#if defined(HD_HAS_alphaThreshold)
    float alphaThreshold = HdGet_alphaThreshold();
#else
    float alphaThreshold = 0;
#endif
    return (color.a < alphaThreshold);
}

vec2 ApplyAxisAlignedAffineTransform(vec4 t, vec2 pt)
{
    return t.xy * pt + t.zw;
}

-- glsl RenderPass.CameraFS

vec2 HorizontallyNormalizedFilmbackCoordinates()
{
    const vec4 transform =
#ifdef HD_HAS_imageToHorizontallyNormalizedFilmback
        HdGet_imageToHorizontallyNormalizedFilmback();
#else
        vec4(vec2(1.0), vec2(0.0));
#endif
    return ApplyAxisAlignedAffineTransform(transform, gl_FragCoord.xy);
}

-- glsl RenderPass.ApplyClipPlanes

void ApplyClipPlanes(vec4 Peye)
{
#if defined(HD_HAS_clipPlanes)
#if defined(HD_NUM_clipPlanes) // more than 1 (clipPlanes[N])
    for (int i=0; i<HD_NUM_clipPlanes; ++i) {
        gl_ClipDistance[i] = dot(HdGet_clipPlanes(i), Peye);
    }
#else                          // only 1      (clipPlanes)
    gl_ClipDistance[0] = dot(HdGet_clipPlanes(), Peye);
#endif
#endif
}

-- glsl RenderPass.NoColorOverrides

vec4 ApplyColorOverrides(vec4 color)
{
    return color;
}

vec3 ApplyMaskColor(vec3 color, float weight, vec4 maskColor)
{
    return color;
}

vec4 ApplyColorOverridesPostLighting(vec4 color)
{
    return color;
}

-- glsl RenderPass.NoSelection

vec4 ApplySelectionColor(vec4 color)
{
    return color;
}

-- glsl RenderPass.ApplyColorOverrides

// Forward declare selection functionality.
// XXX: Currently, the non-empty implementation of this is in hdx.
FORWARD_DECL(vec4 ApplySelectionColor(vec4 color));

// XXX: Make sure to update hdx/shaders/renderPass.glslfx when editing these
// color override methods, since they're currently duplicated. This is because
// we don't have a mixin token for color overrides in a render pass yet.
vec4 ApplyColorOverrides(vec4 color)
{
#if defined(HD_HAS_overrideColor)
    // Mix in override color
    vec4 overrideColor = HdGet_overrideColor();
    color.rgb = mix(color.rgb, overrideColor.rgb, overrideColor.a);
#endif
    return ApplySelectionColor(color);
}

vec3 ApplyMaskColor(vec3 color, float weight, vec4 maskColor)
{
    float strength = maskColor.a * clamp(weight, 0.0, 1.0);
    return mix(color, maskColor.rgb, strength);
}

vec4 ApplyColorOverridesPostLighting(vec4 color)
{
    #if defined(HD_HAS_maskWeight)
        float maskWeight = HdGet_maskWeight();
        vec4 maskColor = GetMaskColor();
        color.rgb = ApplyMaskColor(color.rgb, maskWeight, maskColor);
    #endif
    #if defined(HD_HAS_indicatorWeight)
        float indicatorWeight = HdGet_indicatorWeight();
        vec4 indicatorColor = GetIndicatorColor();
        color.rgb = ApplyMaskColor(color.rgb, indicatorWeight, indicatorColor);
    #endif
    return color;
}

-- layout RenderPass.RenderColor

[
    ["out", "vec4", "colorOut"]
]

-- glsl RenderPass.RenderColor

void RenderOutput(vec4 Peye, vec3 Neye, vec4 color, vec4 patchCoord)
{
    colorOut = color;
}

-- layout RenderPass.RenderId

[
    ["out", "vec4", "primIdOut"],
    ["out", "vec4", "instanceIdOut"]
]

-- glsl RenderPass.RenderId

// XXX: This whole snippet is a little sketchy and should ideally be replaced
// with AoVs.  We generate "primId" and "instanceId", and depending on how
// the client called glDrawBuffers, they will get one or both.

vec4 IntToVec4(int id)
{
    return vec4(((id >>  0) & 0xff) / 255.0,
                ((id >>  8) & 0xff) / 255.0,
                ((id >> 16) & 0xff) / 255.0,
                ((id >> 24) & 0xff) / 255.0);
}

void RenderOutput(vec4 Peye, vec3 Neye, vec4 color, vec4 patchCoord)
{
    // Allow alpha threshold discard for ID renders regardless of material tag
    if (ShouldDiscardByAlpha(color)) {
        discard;
    }

    int primId = HdGet_primID();
    primIdOut = IntToVec4(primId);

    // instanceIndex is a tuple of integers (num nested levels).
    // for picking, we store global instanceId (instanceIndex[0]) in the
    // selection framebuffer and then reconstruct the tuple in postprocess.
    int instanceId = GetDrawingCoord().instanceIndex[0];
    instanceIdOut = IntToVec4(instanceId);
}
