/* COPYRIGHT Esri - https://js.arcgis.com/5.1.0/LICENSE.txt */
import{SliceDraw as e}from"../views/3d/webgl-engine/core/shaderLibrary/Slice.glsl.js";import{Transform as o}from"../views/3d/webgl-engine/core/shaderLibrary/Transform.glsl.js";import{ObjectAndLayerIdColor as t}from"../views/3d/webgl-engine/core/shaderLibrary/attributes/ObjectAndLayerIdColor.glsl.js";import{VertexColor as r}from"../views/3d/webgl-engine/core/shaderLibrary/attributes/VertexColor.glsl.js";import{VisualVariables as a}from"../views/3d/webgl-engine/core/shaderLibrary/shading/VisualVariables.glsl.js";import{ColorConversion as i}from"../views/3d/webgl-engine/core/shaderLibrary/util/ColorConversion.glsl.js";import{addProjViewLocalOrigin as l,addCameraPosition as n}from"../views/3d/webgl-engine/core/shaderLibrary/util/View.glsl.js";import{Float4PassUniform as c}from"../views/3d/webgl-engine/core/shaderModules/Float4PassUniform.js";import{FloatBindUniform as d}from"../views/3d/webgl-engine/core/shaderModules/FloatBindUniform.js";import{glsl as s,If as v}from"../views/3d/webgl-engine/core/shaderModules/glsl.js";import{outputColorHighlightOLID as u}from"../views/3d/webgl-engine/shaders/OutputColorHighlightOLID.glsl.js";import{getTextureBackedBufferModule as p}from"../views/3d/webgl-engine/shaders/PatternTextureBuffer.glsl.js";import{ShaderBuilder as m}from"../views/webgl/ShaderBuilder.js";const f=.70710678118,g=f,w=.08715574274,b=10,h=1;function x(x){const S=p(x),j=null!=S,C=new m;j&&C.include(S.TextureBackedBufferModule,x);const{vertex:V,fragment:T,attributes:P,varyings:$}=C,R=10===x.output;l(V,x),C.include(o);let A="";j?(x.hasVVColor&&(A=S.getTextureAttribute("colorFeatureAttribute")),x.hasVertexColors?(C.varyings.add("vColor","vec4"),C.vertex.code.add(s`void forwardVertexColor() { vColor = ${S.getTextureAttribute("color")}; }`)):C.vertex.code.add(s`void forwardVertexColor() {}`),P.add("textureElementIndex","uint")):(C.include(r,x),x.hasVVColor&&(P.add("colorFeatureAttribute","float"),A="colorFeatureAttribute")),P.add("position","vec3"),V.inputs.add("position",()=>"position"),C.include(a,x),C.include(t,x),T.include(e,x),C.include(u,x),x.draped&&V.uniforms.add(new d("worldToScreenRatio",e=>1/e.screenToPCSRatio)),P.add("uvMapSpace","vec4"),x.hasVertexColors||$.add("vColor","vec4"),$.add("vpos","vec3",{invariant:!0}),$.add("vuv","vec2"),V.uniforms.add(new c("uColor",e=>e.color));const L=3===x.style||4===x.style||5===x.style;return L&&V.code.add(s`
      const mat2 rotate45 = mat2(${s.float(f)}, ${s.float(-g)},
                                 ${s.float(g)}, ${s.float(f)});
    `),!x.draped&&j&&(n(V,x),V.uniforms.add(new d("worldToScreenPerDistanceRatio",e=>1/e.camera.perScreenPixelRatio)),V.code.add(s`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);
}`),V.code.add(s`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;
}`),V.code.add(s`
      float boundingRectDistanceToCamera() {
        vec3 center = ${S.getTextureAttribute("boundingRect")}[0];
        vec3 halfU = ${S.getTextureAttribute("boundingRect")}[1];
        vec3 halfV = ${S.getTextureAttribute("boundingRect")}[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 = ${s.float(w)};

        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);
      }
    `)),V.code.add(s`
    vec2 scaledUV() {
      vec2 uv = uvMapSpace.xy ${v(L," * rotate45")};
      vec2 uvCellOrigin = uvMapSpace.zw ${v(L," * rotate45")};

      ${v(!x.draped,s`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, ${s.float(b)});
      return uvOffset + (uv * discreteWorldToScreenRatio);
    }
  `),V.main.add(s`
    vuv = scaledUV();
    vpos = position;
    forwardVertexColor();
    forwardObjectAndLayerIdColor();
    ${x.hasVertexColors?"vColor *= uColor;":x.hasVVColor?s`vColor = uColor * interpolateVVColor(${A});`:"vColor = uColor;"}
    gl_Position = transformPosition(proj, view, vpos);
  `),T.include(i),x.draped&&T.uniforms.add(new d("texelSize",e=>1/e.camera.pixelRatio)),R||(T.code.add(s`
      const float lineWidth = ${s.float(h)};
      const float spacing = ${s.float(b)};
      const float spacingINV = ${s.float(1/b)};

      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;
      }
    `),x.draped||T.code.add(s`const int maxSamples = 5;
float sampleAA(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;
}`)),T.main.add(s`
    discardBySlice(vpos);
    vec4 color = vColor;
    ${v(!R,s`color.a *= ${y(x)};`)}
    outputColorHighlightOLID(applySlice(color, vpos), color.rgb);
  `),C}function y(e){function o(o){return e.draped?s`coverage(vuv.${o}, texelSize)`:s`sampleAA(vuv.${o})`}switch(e.style){case 3:case 0:return o("y");case 4:case 1:return o("x");case 5:case 2:return s`1.0 - (1.0 - ${o("x")}) * (1.0 - ${o("y")})`;default:return"0.0"}}const S=Object.freeze(Object.defineProperty({__proto__:null,build:x},Symbol.toStringTag,{value:"Module"}));export{S as P,x as b};
