/**
 * Copyright (c) 2024 mol* contributors, licensed under MIT, See LICENSE file for more info.
 *
 * @author Ludovic Autin <autin@scripps.edu>
 * @author Alexander Rose <alexander.rose@weirdbyte.de>
 */
export declare const dof_frag = "\nprecision highp float;\nprecision highp int;\nprecision highp sampler2D;\n\n#include common\n\nuniform sampler2D tColor;\nuniform sampler2D tDepthOpaque;\nuniform sampler2D tDepthTransparent;\n\nuniform vec2 uTexSize;\nuniform vec4 uBounds;\n\nuniform float uBlurSpread;\nuniform float uInFocus;\nuniform float uPPM;\n\nuniform float uNear; // Near plane\nuniform float uFar;  // Far plane\n\nuniform mat4 uInvProjection; // Inverse projection\nuniform mat4 uProjection; // projection\n\nuniform int uMode; // 0-planar, 1-spherical\nuniform vec3 uCenter; // Center of focus sphere in view space\n\n// Function to convert depth value from depth buffer to view space Z\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\n// Retrieve depth from opaque depth texture\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\n// Retrieve depth from transparent depth texture\nfloat getDepthTransparent(const in vec2 coords) {\n    return unpackRGBAToDepthWithAlpha(texture2D(tDepthTransparent, coords)).x;\n}\n\nbool isBackground(const in float depth) {\n    return depth == 1.0;\n}\n\nfloat getDepth(const in vec2 coords) {\n    return min(getDepthOpaque(coords), getDepthTransparent(coords));\n}\n\nfloat getCOC(vec2 uv) {\n    float depth = getDepth(uv);\n    float viewDist = getViewZ(depth);\n    vec3 aposition = screenSpaceToViewSpace(vec3(uv.xy, depth), uInvProjection);\n    float focusDist = length(aposition - uCenter);\n    float coc = 0.0;  // Circle of Confusion\n    if (uMode == 0) { // planar Depth of field\n        coc = (abs(viewDist) - uInFocus) / uPPM;  //focus distance, focus range\n    } else if(uMode == 1) { // spherical Depth of field\n        coc = focusDist / uPPM ;\n    }\n    coc = clamp(coc, -1.0, 1.0);\n    return coc;\n}\n\n// Simple box blur for blurring the image\nvec3 getBlurredImage(vec2 coords) {\n    vec4 blurColor = vec4(0);\n    vec2 texelSize = vec2(1.0 / uTexSize.x, 1.0 / uTexSize.y);\n    float count = 0.0;\n    for (int x = 0; x < int(dBlurSize); x++) {\n        for (int y = 0; y < int(dBlurSize); y++) {\n            vec2 offset = vec2(float(x) - float(dBlurSize) / 2.0, float(y) - float(dBlurSize) / 2.0);\n            vec2 uvPixel = coords.xy + offset * texelSize * uBlurSpread;\n            float coc = getCOC(uvPixel);\n            coc = smoothstep(0.0, 1.0, abs(coc));\n            // mix blurColor with new color with weight coc\n            blurColor.rgb = blurColor.rgb + texture2D(tColor, uvPixel).xyz * coc;\n            count+=coc;\n        }\n    }\n    blurColor = blurColor / count;\n    return blurColor.rgb;\n}\n\n// simplification from https://catlikecoding.com/unity/tutorials/advanced-rendering/depth-of-field/\nvoid main() {\n    vec2 uv = gl_FragCoord.xy / uTexSize;\n    vec4 color = texture2D(tColor, uv);\n    float depth = getDepth(uv);\n\n    float viewDist = getViewZ(depth);\n\n    vec3 aposition = screenSpaceToViewSpace(vec3(uv.xy, depth), uInvProjection);\n    float focusDist = length(aposition - uCenter);\n    vec3 blurColor = getBlurredImage(uv);\n\n    float coc = getCOC(uv); // Circle of Confusion\n\n    // for debugging the coc\n    // color.rgb = (coc < 0.0) ? (1.0 - abs(coc)) * vec3(1.0,0.0,0.0) : vec3(0.0, 1.0 - coc, 0.0) ;//mix(color.rgb, blurColor.rgb, abs(coc));\n    color.rgb = mix(color.rgb, blurColor, smoothstep(0.0, 1.0, abs(coc))); // Smooth blending based on CoC\n    gl_FragColor = color;\n}\n";
