/* COPYRIGHT Esri - https://js.arcgis.com/5.1.2/LICENSE.txt */
import{create as e}from"../core/libs/gl-matrix-2/factories/vec2f64.js";import{ScreenSpacePass as l}from"../views/3d/webgl-engine/core/shaderLibrary/ScreenSpacePass.glsl.js";import{ReadDepth as o}from"../views/3d/webgl-engine/core/shaderLibrary/output/ReadDepth.glsl.js";import{GlobalIlluminationWeights as i}from"../views/3d/webgl-engine/core/shaderLibrary/shading/GlobalIlluminationWeights.glsl.js";import{CameraSpace as t}from"../views/3d/webgl-engine/core/shaderLibrary/util/CameraSpace.glsl.js";import{BooleanBindUniform as a}from"../views/3d/webgl-engine/core/shaderModules/BooleanBindUniform.js";import{Float2DrawUniform as n}from"../views/3d/webgl-engine/core/shaderModules/Float2DrawUniform.js";import{FloatPassUniform as s}from"../views/3d/webgl-engine/core/shaderModules/FloatPassUniform.js";import{glsl as r}from"../views/3d/webgl-engine/core/shaderModules/glsl.js";import{Texture2DDrawUniform as m}from"../views/3d/webgl-engine/core/shaderModules/Texture2DDrawUniform.js";import{Texture2DPassUniform as u}from"../views/3d/webgl-engine/core/shaderModules/Texture2DPassUniform.js";import{GlobalIlluminationColorQuantization as c}from"../views/3d/webgl-engine/effects/globalIllumination/GlobalIlluminationColorQuantization.glsl.js";import{ditherNoise as p}from"../views/3d/webgl-engine/shaders/ditherNoise.glsl.js";import{OITResolutionConfiguration as h}from"../views/3d/webgl-engine/shaders/oitResolution.glsl.js";import{NoParameters as d}from"../views/webgl/NoParameters.js";import{ShaderBuilder as f}from"../views/webgl/ShaderBuilder.js";const g=4;class b extends d{constructor(){super(...arguments),this.blurSize=e()}}function S(){const e=new f,h=e.fragment;e.include(l),e.include(t),e.include(i);const d=(g+3)/2,b=1/(2*d*d);h.include(o),h.include(p,w),h.include(c);const S=5e4;h.uniforms.add(new a("hasEmission",e=>e.hasEmission),new u("depthMap",e=>e.depthTexture),new u("normalMap",e=>e.normalTexture),new m("globalIlluminationTexture",e=>e.texture),new m("globalIlluminationWeightTexture",e=>e.weightTexture),new n("blurSize",e=>e.blurSize),new s("scaleGlobalIllumination",e=>e.scaleGlobalIllumination),new s("projScale",(e,l)=>{const o=l.camera.distance;return o>S?Math.max(0,e.projScale-(o-S)):e.projScale}));const v=.1,W=400,I=.03,O=.08,x=1.5;return h.code.add(r`
    void accumulateBlurSample(
      vec2 sampleUv,
      float sampleOffset,
      float centerDepth,
      vec3 centerNormal,
      float depthSharpness,
      bool skipOcclusionBlur,
      inout float emissionWeightSum,
      inout vec3 emissionSum,
      inout float occlusionWeightSum,
      inout float occlusionSum,
      float centerOcclusionBlendWeight
    ) {
      vec4 sampleGlobalIllumination = texture(globalIlluminationTexture, sampleUv);
      vec3 sampleNormal = texture(normalMap, sampleUv).rgb;
      float sampleDepth = linearDepthFromTexture(depthMap, sampleUv);

      float depthDelta = sampleDepth - centerDepth;
      bool isScaledGlobalIllumination = scaleGlobalIllumination < 1.0;
      float normalSimilarityWeight = globalIlluminationNormalSimilarityWeight(sampleNormal, centerNormal);
      float depthNormalCorrection = globalIlluminationDepthNormalCorrection(sampleNormal);
      vec3 emission = sampleGlobalIllumination.rgb;
      float emissionSpatialWeightMultiplier = isScaledGlobalIllumination ? ${r.float(W)} : 1.0;

      float emissionWeight = exp(
        -sampleOffset * sampleOffset * ${r.float(b)} * ${r.float(v)} * emissionSpatialWeightMultiplier
        - depthDelta * depthDelta * depthSharpness * depthNormalCorrection
      );
      emissionWeight *= normalSimilarityWeight;
      emissionWeightSum += emissionWeight;
      emissionSum += emissionWeight * emission;

      if (skipOcclusionBlur) {
        return;
      }

      float occlusionSpatialKernelScale = centerOcclusionBlendWeight > ${r.float(I)}
        ? ${r.float(O)}
        : ${r.float(x)};
      float occlusionWeight = exp(-sampleOffset * sampleOffset * occlusionSpatialKernelScale - depthDelta * depthDelta * depthSharpness);
      occlusionWeight *= normalSimilarityWeight;
      occlusionWeightSum += occlusionWeight;
      occlusionSum += occlusionWeight * sampleGlobalIllumination.a;
    }
  `),h.main.add(r`
    vec3 emissionSum = vec3(0.0);
    float emissionWeightSum = 0.0;

    vec4 centerGlobalIllumination = texture(globalIlluminationTexture, uv);
    float centerOcclusionBlendWeight = texture(globalIlluminationWeightTexture, uv).r;
    bool isScaledGlobalIllumination = scaleGlobalIllumination < 1.0;
    bool shouldReuseCenterOcclusion = isScaledGlobalIllumination && centerOcclusionBlendWeight <= ${r.float(I)};
    bool shouldSkipLowQualityBlur = !hasEmission && shouldReuseCenterOcclusion;
    if (shouldSkipLowQualityBlur) {
      fragColor = vec4(
        quantizeGlobalIlluminationColor(centerGlobalIllumination.rgb),
        centerGlobalIllumination.a
      );
      return;
    }

    float centerDepth = linearDepthFromTexture(depthMap, uv);
    vec3 centerNormal = texture(normalMap, uv).rgb;
    float occlusionSum = 0.0;
    float occlusionWeightSum = 0.0;

    float depthSharpness = globalIlluminationDepthSharpness(projScale, centerDepth);
    for (int sampleOffset = -${r.int(g)}; sampleOffset <= ${r.int(g)}; ++sampleOffset) {
      float sampleOffsetFloat = float(sampleOffset);
      vec2 sampleUv = uv + sampleOffsetFloat * blurSize;
      accumulateBlurSample(
        sampleUv,
        sampleOffsetFloat,
        centerDepth,
        centerNormal,
        depthSharpness,
        shouldReuseCenterOcclusion,
        emissionWeightSum,
        emissionSum,
        occlusionWeightSum,
        occlusionSum,
        centerOcclusionBlendWeight
      );
    }

    float occlusion = shouldReuseCenterOcclusion ? centerGlobalIllumination.a : occlusionSum / occlusionWeightSum;
    vec3 blurredEmission = (emissionSum / emissionWeightSum).rgb;

    // heuristic dithering of the colors to remove banding, color shifts and wrong color accumulation
    float dither = ditherNoise(vec4(blurredEmission, occlusion)) - 1./32768.0;
    blurredEmission += isScaledGlobalIllumination ? 0.85 * dither : dither;

    fragColor = vec4(quantizeGlobalIlluminationColor(blurredEmission), occlusion);
  `),e}const w=new h;w.useFloatBlend=!1;const v=Object.freeze(Object.defineProperty({__proto__:null,GlobalIlluminationBlurDrawParameters:b,build:S},Symbol.toStringTag,{value:"Module"}));export{b as G,v as a,S as b};
