-- glslfx version 0.1

//
// Copyright 2018 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": {
            "fragmentShader": {
                "source": [ "OitResolve.Image" ]
            }
        }
    }
}

-- glsl OitResolve.Image

vec4 imageShader(vec2 uv)
{
#if defined(HD_HAS_hdxOitDataBuffer)
    int screenWidth = int(HdGet_oitScreenSize().x);

    // +1 because index 0 of counter buffer is reserved as atomic counter in
    // WriteOitLayersToBuffer
    int screenIndex = int(gl_FragCoord.x) + int(gl_FragCoord.y) * screenWidth;
    screenIndex += 1;

    int nodeIndex = hdxOitCounterBuffer[screenIndex];
    int numDepths = 0;

    // XXX renderPass.WriteOitLayersToBuffer does not clamp the number of
    //     depth samples we store for a pixel. Here we process no more than
    //     'maxSamples' for a pixel. (If there are greater than 'maxSamples'
    //     samples stored for this pixel some will currently not contribute)
    const int maxSamples = 8;
    vec4 sortedColor[maxSamples];
    float sortedDepth[maxSamples];

    while (nodeIndex != -1 && 
           numDepths < maxSamples && 
           nodeIndex < hdxOitDataBuffer.length()) 
    {
        float currentDepth = hdxOitDepthBuffer[nodeIndex]; 
        int insertIndex = numDepths; 
        // Recall that depths are in eye space, so inequality is flipped.
        while (insertIndex > 0 && sortedDepth[insertIndex - 1] < currentDepth) {
            sortedDepth[insertIndex] = sortedDepth[insertIndex - 1];
            sortedColor[insertIndex] = sortedColor[insertIndex - 1]; 
            insertIndex -= 1; 
        }
        sortedColor[insertIndex] = hdxOitDataBuffer[nodeIndex];
        sortedDepth[insertIndex] = hdxOitDepthBuffer[nodeIndex];
        numDepths += 1; 
        nodeIndex = hdxOitIndexBuffer[nodeIndex]; 
    } 

    int depth = 0;
    vec4 colorAccum = vec4(0);
    while (depth < numDepths) {
        float ca = sortedColor[depth].a * (1 - colorAccum.a);
        vec3 cb = sortedColor[depth].rgb;
        colorAccum.rgb = colorAccum.rgb + cb * ca;
        colorAccum.a = colorAccum.a + ca;

        if (colorAccum.a >= 1.0) break;

        depth += 1; 
    }

    colorAccum = clamp(colorAccum, vec4(0), vec4(1));
    return colorAccum;
#else
    return vec4(0);
#endif
}
