"use strict";

var _interopRequireWildcard = require("@babel/runtime/helpers/interopRequireWildcard");

var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");

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

var _typeof2 = _interopRequireDefault(require("@babel/runtime/helpers/typeof"));

var THREE = _interopRequireWildcard(require("three"));

// This file has been added and patched after installing the NPM modules (via NPM script 'prepare')
var threeExamples = {};
/**
 * @author Don McCurdy / https://www.donmccurdy.com
 */

threeExamples.DRACOLoader = function (manager) {
  THREE.Loader.call(this, manager);
  this.decoderPath = '';
  this.decoderConfig = {};
  this.decoderBinary = null;
  this.decoderPending = null;
  this.workerLimit = 4;
  this.workerPool = [];
  this.workerNextTaskID = 1;
  this.workerSourceURL = '';
  this.defaultAttributeIDs = {
    position: 'POSITION',
    normal: 'NORMAL',
    color: 'COLOR',
    uv: 'TEX_COORD'
  };
  this.defaultAttributeTypes = {
    position: 'Float32Array',
    normal: 'Float32Array',
    color: 'Float32Array',
    uv: 'Float32Array'
  };
};

threeExamples.DRACOLoader.prototype = Object.assign(Object.create(THREE.Loader.prototype), {
  constructor: threeExamples.DRACOLoader,
  setDecoderPath: function setDecoderPath(path) {
    this.decoderPath = path;
    return this;
  },
  setDecoderConfig: function setDecoderConfig(config) {
    this.decoderConfig = config;
    return this;
  },
  setWorkerLimit: function setWorkerLimit(workerLimit) {
    this.workerLimit = workerLimit;
    return this;
  },

  /** @deprecated */
  setVerbosity: function setVerbosity() {
    console.warn('threeExamples.DRACOLoader: The .setVerbosity() method has been removed.');
  },

  /** @deprecated */
  setDrawMode: function setDrawMode() {
    console.warn('threeExamples.DRACOLoader: The .setDrawMode() method has been removed.');
  },

  /** @deprecated */
  setSkipDequantization: function setSkipDequantization() {
    console.warn('threeExamples.DRACOLoader: The .setSkipDequantization() method has been removed.');
  },
  load: function load(url, onLoad, onProgress, onError) {
    var _this = this;

    var loader = new THREE.FileLoader(this.manager);
    loader.setPath(this.path);
    loader.setResponseType('arraybuffer');

    if (this.crossOrigin === 'use-credentials') {
      loader.setWithCredentials(true);
    }

    loader.load(url, function (buffer) {
      var taskConfig = {
        attributeIDs: _this.defaultAttributeIDs,
        attributeTypes: _this.defaultAttributeTypes,
        useUniqueIDs: false
      };

      _this.decodeGeometry(buffer, taskConfig).then(onLoad)["catch"](onError);
    }, onProgress, onError);
  },

  /** @deprecated Kept for backward-compatibility with previous DRACOLoader versions. */
  decodeDracoFile: function decodeDracoFile(buffer, callback, attributeIDs, attributeTypes) {
    var taskConfig = {
      attributeIDs: attributeIDs || this.defaultAttributeIDs,
      attributeTypes: attributeTypes || this.defaultAttributeTypes,
      useUniqueIDs: !!attributeIDs
    };
    this.decodeGeometry(buffer, taskConfig).then(callback);
  },
  decodeGeometry: function decodeGeometry(buffer, taskConfig) {
    var _this2 = this;

    // TODO: For backward-compatibility, support 'attributeTypes' objects containing
    // references (rather than names) to typed array constructors. These must be
    // serialized before sending them to the worker.
    for (var attribute in taskConfig.attributeTypes) {
      var type = taskConfig.attributeTypes[attribute];

      if (type.BYTES_PER_ELEMENT !== undefined) {
        taskConfig.attributeTypes[attribute] = type.name;
      }
    } //


    var taskKey = JSON.stringify(taskConfig); // Check for an existing task using this buffer. A transferred buffer cannot be transferred
    // again from this thread.

    if (threeExamples.DRACOLoader.taskCache.has(buffer)) {
      var cachedTask = threeExamples.DRACOLoader.taskCache.get(buffer);

      if (cachedTask.key === taskKey) {
        return cachedTask.promise;
      } else if (buffer.byteLength === 0) {
        // Technically, it would be possible to wait for the previous task to complete,
        // transfer the buffer back, and decode again with the second configuration. That
        // is complex, and I don't know of any reason to decode a Draco buffer twice in
        // different ways, so this is left unimplemented.
        throw new Error('threeExamples.DRACOLoader: Unable to re-decode a buffer with different ' + 'settings. Buffer has already been transferred.');
      }
    } //


    var worker;
    var taskID = this.workerNextTaskID++;
    var taskCost = buffer.byteLength; // Obtain a worker and assign a task, and construct a geometry instance
    // when the task completes.

    var geometryPending = this._getWorker(taskID, taskCost).then(function (_worker) {
      worker = _worker;
      return new Promise(function (resolve, reject) {
        worker._callbacks[taskID] = {
          resolve: resolve,
          reject: reject
        };
        worker.postMessage({
          type: 'decode',
          id: taskID,
          taskConfig: taskConfig,
          buffer: buffer
        }, [buffer]); // this.debug();
      });
    }).then(function (message) {
      return _this2._createGeometry(message.geometry);
    }); // Remove task from the task list.


    geometryPending["finally"](function () {
      if (worker && taskID) {
        _this2._releaseTask(worker, taskID); // this.debug();

      }
    }); // Cache the task result.

    threeExamples.DRACOLoader.taskCache.set(buffer, {
      key: taskKey,
      promise: geometryPending
    });
    return geometryPending;
  },
  _createGeometry: function _createGeometry(geometryData) {
    var geometry = new THREE.BufferGeometry();

    if (geometryData.index) {
      geometry.setIndex(new THREE.BufferAttribute(geometryData.index.array, 1));
    }

    for (var i = 0; i < geometryData.attributes.length; i++) {
      var attribute = geometryData.attributes[i];
      var name = attribute.name;
      var array = attribute.array;
      var itemSize = attribute.itemSize;
      geometry.setAttribute(name, new THREE.BufferAttribute(array, itemSize));
    }

    return geometry;
  },
  _loadLibrary: function _loadLibrary(url, responseType) {
    var loader = new THREE.FileLoader(this.manager);
    loader.setPath(this.decoderPath);
    loader.setResponseType(responseType);
    return new Promise(function (resolve, reject) {
      loader.load(url, resolve, undefined, reject);
    });
  },
  preload: function preload() {
    this._initDecoder();

    return this;
  },
  _initDecoder: function _initDecoder() {
    var _this3 = this;

    if (this.decoderPending) return this.decoderPending;
    var useJS = (typeof WebAssembly === "undefined" ? "undefined" : (0, _typeof2["default"])(WebAssembly)) !== 'object' || this.decoderConfig.type === 'js';
    var librariesPending = [];

    if (useJS) {
      librariesPending.push(this._loadLibrary('draco_decoder.js', 'text'));
    } else {
      librariesPending.push(this._loadLibrary('draco_wasm_wrapper.js', 'text'));
      librariesPending.push(this._loadLibrary('draco_decoder.wasm', 'arraybuffer'));
    }

    this.decoderPending = Promise.all(librariesPending).then(function (libraries) {
      var jsContent = libraries[0];

      if (!useJS) {
        _this3.decoderConfig.wasmBinary = libraries[1];
      }

      var fn = threeExamples.DRACOLoader.DRACOWorker.toString();
      var body = ['/* draco decoder */', jsContent, '', '/* worker */', fn.substring(fn.indexOf('{') + 1, fn.lastIndexOf('}'))].join('\n');
      _this3.workerSourceURL = URL.createObjectURL(new Blob([body]));
    });
    return this.decoderPending;
  },
  _getWorker: function _getWorker(taskID, taskCost) {
    var _this4 = this;

    return this._initDecoder().then(function () {
      if (_this4.workerPool.length < _this4.workerLimit) {
        var worker = new Worker(_this4.workerSourceURL);
        worker._callbacks = {};
        worker._taskCosts = {};
        worker._taskLoad = 0;
        worker.postMessage({
          type: 'init',
          decoderConfig: _this4.decoderConfig
        });

        worker.onmessage = function (e) {
          var message = e.data;

          switch (message.type) {
            case 'decode':
              worker._callbacks[message.id].resolve(message);

              break;

            case 'error':
              worker._callbacks[message.id].reject(message);

              break;

            default:
              console.error('threeExamples.DRACOLoader: Unexpected message, "' + message.type + '"');
          }
        };

        _this4.workerPool.push(worker);
      } else {
        _this4.workerPool.sort(function (a, b) {
          return a._taskLoad > b._taskLoad ? -1 : 1;
        });
      }

      var worker = _this4.workerPool[_this4.workerPool.length - 1];
      worker._taskCosts[taskID] = taskCost;
      worker._taskLoad += taskCost;
      return worker;
    });
  },
  _releaseTask: function _releaseTask(worker, taskID) {
    worker._taskLoad -= worker._taskCosts[taskID];
    delete worker._callbacks[taskID];
    delete worker._taskCosts[taskID];
  },
  debug: function debug() {
    console.log('Task load: ', this.workerPool.map(function (worker) {
      return worker._taskLoad;
    }));
  },
  dispose: function dispose() {
    for (var i = 0; i < this.workerPool.length; ++i) {
      this.workerPool[i].terminate();
    }

    this.workerPool.length = 0;
    return this;
  }
});
/* WEB WORKER */

