-- glslfx version 0.1

//
// Copyright 2019 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/hdx/shaders/renderPass.glslfx

--- --------------------------------------------------------------------------

-- glsl HdxRenderPass.RenderOitOpaquePixels

layout (location = 0) out vec4 colorOut;

void RenderOutput(vec4 Peye, vec3 Neye, vec4 color, vec4 patchCoord)
{
    if (color.a >= 1.0) {
        colorOut = vec4(color.rgb, 1);
    } else {
        discard;
    }
}

-- glsl HdxRenderPass.WriteOitLayersToBuffer

layout (early_fragment_tests) in;

void RenderOutput(vec4 Peye, vec3 Neye, vec4 color, vec4 patchCoord)
{
#if defined(HD_HAS_hdxOitDataBuffer)
    if (color.a < 1.0 && color.a > 0.0001) {
        int screenWidth = int(HdGet_oitScreenSize().x);

        // +1 because the counter buffer is cleared with -1, but we want the
        // first index to start at 0.
        int writeIndex = atomicAdd(hdxOitCounterBuffer[0], 1) + 1;

        if (writeIndex < hdxOitDataBuffer.length()) {
            int screenIndex =
                int(gl_FragCoord.x) + int(gl_FragCoord.y) * screenWidth;

            if (screenIndex < hdxOitCounterBuffer.length()) {
                int prevIndex =
                    atomicExchange(hdxOitCounterBuffer[screenIndex+1], writeIndex);
                hdxOitDataBuffer[writeIndex] = color;

                // Note that we have a choice here to either pick gl_FragCoord.z or
                // the depth value from Peye. The former is obtained by applying
                // the perspective transform and cannot be changed by a shader.
                //
                // We pick Peye here so that a shader has an opportunity to change
                // the depth of the sample inserted into the OIT list.
                //
                // This is used by volumes. However, non-volume translucent
                // geometry should never modify Peye value and call RenderOutput
                // with the Peye value from the vertex shader so that it is
                // consistent with gl_FragCoord. This is because such geometry is
                // subject to a opaque pixel render pass performing a z-test
                // against gl_FragCoord.z.
                //
                // Note there are implications of using the depth value from Peye
                // instead of gl_FragCoord.z here for the subsequent OIT resolve
                // shader: the depth sorting order needs to be flipped and the
                // OIT resolve shader cannot compare depths in the OIT list
                // against the depth buffer unless it takes the perspective
                // transform into account.
                hdxOitDepthBuffer[writeIndex] = Peye.z / Peye.w;
                hdxOitIndexBuffer[writeIndex] = prevIndex;
            }
        } else {
            // We may overrun the counter buffer integer and wrap back to 0 if
            // we have a lot of OIT samples.
            atomicAdd(hdxOitCounterBuffer[0], -1);
        }
    }
#endif
}

-- glsl HdxRenderPass.RenderPick

layout (location = 0) out vec4 primIdOut;
layout (location = 1) out vec4 instanceIdOut;
layout (location = 2) out vec4 elementIdOut;
layout (location = 3) out vec4 edgeIdOut;
layout (location = 4) out vec4 pointIdOut;
layout (location = 5) out vec4 neyeOut;

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);
}

// Fwd declare necessary methods to determine the subprim id of a fragment.
int GetElementID(); // generated via codeGen
int GetAuthoredEdgeId(int); // generated via codeGen
int GetPrimitiveEdgeId(); // defined in edgeId.glslfx, or generated via codeGen
bool IsFragmentOnEdge(); // defined in edgeId.glslfx, or generated via codeGen
int GetPointId(); // defined in pointId.glslfx
bool IsFragmentOnPoint(); // defined in pointId.glslfx

void RenderOutput(vec4 Peye, vec3 Neye, vec4 color, vec4 patchCoord)
{
    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);

    int elementId = GetElementID();
    elementIdOut = IntToVec4(elementId);

    // XXX: This block should be under an #ifdef
    int edgeId = -1;
    if (IsFragmentOnEdge()) {
        edgeId = GetAuthoredEdgeId(GetPrimitiveEdgeId());
    }
    edgeIdOut = IntToVec4(edgeId);

    // XXX: This block should be under an #ifdef
    int pointId = -1;
    if (IsFragmentOnPoint()) {
        pointId = GetPointId();
    }
    pointIdOut = IntToVec4(pointId);
    
    neyeOut = IntToVec4(hd_vec4_2_10_10_10_set(vec4(Neye,0)));
}
