text: /**
   * @module ol/render/webgl/TextureReplay
   */
  import {getUid} from '../../util.js';
  import {intersects} from '../../extent.js';
  import {isEmpty} from '../../obj.js';
  import {fragment, vertex} from '../webgl/texturereplay/defaultshader.js';
  import Locations from '../webgl/texturereplay/defaultshader/Locations.js';
  import WebGLReplay from '../webgl/Replay.js';
  import {CLAMP_TO_EDGE, FLOAT, TEXTURE_2D} from '../../webgl.js';
  import {createTexture} from '../../webgl/Context.js';
  
  var WebGLTextureReplay = (function (WebGLReplay) {
    function WebGLTextureReplay(tolerance, maxExtent) {
      WebGLReplay.call(this, tolerance, maxExtent);
  
      /**
       * @type {number|undefined}
       * @protected
       */
      this.anchorX = undefined;
  
      /**
       * @type {number|undefined}
       * @protected
       */
      this.anchorY = undefined;
  
      /**
       * @type {Array.<number>}
       * @protected
       */
      this.groupIndices = [];
  
      /**
       * @type {Array.<number>}
       * @protected
       */
      this.hitDetectionGroupIndices = [];
  
      /**
       * @type {number|undefined}
       * @protected
       */
      this.height = undefined;
  
      /**
       * @type {number|undefined}
       * @protected
       */
      this.imageHeight = undefined;
  
      /**
       * @type {number|undefined}
       * @protected
       */
      this.imageWidth = undefined;
  
      /**
       * @protected
       * @type {module:ol/render/webgl/texturereplay/defaultshader/Locations}
       */
      this.defaultLocations = null;
  
      /**
       * @protected
       * @type {number|undefined}
       */
      this.opacity = undefined;
  
      /**
       * @type {number|undefined}
       * @protected
       */
      this.originX = undefined;
  
      /**
       * @type {number|undefined}
       * @protected
       */
      this.originY = undefined;
  
      /**
       * @protected
       * @type {boolean|undefined}
       */
      this.rotateWithView = undefined;
  
      /**
       * @protected
       * @type {number|undefined}
       */
      this.rotation = undefined;
  
      /**
       * @protected
       * @type {number|undefined}
       */
      this.scale = undefined;
  
      /**
       * @type {number|undefined}
       * @protected
       */
      this.width = undefined;
    }
  
    if ( WebGLReplay ) WebGLTextureReplay.__proto__ = WebGLReplay;
    WebGLTextureReplay.prototype = Object.create( WebGLReplay && WebGLReplay.prototype );
    WebGLTextureReplay.prototype.constructor = WebGLTextureReplay;
  
    /**
     * @inheritDoc
     */
    WebGLTextureReplay.prototype.getDeleteResourcesFunction = function getDeleteResourcesFunction (context) {
      var verticesBuffer = this.verticesBuffer;
      var indicesBuffer = this.indicesBuffer;
      var textures = this.getTextures(true);
      var gl = context.getGL();
      return function() {
        if (!gl.isContextLost()) {
          var i, ii;
          for (i = 0, ii = textures.length; i < ii; ++i) {
            gl.deleteTexture(textures[i]);
          }
        }
        context.deleteBuffer(verticesBuffer);
        context.deleteBuffer(indicesBuffer);
      };
    };
  
    /**
     * @param {Array.<number>} flatCoordinates Flat coordinates.
     * @param {number} offset Offset.
     * @param {number} end End.
     * @param {number} stride Stride.
     * @return {number} My end.
     * @protected
     */
    WebGLTextureReplay.prototype.drawCoordinates = function drawCoordinates (flatCoordinates, offset, end, stride) {
      var this$1 = this;
  
      var anchorX = /** @type {number} */ (this.anchorX);
      var anchorY = /** @type {number} */ (this.anchorY);
      var height = /** @type {number} */ (this.height);
      var imageHeight = /** @type {number} */ (this.imageHeight);
      var imageWidth = /** @type {number} */ (this.imageWidth);
      var opacity = /** @type {number} */ (this.opacity);
      var originX = /** @type {number} */ (this.originX);
      var originY = /** @type {number} */ (this.originY);
      var rotateWithView = this.rotateWithView ? 1.0 : 0.0;
      // this.rotation_ is anti-clockwise, but rotation is clockwise
      var rotation = /** @type {number} */ (-this.rotation);
      var scale = /** @type {number} */ (this.scale);
      var width = /** @type {number} */ (this.width);
      var cos = Math.cos(rotation);
      var sin = Math.sin(rotation);
      var numIndices = this.indices.length;
      var numVertices = this.vertices.length;
      var i, n, offsetX, offsetY, x, y;
      for (i = offset; i < end; i += stride) {
        x = flatCoordinates[i] - this$1.origin[0];
        y = flatCoordinates[i + 1] - this$1.origin[1];
  
        // There are 4 vertices per [x, y] point, one for each corner of the
        // rectangle we're going to draw. We'd use 1 vertex per [x, y] point if
        // WebGL supported Geometry Shaders (which can emit new vertices), but that
        // is not currently the case.
        //
        // And each vertex includes 8 values: the x and y coordinates, the x and
        // y offsets used to calculate the position of the corner, the u and
        // v texture coordinates for the corner, the opacity, and whether the
        // the image should be rotated with the view (rotateWithView).
  
        n = numVertices / 8;
  
        // bottom-left corner
        offsetX = -scale * anchorX;
        offsetY = -scale * (height - anchorY);
        this$1.vertices[numVertices++] = x;
        this$1.vertices[numVertices++] = y;
        this$1.vertices[numVertices++] = offsetX * cos - offsetY * sin;
        this$1.vertices[numVertices++] = offsetX * sin + offsetY * cos;
        this$1.vertices[numVertices++] = originX / imageWidth;
        this$1.vertices[numVertices++] = (originY + height) / imageHeight;
        this$1.vertices[numVertices++] = opacity;
        this$1.vertices[numVertices++] = rotateWithView;
  
        // bottom-right corner
        offsetX = scale * (width - anchorX);
        offsetY = -scale * (height - anchorY);
        this$1.vertices[numVertices++] = x;
        this$1.vertices[numVertices++] = y;
        this$1.vertices[numVertices++] = offsetX * cos - offsetY * sin;
        this$1.vertices[numVertices++] = offsetX * sin + offsetY * cos;
        this$1.vertices[numVertices++] = (originX + width) / imageWidth;
        this$1.vertices[numVertices++] = (originY + height) / imageHeight;
        this$1.vertices[numVertices++] = opacity;
        this$1.vertices[numVertices++] = rotateWithView;
  
        // top-right corner
        offsetX = scale * (width - anchorX);
        offsetY = scale * anchorY;
        this$1.vertices[numVertices++] = x;
        this$1.vertices[numVertices++] = y;
        this$1.vertices[numVertices++] = offsetX * cos - offsetY * sin;
        this$1.vertices[numVertices++] = offsetX * sin + offsetY * cos;
        this$1.vertices[numVertices++] = (originX + width) / imageWidth;
        this$1.vertices[numVertices++] = originY / imageHeight;
        this$1.vertices[numVertices++] = opacity;
        this$1.vertices[numVertices++] = rotateWithView;
  
        // top-left corner
        offsetX = -scale * anchorX;
        offsetY = scale * anchorY;
        this$1.vertices[numVertices++] = x;
        this$1.vertices[numVertices++] = y;
        this$1.vertices[numVertices++] = offsetX * cos - offsetY * sin;
        this$1.vertices[numVertices++] = offsetX * sin + offsetY * cos;
        this$1.vertices[numVertices++] = originX / imageWidth;
        this$1.vertices[numVertices++] = originY / imageHeight;
        this$1.vertices[numVertices++] = opacity;
        this$1.vertices[numVertices++] = rotateWithView;
  
        this$1.indices[numIndices++] = n;
        this$1.indices[numIndices++] = n + 1;
        this$1.indices[numIndices++] = n + 2;
        this$1.indices[numIndices++] = n;
        this$1.indices[numIndices++] = n + 2;
        this$1.indices[numIndices++] = n + 3;
      }
  
      return numVertices;
    };
  
    /**
     * @protected
     * @param {Array.<WebGLTexture>} textures Textures.
     * @param {Array.<HTMLCanvasElement|HTMLImageElement|HTMLVideoElement>} images Images.
     * @param {!Object.<string, WebGLTexture>} texturePerImage Texture cache.
     * @param {WebGLRenderingContext} gl Gl.
     */
    WebGLTextureReplay.prototype.createTextures = function createTextures (textures, images, texturePerImage, gl) {
      var texture, image, uid, i;
      var ii = images.length;
      for (i = 0; i < ii; ++i) {
        image = images[i];
  
        uid = getUid(image).toString();
        if (uid in texturePerImage) {
          texture = texturePerImage[uid];
        } else {
          texture = createTexture(
            gl, image, CLAMP_TO_EDGE, CLAMP_TO_EDGE);
          texturePerImage[uid] = texture;
        }
        textures[i] = texture;
      }
    };
  
    /**
     * @inheritDoc
     */
    WebGLTextureReplay.prototype.setUpProgram = function setUpProgram (gl, context, size, pixelRatio) {
      // get the program
      var program = context.getProgram(fragment, vertex);
  
      // get the locations
      var locations;
      if (!this.defaultLocations) {
        locations = new Locations(gl, program);
        this.defaultLocations = locations;
      } else {
        locations = this.defaultLocations;
      }
  
      // use the program (FIXME: use the return value)
      context.useProgram(program);
  
      // enable the vertex attrib arrays
      gl.enableVertexAttribArray(locations.a_position);
      gl.vertexAttribPointer(locations.a_position, 2, FLOAT,
        false, 32, 0);
  
      gl.enableVertexAttribArray(locations.a_offsets);
      gl.vertexAttribPointer(locations.a_offsets, 2, FLOAT,
        false, 32, 8);
  
      gl.enableVertexAttribArray(locations.a_texCoord);
      gl.vertexAttribPointer(locations.a_texCoord, 2, FLOAT,
        false, 32, 16);
  
      gl.enableVertexAttribArray(locations.a_opacity);
      gl.vertexAttribPointer(locations.a_opacity, 1, FLOAT,
        false, 32, 24);
  
      gl.enableVertexAttribArray(locations.a_rotateWithView);
      gl.vertexAttribPointer(locations.a_rotateWithView, 1, FLOAT,
        false, 32, 28);
  
      return locations;
    };
  
    /**
     * @inheritDoc
     */
    WebGLTextureReplay.prototype.shutDownProgram = function shutDownProgram (gl, locations) {
      gl.disableVertexAttribArray(locations.a_position);
      gl.disableVertexAttribArray(locations.a_offsets);
      gl.disableVertexAttribArray(locations.a_texCoord);
      gl.disableVertexAttribArray(locations.a_opacity);
      gl.disableVertexAttribArray(locations.a_rotateWithView);
    };
  
    /**
     * @inheritDoc
     */
    WebGLTextureReplay.prototype.drawReplay = function drawReplay (gl, context, skippedFeaturesHash, hitDetection) {
      var this$1 = this;
  
      var textures = hitDetection ? this.getHitDetectionTextures() : this.getTextures();
      var groupIndices = hitDetection ? this.hitDetectionGroupIndices : this.groupIndices;
  
      if (!isEmpty(skippedFeaturesHash)) {
        this.drawReplaySkipping(gl, context, skippedFeaturesHash, textures, groupIndices);
      } else {
        var i, ii, start;
        for (i = 0, ii = textures.length, start = 0; i < ii; ++i) {
          gl.bindTexture(TEXTURE_2D, textures[i]);
          var end = groupIndices[i];
          this$1.drawElements(gl, context, start, end);
          start = end;
        }
      }
    };
  
    /**
     * Draw the replay while paying attention to skipped features.
     *
     * This functions creates groups of features that can be drawn to together,
     * so that the number of `drawElements` calls is minimized.
     *
     * For example given the following texture groups:
     *
     *    Group 1: A B C
     *    Group 2: D [E] F G
     *
     * If feature E should be skipped, the following `drawElements` calls will be
     * made:
     *
     *    drawElements with feature A, B and C
     *    drawElements with feature D
     *    drawElements with feature F and G
     *
     * @protected
     * @param {WebGLRenderingContext} gl gl.
     * @param {module:ol/webgl/Context} context Context.
     * @param {Object.<string, boolean>} skippedFeaturesHash Ids of features
     *  to skip.
     * @param {Array.<WebGLTexture>} textures Textures.
     * @param {Array.<number>} groupIndices Texture group indices.
     */
    WebGLTextureReplay.prototype.drawReplaySkipping = function drawReplaySkipping (gl, context, skippedFeaturesHash, textures, groupIndices) {
      var this$1 = this;
  
      var featureIndex = 0;
  
      var i, ii;
      for (i = 0, ii = textures.length; i < ii; ++i) {
        gl.bindTexture(TEXTURE_2D, textures[i]);
        var groupStart = (i > 0) ? groupIndices[i - 1] : 0;
        var groupEnd = groupIndices[i];
  
        var start = groupStart;
        var end = groupStart;
        while (featureIndex < this.startIndices.length &&
            this.startIndices[featureIndex] <= groupEnd) {
          var feature = this$1.startIndicesFeature[featureIndex];
  
          var featureUid = getUid(feature).toString();
          if (skippedFeaturesHash[featureUid] !== undefined) {
            // feature should be skipped
            if (start !== end) {
              // draw the features so far
              this$1.drawElements(gl, context, start, end);
            }
            // continue with the next feature
            start = (featureIndex === this$1.startIndices.length - 1) ?
              groupEnd : this$1.startIndices[featureIndex + 1];
            end = start;
          } else {
            // the feature is not skipped, augment the end index
            end = (featureIndex === this$1.startIndices.length - 1) ?
              groupEnd : this$1.startIndices[featureIndex + 1];
          }
          featureIndex++;
        }
  
        if (start !== end) {
          // draw the remaining features (in case there was no skipped feature
          // in this texture group, all features of a group are drawn together)
          this$1.drawElements(gl, context, start, end);
        }
      }
    };
  
    /**
     * @inheritDoc
     */
    WebGLTextureReplay.prototype.drawHitDetectionReplayOneByOne = function drawHitDetectionReplayOneByOne (gl, context, skippedFeaturesHash, featureCallback, opt_hitExtent) {
      var this$1 = this;
  
      var i, groupStart, start, end, feature, featureUid;
      var featureIndex = this.startIndices.length - 1;
      var hitDetectionTextures = this.getHitDetectionTextures();
      for (i = hitDetectionTextures.length - 1; i >= 0; --i) {
        gl.bindTexture(TEXTURE_2D, hitDetectionTextures[i]);
        groupStart = (i > 0) ? this$1.hitDetectionGroupIndices[i - 1] : 0;
        end = this$1.hitDetectionGroupIndices[i];
  
        // draw all features for this texture group
        while (featureIndex >= 0 &&
            this.startIndices[featureIndex] >= groupStart) {
          start = this$1.startIndices[featureIndex];
          feature = this$1.startIndicesFeature[featureIndex];
          featureUid = getUid(feature).toString();
  
          if (skippedFeaturesHash[featureUid] === undefined &&
              feature.getGeometry() &&
              (opt_hitExtent === undefined || intersects(
                /** @type {Array<number>} */ (opt_hitExtent),
                feature.getGeometry().getExtent()))) {
            gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
            this$1.drawElements(gl, context, start, end);
  
            var result = featureCallback(feature);
            if (result) {
              return result;
            }
          }
  
          end = start;
          featureIndex--;
        }
      }
      return undefined;
    };
  
    /**
     * @inheritDoc
     */
    WebGLTextureReplay.prototype.finish = function finish (context) {
      this.anchorX = undefined;
      this.anchorY = undefined;
      this.height = undefined;
      this.imageHeight = undefined;
      this.imageWidth = undefined;
      this.indices = null;
      this.opacity = undefined;
      this.originX = undefined;
      this.originY = undefined;
      this.rotateWithView = undefined;
      this.rotation = undefined;
      this.scale = undefined;
      this.vertices = null;
      this.width = undefined;
    };
  
    /**
     * @abstract
     * @protected
     * @param {boolean=} opt_all Return hit detection textures with regular ones.
     * @returns {Array.<WebGLTexture>} Textures.
     */
    WebGLTextureReplay.prototype.getTextures = function getTextures (opt_all) {};
  
    /**
     * @abstract
     * @protected
     * @returns {Array.<WebGLTexture>} Textures.
     */
    WebGLTextureReplay.prototype.getHitDetectionTextures = function getHitDetectionTextures () {};
  
    return WebGLTextureReplay;
  }(WebGLReplay));
  
  
  export default WebGLTextureReplay;
  
  //# sourceMappingURL=TextureReplay.js.map