threeExamples.DRACOLoader.DRACOWorker = function () {
  var decoderConfig;
  var decoderPending;

  onmessage = function onmessage(e) {
    var message = e.data;

    switch (message.type) {
      case 'init':
        decoderConfig = message.decoderConfig;
        decoderPending = new Promise(function (resolve
        /*, reject*/
        ) {
          decoderConfig.onModuleLoaded = function (draco) {
            // Module is Promise-like. Wrap before resolving to avoid loop.
            resolve({
              draco: draco
            });
          };

          DracoDecoderModule(decoderConfig);
        });
        break;

      case 'decode':
        var buffer = message.buffer;
        var taskConfig = message.taskConfig;
        decoderPending.then(function (module) {
          var draco = module.draco;
          var decoder = new draco.Decoder();
          var decoderBuffer = new draco.DecoderBuffer();
          decoderBuffer.Init(new Int8Array(buffer), buffer.byteLength);

          try {
            var geometry = decodeGeometry(draco, decoder, decoderBuffer, taskConfig);
            var buffers = geometry.attributes.map(function (attr) {
              return attr.array.buffer;
            });
            if (geometry.index) buffers.push(geometry.index.array.buffer);
            self.postMessage({
              type: 'decode',
              id: message.id,
              geometry: geometry
            }, buffers);
          } catch (error) {
            console.error(error);
            self.postMessage({
              type: 'error',
              id: message.id,
              error: error.message
            });
          } finally {
            draco.destroy(decoderBuffer);
            draco.destroy(decoder);
          }
        });
        break;
    }
  };

  function decodeGeometry(draco, decoder, decoderBuffer, taskConfig) {
    var attributeIDs = taskConfig.attributeIDs;
    var attributeTypes = taskConfig.attributeTypes;
    var dracoGeometry;
    var decodingStatus;
    var geometryType = decoder.GetEncodedGeometryType(decoderBuffer);

    if (geometryType === draco.TRIANGULAR_MESH) {
      dracoGeometry = new draco.Mesh();
      decodingStatus = decoder.DecodeBufferToMesh(decoderBuffer, dracoGeometry);
    } else if (geometryType === draco.POINT_CLOUD) {
      dracoGeometry = new draco.PointCloud();
      decodingStatus = decoder.DecodeBufferToPointCloud(decoderBuffer, dracoGeometry);
    } else {
      throw new Error('threeExamples.DRACOLoader: Unexpected geometry type.');
    }

    if (!decodingStatus.ok() || dracoGeometry.ptr === 0) {
      throw new Error('threeExamples.DRACOLoader: Decoding failed: ' + decodingStatus.error_msg());
    }

    var geometry = {
      index: null,
      attributes: []
    }; // Gather all vertex attributes.

    for (var attributeName in attributeIDs) {
      var attributeType = self[attributeTypes[attributeName]];
      var attribute;
      var attributeID; // A Draco file may be created with default vertex attributes, whose attribute IDs
      // are mapped 1:1 from their semantic name (POSITION, NORMAL, ...). Alternatively,
      // a Draco file may contain a custom set of attributes, identified by known unique
      // IDs. glTF files always do the latter, and `.drc` files typically do the former.

      if (taskConfig.useUniqueIDs) {
        attributeID = attributeIDs[attributeName];
        attribute = decoder.GetAttributeByUniqueId(dracoGeometry, attributeID);
      } else {
        attributeID = decoder.GetAttributeId(dracoGeometry, draco[attributeIDs[attributeName]]);
        if (attributeID === -1) continue;
        attribute = decoder.GetAttribute(dracoGeometry, attributeID);
      }

      geometry.attributes.push(decodeAttribute(draco, decoder, dracoGeometry, attributeName, attributeType, attribute));
    } // Add index.


    if (geometryType === draco.TRIANGULAR_MESH) {
      // Generate mesh faces.
      var numFaces = dracoGeometry.num_faces();
      var index = new Uint32Array(numFaces * 3);
      var indexArray = new draco.DracoInt32Array();

      for (var i = 0; i < numFaces; ++i) {
        decoder.GetFaceFromMesh(dracoGeometry, i, indexArray);

        for (var j = 0; j < 3; ++j) {
          index[i * 3 + j] = indexArray.GetValue(j);
        }
      }

      geometry.index = {
        array: index,
        itemSize: 1
      };
      draco.destroy(indexArray);
    }

    draco.destroy(dracoGeometry);
    return geometry;
  }

  function decodeAttribute(draco, decoder, dracoGeometry, attributeName, attributeType, attribute) {
    var numComponents = attribute.num_components();
    var numPoints = dracoGeometry.num_points();
    var numValues = numPoints * numComponents;
    var dracoArray;
    var array;

    switch (attributeType) {
      case Float32Array:
        dracoArray = new draco.DracoFloat32Array();
        decoder.GetAttributeFloatForAllPoints(dracoGeometry, attribute, dracoArray);
        array = new Float32Array(numValues);
        break;

      case Int8Array:
        dracoArray = new draco.DracoInt8Array();
        decoder.GetAttributeInt8ForAllPoints(dracoGeometry, attribute, dracoArray);
        array = new Int8Array(numValues);
        break;

      case Int16Array:
        dracoArray = new draco.DracoInt16Array();
        decoder.GetAttributeInt16ForAllPoints(dracoGeometry, attribute, dracoArray);
        array = new Int16Array(numValues);
        break;

      case Int32Array:
        dracoArray = new draco.DracoInt32Array();
        decoder.GetAttributeInt32ForAllPoints(dracoGeometry, attribute, dracoArray);
        array = new Int32Array(numValues);
        break;

      case Uint8Array:
        dracoArray = new draco.DracoUInt8Array();
        decoder.GetAttributeUInt8ForAllPoints(dracoGeometry, attribute, dracoArray);
        array = new Uint8Array(numValues);
        break;

      case Uint16Array:
        dracoArray = new draco.DracoUInt16Array();
        decoder.GetAttributeUInt16ForAllPoints(dracoGeometry, attribute, dracoArray);
        array = new Uint16Array(numValues);
        break;

      case Uint32Array:
        dracoArray = new draco.DracoUInt32Array();
        decoder.GetAttributeUInt32ForAllPoints(dracoGeometry, attribute, dracoArray);
        array = new Uint32Array(numValues);
        break;

      default:
        throw new Error('threeExamples.DRACOLoader: Unexpected attribute type.');
    }

    for (var i = 0; i < numValues; i++) {
      array[i] = dracoArray.GetValue(i);
    }

    draco.destroy(dracoArray);
    return {
      name: attributeName,
      array: array,
      itemSize: numComponents
    };
  }
};

threeExamples.DRACOLoader.taskCache = new WeakMap();
/** Deprecated static methods */

/** @deprecated */

threeExamples.DRACOLoader.setDecoderPath = function () {
  console.warn('threeExamples.DRACOLoader: The .setDecoderPath() method has been removed. Use instance methods.');
};
/** @deprecated */


threeExamples.DRACOLoader.setDecoderConfig = function () {
  console.warn('threeExamples.DRACOLoader: The .setDecoderConfig() method has been removed. Use instance methods.');
};
/** @deprecated */


threeExamples.DRACOLoader.releaseDecoderModule = function () {
  console.warn('threeExamples.DRACOLoader: The .releaseDecoderModule() method has been removed. Use instance methods.');
};
/** @deprecated */


threeExamples.DRACOLoader.getDecoderModule = function () {
  console.warn('threeExamples.DRACOLoader: The .getDecoderModule() method has been removed. Use instance methods.');
};

var _default = threeExamples.DRACOLoader;
exports["default"] = _default;