/*
All material copyright ESRI, All Rights Reserved, unless otherwise specified.
See https://js.arcgis.com/4.24/esri/copyright.txt for details.
*/
define(["exports","../views/3d/webgl-engine/core/shaderLibrary/ShaderOutputOptions","../views/3d/webgl-engine/core/shaderLibrary/Slice.glsl","../views/3d/webgl-engine/core/shaderLibrary/Transform.glsl","../views/3d/webgl-engine/core/shaderLibrary/attributes/VertexColor.glsl","../views/3d/webgl-engine/core/shaderLibrary/output/OutputDepth.glsl","../views/3d/webgl-engine/core/shaderLibrary/output/OutputHighlight.glsl","../views/3d/webgl-engine/core/shaderLibrary/shading/MultipassTerrainTest.glsl","../views/3d/webgl-engine/core/shaderLibrary/util/AlphaCutoff","../views/3d/webgl-engine/core/shaderLibrary/util/ColorConversion.glsl","../views/3d/webgl-engine/core/shaderLibrary/util/View.glsl","../views/3d/webgl-engine/core/shaderModules/Float2PassUniform","../views/3d/webgl-engine/core/shaderModules/Float4PassUniform","../views/3d/webgl-engine/core/shaderModules/FloatPassUniform","../views/3d/webgl-engine/core/shaderModules/interfaces","../views/3d/webgl-engine/core/shaderModules/ShaderBuilder","../views/3d/webgl-engine/lib/basicInterfaces","../views/3d/webgl-engine/lib/VertexAttribute","../views/3d/webgl-engine/materials/PatternStyle"],(function(e,t,a,o,r,l,i,n,s,d,c,g,u,p,v,f,h,m,w){"use strict";const S=.70710678118,b=S,y=.08715574274;function P(e){const P=new f.ShaderBuilder,T=e.hasMultipassTerrain&&(e.output===t.ShaderOutput.Color||e.output===t.ShaderOutput.Alpha);e.draped||P.extensions.add("GL_OES_standard_derivatives");const C=e.output===t.ShaderOutput.Depth,{vertex:D,fragment:O}=P;c.addProjViewLocalOrigin(P,e),P.include(o.Transform,{hasModelTransformation:!1,linearDepth:C}),P.include(r.VertexColor,e),C&&(P.include(l.OutputDepth,e),D.uniforms.add(new g.Float2PassUniform("nearFar",((e,t)=>t.camera.nearFar))),P.varyings.add("linearDepth","float")),e.draped?D.uniforms.add(new p.FloatPassUniform("worldToScreenRatio",((e,t)=>1/t.screenToPCSRatio))):P.attributes.add(m.VertexAttribute.BOUNDINGRECT,"mat3"),P.attributes.add(m.VertexAttribute.POSITION,"vec3"),P.attributes.add(m.VertexAttribute.UVMAPSPACE,"vec4"),P.varyings.add("vpos","vec3"),P.varyings.add("vuv","vec2"),T&&P.varyings.add("depth","float");const R=e.style===w.Style.ForwardDiagonal||e.style===w.Style.BackwardDiagonal||e.style===w.Style.DiagonalCross;return R&&D.code.add(v.glsl`
      const mat2 rotate45 = mat2(${v.glsl.float(S)}, ${v.glsl.float(-b)},
                                 ${v.glsl.float(b)}, ${v.glsl.float(S)});
    `),e.draped||(c.addCameraPosition(D,e),D.uniforms.add(new p.FloatPassUniform("worldToScreenPerDistanceRatio",((e,t)=>1/t.camera.perScreenPixelRatio))),D.code.add(v.glsl`vec3 projectPointToLineSegment(vec3 center, vec3 halfVector, vec3 point) {
float projectedLength = dot(halfVector, point - center) / dot(halfVector, halfVector);
return center + halfVector * clamp(projectedLength, -1.0, 1.0);
}`),D.code.add(v.glsl`vec3 intersectRayPlane(vec3 rayDir, vec3 rayOrigin, vec3 planeNormal, vec3 planePoint) {
float d = dot(planeNormal, planePoint);
float t = (d - dot(planeNormal, rayOrigin)) / dot(planeNormal, rayDir);
return rayOrigin + t * rayDir;
}`),D.code.add(v.glsl`
      float boundingRectDistanceToCamera() {
        vec3 center = vec3(boundingRect[0][0], boundingRect[0][1], boundingRect[0][2]);
        vec3 halfU = vec3(boundingRect[1][0], boundingRect[1][1], boundingRect[1][2]);
        vec3 halfV = vec3(boundingRect[2][0], boundingRect[2][1], boundingRect[2][2]);
        vec3 n = normalize(cross(halfU, halfV));

        vec3 viewDir = - vec3(view[0][2], view[1][2], view[2][2]);

        float viewAngle = dot(viewDir, n);
        float minViewAngle = ${v.glsl.float(y)};

        if (abs(viewAngle) < minViewAngle) {
          // view direction is (almost) parallel to plane -> clamp it to min angle
          float normalComponent = sign(viewAngle) * minViewAngle - viewAngle;
          viewDir = normalize(viewDir + normalComponent * n);
        }

        // intersect view direction with infinite plane that contains bounding rect
        vec3 planeProjected = intersectRayPlane(viewDir, cameraPosition, n, center);

        // clip to bounds by projecting to u and v line segments individually
        vec3 uProjected = projectPointToLineSegment(center, halfU, planeProjected);
        vec3 vProjected = projectPointToLineSegment(center, halfV, planeProjected);

        // use to calculate the closest point to camera on bounding rect
        vec3 closestPoint = uProjected + vProjected - center;

        return length(closestPoint - cameraPosition);
      }
    `)),D.code.add(v.glsl`
    vec2 scaledUV() {
      vec2 uv = uvMapSpace.xy ${R?" * rotate45":""};
      vec2 uvCellOrigin = uvMapSpace.zw ${R?" * rotate45":""};

      ${e.draped?"":v.glsl`
            float distanceToCamera = boundingRectDistanceToCamera();
            float worldToScreenRatio = worldToScreenPerDistanceRatio / distanceToCamera;
          `}

      // Logarithmically discretize ratio to avoid jittering
      float step = 0.1;
      float discreteWorldToScreenRatio = log(worldToScreenRatio);
      discreteWorldToScreenRatio = ceil(discreteWorldToScreenRatio / step) * step;
      discreteWorldToScreenRatio = exp(discreteWorldToScreenRatio);

      vec2 uvOffset = mod(uvCellOrigin * discreteWorldToScreenRatio, ${v.glsl.float(e.patternSpacing)});
      return uvOffset + (uv * discreteWorldToScreenRatio);
    }
  `),D.code.add(v.glsl`
    void main(void) {
      vuv = scaledUV();
      vpos = position;
      ${T?"depth = (view * vec4(vpos, 1.0)).z;":""}
      forwardNormalizedVertexColor();
      gl_Position = ${C?v.glsl`transformPositionWithDepth(proj, view, vpos, nearFar, linearDepth);`:v.glsl`transformPosition(proj, view, vpos);`}
    }
  `),P.include(a.SliceDraw,e),O.include(d.ColorConversion),e.draped&&O.uniforms.add(new p.FloatPassUniform("texelSize",((e,t)=>1/t.camera.pixelRatio))),e.output===t.ShaderOutput.Highlight&&P.include(i.OutputHighlight),T&&P.include(n.multipassTerrainTest,e),e.output!==t.ShaderOutput.Highlight&&(O.code.add(v.glsl`
      const float lineWidth = ${v.glsl.float(e.lineWidth)};
      const float spacing = ${v.glsl.float(e.patternSpacing)};
      const float spacingINV = ${v.glsl.float(1/e.patternSpacing)};

      float coverage(float p, float txlSize) {
        p = mod(p, spacing);

        float halfTxlSize = txlSize / 2.0;

        float start = p - halfTxlSize;
        float end = p + halfTxlSize;

        float coverage = (ceil(end * spacingINV) - floor(start * spacingINV)) * lineWidth;
        coverage -= min(lineWidth, mod(start, spacing));
        coverage -= max(lineWidth - mod(end, spacing), 0.0);

        return coverage / txlSize;
      }
    `),e.draped||O.code.add(v.glsl`const int maxSamples = 5;
float sample(float p) {
vec2 dxdy = abs(vec2(dFdx(p), dFdy(p)));
float fwidth = dxdy.x + dxdy.y;
ivec2 samples = 1 + ivec2(clamp(dxdy, 0.0, float(maxSamples - 1)));
vec2 invSamples = 1.0 / vec2(samples);
float accumulator = 0.0;
for (int j = 0; j < maxSamples; j++) {
if(j >= samples.y) {
break;
}
for (int i = 0; i < maxSamples; i++) {
if(i >= samples.x) {
break;
}
vec2 step = vec2(i,j) * invSamples - 0.5;
accumulator += coverage(p + step.x * dxdy.x + step.y * dxdy.y, fwidth);
}
}
accumulator /= float(samples.x * samples.y);
return accumulator;
}`)),O.uniforms.add(new u.Float4PassUniform("uColor",(e=>e.color))),O.code.add(v.glsl`
    void main() {
      discardBySlice(vpos);
      ${T?"terrainDepthTest(gl_FragCoord, depth);":""}
      vec4 color = ${e.hasVertexColors?"vColor * uColor;":"uColor;"}
      color = highlightSlice(color, vpos);

      ${e.output!==t.ShaderOutput.Highlight?v.glsl`color.a *= ${x(e)};`:""}

      if (color.a < ${v.glsl.float(s.symbolAlphaCutoff)}) {
        discard;
      }

      ${e.output===t.ShaderOutput.Alpha?v.glsl`gl_FragColor = vec4(color.a);`:""}

      ${e.output===t.ShaderOutput.Color?v.glsl`gl_FragColor = color; ${e.transparencyPassType===h.TransparencyPassType.Color?"gl_FragColor = premultiplyAlpha(gl_FragColor);":""}`:""}
      ${e.output===t.ShaderOutput.Highlight?v.glsl`outputHighlight();`:""}
      ${e.output===t.ShaderOutput.Depth?v.glsl`outputDepth(linearDepth);`:""};
    }
  `),P}function x(e){function t(t){return e.draped?v.glsl`coverage(vuv.${t}, texelSize)`:v.glsl`sample(vuv.${t})`}switch(e.style){case w.Style.ForwardDiagonal:case w.Style.Horizontal:return t("y");case w.Style.BackwardDiagonal:case w.Style.Vertical:return t("x");case w.Style.DiagonalCross:case w.Style.Cross:return v.glsl`
        1.0 - (1.0 - ${t("x")}) * (1.0 - ${t("y")})
      `;default:return"0.0"}}const T=Object.freeze(Object.defineProperty({__proto__:null,build:P},Symbol.toStringTag,{value:"Module"}));e.Pattern=T,e.build=P}));
