"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 = {};
/** Copyright 2016 The Draco Authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * @param {THREE.LoadingManager} manager
 */

threeExamples.DRACOLoader = function (manager) {
  this.timeLoaded = 0;
  this.manager = manager || THREE.DefaultLoadingManager;
  this.materials = null;
  this.verbosity = 0;
  this.attributeOptions = {};
  this.drawMode = THREE.TrianglesDrawMode; // Native Draco attribute type to Three.JS attribute type.

  this.nativeAttributeMap = {
    position: "POSITION",
    normal: "NORMAL",
    color: "COLOR",
    uv: "TEX_COORD"
  };
};

threeExamples.DRACOLoader.prototype = {
  constructor: threeExamples.DRACOLoader,
  load: function load(url, onLoad, onProgress, onError) {
    var scope = this;
    var loader = new THREE.FileLoader(scope.manager);
    loader.setPath(this.path);
    loader.setResponseType("arraybuffer");
    loader.load(url, function (blob) {
      scope.decodeDracoFile(blob, onLoad);
    }, onProgress, onError);
  },
  setPath: function setPath(value) {
    this.path = value;
    return this;
  },
  setVerbosity: function setVerbosity(level) {
    this.verbosity = level;
    return this;
  },

  /**
   *  Sets desired mode for generated geometry indices.
   *  Can be either:
   *      THREE.TrianglesDrawMode
   *      THREE.TriangleStripDrawMode
   */
  setDrawMode: function setDrawMode(drawMode) {
    this.drawMode = drawMode;
    return this;
  },

  /**
   * Skips dequantization for a specific attribute.
   * |attributeName| is the THREE.js name of the given attribute type.
   * The only currently supported |attributeName| is 'position', more may be
   * added in future.
   */
  setSkipDequantization: function setSkipDequantization(attributeName, skip) {
    var skipDequantization = true;
    if (typeof skip !== "undefined") skipDequantization = skip;
    this.getAttributeOptions(attributeName).skipDequantization = skipDequantization;
    return this;
  },

  /**
   * Decompresses a Draco buffer. Names of attributes (for ID and type maps)
   * must be one of the supported three.js types, including: position, color,
   * normal, uv, uv2, skinIndex, skinWeight.
   *
   * @param {ArrayBuffer} rawBuffer
   * @param {Function} callback
   * @param {Object|undefined} attributeUniqueIdMap Provides a pre-defined ID
   *     for each attribute in the geometry to be decoded. If given,
   *     `attributeTypeMap` is required and `nativeAttributeMap` will be
   *     ignored.
   * @param {Object|undefined} attributeTypeMap Provides a predefined data
   *     type (as a typed array constructor) for each attribute in the
   *     geometry to be decoded.
   */
  decodeDracoFile: function decodeDracoFile(rawBuffer, callback, attributeUniqueIdMap, attributeTypeMap) {
    var scope = this;
    threeExamples.DRACOLoader.getDecoderModule().then(function (module) {
      scope.decodeDracoFileInternal(rawBuffer, module.decoder, callback, attributeUniqueIdMap, attributeTypeMap);
    });
  },
  decodeDracoFileInternal: function decodeDracoFileInternal(rawBuffer, dracoDecoder, callback, attributeUniqueIdMap, attributeTypeMap) {
    /*
     * Here is how to use Draco Javascript decoder and get the geometry.
     */
    var buffer = new dracoDecoder.DecoderBuffer();
    buffer.Init(new Int8Array(rawBuffer), rawBuffer.byteLength);
    var decoder = new dracoDecoder.Decoder();
    /*
     * Determine what type is this file: mesh or point cloud.
     */

    var geometryType = decoder.GetEncodedGeometryType(buffer);

    if (geometryType == dracoDecoder.TRIANGULAR_MESH) {
      if (this.verbosity > 0) {
        console.log("Loaded a mesh.");
      }
    } else if (geometryType == dracoDecoder.POINT_CLOUD) {
      if (this.verbosity > 0) {
        console.log("Loaded a point cloud.");
      }
    } else {
      var errorMsg = "threeExamples.DRACOLoader: Unknown geometry type.";
      console.error(errorMsg);
      throw new Error(errorMsg);
    }

    callback(this.convertDracoGeometryTo3JS(dracoDecoder, decoder, geometryType, buffer, attributeUniqueIdMap, attributeTypeMap));
  },
  addAttributeToGeometry: function addAttributeToGeometry(dracoDecoder, decoder, dracoGeometry, attributeName, attributeType, attribute, geometry, geometryBuffer) {
    if (attribute.ptr === 0) {
      var errorMsg = "threeExamples.DRACOLoader: No attribute " + attributeName;
      console.error(errorMsg);
      throw new Error(errorMsg);
    }

    var numComponents = attribute.num_components();
    var numPoints = dracoGeometry.num_points();
    var numValues = numPoints * numComponents;
    var attributeData;
    var TypedBufferAttribute;

    switch (attributeType) {
      case Float32Array:
        attributeData = new dracoDecoder.DracoFloat32Array();
        decoder.GetAttributeFloatForAllPoints(dracoGeometry, attribute, attributeData);
        geometryBuffer[attributeName] = new Float32Array(numValues);
        TypedBufferAttribute = THREE.Float32BufferAttribute;
        break;

      case Int8Array:
        attributeData = new dracoDecoder.DracoInt8Array();
        decoder.GetAttributeInt8ForAllPoints(dracoGeometry, attribute, attributeData);
        geometryBuffer[attributeName] = new Int8Array(numValues);
        TypedBufferAttribute = THREE.Int8BufferAttribute;
        break;

      case Int16Array:
        attributeData = new dracoDecoder.DracoInt16Array();
        decoder.GetAttributeInt16ForAllPoints(dracoGeometry, attribute, attributeData);
        geometryBuffer[attributeName] = new Int16Array(numValues);
        TypedBufferAttribute = THREE.Int16BufferAttribute;
        break;

      case Int32Array:
        attributeData = new dracoDecoder.DracoInt32Array();
        decoder.GetAttributeInt32ForAllPoints(dracoGeometry, attribute, attributeData);
        geometryBuffer[attributeName] = new Int32Array(numValues);
        TypedBufferAttribute = THREE.Int32BufferAttribute;
        break;

      case Uint8Array:
        attributeData = new dracoDecoder.DracoUInt8Array();
        decoder.GetAttributeUInt8ForAllPoints(dracoGeometry, attribute, attributeData);
        geometryBuffer[attributeName] = new Uint8Array(numValues);
        TypedBufferAttribute = THREE.Uint8BufferAttribute;
        break;

      case Uint16Array:
        attributeData = new dracoDecoder.DracoUInt16Array();
        decoder.GetAttributeUInt16ForAllPoints(dracoGeometry, attribute, attributeData);
        geometryBuffer[attributeName] = new Uint16Array(numValues);
        TypedBufferAttribute = THREE.Uint16BufferAttribute;
        break;

      case Uint32Array:
        attributeData = new dracoDecoder.DracoUInt32Array();
        decoder.GetAttributeUInt32ForAllPoints(dracoGeometry, attribute, attributeData);
        geometryBuffer[attributeName] = new Uint32Array(numValues);
        TypedBufferAttribute = THREE.Uint32BufferAttribute;
        break;

      default:
        var errorMsg = "threeExamples.DRACOLoader: Unexpected attribute type.";
        console.error(errorMsg);
        throw new Error(errorMsg);
    } // Copy data from decoder.


    for (var i = 0; i < numValues; i++) {
      geometryBuffer[attributeName][i] = attributeData.GetValue(i);
    } // Add attribute to THREEJS geometry for rendering.


    geometry.addAttribute(attributeName, new TypedBufferAttribute(geometryBuffer[attributeName], numComponents));
    dracoDecoder.destroy(attributeData);
  },
  convertDracoGeometryTo3JS: function convertDracoGeometryTo3JS(dracoDecoder, decoder, geometryType, buffer, attributeUniqueIdMap, attributeTypeMap) {
    // TODO: Should not assume native Draco attribute IDs apply.
    if (this.getAttributeOptions("position").skipDequantization === true) {
      decoder.SkipAttributeTransform(dracoDecoder.POSITION);
    }

    var dracoGeometry;
    var decodingStatus;
    var start_time = performance.now();

    if (geometryType === dracoDecoder.TRIANGULAR_MESH) {
      dracoGeometry = new dracoDecoder.Mesh();
      decodingStatus = decoder.DecodeBufferToMesh(buffer, dracoGeometry);
    } else {
      dracoGeometry = new dracoDecoder.PointCloud();
      decodingStatus = decoder.DecodeBufferToPointCloud(buffer, dracoGeometry);
    }

    if (!decodingStatus.ok() || dracoGeometry.ptr == 0) {
      var errorMsg = "threeExamples.DRACOLoader: Decoding failed: ";
      errorMsg += decodingStatus.error_msg();
      console.error(errorMsg);
      dracoDecoder.destroy(decoder);
      dracoDecoder.destroy(dracoGeometry);
      throw new Error(errorMsg);
    }

    var decode_end = performance.now();
    dracoDecoder.destroy(buffer);
    /*
     * Example on how to retrieve mesh and attributes.
     */

    var numFaces;

    if (geometryType == dracoDecoder.TRIANGULAR_MESH) {
      numFaces = dracoGeometry.num_faces();

      if (this.verbosity > 0) {
        console.log("Number of faces loaded: " + numFaces.toString());
      }
    } else {
      numFaces = 0;
    }

    var numPoints = dracoGeometry.num_points();
    var numAttributes = dracoGeometry.num_attributes();

    if (this.verbosity > 0) {
      console.log("Number of points loaded: " + numPoints.toString());
      console.log("Number of attributes loaded: " + numAttributes.toString());
    } // Verify if there is position attribute.
    // TODO: Should not assume native Draco attribute IDs apply.


    var posAttId = decoder.GetAttributeId(dracoGeometry, dracoDecoder.POSITION);

    if (posAttId == -1) {
      var errorMsg = "threeExamples.DRACOLoader: No position attribute found.";
      console.error(errorMsg);
      dracoDecoder.destroy(decoder);
      dracoDecoder.destroy(dracoGeometry);
      throw new Error(errorMsg);
    }

    var posAttribute = decoder.GetAttribute(dracoGeometry, posAttId); // Structure for converting to THREEJS geometry later.

    var geometryBuffer = {}; // Import data to Three JS geometry.

    var geometry = new THREE.BufferGeometry(); // Do not use both the native attribute map and a provided (e.g. glTF) map.

    if (attributeUniqueIdMap) {
      // Add attributes of user specified unique id. E.g. GLTF models.
      for (var attributeName in attributeUniqueIdMap) {
        var attributeType = attributeTypeMap[attributeName];
        var attributeId = attributeUniqueIdMap[attributeName];
        var attribute = decoder.GetAttributeByUniqueId(dracoGeometry, attributeId);
        this.addAttributeToGeometry(dracoDecoder, decoder, dracoGeometry, attributeName, attributeType, attribute, geometry, geometryBuffer);
      }
    } else {
      // Add native Draco attribute type to geometry.
      for (var attributeName in this.nativeAttributeMap) {
        var attId = decoder.GetAttributeId(dracoGeometry, dracoDecoder[this.nativeAttributeMap[attributeName]]);

        if (attId !== -1) {
          if (this.verbosity > 0) {
            console.log("Loaded " + attributeName + " attribute.");
          }

          var attribute = decoder.GetAttribute(dracoGeometry, attId);
          this.addAttributeToGeometry(dracoDecoder, decoder, dracoGeometry, attributeName, Float32Array, attribute, geometry, geometryBuffer);
        }
      }
    } // For mesh, we need to generate the faces.


    if (geometryType == dracoDecoder.TRIANGULAR_MESH) {
      if (this.drawMode === THREE.TriangleStripDrawMode) {
        var stripsArray = new dracoDecoder.DracoInt32Array();
        decoder.GetTriangleStripsFromMesh(dracoGeometry, stripsArray);
        geometryBuffer.indices = new Uint32Array(stripsArray.size());

        for (var i = 0; i < stripsArray.size(); ++i) {
          geometryBuffer.indices[i] = stripsArray.GetValue(i);
        }

        dracoDecoder.destroy(stripsArray);
      } else {
        var numIndices = numFaces * 3;
        geometryBuffer.indices = new Uint32Array(numIndices);
        var ia = new dracoDecoder.DracoInt32Array();

        for (var i = 0; i < numFaces; ++i) {
          decoder.GetFaceFromMesh(dracoGeometry, i, ia);
          var index = i * 3;
          geometryBuffer.indices[index] = ia.GetValue(0);
          geometryBuffer.indices[index + 1] = ia.GetValue(1);
          geometryBuffer.indices[index + 2] = ia.GetValue(2);
        }

        dracoDecoder.destroy(ia);
      }
    }

    geometry.drawMode = this.drawMode;

    if (geometryType == dracoDecoder.TRIANGULAR_MESH) {
      geometry.setIndex(new (geometryBuffer.indices.length > 65535 ? THREE.Uint32BufferAttribute : THREE.Uint16BufferAttribute)(geometryBuffer.indices, 1));
    } // TODO: Should not assume native Draco attribute IDs apply.
    // TODO: Can other attribute types be quantized?


    var posTransform = new dracoDecoder.AttributeQuantizationTransform();

    if (posTransform.InitFromAttribute(posAttribute)) {
      // Quantized attribute. Store the quantization parameters into the
      // THREE.js attribute.
      geometry.attributes["position"].isQuantized = true;
      geometry.attributes["position"].maxRange = posTransform.range();
      geometry.attributes["position"].numQuantizationBits = posTransform.quantization_bits();
      geometry.attributes["position"].minValues = new Float32Array(3);

      for (var i = 0; i < 3; ++i) {
        geometry.attributes["position"].minValues[i] = posTransform.min_value(i);
      }
    }

    dracoDecoder.destroy(posTransform);
    dracoDecoder.destroy(decoder);
    dracoDecoder.destroy(dracoGeometry);
    this.decode_time = decode_end - start_time;
    this.import_time = performance.now() - decode_end;

    if (this.verbosity > 0) {
      console.log("Decode time: " + this.decode_time);
      console.log("Import time: " + this.import_time);
    }

    return geometry;
  },
  isVersionSupported: function isVersionSupported(version, callback) {
    threeExamples.DRACOLoader.getDecoderModule().then(function (module) {
      callback(module.decoder.isVersionSupported(version));
    });
  },
  getAttributeOptions: function getAttributeOptions(attributeName) {
    if (typeof this.attributeOptions[attributeName] === "undefined") this.attributeOptions[attributeName] = {};
    return this.attributeOptions[attributeName];
  }
};
threeExamples.DRACOLoader.decoderPath = "./";
threeExamples.DRACOLoader.decoderConfig = {};
threeExamples.DRACOLoader.decoderModulePromise = null;
/**
 * Sets the base path for decoder source files.
 * @param {string} path
 */

