export declare const compose_frag = "\nprecision highp float;\nprecision highp sampler2D;\n\nuniform sampler2D tShaded;\nuniform sampler2D tColor;\nuniform sampler2D tNormal;\nuniform sampler2D tTransparentColor;\nuniform sampler2D tSsaoDepth;\nuniform sampler2D tSsaoDepthTransparent;\nuniform sampler2D tDepthOpaque;\nuniform sampler2D tDepthTransparent;\nuniform sampler2D tOutlines;\nuniform vec2 uTexSize;\n\nuniform float uNear;\nuniform float uFar;\nuniform float uFogNear;\nuniform float uFogFar;\nuniform vec3 uFogColor;\nuniform vec3 uOutlineColor;\nuniform vec3 uOcclusionColor;\nuniform bool uTransparentBackground;\n\nuniform float uDenoiseThreshold;\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\nfloat getDepthTransparent(const in vec2 coords) {\n    #if defined(dTransparentOutline) || defined(dOcclusionEnable)\n        return unpackRGBAToDepthWithAlpha(texture2D(tDepthTransparent, coords)).x;\n    #else\n        return 1.0;\n    #endif\n}\n\nbool isBackground(const in float depth) {\n    return depth == 1.0;\n}\n\nfloat getSsao(vec2 coords) {\n    float rawSsao = unpackRGToUnitInterval(texture2D(tSsaoDepth, coords).xy);\n    if (rawSsao > 0.999) {\n        return 1.0;\n    } else if (rawSsao > 0.001) {\n        return rawSsao;\n    }\n    // treat values close to 0.0 as errors and return no occlusion\n    return 1.0;\n}\n\nfloat getSsaoTransparent(vec2 coords) {\n    float rawSsao = unpackRGToUnitInterval(texture2D(tSsaoDepthTransparent, coords).xy);\n    if (rawSsao > 0.999) {\n        return 1.0;\n    } else if (rawSsao > 0.001) {\n        return rawSsao;\n    }\n    // treat values close to 0.0 as errors and return no occlusion\n    return 1.0;\n}\n\n//\n\n// TODO: investigate\n// https://interplayoflight.wordpress.com/2022/03/26/raytraced-global-illumination-denoising/\n\n//\n\n#define INV_SQRT_OF_2PI 0.39894228040143267793994605993439  // 1.0/SQRT_OF_2PI\n#define INV_PI 0.31830988618379067153776752674503\n\n// https://github.com/BrutPitt/glslSmartDeNoise\n//\n//  smartDeNoise - parameters\n//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n//\n//  sampler2D tex     - sampler image / texture\n//  vec2 uv           - actual fragment coord\n//  float sigma  >  0 - sigma Standard Deviation\n//  float kSigma >= 0 - sigma coefficient\n//      kSigma * sigma  -->  radius of the circular kernel\n//  float threshold   - edge sharpening threshold\n\nfloat NormalWeightStrength = 6.0;\n\nvec4 smartDeNoise(sampler2D tex, vec2 uv) {\n    float sigma = 3.0;\n    float kSigma = 2.0;\n    float threshold = uDenoiseThreshold;\n\n    vec4 centrPx = texture2D(tex, uv);\n    if (threshold == 0.0) return centrPx;\n\n    float invSigmaQx2 = 0.5 / (sigma * sigma);      // 1.0 / (sigma^2 * 2.0)\n    float invSigmaQx2PI = INV_PI * invSigmaQx2;    // 1.0 / (sqrt(PI) * sigma)\n\n    float invThresholdSqx2 = 0.5 / (threshold * threshold);     // 1.0 / (sigma^2 * 2.0)\n    float invThresholdSqrt2PI = INV_SQRT_OF_2PI / threshold;   // 1.0 / (sqrt(2*PI) * sigma)\n\n    float zBuff = 0.0;\n    vec4 aBuff = vec4(0.0);\n\n    vec3 normal = texture2D(tNormal, uv).xyz;\n\n    for (int x = -6; x <= 6; ++x) {\n        for (int y = -6; y <= 6; ++y) {\n            vec2 d = vec2(float(x), float(y));\n\n            float blurFactor = exp(-dot(d , d) * invSigmaQx2) * invSigmaQx2PI;\n            vec2 uvSample = uv + d / uTexSize;\n\n            vec3 normalSample = texture2D(tNormal, uvSample).xyz;\n            float normalW = saturate(dot(normal, normalSample));\n            normalW = pow(normalW, NormalWeightStrength);\n            blurFactor *= normalW;\n\n            vec4 walkPx = texture2D(tex, uvSample);\n\n            vec4 dC = walkPx - centrPx;\n            float deltaFactor = exp(-dot(dC, dC) * invThresholdSqx2) * invThresholdSqrt2PI * blurFactor;\n\n            zBuff += deltaFactor;\n            aBuff += deltaFactor * walkPx;\n        }\n    }\n\n    if (zBuff <= EPSILON) {\n        return centrPx;\n    }\n\n    return aBuff / zBuff;\n}\n\nint squaredOutlineScale = dOutlineScale * dOutlineScale;\nvoid getOutline(const in vec2 coords, out bool hasOpaque, out bool hasTransparent, out float opaqueDepth, out float transparentDepth, out float alpha) {\n    vec2 invTexSize = 1.0 / uTexSize;\n    \n    hasOpaque = false;\n    hasTransparent = false;\n    opaqueDepth = 1.0;\n    transparentDepth = 1.0;\n    alpha = 0.0;\n    for (int y = -dOutlineScale; y <= dOutlineScale; y++) {\n        for (int x = -dOutlineScale; x <= dOutlineScale; x++) {\n            if (x * x + y * y > squaredOutlineScale) {\n                continue;\n            }\n\n            vec2 sampleCoords = coords + vec2(float(x), float(y)) * invTexSize;\n\n            vec4 sampleOutlineCombined = texture2D(tOutlines, sampleCoords);\n            float sampleOpaqueDepth = unpackRGToUnitInterval(sampleOutlineCombined.gb);\n            float sampleTransparentDepth = sampleOutlineCombined.a;\n            vec2 sampleFlagWithAlpha = unpack2x4(sampleOutlineCombined.r);\n\n            float sampleFlag = sampleFlagWithAlpha.x;\n            float sampleAlpha = clamp(sampleFlagWithAlpha.y * 0.5, 0.01, 1.0);\n            \n            if ((sampleFlag > 0.20 && sampleFlag < 0.30) || (sampleFlag > 0.70 && sampleFlag < 0.80)) { // transparent || both\n                if (sampleOpaqueDepth < opaqueDepth) {\n                    hasOpaque = true;\n                    opaqueDepth = sampleOpaqueDepth;\n                }\n            }\n            \n            if ((((sampleFlag > 0.45 && sampleFlag < 0.55) || (sampleFlag > 0.70 && sampleFlag < 0.80))) && sampleTransparentDepth < transparentDepth) { // transparent || both\n                hasTransparent = true;\n                transparentDepth = sampleTransparentDepth;\n                alpha = sampleAlpha;\n            }\n        }\n    }\n}\n\nvoid main() {\n    vec2 coords = gl_FragCoord.xy / uTexSize;\n\n    #ifdef dDenoise\n        vec4 color = smartDeNoise(tColor, coords);\n    #else\n        vec4 color = texture2D(tColor, coords);\n    #endif\n\n    float opaqueDepth = getDepthOpaque(coords);\n    float backgroundViewZ = 2.0 * uFar;\n    float opaqueSelfViewZ = isBackground(opaqueDepth) ? backgroundViewZ : getViewZ(opaqueDepth);\n    float fogFactor = smoothstep(uFogNear, uFogFar, abs(opaqueSelfViewZ));\n    float fogAlpha = 1.0 - fogFactor;\n\n    float transparentDepth = 1.0;\n    #ifdef dBlendTransparency\n        bool blendTransparency = true;\n        vec4 transparentColor = texture2D(tTransparentColor, coords);\n\n        transparentDepth = getDepthTransparent(coords);\n    #endif\n\n    float alpha = 1.0;\n    if (!uTransparentBackground) {\n        // mix opaque objects with background color\n        color.rgb = mix(color.rgb, uFogColor, fogFactor);\n    } else {\n        // pre-multiplied alpha expected for transparent background\n        alpha = fogAlpha;\n        color.rgb *= fogAlpha;\n    }\n\n    #if defined(dOcclusionEnable)\n        if (!isBackground(opaqueDepth)) {\n            float occlusionFactor = getSsao(coords);\n\n            if (!uTransparentBackground) {\n                color.rgb = mix(mix(uOcclusionColor, uFogColor, fogFactor), color.rgb, occlusionFactor);\n            } else {\n                color.rgb = mix(uOcclusionColor * (1.0 - fogFactor), color.rgb, occlusionFactor);\n            }\n        }\n        #ifdef dBlendTransparency\n            if (!isBackground(transparentDepth)) {\n                float viewDist = abs(getViewZ(transparentDepth));\n                float fogFactor = smoothstep(uFogNear, uFogFar, viewDist);\n                float occlusionFactor = getSsaoTransparent(coords);\n                transparentColor.rgb = mix(uOcclusionColor * (1.0 - fogFactor), transparentColor.rgb, occlusionFactor);\n            }\n        #endif\n    #endif\n\n    #ifdef dOutlineEnable\n        bool hasOpaque;\n        bool hasTransparent;\n        float outlineOpaqueDepth;\n        float outlineTransparentDepth;\n        float outlineAlpha;\n        getOutline(coords, hasOpaque, hasTransparent, outlineOpaqueDepth, outlineTransparentDepth, outlineAlpha);\n\n        if (hasOpaque) {\n            float viewDist = abs(getViewZ(outlineOpaqueDepth));\n            float fogFactor = smoothstep(uFogNear, uFogFar, viewDist);\n            if (!uTransparentBackground) {                    \n                color.rgb = mix(uOutlineColor, uFogColor, fogFactor);\n            } else {\n                alpha = 1.0 - fogFactor;\n                color.rgb = mix(uOutlineColor, vec3(0.0), fogFactor);\n            }\n        }  \n\n        #ifdef dBlendTransparency            \n            if (hasTransparent) {\n                if (hasOpaque && outlineOpaqueDepth < outlineTransparentDepth) {\n                    blendTransparency = false;\n                } else {\n                    float finalOutlineAlpha = clamp(outlineAlpha * 2.0, 0.0, 1.0);\n                    float viewDist = abs(getViewZ(outlineTransparentDepth));\n                    float fogFactor = smoothstep(uFogNear, uFogFar, viewDist);\n                    float finalAlpha = max(transparentColor.a, finalOutlineAlpha * (1.0 - fogFactor));\n                    transparentColor.a = finalAlpha;\n                    transparentColor.rgb = uOutlineColor * finalAlpha;\n                }\n            }\n        #endif\n    #endif\n\n    #ifdef dBlendTransparency\n        if (blendTransparency) {\n            if (transparentColor.a != 0.0) {\n                // blending\n                color = transparentColor + color * (1.0 - transparentColor.a);\n                alpha = transparentColor.a + alpha * (1.0 - transparentColor.a);\n            }\n        }\n    #endif\n\n    gl_FragColor = vec4(color.rgb, alpha);\n}\n";
