/*
All material copyright Esri, All Rights Reserved, unless otherwise specified.
See https://js.arcgis.com/5.0/esri/copyright.txt for details.
*/
import{NoPerspectiveRead as e}from"../util/NoPerspective.glsl.js";import{addCameraPosition as t,addPixelRatio as o}from"../util/View.glsl.js";import{Float4PassUniform as r}from"../../shaderModules/Float4PassUniform.js";import{FloatBindUniform as i}from"../../shaderModules/FloatBindUniform.js";import{FloatPassUniform as l}from"../../shaderModules/FloatPassUniform.js";import{glsl as a,If as s}from"../../shaderModules/glsl.js";import{Texture2DPassUniform as n}from"../../shaderModules/Texture2DPassUniform.js";import{computeTextureSize as p}from"../../../materials/stippleTextureRepository.js";import{ensureColor4 as d}from"../../../shaders/ensureColor4.js";function c(p,c){if(!c.stippleEnabled)return void p.fragment.code.add(a`float getStippleAlpha(float lineWidth) { return 1.0; }
void discardByStippleAlpha(float stippleAlpha, float threshold) {}
vec4 blendStipple(vec4 color, float stippleAlpha) { return color; }`);const u=!(c.draped&&c.stipplePreferContinuous),{vertex:S,fragment:h}=p;c.draped||(t(S,c),S.uniforms.add(new i("worldToScreenPerDistanceRatio",({camera:e})=>1/e.perScreenPixelRatio)).code.add(a`float computeWorldToScreenRatio(vec3 segmentCenter) {
float segmentDistanceToCamera = length(segmentCenter - cameraPosition);
return worldToScreenPerDistanceRatio / segmentDistanceToCamera;
}`)),p.varyings.add("vStippleDistance","float"),p.varyings.add("vStippleDistanceLimits","vec2"),p.varyings.add("vStipplePatternStretch","float"),S.code.add(a`
    float discretizeWorldToScreenRatio(float worldToScreenRatio) {
      float step = ${a.float(m)};

      float discreteWorldToScreenRatio = log(worldToScreenRatio);
      discreteWorldToScreenRatio = ceil(discreteWorldToScreenRatio / step) * step;
      discreteWorldToScreenRatio = exp(discreteWorldToScreenRatio);
      return discreteWorldToScreenRatio;
    }
  `),o(S),S.code.add(a`
    vec2 computeStippleDistanceLimits(float startPseudoScreen, float segmentLengthPseudoScreen, float segmentLengthScreen, float patternLength) {

      // First check if the segment is long enough to support fully screen space patterns.
      // Force sparse mode for segments that are very large in screen space even if it is not allowed,
      // to avoid imprecision from calculating with large floats.
      if (segmentLengthPseudoScreen >= ${u?"patternLength":"1e4"}) {
        // Round the screen length to get an integer number of pattern repetitions (minimum 1).
        float repetitions = segmentLengthScreen / (patternLength * pixelRatio);
        float flooredRepetitions = max(1.0, floor(repetitions + 0.5));
        float segmentLengthScreenRounded = flooredRepetitions * patternLength;

        float stretch = repetitions / flooredRepetitions;

        // We need to impose a lower bound on the stretch factor to prevent the dots from merging together when there is only 1 repetition.
        // 0.75 is the lowest possible stretch value for flooredRepetitions > 1, so it makes sense as lower bound.
        vStipplePatternStretch = max(0.75, stretch);

        return vec2(0.0, segmentLengthScreenRounded);
      }
      return vec2(startPseudoScreen, startPseudoScreen + segmentLengthPseudoScreen);
    }
  `),h.uniforms.add(new n("stipplePatternTexture",e=>e.stippleTexture),new l("stipplePatternPixelSizeInv",e=>1/f(e))),c.stippleOffColorEnabled&&h.uniforms.add(new r("stippleOffColor",e=>d(e.stippleOffColor))),p.include(e),h.code.add(a`float getStippleSDF(out bool isClamped) {
float stippleDistanceClamped = noPerspectiveRead(clamp(vStippleDistance, vStippleDistanceLimits.x, vStippleDistanceLimits.y));
float lineSizeInv = noPerspectiveRead(vLineSizeInv);
vec2 aaCorrectedLimits = vStippleDistanceLimits + vec2(1.0, -1.0) / gl_FragCoord.w;
isClamped = vStippleDistance < aaCorrectedLimits.x || vStippleDistance > aaCorrectedLimits.y;
float u = stippleDistanceClamped * stipplePatternPixelSizeInv * lineSizeInv;
u = fract(u);
float sdf = texture(stipplePatternTexture, vec2(u, 0.5)).r;
return (sdf - 0.5) * vStipplePatternStretch + 0.5;
}
float getStippleSDF() {
bool ignored;
return getStippleSDF(ignored);
}
float getStippleAlpha(float lineWidth) {
bool isClamped;
float stippleSDF = getStippleSDF(isClamped);
float antiAliasedResult = clamp(stippleSDF * lineWidth + 0.5, 0.0, 1.0);
return isClamped ? floor(antiAliasedResult + 0.5) : antiAliasedResult;
}`),h.code.add(a`
    void discardByStippleAlpha(float stippleAlpha, float threshold) {
     ${s(!c.stippleOffColorEnabled,"if (stippleAlpha < threshold) { discard; }")}
    }

    vec4 blendStipple(vec4 color, float stippleAlpha) {
      return ${c.stippleOffColorEnabled?"mix(color, stippleOffColor, stippleAlpha)":"vec4(color.rgb, color.a * stippleAlpha)"};
    }
  `)}function f(e){const t=e.stipplePattern;return t?p(e.stipplePattern)/t.pixelRatio:1}const m=.4;export{c as LineStipple,f as computePixelSize};