threeExamples.DRACOLoader.setDecoderPath = function (path) {
  threeExamples.DRACOLoader.decoderPath = path;
};
/**
 * Sets decoder configuration and releases singleton decoder module. Module
 * will be recreated with the next decoding call.
 * @param {Object} config
 */


threeExamples.DRACOLoader.setDecoderConfig = function (config) {
  var wasmBinary = threeExamples.DRACOLoader.decoderConfig.wasmBinary;
  threeExamples.DRACOLoader.decoderConfig = config || {};
  threeExamples.DRACOLoader.releaseDecoderModule(); // Reuse WASM binary.

  if (wasmBinary) threeExamples.DRACOLoader.decoderConfig.wasmBinary = wasmBinary;
};
/**
 * Releases the singleton DracoDecoderModule instance. Module will be recreated
 * with the next decoding call.
 */


threeExamples.DRACOLoader.releaseDecoderModule = function () {
  threeExamples.DRACOLoader.decoderModulePromise = null;
};
/**
 * Gets WebAssembly or asm.js singleton instance of DracoDecoderModule
 * after testing for browser support. Returns Promise that resolves when
 * module is available.
 * @return {Promise<{decoder: DracoDecoderModule}>}
 */


threeExamples.DRACOLoader.getDecoderModule = function () {
  var scope = this;
  var path = threeExamples.DRACOLoader.decoderPath;
  var config = threeExamples.DRACOLoader.decoderConfig;
  var promise = threeExamples.DRACOLoader.decoderModulePromise;
  if (promise) return promise; // Load source files.

  if (typeof DracoDecoderModule !== "undefined") {
    // Loaded externally.
    promise = Promise.resolve();
  } else if ((typeof WebAssembly === "undefined" ? "undefined" : (0, _typeof2["default"])(WebAssembly)) !== "object" || config.type === "js") {
    // Load with asm.js.
    promise = threeExamples.DRACOLoader._loadScript(path + "draco_decoder.js");
  } else {
    // Load with WebAssembly.
    config.wasmBinaryFile = path + "draco_decoder.wasm";
    promise = threeExamples.DRACOLoader._loadScript(path + "draco_wasm_wrapper.js").then(function () {
      return threeExamples.DRACOLoader._loadArrayBuffer(config.wasmBinaryFile);
    }).then(function (wasmBinary) {
      config.wasmBinary = wasmBinary;
    });
  } // Wait for source files, then create and return a decoder.


  promise = promise.then(function () {
    return new Promise(function (resolve) {
      config.onModuleLoaded = function (decoder) {
        scope.timeLoaded = performance.now(); // Module is Promise-like. Wrap before resolving to avoid loop.

        resolve({
          decoder: decoder
        });
      };

      DracoDecoderModule(config);
    });
  });
  threeExamples.DRACOLoader.decoderModulePromise = promise;
  return promise;
};
/**
 * @param {string} src
 * @return {Promise}
 */


threeExamples.DRACOLoader._loadScript = function (src) {
  var prevScript = document.getElementById("decoder_script");

  if (prevScript !== null) {
    prevScript.parentNode.removeChild(prevScript);
  }

  var head = document.getElementsByTagName("head")[0];
  var script = document.createElement("script");
  script.id = "decoder_script";
  script.type = "text/javascript";
  script.src = src;
  return new Promise(function (resolve) {
    script.onload = resolve;
    head.appendChild(script);
  });
};
/**
 * @param {string} src
 * @return {Promise}
 */


threeExamples.DRACOLoader._loadArrayBuffer = function (src) {
  var loader = new THREE.FileLoader();
  loader.setResponseType("arraybuffer");
  return new Promise(function (resolve, reject) {
    loader.load(src, resolve, undefined, reject);
  });
};

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