"use strict";

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.default = void 0;

var _constants = _interopRequireDefault(require("../../constants"));

var _buffer = _interopRequireDefault(require("../../webgl/buffer"));

var _transformFeedback = _interopRequireDefault(require("../../webgl/transform-feedback"));

var _model = _interopRequireDefault(require("../model"));

var _webglUtils = require("../../webgl-utils");

var _assert = _interopRequireDefault(require("../../utils/assert"));

var _utils = require("../../utils");

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

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 _instanceof(left, right) { if (right != null && typeof Symbol !== "undefined" && right[Symbol.hasInstance]) { return right[Symbol.hasInstance](left); } else { return left instanceof right; } }

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; }

var PASS_THROUGH_FS = "void main()\n{\n}\n";

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

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

    _classCallCheck(this, Transform);

    (0, _webglUtils.assertWebGL2Context)(gl);
    this.gl = gl;
    this.model = null;
    this._buffersSwapable = false;
    this.currentIndex = 0;
    this.sourceBuffers = new Array(2);
    this.destinationBuffers = new Array(2);
    this.transformFeedbacks = new Array(2);
    this._buffersToDelete = [];
    this.elementCount = 0;
    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: "initialize",
    value: function initialize(_ref) {
      var _ref$sourceBuffers = _ref.sourceBuffers,
          sourceBuffers = _ref$sourceBuffers === void 0 ? null : _ref$sourceBuffers,
          _ref$destinationBuffe = _ref.destinationBuffers,
          destinationBuffers = _ref$destinationBuffe === void 0 ? null : _ref$destinationBuffe,
          _ref$vs = _ref.vs,
          vs = _ref$vs === void 0 ? null : _ref$vs,
          _ref$sourceDestinatio = _ref.sourceDestinationMap,
          sourceDestinationMap = _ref$sourceDestinatio === void 0 ? null : _ref$sourceDestinatio,
          _ref$varyings = _ref.varyings,
          varyings = _ref$varyings === void 0 ? null : _ref$varyings,
          _ref$drawMode = _ref.drawMode,
          drawMode = _ref$drawMode === void 0 ? _constants.default.POINTS : _ref$drawMode,
          _ref$elementCount = _ref.elementCount,
          elementCount = _ref$elementCount === void 0 ? null : _ref$elementCount;
      (0, _assert.default)(sourceBuffers && vs && varyings && elementCount); // If destinationBuffers are not provided, sourceDestinationMap must be provided
      // to create destinaitonBuffers with layout of corresponding source buffer.

      (0, _assert.default)(destinationBuffers || sourceDestinationMap);

      if (sourceDestinationMap) {
        this.sourceDestinationMap = sourceDestinationMap;
        this._buffersSwapable = true;
      }

      var index = 0;
      this.varyings = [];
      this.varyingMap = {};
      var _iteratorNormalCompletion2 = true;
      var _didIteratorError2 = false;
      var _iteratorError2 = undefined;

      try {
        for (var _iterator2 = varyings[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) {
          var varying = _step2.value;
          this.varyings[index] = varying;
          this.varyingMap[varying] = index;
          index++;
        }
      } catch (err) {
        _didIteratorError2 = true;
        _iteratorError2 = err;
      } finally {
        try {
          if (!_iteratorNormalCompletion2 && _iterator2.return != null) {
            _iterator2.return();
          }
        } finally {
          if (_didIteratorError2) {
            throw _iteratorError2;
          }
        }
      }

      this._bindBuffers({
        sourceBuffers: sourceBuffers,
        destinationBuffers: destinationBuffers
      });

      this._buildModel({
        vs: vs,
        drawMode: drawMode,
        elementCount: elementCount
      });
    } // 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$destinationBuff = _ref2.destinationBuffers,
          destinationBuffers = _ref2$destinationBuff === void 0 ? null : _ref2$destinationBuff;

      if (!sourceBuffers && !destinationBuffers) {
        _utils.log.warn('Transform : no buffers updated')();

        return this;
      }

      var currentIndex = this.currentIndex,
          varyingMap = this.varyingMap,
          _buffersSwapable = this._buffersSwapable,
          transformFeedbacks = this.transformFeedbacks;

      for (var bufferName in sourceBuffers) {
        (0, _assert.default)(_instanceof(sourceBuffers[bufferName], _buffer.default));
      }

      for (var _bufferName in destinationBuffers) {
        (0, _assert.default)(_instanceof(destinationBuffers[_bufferName], _buffer.default));
      }

      Object.assign(this.sourceBuffers[currentIndex], sourceBuffers);
      Object.assign(this.destinationBuffers[currentIndex], destinationBuffers);
      transformFeedbacks[currentIndex].bindBuffers(this.destinationBuffers[currentIndex], {
        varyingMap: varyingMap
      });

      if (_buffersSwapable) {
        var nextIndex = (currentIndex + 1) % 2;

        for (var sourceBufferName in this.sourceDestinationMap) {
          var destinationBufferName = this.sourceDestinationMap[sourceBufferName];
          this.sourceBuffers[nextIndex][sourceBufferName] = this.destinationBuffers[currentIndex][destinationBufferName];
          this.destinationBuffers[nextIndex][destinationBufferName] = this.sourceBuffers[currentIndex][sourceBufferName];
        }

        transformFeedbacks[nextIndex].bindBuffers(this.destinationBuffers[nextIndex], {
          varyingMap: varyingMap
        });
      }

      return this;
    } // Run one transformfeedback loop.

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

      var model = this.model,
          transformFeedbacks = this.transformFeedbacks,
          sourceBuffers = this.sourceBuffers,
          currentIndex = this.currentIndex;
      model.setAttributes(sourceBuffers[currentIndex]);
      model.draw({
        transformFeedback: transformFeedbacks[currentIndex],
        uniforms: uniforms,
        parameters: _defineProperty({}, _constants.default.RASTERIZER_DISCARD, true)
      });
    } // Swap source and destination buffers.

  }, {
    key: "swapBuffers",
    value: function swapBuffers() {
      (0, _assert.default)(this._buffersSwapable);
      this.currentIndex = (this.currentIndex + 1) % 2;
    } // Return Buffer object for given varying name.

  }, {
    key: "getBuffer",
    value: function getBuffer() {
      var varyingName = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null;
      var destinationBuffers = this.destinationBuffers,
          currentIndex = this.currentIndex;
      (0, _assert.default)(varyingName && destinationBuffers[currentIndex][varyingName]);
      return destinationBuffers[currentIndex][varyingName];
    } // Private
    // build source and destination buffers

  }, {
    key: "_bindBuffers",
    value: function _bindBuffers(_ref4) {
      var _ref4$sourceBuffers = _ref4.sourceBuffers,
          sourceBuffers = _ref4$sourceBuffers === void 0 ? null : _ref4$sourceBuffers,
          _ref4$destinationBuff = _ref4.destinationBuffers,
          destinationBuffers = _ref4$destinationBuff === void 0 ? null : _ref4$destinationBuff;
      var _buffersSwapable = this._buffersSwapable;

      for (var bufferName in sourceBuffers) {
        (0, _assert.default)(_instanceof(sourceBuffers[bufferName], _buffer.default));
      }

      for (var _bufferName2 in destinationBuffers) {
        (0, _assert.default)(_instanceof(destinationBuffers[_bufferName2], _buffer.default));
      }

      this.sourceBuffers[0] = Object.assign({}, sourceBuffers);
      this.destinationBuffers[0] = Object.assign({}, destinationBuffers);

      if (_buffersSwapable) {
        this.sourceBuffers[1] = {};
        this.destinationBuffers[1] = {};

        for (var sourceBufferName in this.sourceDestinationMap) {
          var destinationBufferName = this.sourceDestinationMap[sourceBufferName];

          if (!this.destinationBuffers[0][destinationBufferName]) {
            // 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;
            this.destinationBuffers[0][destinationBufferName] = new _buffer.default(this.gl, {
              bytes: bytes,
              type: type,
              usage: usage,
              layout: layout
            });

            this._buffersToDelete.push(this.destinationBuffers[0][destinationBufferName]);
          }

          this.sourceBuffers[1][sourceBufferName] = this.destinationBuffers[0][destinationBufferName];
          this.destinationBuffers[1][destinationBufferName] = this.sourceBuffers[0][sourceBufferName];
        }
      }
    } // build Model and TransformFeedback objects

  }, {
    key: "_buildModel",
    value: function _buildModel(_ref5) {
      var vs = _ref5.vs,
          drawMode = _ref5.drawMode,
          elementCount = _ref5.elementCount;
      var varyings = this.varyings,
          varyingMap = this.varyingMap,
          _buffersSwapable = this._buffersSwapable; // Append matching version string to FS.

      var fs = PASS_THROUGH_FS;
      var vsLines = vs.split('\n');

      if (vsLines[0].indexOf('#version ') === 0) {
        fs = "".concat(vsLines[0], "\n").concat(PASS_THROUGH_FS, "\n");
      }

      this.model = new _model.default(this.gl, {
        vs: vs,
        fs: fs,
        varyings: varyings,
        drawMode: drawMode,
        vertexCount: elementCount
      });
      this.transformFeedbacks[0] = new _transformFeedback.default(this.gl, {
        buffers: this.destinationBuffers[0],
        varyingMap: varyingMap
      });

      if (_buffersSwapable) {
        this.transformFeedbacks[1] = new _transformFeedback.default(this.gl, {
          buffers: this.destinationBuffers[1],
          varyingMap: this.varyingMap
        });
      }
    }
  }]);

  return Transform;
}();

exports.default = Transform;
//# sourceMappingURL=transform.js.map