/*
All material copyright ESRI, All Rights Reserved, unless otherwise specified.
See https://js.arcgis.com/4.24/esri/copyright.txt for details.
*/
define(["exports","../core/maybe","./vec2","./vec2f64","./vec4f64","../views/3d/layers/graphics/sdfPrimitives","../views/3d/webgl-engine/core/shaderLibrary/ShaderOutputOptions","../views/3d/webgl-engine/core/shaderLibrary/Slice.glsl","../views/3d/webgl-engine/core/shaderLibrary/hud/AlignPixel.glsl","../views/3d/webgl-engine/core/shaderLibrary/hud/HUD.glsl","../views/3d/webgl-engine/core/shaderLibrary/hud/HUDOcclusionPass.glsl","../views/3d/webgl-engine/core/shaderLibrary/output/OutputHighlight.glsl","../views/3d/webgl-engine/core/shaderLibrary/shading/VisualVariables.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/RgbaFloatEncoding.glsl","../views/3d/webgl-engine/core/shaderLibrary/util/ScreenSizePerspective.glsl","../views/3d/webgl-engine/core/shaderModules/Float2PassUniform","../views/3d/webgl-engine/core/shaderModules/Float4PassUniform","../views/3d/webgl-engine/core/shaderModules/Float4sPassUniform","../views/3d/webgl-engine/core/shaderModules/FloatPassUniform","../views/3d/webgl-engine/core/shaderModules/FloatsPassUniform","../views/3d/webgl-engine/core/shaderModules/interfaces","../views/3d/webgl-engine/core/shaderModules/ShaderBuilder","../views/3d/webgl-engine/core/shaderModules/Texture2DPassUniform","../views/3d/webgl-engine/lib/basicInterfaces","../views/3d/webgl-engine/lib/VertexAttribute","../views/3d/webgl-engine/materials/VisualVariablePassParameters"],(function(e,o,l,i,r,a,t,s,n,c,d,u,g,v,p,f,b,h,m,C,x,w,P,S,z,F,y,A){"use strict";function O(e){const O=new S.ShaderBuilder,$=e.signedDistanceFieldEnabled;if(O.include(n.AlignPixel),O.include(c.HUD,e),O.include(s.SliceDraw,e),e.output===t.ShaderOutput.Occlusion)return O.include(d.HUDOcclusionPass,e),O;const{vertex:_,fragment:B}=O;O.include(b.ScreenSizePerspective),B.include(f.RgbaFloatEncoding),B.include(p.ColorConversion),O.include(g.VisualVariables,e),O.varyings.add("vcolor","vec4"),O.varyings.add("vtc","vec2"),O.varyings.add("vsize","vec2"),e.binaryHighlightOcclusionEnabled&&O.varyings.add("voccluded","float"),_.uniforms.add([new m.Float4PassUniform("viewport",((e,o)=>o.camera.fullViewport)),new h.Float2PassUniform("screenOffset",((e,o)=>l.set(j,2*e.screenOffset[0]*o.camera.pixelRatio,2*e.screenOffset[1]*o.camera.pixelRatio))),new h.Float2PassUniform("anchorPosition",(e=>U(e))),new m.Float4PassUniform("materialColor",(e=>e.color)),new x.FloatPassUniform("pixelRatio",((e,o)=>o.camera.pixelRatio))]),$&&(_.uniforms.add(new m.Float4PassUniform("outlineColor",(e=>e.outlineColor))),B.uniforms.add([new m.Float4PassUniform("outlineColor",(e=>D(e)?e.outlineColor:r.ZEROS)),new x.FloatPassUniform("outlineSize",(e=>D(e)?e.outlineSize:0))])),e.hasScreenSizePerspective&&(b.addScreenSizePerspective(_),b.addScreenSizePerspectiveAlignment(_)),(e.debugDrawLabelBorder||e.binaryHighlightOcclusionEnabled)&&O.varyings.add("debugBorderCoords","vec4"),O.attributes.add(y.VertexAttribute.UV0,"vec2"),O.attributes.add(y.VertexAttribute.COLOR,"vec4"),O.attributes.add(y.VertexAttribute.SIZE,"vec2"),O.attributes.add(y.VertexAttribute.AUXPOS2,"vec4"),_.code.add(P.glsl`
    void main(void) {
      ProjectHUDAux projectAux;
      vec4 posProj = projectPositionHUD(projectAux);

      if (rejectBySlice(projectAux.posModel)) {
        // Project outside of clip plane
        gl_Position = vec4(1e038, 1e038, 1e038, 1.0);
        return;
      }
      vec2 inputSize;
      ${e.hasScreenSizePerspective?P.glsl`
      inputSize = screenSizePerspectiveScaleVec2(size, projectAux.absCosAngle, projectAux.distanceToCamera, screenSizePerspective);
      vec2 screenOffsetScaled = screenSizePerspectiveScaleVec2(screenOffset, projectAux.absCosAngle, projectAux.distanceToCamera, screenSizePerspectiveAlignment);
         `:P.glsl`
      inputSize = size;
      vec2 screenOffsetScaled = screenOffset;`}

      ${e.vvSize?"inputSize *= vvScale(auxpos2).xx;":""}

      vec2 combinedSize = inputSize * pixelRatio;
      vec4 quadOffset = vec4(0.0);

      ${e.occlusionTestEnabled||e.binaryHighlightOcclusionEnabled?"bool visible = testVisibilityHUD(posProj);":""}

      ${e.binaryHighlightOcclusionEnabled?"voccluded = visible ? 0.0 : 1.0;":""}
    `);const L=P.glsl`vec2 uv01 = floor(uv0);
vec2 uv = uv0 - uv01;
quadOffset.xy = ((uv01 - anchorPosition) * 2.0 * combinedSize + screenOffsetScaled) / viewport.zw * posProj.w;`,V=e.pixelSnappingEnabled?$?P.glsl`posProj = alignToPixelOrigin(posProj, viewport.zw) + quadOffset;`:P.glsl`posProj += quadOffset;
if (inputSize.x == size.x) {
posProj = alignToPixelOrigin(posProj, viewport.zw);
}`:P.glsl`posProj += quadOffset;`;e.vvColor&&_.uniforms.add([new C.Float4sPassUniform("vvColorColors",(e=>e.vvColorColors),A.vvColorNumber),new w.FloatsPassUniform("vvColorValues",(e=>e.vvColorValues),A.vvColorNumber)]),_.uniforms.add(new h.Float2PassUniform("textureCoordinateScaleFactor",(e=>o.isSome(e.texture)&&o.isSome(e.texture.descriptor.textureCoordinateScaleFactor)?e.texture.descriptor.textureCoordinateScaleFactor:i.ONES))),_.code.add(P.glsl`
    ${e.occlusionTestEnabled?"if (visible) {":""}
    ${L}
    ${e.vvColor?"vcolor = vvGetColor(auxpos2, vvColorValues, vvColorColors) * materialColor;":"vcolor = color / 255.0 * materialColor;"}

    bool alphaDiscard = vcolor.a < ${P.glsl.float(v.symbolAlphaCutoff)};
    ${$?`alphaDiscard = alphaDiscard && outlineColor.a < ${P.glsl.float(v.symbolAlphaCutoff)};`:""}
    if (alphaDiscard) {
      // "early discard" if both symbol color (= fill) and outline color (if applicable) are transparent
      gl_Position = vec4(1e38, 1e38, 1e38, 1.0);
      return;
    } else {
      ${V}
      gl_Position = posProj;
    }

    vtc = uv * textureCoordinateScaleFactor;

    ${e.debugDrawLabelBorder?"debugBorderCoords = vec4(uv01, 1.5 / combinedSize);":""}
    vsize = inputSize;
    ${e.occlusionTestEnabled?P.glsl`} else { vtc = vec2(0.0);
      ${e.debugDrawLabelBorder?"debugBorderCoords = vec4(0.5, 0.5, 1.5 / combinedSize);}":"}"}`:""}
  }
  `),B.uniforms.add(new z.Texture2DPassUniform("tex",(e=>e.texture)));const E=e.debugDrawLabelBorder?P.glsl`(isBorder > 0.0 ? 0.0 : ${P.glsl.float(v.defaultMaskAlphaCutoff)})`:P.glsl.float(v.defaultMaskAlphaCutoff),H=P.glsl`
    ${e.debugDrawLabelBorder?P.glsl`
      float isBorder = float(any(lessThan(debugBorderCoords.xy, debugBorderCoords.zw)) || any(greaterThan(debugBorderCoords.xy, 1.0 - debugBorderCoords.zw)));`:""}

    ${$?P.glsl`
      vec4 fillPixelColor = vcolor;

      // Attempt to sample texel centers to avoid that thin cross outlines
      // disappear with large symbol sizes.
      // see: https://devtopia.esri.com/WebGIS/arcgis-js-api/issues/7058#issuecomment-603041
      const float txSize = ${P.glsl.float(a.DEFAULT_TEX_SIZE)};
      const float texelSize = 1.0 / txSize;
      // Calculate how much we have to add/subtract to/from each texel to reach the size of an onscreen pixel
      vec2 scaleFactor = (vsize - txSize) * texelSize;
      vec2 samplePos = vtc + (vec2(1.0, -1.0) * texelSize) * scaleFactor;

      // Get distance and map it into [-0.5, 0.5]
      float d = rgba2float(texture2D(tex, samplePos)) - 0.5;

      // Distance in output units (i.e. pixels)
      float dist = d * vsize.x;

      // Create smooth transition from the icon into its outline
      float fillAlphaFactor = clamp(0.5 - dist, 0.0, 1.0);
      fillPixelColor.a *= fillAlphaFactor;

      if (outlineSize > 0.25) {
        vec4 outlinePixelColor = outlineColor;
        float clampedOutlineSize = min(outlineSize, 0.5*vsize.x);

        // Create smooth transition around outline
        float outlineAlphaFactor = clamp(0.5 - (abs(dist) - 0.5*clampedOutlineSize), 0.0, 1.0);
        outlinePixelColor.a *= outlineAlphaFactor;

        if (
          outlineAlphaFactor + fillAlphaFactor < ${E} ||
          fillPixelColor.a + outlinePixelColor.a < ${P.glsl.float(v.symbolAlphaCutoff)}
        ) {
          discard;
        }

        // perform un-premultiplied over operator (see https://en.wikipedia.org/wiki/Alpha_compositing#Description)
        float compositeAlpha = outlinePixelColor.a + fillPixelColor.a * (1.0 - outlinePixelColor.a);
        vec3 compositeColor = vec3(outlinePixelColor) * outlinePixelColor.a +
          vec3(fillPixelColor) * fillPixelColor.a * (1.0 - outlinePixelColor.a);

        gl_FragColor = vec4(compositeColor, compositeAlpha);
      } else {
        if (fillAlphaFactor < ${E}) {
          discard;
        }

        gl_FragColor = premultiplyAlpha(fillPixelColor);
      }

      // visualize SDF:
      // gl_FragColor = vec4(clamp(-dist/vsize.x*2.0, 0.0, 1.0), clamp(dist/vsize.x*2.0, 0.0, 1.0), 0.0, 1.0);
      `:P.glsl`
          vec4 texColor = texture2D(tex, vtc, -0.5);
          if (texColor.a < ${E}) {
            discard;
          }
          gl_FragColor = texColor * premultiplyAlpha(vcolor);
          `}

    // Draw debug border with transparency, so that original texels along border are still partially visible
    ${e.debugDrawLabelBorder?P.glsl`gl_FragColor = mix(gl_FragColor, vec4(1.0, 0.0, 1.0, 1.0), isBorder * 0.5);`:""}
  `;return e.output===t.ShaderOutput.Alpha&&B.code.add(P.glsl`
      void main() {
        ${H}
        gl_FragColor = vec4(gl_FragColor.a);
      }
      `),e.output===t.ShaderOutput.Color&&B.code.add(P.glsl`
    void main() {
      ${H}
      ${e.transparencyPassType===F.TransparencyPassType.FrontFace?"gl_FragColor.rgb /= gl_FragColor.a;":""}
    }
    `),e.output===t.ShaderOutput.Highlight&&(O.include(u.OutputHighlight),B.code.add(P.glsl`
    void main() {
      ${H}
      ${e.binaryHighlightOcclusionEnabled?P.glsl`
          if (voccluded == 1.0) {
            gl_FragColor = vec4(1.0, 1.0, 0.0, 1.0);
          } else {
            gl_FragColor = vec4(1.0, 0.0, 1.0, 1.0);
          }`:"outputHighlight();"}
    }
    `)),O}function D(e){return e.outlineColor[3]>0&&e.outlineSize>0}function U(e,o=j){return e.textureIsSignedDistanceField?$(e.anchorPosition,e.distanceFieldBoundingBox,o):l.copy(o,e.anchorPosition),o}function $(e,i,r){o.isSome(i)?l.set(r,e[0]*(i[2]-i[0])+i[0],e[1]*(i[3]-i[1])+i[1]):l.set(r,0,0)}const j=i.create(),_=Object.freeze(Object.defineProperty({__proto__:null,build:O,calculateAnchorPosForRendering:U},Symbol.toStringTag,{value:"Module"}));e.HUDMaterial=_,e.build=O,e.calculateAnchorPosForRendering=U}));
