/**
 * Copyright (c) 2019-2025 mol* contributors, licensed under MIT, See LICENSE file for more info.
 *
 * @author Áron Samuel Kovács <aron.kovacs@mail.muni.cz>
 * @author Alexander Rose <alexander.rose@weirdbyte.de>
 * @author Gianluca Tomasello <giagitom@gmail.com>
 */
export declare const outlines_frag = "\nprecision highp float;\nprecision highp int;\nprecision highp sampler2D;\n\nuniform sampler2D tDepthOpaque;\nuniform sampler2D tDepthTransparent;\nuniform vec2 uTexSize;\n\nuniform float uNear;\nuniform float uFar;\nuniform mat4 uInvProjection;\n\nuniform float uOutlineThreshold;\n\n#include common\n\nfloat getViewZ(const in float depth) {\n    #if dOrthographic == 1\n        return orthographicDepthToViewZ(depth, uNear, uFar);\n    #else\n        return perspectiveDepthToViewZ(depth, uNear, uFar);\n    #endif\n}\n\nfloat getDepthOpaque(const in vec2 coords) {\n    #ifdef depthTextureSupport\n        return texture2D(tDepthOpaque, coords).r;\n    #else\n        return unpackRGBAToDepth(texture2D(tDepthOpaque, coords));\n    #endif\n}\n\nvec2 getDepthTransparentWithAlpha(const in vec2 coords) {\n    #ifdef dTransparentOutline\n        return unpackRGBAToDepthWithAlpha(texture2D(tDepthTransparent, coords));\n    #else\n        return vec2(1.0, 0.0);\n    #endif\n}\n\nbool isBackground(const in float depth) {\n    return depth == 1.0;\n}\n\nfloat getPixelSize(const in vec2 coords, const in float depth) {\n    vec3 viewPos0 = screenSpaceToViewSpace(vec3(coords, depth), uInvProjection);\n    vec3 viewPos1 = screenSpaceToViewSpace(vec3(coords + vec2(1.0, 0.0) / uTexSize, depth), uInvProjection);\n    return distance(viewPos0, viewPos1);\n}\n\nvoid main(void) {\n    float backgroundViewZ = 2.0 * uFar;\n\n    vec2 coords = gl_FragCoord.xy / uTexSize;\n    vec2 invTexSize = 1.0 / uTexSize;\n\n    float selfDepthOpaque = getDepthOpaque(coords);\n    float selfViewZOpaque = isBackground(selfDepthOpaque) ? backgroundViewZ : getViewZ(selfDepthOpaque);\n    float pixelSizeOpaque = getPixelSize(coords, selfDepthOpaque) * uOutlineThreshold;\n\n    vec2 selfDepthTransparentWithAlpha = getDepthTransparentWithAlpha(coords);\n    float selfDepthTransparent = selfDepthTransparentWithAlpha.x;\n    float selfViewZTransparent = isBackground(selfDepthTransparent) ? backgroundViewZ : getViewZ(selfDepthTransparent);\n    float pixelSizeTransparent = getPixelSize(coords, selfDepthTransparent) * uOutlineThreshold;\n\n    float bestOpaqueDepth = 1.0;\n    float bestTransparentDepth = 1.0;\n    float bestTransparentAlpha = 0.0;\n\n    float opaqueOutlineFlag = 0.0;\n    float transparentOutlineFlag = 0.0;\n\n    for (int y = -1; y <= 1; y++) {\n        for (int x = -1; x <= 1; x++) {\n            vec2 sampleCoords = coords + vec2(float(x), float(y)) * invTexSize;\n\n            // Opaque\n            float sampleDepthOpaque = getDepthOpaque(sampleCoords);\n            float sampleViewZOpaque = isBackground(sampleDepthOpaque) ? backgroundViewZ : getViewZ(sampleDepthOpaque);\n            if (abs(selfViewZOpaque - sampleViewZOpaque) > pixelSizeOpaque && selfDepthOpaque > sampleDepthOpaque && sampleDepthOpaque <= bestOpaqueDepth) {\n                bestOpaqueDepth = sampleDepthOpaque;\n                opaqueOutlineFlag = 1.0;\n            }\n\n            // Transparent\n            vec2 sampleDepthTransparentWithAlpha = getDepthTransparentWithAlpha(sampleCoords);\n            float sampleDepthTransparent = sampleDepthTransparentWithAlpha.x;\n            float sampleAlphaTransparent = sampleDepthTransparentWithAlpha.y;\n            float sampleViewZTransparent = isBackground(sampleDepthTransparent) ? backgroundViewZ : getViewZ(sampleDepthTransparent);\n            if (abs(selfViewZTransparent - sampleViewZTransparent) > pixelSizeTransparent && selfDepthTransparent > sampleDepthTransparent && sampleDepthTransparent <= bestTransparentDepth) {\n                bestTransparentDepth = sampleDepthTransparent;\n                bestTransparentAlpha = sampleAlphaTransparent;\n                transparentOutlineFlag = 1.0;\n            }\n        }\n    }\n\n    if (transparentOutlineFlag > 0.0 && bestOpaqueDepth < 1.0 && bestTransparentDepth > bestOpaqueDepth) {\n        transparentOutlineFlag = 0.0;\n        bestTransparentAlpha = 0.0;\n    }\n\n    vec2 depthPacked; // Pack depth in G/B channels\n    float outlineTypeFlag = 0.0;\n    if (opaqueOutlineFlag > 0.0 && transparentOutlineFlag > 0.0) {\n        outlineTypeFlag = 0.75; // Both\n        depthPacked = packUnitIntervalToRG(bestOpaqueDepth);\n    } else if (transparentOutlineFlag > 0.0) {\n        outlineTypeFlag = 0.5;  // Transparent only\n        depthPacked = packUnitIntervalToRG(bestTransparentDepth);\n    } else if (opaqueOutlineFlag > 0.0) {\n        outlineTypeFlag = 0.25; // Opaque only\n        depthPacked = packUnitIntervalToRG(bestOpaqueDepth);\n    }\n\n    float alpha = clamp(bestTransparentAlpha, 0.0, 0.5) * 2.0; // limiting to range [0.0, 0.5] to improve alpha precision since we don't need a wider range\n    float packedFlagWithAlpha = pack2x4(vec2(outlineTypeFlag, alpha)); // pack outlineType with alpha\n    gl_FragColor = vec4(packedFlagWithAlpha, depthPacked.x, depthPacked.y, bestTransparentDepth);\n}\n";
