text: function _instanceof(left, right) { if (right != null && typeof Symbol !== "undefined" && right[Symbol.hasInstance]) { return right[Symbol.hasInstance](left); } else { return left instanceof right; } }
  
  function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }
  
  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; }
  
  function _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === "object" || typeof call === "function")) { return call; } return _assertThisInitialized(self); }
  
  function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
  
  function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; }
  
  function _classCallCheck(instance, Constructor) { if (!_instanceof(instance, Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
  
  import Resource from './resource';
  import { assertWebGL2Context } from '../webgl-utils';
  import { getGLTypeFromTypedArray, getTypedArrayFromGLType } from '../webgl-utils/typed-array-utils';
  import assert from '../utils/assert';
  var GL_COPY_READ_BUFFER = 0x8F36;
  var GL_COPY_WRITE_BUFFER = 0x8F37;
  var GL_TRANSFORM_FEEDBACK_BUFFER = 0x8C8E;
  var GL_UNIFORM_BUFFER = 0x8A11;
  var GL_ARRAY_BUFFER = 0x8892;
  var GL_STATIC_DRAW = 0x88E4;
  var GL_FLOAT = 0x1406;
  export var BufferLayout =
  /**
   * @classdesc
   * Store characteristics of a data layout
   * This data can be used when updating vertex attributes with
   * the associated buffer, freeing the application from keeping
   * track of this metadata.
   *
   * @class
   * @param {GLuint} size - number of values per element (1-4)
   * @param {GLuint} type - type of values (e.g. gl.FLOAT)
   * @param {GLbool} normalized=false - normalize integers to [-1,1] or [0,1]
   * @param {GLuint} integer=false - WebGL2 only, int-to-float conversion
   * @param {GLuint} stride=0 - supports strided arrays
   * @param {GLuint} offset=0 - supports strided arrays
   */
  function BufferLayout() {
    var _ref = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},
        type = _ref.type,
        _ref$size = _ref.size,
        size = _ref$size === void 0 ? 1 : _ref$size,
        _ref$offset = _ref.offset,
        offset = _ref$offset === void 0 ? 0 : _ref$offset,
        _ref$stride = _ref.stride,
        stride = _ref$stride === void 0 ? 0 : _ref$stride,
        _ref$normalized = _ref.normalized,
        normalized = _ref$normalized === void 0 ? false : _ref$normalized,
        _ref$integer = _ref.integer,
        integer = _ref$integer === void 0 ? false : _ref$integer,
        _ref$instanced = _ref.instanced,
        instanced = _ref$instanced === void 0 ? 0 : _ref$instanced;
  
    _classCallCheck(this, BufferLayout);
  
    this.type = type;
    this.size = size;
    this.offset = offset;
    this.stride = stride;
    this.normalized = normalized;
    this.integer = integer;
    this.instanced = instanced;
  };
  
  var Buffer =
  /*#__PURE__*/
  function (_Resource) {
    _inherits(Buffer, _Resource);
  
    function Buffer(gl) {
      var _this;
  
      var opts = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
  
      _classCallCheck(this, Buffer);
  
      _this = _possibleConstructorReturn(this, (Buffer.__proto__ || Object.getPrototypeOf(Buffer)).call(this, gl, opts)); // In WebGL1, we need to make sure we use GL.ELEMENT_ARRAY_BUFFER when
      // initializing element buffers, otherwise the buffer type will be locked
      // to a generic (non-element) buffer.
      // In WebGL2, we can use GL_COPY_READ_BUFFER which avoids locking the type here
  
      _this.target = opts.target || (_this.gl.webgl2 ? GL_COPY_READ_BUFFER : GL_ARRAY_BUFFER);
  
      _this.setData(opts);
  
      Object.seal(_assertThisInitialized(_this));
      return _this;
    } // Stores the layout of data with the buffer, makes it easy to e.g. set it as an attribute later
  
  
    _createClass(Buffer, [{
      key: "setDataLayout",
      value: function setDataLayout(_ref2) {
        var layout = _ref2.layout,
            type = _ref2.type,
            _ref2$size = _ref2.size,
            size = _ref2$size === void 0 ? 1 : _ref2$size,
            _ref2$offset = _ref2.offset,
            offset = _ref2$offset === void 0 ? 0 : _ref2$offset,
            _ref2$stride = _ref2.stride,
            stride = _ref2$stride === void 0 ? 0 : _ref2$stride,
            _ref2$normalized = _ref2.normalized,
            normalized = _ref2$normalized === void 0 ? false : _ref2$normalized,
            _ref2$integer = _ref2.integer,
            integer = _ref2$integer === void 0 ? false : _ref2$integer,
            _ref2$instanced = _ref2.instanced,
            instanced = _ref2$instanced === void 0 ? 0 : _ref2$instanced;
        this.layout = layout || new BufferLayout({
          type: type || this.type,
          // Use autodeduced type if available
          size: size,
          offset: offset,
          stride: stride,
          normalized: normalized,
          integer: integer,
          instanced: instanced
        });
        return this;
      }
    }, {
      key: "updateLayout",
      value: function updateLayout(opts) {
        Object.assign(this.layout, opts);
      } // Creates and initializes the buffer object's data store.
  
    }, {
      key: "initialize",
      value: function initialize() {
        var _ref3 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},
            data = _ref3.data,
            bytes = _ref3.bytes,
            _ref3$usage = _ref3.usage,
            usage = _ref3$usage === void 0 ? GL_STATIC_DRAW : _ref3$usage,
            layout = _ref3.layout,
            type = _ref3.type,
            _ref3$size = _ref3.size,
            size = _ref3$size === void 0 ? 1 : _ref3$size,
            _ref3$offset = _ref3.offset,
            offset = _ref3$offset === void 0 ? 0 : _ref3$offset,
            _ref3$stride = _ref3.stride,
            stride = _ref3$stride === void 0 ? 0 : _ref3$stride,
            _ref3$normalized = _ref3.normalized,
            normalized = _ref3$normalized === void 0 ? false : _ref3$normalized,
            _ref3$integer = _ref3.integer,
            integer = _ref3$integer === void 0 ? false : _ref3$integer,
            _ref3$instanced = _ref3.instanced,
            instanced = _ref3$instanced === void 0 ? 0 : _ref3$instanced,
            _ref3$index = _ref3.index,
            index = _ref3$index === void 0 ? null : _ref3$index;
  
        var opts = arguments[0];
  
        if (!data) {
          type = type || GL_FLOAT; // Workaround needed for Safari (#291):
          // gl.bufferData with size (second argument) equal to 0 crashes.
          // hence create zero sized array.
  
          if (!bytes || bytes === 0) {
            bytes = 0;
            data = new Float32Array(0);
          }
        } else {
          type = type || getGLTypeFromTypedArray(data);
          bytes = data.byteLength;
          assert(type);
        }
  
        this.bytes = bytes;
        this.bytesUsed = bytes;
        this.data = data;
        this.type = type;
        this.usage = usage;
        this.index = index; // Call after type is set
  
        this.setDataLayout(Object.assign(opts)); // Create the buffer - binding it here for the first time locks the type
        // In WebGL2, use GL_COPY_WRITE_BUFFER to avoid locking the type
  
        var target = this.gl.webgl2 ? GL_COPY_WRITE_BUFFER : this.target;
        this.gl.bindBuffer(target, this.handle);
        this.gl.bufferData(target, data || bytes, usage);
        this.gl.bindBuffer(target, null);
        return this;
      } // DEPRECATED - Can we change to call `subData`?
  
    }, {
      key: "setData",
      value: function setData(options) {
        return this.initialize(options);
      } // Updates a subset of a buffer object's data store.
  
    }, {
      key: "subData",
      value: function subData() {
        var _ref4 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},
            data = _ref4.data,
            _ref4$offset = _ref4.offset,
            offset = _ref4$offset === void 0 ? 0 : _ref4$offset,
            _ref4$srcOffset = _ref4.srcOffset,
            srcOffset = _ref4$srcOffset === void 0 ? 0 : _ref4$srcOffset,
            length = _ref4.length;
  
        assert(data); // Create the buffer - binding it here for the first time locks the type
        // In WebGL2, use GL_COPY_WRITE_BUFFER to avoid locking the type
  
        var target = this.gl.webgl2 ? GL_COPY_WRITE_BUFFER : this.target;
        this.gl.bindBuffer(target, this.handle); // WebGL2: subData supports additional srcOffset and length parameters
  
        if (srcOffset !== 0 || length !== undefined) {
          assertWebGL2Context(this.gl);
          this.gl.bufferSubData(this.target, offset, data, srcOffset, length || 0);
        } else {
          this.gl.bufferSubData(target, offset, data);
        }
  
        this.gl.bindBuffer(target, null);
        return this;
      } // WEBGL2 ONLY: Copies part of the data of another buffer into this buffer
  
    }, {
      key: "copyData",
      value: function copyData(_ref5) {
        var sourceBuffer = _ref5.sourceBuffer,
            _ref5$readOffset = _ref5.readOffset,
            readOffset = _ref5$readOffset === void 0 ? 0 : _ref5$readOffset,
            _ref5$writeOffset = _ref5.writeOffset,
            writeOffset = _ref5$writeOffset === void 0 ? 0 : _ref5$writeOffset,
            size = _ref5.size;
        assertWebGL2Context(this.gl); // Use GL_COPY_READ_BUFFER+GL_COPY_WRITE_BUFFER avoid disturbing other targets and locking type
  
        this.gl.bindBuffer(GL_COPY_READ_BUFFER, sourceBuffer.handle);
        this.gl.bindBuffer(GL_COPY_WRITE_BUFFER, this.handle);
        this.gl.copyBufferSubData(GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER, readOffset, writeOffset, size);
        this.gl.bindBuffer(GL_COPY_READ_BUFFER, null);
        this.gl.bindBuffer(GL_COPY_WRITE_BUFFER, null);
        return this;
      } // WEBGL2 ONLY: Reads data from buffer into an ArrayBufferView or SharedArrayBuffer.
  
    }, {
      key: "getData",
      value: function getData() {
        var _ref6 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},
            _ref6$dstData = _ref6.dstData,
            dstData = _ref6$dstData === void 0 ? null : _ref6$dstData,
            _ref6$srcByteOffset = _ref6.srcByteOffset,
            srcByteOffset = _ref6$srcByteOffset === void 0 ? 0 : _ref6$srcByteOffset,
            _ref6$dstOffset = _ref6.dstOffset,
            dstOffset = _ref6$dstOffset === void 0 ? 0 : _ref6$dstOffset,
            _ref6$length = _ref6.length,
            length = _ref6$length === void 0 ? 0 : _ref6$length;
  
        assertWebGL2Context(this.gl);
        var ArrayType = getTypedArrayFromGLType(this.type, {
          clamped: false
        });
  
        var sourceAvailableElementCount = this._getAvailableElementCount(srcByteOffset);
  
        var dstAvailableElementCount;
        var dstElementCount;
        var dstElementOffset = dstOffset;
  
        if (dstData) {
          dstElementCount = dstData.length;
          dstAvailableElementCount = dstElementCount - dstElementOffset;
        } else {
          // Allocate ArrayBufferView with enough size to copy all eligible data.
          dstAvailableElementCount = Math.min(sourceAvailableElementCount, length || sourceAvailableElementCount);
          dstElementCount = dstElementOffset + dstAvailableElementCount;
        }
  
        var copyElementCount = Math.min(sourceAvailableElementCount, dstAvailableElementCount);
        length = length || copyElementCount;
        assert(length <= copyElementCount, 'Invalid srcByteOffset, dstOffset and length combination');
        dstData = dstData || new ArrayType(dstElementCount); // Use GL_COPY_READ_BUFFER to avoid disturbing other targets and locking type
  
        this.gl.bindBuffer(GL_COPY_READ_BUFFER, this.handle);
        this.gl.getBufferSubData(GL_COPY_READ_BUFFER, srcByteOffset, dstData, dstOffset, length);
        this.gl.bindBuffer(GL_COPY_READ_BUFFER, null);
        return dstData;
      }
      /**
       * Binds a buffer to a given binding point (target).
       *   GL_TRANSFORM_FEEDBACK_BUFFER and GL.UNIFORM_BUFFER take an index, and optionally a range.
       *
       * @param {Glenum} target - target for the bind operation.
       *
       * @param {GLuint} index= - the index of the target.
       *   - GL_TRANSFORM_FEEDBACK_BUFFER and GL.UNIFORM_BUFFER need an index to affect state
       * @param {GLuint} offset=0 - the index of the target.
       *   - GL.UNIFORM_BUFFER: `offset` must be aligned to GL.UNIFORM_BUFFER_OFFSET_ALIGNMENT.
       * @param {GLuint} size= - the index of the target.
       *   - GL.UNIFORM_BUFFER: `size` must be a minimum of GL.UNIFORM_BLOCK_SIZE_DATA.
       * @returns {Buffer} - Returns itself for chaining.
       */
  
    }, {
      key: "bind",
      value: function bind() {
        var _ref7 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},
            _ref7$target = _ref7.target,
            target = _ref7$target === void 0 ? this.target : _ref7$target,
            _ref7$index = _ref7.index,
            index = _ref7$index === void 0 ? this.index : _ref7$index,
            _ref7$offset = _ref7.offset,
            offset = _ref7$offset === void 0 ? 0 : _ref7$offset,
            size = _ref7.size;
  
        // NOTE: While GL_TRANSFORM_FEEDBACK_BUFFER and GL.UNIFORM_BUFFER could
        // be used as direct binding points, they will not affect transform feedback or
        // uniform buffer state. Instead indexed bindings need to be made.
        var type = target === GL_UNIFORM_BUFFER || target === GL_TRANSFORM_FEEDBACK_BUFFER ? size !== undefined ? 'ranged' : 'indexed' : 'non-indexed';
  
        switch (type) {
          case 'non-indexed':
            this.gl.bindBuffer(target, this.handle);
            break;
  
          case 'indexed':
            assertWebGL2Context(this.gl);
            assert(offset === 0); // Make sure offset wasn't supplied
  
            this.gl.bindBufferBase(target, index, this.handle);
            break;
  
          case 'ranged':
            assertWebGL2Context(this.gl);
            this.gl.bindBufferRange(target, index, this.handle, offset, size);
            break;
  
          default:
            assert(false);
        }
  
        return this;
      }
    }, {
      key: "unbind",
      value: function unbind() {
        var _ref8 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},
            _ref8$target = _ref8.target,
            target = _ref8$target === void 0 ? this.target : _ref8$target,
            _ref8$index = _ref8.index,
            index = _ref8$index === void 0 ? this.index : _ref8$index;
  
        var isIndexedBuffer = target === GL_UNIFORM_BUFFER || target === GL_TRANSFORM_FEEDBACK_BUFFER;
  
        if (isIndexedBuffer) {
          this.gl.bindBufferBase(target, index, null);
        } else {
          this.gl.bindBuffer(target, null);
        }
  
        return this;
      } // TODO - is this the right place?
      // gl.TRANSFORM_FEEDBACK_BUFFER_BINDING: Returns a WebGLBuffer.
      // gl.TRANSFORM_FEEDBACK_BUFFER_SIZE: Returns a GLsizeiptr.
      // gl.TRANSFORM_FEEDBACK_BUFFER_START: Returns a GLintptr.
      // gl.UNIFORM_BUFFER_BINDING: Returns a WebGLBuffer.
      // gl.UNIFORM_BUFFER_SIZE: Returns a GLsizeiptr.
      // gl.UNIFORM_BUFFER_START: Returns a GLintptr.
  
    }, {
      key: "getIndexedParameter",
      value: function getIndexedParameter(binding, index) {
        // Create the buffer - if binding it here for the first time, this locks the type
        // In WebGL2, use GL_COPY_READ_BUFFER to avoid locking the type
        var target = this.gl.webgl2 ? GL_COPY_READ_BUFFER : this.target;
        this.gl.bindBuffer(target, index);
        return this.gl.getIndexedParameter(binding, index);
      } // RESOURCE METHODS
  
    }, {
      key: "_createHandle",
      value: function _createHandle() {
        return this.gl.createBuffer();
      }
    }, {
      key: "_deleteHandle",
      value: function _deleteHandle() {
        this.gl.deleteBuffer(this.handle);
      }
    }, {
      key: "_getParameter",
      value: function _getParameter(pname) {
        this.gl.bindBuffer(this.target, this.handle);
        var value = this.gl.getBufferParameter(this.target, pname);
        this.gl.bindBuffer(this.target, null);
        return value;
      }
    }, {
      key: "_getAvailableElementCount",
      value: function _getAvailableElementCount(srcByteOffset) {
        var ArrayType = getTypedArrayFromGLType(this.type, {
          clamped: false
        });
        var sourceElementCount = this.bytes / ArrayType.BYTES_PER_ELEMENT;
        var sourceElementOffset = srcByteOffset / ArrayType.BYTES_PER_ELEMENT;
        return sourceElementCount - sourceElementOffset;
      }
    }]);
  
    return Buffer;
  }(Resource);
  
  export { Buffer as default };
  //# sourceMappingURL=buffer.js.map