function _instanceof(left, right) { if (right != null && typeof Symbol !== "undefined" && right[Symbol.hasInstance]) { return right[Symbol.hasInstance](left); } else { return left instanceof right; } }

function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }

function _classCallCheck(instance, Constructor) { if (!_instanceof(instance, Constructor)) { throw new TypeError("Cannot call a class as a function"); } }

function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }

function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }

import GL from '../constants';
import Model from './model';
import Buffer from '../webgl/buffer';
import TransformFeedback from '../webgl/transform-feedback';
import { isWebGL2, assertWebGL2Context, getShaderVersion } from '../webgl-utils';
import assert from '../utils/assert';
import { log } from '../utils';
var FS100 = 'void main() {}';
var FS300 = "#version 300 es\n".concat(FS100);

var Transform =
/*#__PURE__*/
function () {
  _createClass(Transform, null, [{
    key: "isSupported",
    value: function isSupported(gl) {
      // For now WebGL2 only
      return isWebGL2(gl);
    }
  }]);

  function Transform(gl) {
    var opts = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};

    _classCallCheck(this, Transform);

    assertWebGL2Context(gl);
    this.gl = gl;
    this.model = null;
    this._swapBuffers = false;
    this.currentIndex = 0;
    this.sourceBuffers = new Array(2);
    this.feedbackBuffers = new Array(2);
    this.transformFeedbacks = new Array(2);
    this._buffersToDelete = [];

    this._initialize(opts);

    Object.seal(this);
  } // Delete owned resources.


  _createClass(Transform, [{
    key: "delete",
    value: function _delete() {
      var _iteratorNormalCompletion = true;
      var _didIteratorError = false;
      var _iteratorError = undefined;

      try {
        for (var _iterator = this._buffersToDelete[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
          var buffer = _step.value;
          buffer.delete();
        }
      } catch (err) {
        _didIteratorError = true;
        _iteratorError = err;
      } finally {
        try {
          if (!_iteratorNormalCompletion && _iterator.return != null) {
            _iterator.return();
          }
        } finally {
          if (_didIteratorError) {
            throw _iteratorError;
          }
        }
      }

      this.model.delete();
    }
  }, {
    key: "getBuffer",
    // Return Buffer object for given varying name.
    value: function getBuffer() {
      var varyingName = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null;
      assert(varyingName && this.feedbackBuffers[this.currentIndex][varyingName]);
      return this.feedbackBuffers[this.currentIndex][varyingName];
    } // Run one transform feedback loop.

  }, {
    key: "run",
    value: function run() {
      var _ref = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},
          _ref$uniforms = _ref.uniforms,
          uniforms = _ref$uniforms === void 0 ? {} : _ref$uniforms,
          _ref$unbindModels = _ref.unbindModels,
          unbindModels = _ref$unbindModels === void 0 ? [] : _ref$unbindModels;

      this.model.setAttributes(this.sourceBuffers[this.currentIndex]);
      this.model.transform({
        transformFeedback: this.transformFeedbacks[this.currentIndex],
        parameters: _defineProperty({}, GL.RASTERIZER_DISCARD, true),
        uniforms: uniforms,
        unbindModels: unbindModels
      });
    } // Swap source and destination buffers.

  }, {
    key: "swapBuffers",
    value: function swapBuffers() {
      assert(this._swapBuffers);
      this.currentIndex = (this.currentIndex + 1) % 2;
    } // Update some or all buffer bindings.

  }, {
    key: "update",
    value: function update(_ref2) {
      var _ref2$sourceBuffers = _ref2.sourceBuffers,
          sourceBuffers = _ref2$sourceBuffers === void 0 ? null : _ref2$sourceBuffers,
          _ref2$feedbackBuffers = _ref2.feedbackBuffers,
          feedbackBuffers = _ref2$feedbackBuffers === void 0 ? null : _ref2$feedbackBuffers,
          _ref2$elementCount = _ref2.elementCount,
          elementCount = _ref2$elementCount === void 0 ? this.elementCount : _ref2$elementCount;

      if (!sourceBuffers && !feedbackBuffers) {
        log.warn('Transform : no buffers updated')();
        return this;
      }

      this.model.setVertexCount(elementCount);

      for (var bufferName in feedbackBuffers) {
        assert(_instanceof(feedbackBuffers[bufferName], Buffer));
      }

      var currentIndex = this.currentIndex;
      Object.assign(this.sourceBuffers[currentIndex], sourceBuffers);
      Object.assign(this.feedbackBuffers[currentIndex], feedbackBuffers);
      this.transformFeedbacks[currentIndex].setBuffers(this.feedbackBuffers[currentIndex]);

      if (this._swapBuffers) {
        var nextIndex = (currentIndex + 1) % 2;

        for (var sourceBufferName in this.feedbackMap) {
          var feedbackBufferName = this.feedbackMap[sourceBufferName];
          this.sourceBuffers[nextIndex][sourceBufferName] = this.feedbackBuffers[currentIndex][feedbackBufferName];
          this.feedbackBuffers[nextIndex][feedbackBufferName] = this.sourceBuffers[currentIndex][sourceBufferName]; // make sure the new destination buffer is a Buffer object

          assert(_instanceof(this.feedbackBuffers[nextIndex][feedbackBufferName], Buffer));
        }

        this.transformFeedbacks[nextIndex].setBuffers(this.feedbackBuffers[nextIndex]);
      }

      return this;
    } // Private

  }, {
    key: "_initialize",
    value: function _initialize(_ref3) {
      var _ref3$id = _ref3.id,
          id = _ref3$id === void 0 ? 'transform' : _ref3$id,
          vs = _ref3.vs,
          varyings = _ref3.varyings,
          _ref3$drawMode = _ref3.drawMode,
          drawMode = _ref3$drawMode === void 0 ? GL.POINTS : _ref3$drawMode,
          elementCount = _ref3.elementCount,
          sourceBuffers = _ref3.sourceBuffers,
          _ref3$feedbackBuffers = _ref3.feedbackBuffers,
          feedbackBuffers = _ref3$feedbackBuffers === void 0 ? null : _ref3$feedbackBuffers,
          _ref3$feedbackMap = _ref3.feedbackMap,
          feedbackMap = _ref3$feedbackMap === void 0 ? null : _ref3$feedbackMap,
          _ref3$destinationBuff = _ref3.destinationBuffers,
          destinationBuffers = _ref3$destinationBuff === void 0 ? null : _ref3$destinationBuff,
          _ref3$sourceDestinati = _ref3.sourceDestinationMap,
          sourceDestinationMap = _ref3$sourceDestinati === void 0 ? null : _ref3$sourceDestinati;

      if (destinationBuffers) {
        log.deprecated('destinationBuffers', 'feedbackBuffers')();
        feedbackBuffers = feedbackBuffers || destinationBuffers;
      }

      if (sourceDestinationMap) {
        log.deprecated('sourceDestinationMap', 'feedbackMap')();
        feedbackMap = feedbackMap || sourceDestinationMap;
      }

      assert(sourceBuffers && vs && elementCount >= 0); // If feedbackBuffers are not provided, sourceDestinationMap must be provided
      // to create destinaitonBuffers with layout of corresponding source buffer.

      assert(feedbackBuffers || feedbackMap, ' Transform needs feedbackBuffers or feedbackMap');

      for (var bufferName in feedbackBuffers || {}) {
        assert(_instanceof(feedbackBuffers[bufferName], Buffer));
      } // If varyings are not provided feedbackMap must be provided to deduce varyings


      assert(Array.isArray(varyings) || feedbackMap);
      var varyingsArray = varyings;

      if (!Array.isArray(varyings)) {
        varyingsArray = Object.values(feedbackMap);
      }

      if (feedbackMap) {
        this.feedbackMap = feedbackMap;
        this._swapBuffers = true;
      }

      this._setupBuffers({
        sourceBuffers: sourceBuffers,
        feedbackBuffers: feedbackBuffers
      });

      this._buildModel({
        id: id,
        vs: vs,
        varyings: varyingsArray,
        drawMode: drawMode,
        elementCount: elementCount
      });
    } // setup source and destination buffers

  }, {
    key: "_setupBuffers",
    value: function _setupBuffers(_ref4) {
      var _ref4$sourceBuffers = _ref4.sourceBuffers,
          sourceBuffers = _ref4$sourceBuffers === void 0 ? null : _ref4$sourceBuffers,
          _ref4$feedbackBuffers = _ref4.feedbackBuffers,
          feedbackBuffers = _ref4$feedbackBuffers === void 0 ? null : _ref4$feedbackBuffers;
      this.sourceBuffers[0] = Object.assign({}, sourceBuffers);
      this.feedbackBuffers[0] = Object.assign({}, feedbackBuffers);

      if (this._swapBuffers) {
        this.sourceBuffers[1] = {};
        this.feedbackBuffers[1] = {};

        for (var sourceBufferName in this.feedbackMap) {
          var feedbackBufferName = this.feedbackMap[sourceBufferName];

          if (!this.feedbackBuffers[0][feedbackBufferName]) {
            // Create new buffer with same layout and settings as source buffer
            var sourceBuffer = this.sourceBuffers[0][sourceBufferName];
            var bytes = sourceBuffer.bytes,
                type = sourceBuffer.type,
                usage = sourceBuffer.usage,
                layout = sourceBuffer.layout;
            var buffer = new Buffer(this.gl, {
              bytes: bytes,
              type: type,
              usage: usage,
              layout: layout
            });
            this.feedbackBuffers[0][feedbackBufferName] = buffer;

            this._buffersToDelete.push(this.feedbackBuffers[0][feedbackBufferName]);
          }

          this.sourceBuffers[1][sourceBufferName] = this.feedbackBuffers[0][feedbackBufferName];
          this.feedbackBuffers[1][feedbackBufferName] = this.sourceBuffers[0][sourceBufferName]; // make sure the new destination buffer is a Buffer object

          assert(_instanceof(this.feedbackBuffers[1][feedbackBufferName], Buffer));
        }
      }
    } // build Model and TransformFeedback objects

  }, {
    key: "_buildModel",
    value: function _buildModel(_ref5) {
      var id = _ref5.id,
          vs = _ref5.vs,
          varyings = _ref5.varyings,
          drawMode = _ref5.drawMode,
          elementCount = _ref5.elementCount;
      // use a minimal fragment shader with matching version of vertex shader.
      var fs = getShaderVersion(vs) === 300 ? FS300 : FS100;
      this.model = new Model(this.gl, {
        id: id,
        vs: vs,
        fs: fs,
        varyings: varyings,
        drawMode: drawMode,
        vertexCount: elementCount
      });
      this.transformFeedbacks[0] = new TransformFeedback(this.gl, {
        program: this.model.program,
        buffers: this.feedbackBuffers[0]
      });

      if (this._swapBuffers) {
        this.transformFeedbacks[1] = new TransformFeedback(this.gl, {
          program: this.model.program,
          buffers: this.feedbackBuffers[1]
        });
      }
    }
  }, {
    key: "elementCount",
    get: function get() {
      return this.model.getVertexCount();
    }
  }]);

  return Transform;
}();

export { Transform as default };
//# sourceMappingURL=transform.js.map