text: /**
   * Classes and utilities for generating shaders from literal style objects
   * @module ol/webgl/ShaderBuilder
   */
  import { ValueTypes, expressionToGlsl, getStringNumberEquivalent, uniformNameForVariable, } from '../style/expressions.js';
  /**
   * @typedef {Object} VaryingDescription
   * @property {string} name Varying name, as will be declared in the header.
   * @property {string} type Varying type, either `float`, `vec2`, `vec4`...
   * @property {string} expression Expression which will be assigned to the varying in the vertex shader, and
   * passed on to the fragment shader.
   */
  /**
   * @classdesc
   * This class implements a classic builder pattern for generating many different types of shaders.
   * Methods can be chained, e. g.:
   *
   * ```js
   * const shader = new ShaderBuilder()
   *   .addVarying('v_width', 'float', 'a_width')
   *   .addUniform('u_time')
   *   .setColorExpression('...')
   *   .setSizeExpression('...')
   *   .outputSymbolFragmentShader();
   * ```
   */
  var ShaderBuilder = /** @class */ (function () {
      function ShaderBuilder() {
          /**
           * Uniforms; these will be declared in the header (should include the type).
           * @type {Array<string>}
           * @private
           */
          this.uniforms = [];
          /**
           * Attributes; these will be declared in the header (should include the type).
           * @type {Array<string>}
           * @private
           */
          this.attributes = [];
          /**
           * Varyings with a name, a type and an expression.
           * @type {Array<VaryingDescription>}
           * @private
           */
          this.varyings = [];
          /**
           * @type {string}
           * @private
           */
          this.sizeExpression = 'vec2(1.0)';
          /**
           * @type {string}
           * @private
           */
          this.rotationExpression = '0.0';
          /**
           * @type {string}
           * @private
           */
          this.offsetExpression = 'vec2(0.0)';
          /**
           * @type {string}
           * @private
           */
          this.colorExpression = 'vec4(1.0)';
          /**
           * @type {string}
           * @private
           */
          this.texCoordExpression = 'vec4(0.0, 0.0, 1.0, 1.0)';
          /**
           * @type {string}
           * @private
           */
          this.discardExpression = 'false';
          /**
           * @type {boolean}
           * @private
           */
          this.rotateWithView = false;
      }
      /**
       * Adds a uniform accessible in both fragment and vertex shaders.
       * The given name should include a type, such as `sampler2D u_texture`.
       * @param {string} name Uniform name
       * @return {ShaderBuilder} the builder object
       */
      ShaderBuilder.prototype.addUniform = function (name) {
          this.uniforms.push(name);
          return this;
      };
      /**
       * Adds an attribute accessible in the vertex shader, read from the geometry buffer.
       * The given name should include a type, such as `vec2 a_position`.
       * @param {string} name Attribute name
       * @return {ShaderBuilder} the builder object
       */
      ShaderBuilder.prototype.addAttribute = function (name) {
          this.attributes.push(name);
          return this;
      };
      /**
       * Adds a varying defined in the vertex shader and accessible from the fragment shader.
       * The type and expression of the varying have to be specified separately.
       * @param {string} name Varying name
       * @param {'float'|'vec2'|'vec3'|'vec4'} type Type
       * @param {string} expression Expression used to assign a value to the varying.
       * @return {ShaderBuilder} the builder object
       */
      ShaderBuilder.prototype.addVarying = function (name, type, expression) {
          this.varyings.push({
              name: name,
              type: type,
              expression: expression,
          });
          return this;
      };
      /**
       * Sets an expression to compute the size of the shape.
       * This expression can use all the uniforms and attributes available
       * in the vertex shader, and should evaluate to a `vec2` value.
       * @param {string} expression Size expression
       * @return {ShaderBuilder} the builder object
       */
      ShaderBuilder.prototype.setSizeExpression = function (expression) {
          this.sizeExpression = expression;
          return this;
      };
      /**
       * Sets an expression to compute the rotation of the shape.
       * This expression can use all the uniforms and attributes available
       * in the vertex shader, and should evaluate to a `float` value in radians.
       * @param {string} expression Size expression
       * @return {ShaderBuilder} the builder object
       */
      ShaderBuilder.prototype.setRotationExpression = function (expression) {
          this.rotationExpression = expression;
          return this;
      };
      /**
       * Sets an expression to compute the offset of the symbol from the point center.
       * This expression can use all the uniforms and attributes available
       * in the vertex shader, and should evaluate to a `vec2` value.
       * Note: will only be used for point geometry shaders.
       * @param {string} expression Offset expression
       * @return {ShaderBuilder} the builder object
       */
      ShaderBuilder.prototype.setSymbolOffsetExpression = function (expression) {
          this.offsetExpression = expression;
          return this;
      };
      /**
       * Sets an expression to compute the color of the shape.
       * This expression can use all the uniforms, varyings and attributes available
       * in the fragment shader, and should evaluate to a `vec4` value.
       * @param {string} expression Color expression
       * @return {ShaderBuilder} the builder object
       */
      ShaderBuilder.prototype.setColorExpression = function (expression) {
          this.colorExpression = expression;
          return this;
      };
      /**
       * Sets an expression to compute the texture coordinates of the vertices.
       * This expression can use all the uniforms and attributes available
       * in the vertex shader, and should evaluate to a `vec4` value.
       * @param {string} expression Texture coordinate expression
       * @return {ShaderBuilder} the builder object
       */
      ShaderBuilder.prototype.setTextureCoordinateExpression = function (expression) {
          this.texCoordExpression = expression;
          return this;
      };
      /**
       * Sets an expression to determine whether a fragment (pixel) should be discarded,
       * i.e. not drawn at all.
       * This expression can use all the uniforms, varyings and attributes available
       * in the fragment shader, and should evaluate to a `bool` value (it will be
       * used in an `if` statement)
       * @param {string} expression Fragment discard expression
       * @return {ShaderBuilder} the builder object
       */
      ShaderBuilder.prototype.setFragmentDiscardExpression = function (expression) {
          this.discardExpression = expression;
          return this;
      };
      /**
       * Sets whether the symbols should rotate with the view or stay aligned with the map.
       * Note: will only be used for point geometry shaders.
       * @param {boolean} rotateWithView Rotate with view
       * @return {ShaderBuilder} the builder object
       */
      ShaderBuilder.prototype.setSymbolRotateWithView = function (rotateWithView) {
          this.rotateWithView = rotateWithView;
          return this;
      };
      /**
       * @return {string} Previously set size expression
       */
      ShaderBuilder.prototype.getSizeExpression = function () {
          return this.sizeExpression;
      };
      /**
       * @return {string} Previously set symbol offset expression
       */
      ShaderBuilder.prototype.getOffsetExpression = function () {
          return this.offsetExpression;
      };
      /**
       * @return {string} Previously set color expression
       */
      ShaderBuilder.prototype.getColorExpression = function () {
          return this.colorExpression;
      };
      /**
       * @return {string} Previously set texture coordinate expression
       */
      ShaderBuilder.prototype.getTextureCoordinateExpression = function () {
          return this.texCoordExpression;
      };
      /**
       * @return {string} Previously set fragment discard expression
       */
      ShaderBuilder.prototype.getFragmentDiscardExpression = function () {
          return this.discardExpression;
      };
      /**
       * Generates a symbol vertex shader from the builder parameters,
       * intended to be used on point geometries.
       *
       * Three uniforms are hardcoded in all shaders: `u_projectionMatrix`, `u_offsetScaleMatrix`,
       * `u_offsetRotateMatrix`, `u_time`.
       *
       * The following attributes are hardcoded and expected to be present in the vertex buffers:
       * `vec2 a_position`, `float a_index` (being the index of the vertex in the quad, 0 to 3).
       *
       * The following varyings are hardcoded and gives the coordinate of the pixel both in the quad and on the texture:
       * `vec2 v_quadCoord`, `vec2 v_texCoord`
       *
       * @param {boolean} [forHitDetection] If true, the shader will be modified to include hit detection variables
       * (namely, hit color with encoded feature id).
       * @return {string} The full shader as a string.
       */
      ShaderBuilder.prototype.getSymbolVertexShader = function (forHitDetection) {
          var offsetMatrix = this.rotateWithView
              ? 'u_offsetScaleMatrix * u_offsetRotateMatrix'
              : 'u_offsetScaleMatrix';
          var attributes = this.attributes;
          var varyings = this.varyings;
          if (forHitDetection) {
              attributes = attributes.concat('vec4 a_hitColor');
              varyings = varyings.concat({
                  name: 'v_hitColor',
                  type: 'vec4',
                  expression: 'a_hitColor',
              });
          }
          return "precision mediump float;\nuniform mat4 u_projectionMatrix;\nuniform mat4 u_offsetScaleMatrix;\nuniform mat4 u_offsetRotateMatrix;\nuniform float u_time;\nuniform float u_zoom;\nuniform float u_resolution;\n" + this.uniforms
              .map(function (uniform) {
              return 'uniform ' + uniform + ';';
          })
              .join('\n') + "\nattribute vec2 a_position;\nattribute float a_index;\n" + attributes
              .map(function (attribute) {
              return 'attribute ' + attribute + ';';
          })
              .join('\n') + "\nvarying vec2 v_texCoord;\nvarying vec2 v_quadCoord;\n" + varyings
              .map(function (varying) {
              return 'varying ' + varying.type + ' ' + varying.name + ';';
          })
              .join('\n') + "\nvoid main(void) {\n  mat4 offsetMatrix = " + offsetMatrix + ";\n  vec2 halfSize = " + this.sizeExpression + " * 0.5;\n  vec2 offset = " + this.offsetExpression + ";\n  float angle = " + this.rotationExpression + ";\n  float offsetX;\n  float offsetY;\n  if (a_index == 0.0) {\n    offsetX = (offset.x - halfSize.x) * cos(angle) + (offset.y - halfSize.y) * sin(angle);\n    offsetY = (offset.y - halfSize.y) * cos(angle) - (offset.x - halfSize.x) * sin(angle);\n  } else if (a_index == 1.0) {\n    offsetX = (offset.x + halfSize.x) * cos(angle) + (offset.y - halfSize.y) * sin(angle);\n    offsetY = (offset.y - halfSize.y) * cos(angle) - (offset.x + halfSize.x) * sin(angle);\n  } else if (a_index == 2.0) {\n    offsetX = (offset.x + halfSize.x) * cos(angle) + (offset.y + halfSize.y) * sin(angle);\n    offsetY = (offset.y + halfSize.y) * cos(angle) - (offset.x + halfSize.x) * sin(angle);\n  } else {\n    offsetX = (offset.x - halfSize.x) * cos(angle) + (offset.y + halfSize.y) * sin(angle);\n    offsetY = (offset.y + halfSize.y) * cos(angle) - (offset.x - halfSize.x) * sin(angle);\n  }\n  vec4 offsets = offsetMatrix * vec4(offsetX, offsetY, 0.0, 0.0);\n  gl_Position = u_projectionMatrix * vec4(a_position, 0.0, 1.0) + offsets;\n  vec4 texCoord = " + this.texCoordExpression + ";\n  float u = a_index == 0.0 || a_index == 3.0 ? texCoord.s : texCoord.p;\n  float v = a_index == 2.0 || a_index == 3.0 ? texCoord.t : texCoord.q;\n  v_texCoord = vec2(u, v);\n  u = a_index == 0.0 || a_index == 3.0 ? 0.0 : 1.0;\n  v = a_index == 2.0 || a_index == 3.0 ? 0.0 : 1.0;\n  v_quadCoord = vec2(u, v);\n" + varyings
              .map(function (varying) {
              return '  ' + varying.name + ' = ' + varying.expression + ';';
          })
              .join('\n') + "\n}";
      };
      /**
       * Generates a symbol fragment shader from the builder parameters,
       * intended to be used on point geometries.
       *
       * Expects the following varyings to be transmitted by the vertex shader:
       * `vec2 v_quadCoord`, `vec2 v_texCoord`
       *
       * @param {boolean} [forHitDetection] If true, the shader will be modified to include hit detection variables
       * (namely, hit color with encoded feature id).
       * @return {string} The full shader as a string.
       */
      ShaderBuilder.prototype.getSymbolFragmentShader = function (forHitDetection) {
          var hitDetectionBypass = forHitDetection
              ? '  if (gl_FragColor.a < 0.1) { discard; } gl_FragColor = v_hitColor;'
              : '';
          var varyings = this.varyings;
          if (forHitDetection) {
              varyings = varyings.concat({
                  name: 'v_hitColor',
                  type: 'vec4',
                  expression: 'a_hitColor',
              });
          }
          return "precision mediump float;\nuniform float u_time;\nuniform float u_zoom;\nuniform float u_resolution;\n" + this.uniforms
              .map(function (uniform) {
              return 'uniform ' + uniform + ';';
          })
              .join('\n') + "\nvarying vec2 v_texCoord;\nvarying vec2 v_quadCoord;\n" + varyings
              .map(function (varying) {
              return 'varying ' + varying.type + ' ' + varying.name + ';';
          })
              .join('\n') + "\nvoid main(void) {\n  if (" + this.discardExpression + ") { discard; }\n  gl_FragColor = " + this.colorExpression + ";\n  gl_FragColor.rgb *= gl_FragColor.a;\n" + hitDetectionBypass + "\n}";
      };
      return ShaderBuilder;
  }());
  export { ShaderBuilder };
  /**
   * @typedef {Object} StyleParseResult
   * @property {ShaderBuilder} builder Shader builder pre-configured according to a given style
   * @property {Object<string,import("./Helper").UniformValue>} uniforms Uniform definitions.
   * @property {Array<import("../renderer/webgl/PointsLayer").CustomAttribute>} attributes Attribute descriptions.
   */
  /**
   * Parses a {@link import("../style/literal").LiteralStyle} object and returns a {@link ShaderBuilder}
   * object that has been configured according to the given style, as well as `attributes` and `uniforms`
   * arrays to be fed to the `WebGLPointsRenderer` class.
   *
   * Also returns `uniforms` and `attributes` properties as expected by the
   * {@link module:ol/renderer/webgl/PointsLayer~WebGLPointsLayerRenderer}.
   *
   * @param {import("../style/literal").LiteralStyle} style Literal style.
   * @return {StyleParseResult} Result containing shader params, attributes and uniforms.
   */
  export function parseLiteralStyle(style) {
      var symbStyle = style.symbol;
      var size = symbStyle.size !== undefined ? symbStyle.size : 1;
      var color = symbStyle.color || 'white';
      var texCoord = symbStyle.textureCoord || [0, 0, 1, 1];
      var offset = symbStyle.offset || [0, 0];
      var opacity = symbStyle.opacity !== undefined ? symbStyle.opacity : 1;
      var rotation = symbStyle.rotation !== undefined ? symbStyle.rotation : 0;
      /**
       * @type {import("../style/expressions.js").ParsingContext}
       */
      var vertContext = {
          inFragmentShader: false,
          variables: [],
          attributes: [],
          stringLiteralsMap: {},
          functions: {},
      };
      var parsedSize = expressionToGlsl(vertContext, size, ValueTypes.NUMBER_ARRAY | ValueTypes.NUMBER);
      var parsedOffset = expressionToGlsl(vertContext, offset, ValueTypes.NUMBER_ARRAY);
      var parsedTexCoord = expressionToGlsl(vertContext, texCoord, ValueTypes.NUMBER_ARRAY);
      var parsedRotation = expressionToGlsl(vertContext, rotation, ValueTypes.NUMBER);
      /**
       * @type {import("../style/expressions.js").ParsingContext}
       */
      var fragContext = {
          inFragmentShader: true,
          variables: vertContext.variables,
          attributes: [],
          stringLiteralsMap: vertContext.stringLiteralsMap,
          functions: {},
      };
      var parsedColor = expressionToGlsl(fragContext, color, ValueTypes.COLOR);
      var parsedOpacity = expressionToGlsl(fragContext, opacity, ValueTypes.NUMBER);
      var opacityFilter = '1.0';
      var visibleSize = "vec2(" + expressionToGlsl(fragContext, size, ValueTypes.NUMBER_ARRAY | ValueTypes.NUMBER) + ").x";
      switch (symbStyle.symbolType) {
          case 'square':
              break;
          case 'image':
              break;
          // taken from https://thebookofshaders.com/07/
          case 'circle':
              opacityFilter = "(1.0-smoothstep(1.-4./" + visibleSize + ",1.,dot(v_quadCoord-.5,v_quadCoord-.5)*4.))";
              break;
          case 'triangle':
              var st = '(v_quadCoord*2.-1.)';
              var a = "(atan(" + st + ".x," + st + ".y))";
              opacityFilter = "(1.0-smoothstep(.5-3./" + visibleSize + ",.5,cos(floor(.5+" + a + "/2.094395102)*2.094395102-" + a + ")*length(" + st + ")))";
              break;
          default:
              throw new Error('Unexpected symbol type: ' + symbStyle.symbolType);
      }
      var builder = new ShaderBuilder()
          .setSizeExpression("vec2(" + parsedSize + ")")
          .setRotationExpression(parsedRotation)
          .setSymbolOffsetExpression(parsedOffset)
          .setTextureCoordinateExpression(parsedTexCoord)
          .setSymbolRotateWithView(!!symbStyle.rotateWithView)
          .setColorExpression("vec4(" + parsedColor + ".rgb, " + parsedColor + ".a * " + parsedOpacity + " * " + opacityFilter + ")");
      if (style.filter) {
          var parsedFilter = expressionToGlsl(fragContext, style.filter, ValueTypes.BOOLEAN);
          builder.setFragmentDiscardExpression("!" + parsedFilter);
      }
      /** @type {Object<string,import("../webgl/Helper").UniformValue>} */
      var uniforms = {};
      // define one uniform per variable
      fragContext.variables.forEach(function (varName) {
          var uniformName = uniformNameForVariable(varName);
          builder.addUniform("float " + uniformName);
          uniforms[uniformName] = function () {
              if (!style.variables || style.variables[varName] === undefined) {
                  throw new Error("The following variable is missing from the style: " + varName);
              }
              var value = style.variables[varName];
              if (typeof value === 'string') {
                  value = getStringNumberEquivalent(vertContext, value);
              }
              return value !== undefined ? value : -9999999; // to avoid matching with the first string literal
          };
      });
      if (symbStyle.symbolType === 'image' && symbStyle.src) {
          var texture = new Image();
          texture.src = symbStyle.src;
          builder
              .addUniform('sampler2D u_texture')
              .setColorExpression(builder.getColorExpression() + ' * texture2D(u_texture, v_texCoord)');
          uniforms['u_texture'] = texture;
      }
      // for each feature attribute used in the fragment shader, define a varying that will be used to pass data
      // from the vertex to the fragment shader, as well as an attribute in the vertex shader (if not already present)
      fragContext.attributes.forEach(function (attrName) {
          if (vertContext.attributes.indexOf(attrName) === -1) {
              vertContext.attributes.push(attrName);
          }
          builder.addVarying("v_" + attrName, 'float', "a_" + attrName);
      });
      // for each feature attribute used in the vertex shader, define an attribute in the vertex shader.
      vertContext.attributes.forEach(function (attrName) {
          builder.addAttribute("float a_" + attrName);
      });
      return {
          builder: builder,
          attributes: vertContext.attributes.map(function (attributeName) {
              return {
                  name: attributeName,
                  callback: function (feature, props) {
                      var value = props[attributeName];
                      if (typeof value === 'string') {
                          value = getStringNumberEquivalent(vertContext, value);
                      }
                      return value !== undefined ? value : -9999999; // to avoid matching with the first string literal
                  },
              };
          }),
          uniforms: uniforms,
      };
  }
  //# sourceMappingURL=ShaderBuilder.js.map