|
@@ -14,23 +14,25 @@
|
|
|
//
|
|
|
'use strict';
|
|
|
|
|
|
-// |dracoPath| sets the path for the Draco decoder source files. The default
|
|
|
-// path is "./". If |dracoDecoderType|.type is set to "js", then DRACOLoader
|
|
|
-// will load the Draco JavaScript decoder.
|
|
|
-THREE.DRACOLoader = function(dracoPath, dracoDecoderType, manager) {
|
|
|
+/**
|
|
|
+ * @param {THREE.LoadingManager} manager
|
|
|
+ */
|
|
|
+THREE.DRACOLoader = function(manager) {
|
|
|
this.timeLoaded = 0;
|
|
|
- this.manager = (manager !== undefined) ? manager :
|
|
|
- THREE.DefaultLoadingManager;
|
|
|
+ this.manager = manager || THREE.DefaultLoadingManager;
|
|
|
this.materials = null;
|
|
|
this.verbosity = 0;
|
|
|
this.attributeOptions = {};
|
|
|
- this.dracoDecoderType =
|
|
|
- (dracoDecoderType !== undefined) ? dracoDecoderType : {};
|
|
|
this.drawMode = THREE.TrianglesDrawMode;
|
|
|
- this.dracoSrcPath = (dracoPath !== undefined) ? dracoPath : './';
|
|
|
- if (typeof DracoDecoderModule === 'undefined') {
|
|
|
- THREE.DRACOLoader.loadDracoDecoder(this);
|
|
|
- }
|
|
|
+ // User defined unique id for attributes.
|
|
|
+ this.attributeUniqueIdMap = {};
|
|
|
+ // Native Draco attribute type to Three.JS attribute type.
|
|
|
+ this.nativeAttributeMap = {
|
|
|
+ 'position' : 'POSITION',
|
|
|
+ 'normal' : 'NORMAL',
|
|
|
+ 'color' : 'COLOR',
|
|
|
+ 'uv' : 'TEX_COORD'
|
|
|
+ };
|
|
|
};
|
|
|
|
|
|
THREE.DRACOLoader.prototype = {
|
|
@@ -86,15 +88,30 @@ THREE.DRACOLoader.prototype = {
|
|
|
skipDequantization;
|
|
|
},
|
|
|
|
|
|
- decodeDracoFile: function(rawBuffer, callback) {
|
|
|
+ /**
|
|
|
+ * |attributeUniqueIdMap| specifies attribute unique id for an attribute in
|
|
|
+ * the geometry to be decoded. The name of the attribute must be one of the
|
|
|
+ * supported attribute type in Three.JS, including:
|
|
|
+ * 'position',
|
|
|
+ * 'color',
|
|
|
+ * 'normal',
|
|
|
+ * 'uv',
|
|
|
+ * 'uv2',
|
|
|
+ * 'skinIndex',
|
|
|
+ * 'skinWeight'.
|
|
|
+ * The format is:
|
|
|
+ * attributeUniqueIdMap[attributeName] = attributeId
|
|
|
+ */
|
|
|
+ decodeDracoFile: function(rawBuffer, callback, attributeUniqueIdMap) {
|
|
|
var scope = this;
|
|
|
- THREE.DRACOLoader.getDecoder(this,
|
|
|
- function(dracoDecoder) {
|
|
|
- scope.decodeDracoFileInternal(rawBuffer, dracoDecoder, callback);
|
|
|
- });
|
|
|
+ this.attributeUniqueIdMap = attributeUniqueIdMap || {};
|
|
|
+ THREE.DRACOLoader.getDecoderModule()
|
|
|
+ .then( function ( module ) {
|
|
|
+ scope.decodeDracoFileInternal( rawBuffer, module.decoder, callback );
|
|
|
+ });
|
|
|
},
|
|
|
|
|
|
- decodeDracoFileInternal : function(rawBuffer, dracoDecoder, callback) {
|
|
|
+ decodeDracoFileInternal: function(rawBuffer, dracoDecoder, callback) {
|
|
|
/*
|
|
|
* Here is how to use Draco Javascript decoder and get the geometry.
|
|
|
*/
|
|
@@ -123,6 +140,33 @@ THREE.DRACOLoader.prototype = {
|
|
|
geometryType, buffer));
|
|
|
},
|
|
|
|
|
|
+ addAttributeToGeometry: function(dracoDecoder, decoder, dracoGeometry,
|
|
|
+ attributeName, attribute, geometry,
|
|
|
+ geometryBuffer) {
|
|
|
+ if (attribute.ptr === 0) {
|
|
|
+ var errorMsg = 'THREE.DRACOLoader: No attribute ' + attributeName;
|
|
|
+ console.error(errorMsg);
|
|
|
+ throw new Error(errorMsg);
|
|
|
+ }
|
|
|
+ var numComponents = attribute.num_components();
|
|
|
+ var attributeData = new dracoDecoder.DracoFloat32Array();
|
|
|
+ decoder.GetAttributeFloatForAllPoints(
|
|
|
+ dracoGeometry, attribute, attributeData);
|
|
|
+ var numPoints = dracoGeometry.num_points();
|
|
|
+ var numValues = numPoints * numComponents;
|
|
|
+ // Allocate space for attribute.
|
|
|
+ geometryBuffer[attributeName] = new Float32Array(numValues);
|
|
|
+ // 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 THREE.Float32BufferAttribute(geometryBuffer[attributeName],
|
|
|
+ numComponents));
|
|
|
+ dracoDecoder.destroy(attributeData);
|
|
|
+ },
|
|
|
+
|
|
|
convertDracoGeometryTo3JS: function(dracoDecoder, decoder, geometryType,
|
|
|
buffer) {
|
|
|
if (this.getAttributeOptions('position').skipDequantization === true) {
|
|
@@ -153,12 +197,7 @@ THREE.DRACOLoader.prototype = {
|
|
|
/*
|
|
|
* Example on how to retrieve mesh and attributes.
|
|
|
*/
|
|
|
- var numFaces, numPoints;
|
|
|
- var numVertexCoordinates, numTextureCoordinates, numColorCoordinates;
|
|
|
- var numAttributes;
|
|
|
- var numColorCoordinateComponents = 3;
|
|
|
- // For output basic geometry information.
|
|
|
- var geometryInfoStr;
|
|
|
+ var numFaces;
|
|
|
if (geometryType == dracoDecoder.TRIANGULAR_MESH) {
|
|
|
numFaces = dracoGeometry.num_faces();
|
|
|
if (this.verbosity > 0) {
|
|
@@ -167,20 +206,18 @@ THREE.DRACOLoader.prototype = {
|
|
|
} else {
|
|
|
numFaces = 0;
|
|
|
}
|
|
|
- numPoints = dracoGeometry.num_points();
|
|
|
- numVertexCoordinates = numPoints * 3;
|
|
|
- numTextureCoordinates = numPoints * 2;
|
|
|
- numColorCoordinates = numPoints * 3;
|
|
|
- numAttributes = dracoGeometry.num_attributes();
|
|
|
+
|
|
|
+ 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());
|
|
|
}
|
|
|
|
|
|
- // Get position attribute. Must exists.
|
|
|
+ // Verify if there is position attribute.
|
|
|
var posAttId = decoder.GetAttributeId(dracoGeometry,
|
|
|
- dracoDecoder.POSITION);
|
|
|
+ dracoDecoder.POSITION);
|
|
|
if (posAttId == -1) {
|
|
|
var errorMsg = 'THREE.DRACOLoader: No position attribute found.';
|
|
|
console.error(errorMsg);
|
|
@@ -189,104 +226,39 @@ THREE.DRACOLoader.prototype = {
|
|
|
throw new Error(errorMsg);
|
|
|
}
|
|
|
var posAttribute = decoder.GetAttribute(dracoGeometry, posAttId);
|
|
|
- var posAttributeData = new dracoDecoder.DracoFloat32Array();
|
|
|
- decoder.GetAttributeFloatForAllPoints(
|
|
|
- dracoGeometry, posAttribute, posAttributeData);
|
|
|
- // Get color attributes if exists.
|
|
|
- var colorAttId = decoder.GetAttributeId(dracoGeometry,
|
|
|
- dracoDecoder.COLOR);
|
|
|
- var colAttributeData;
|
|
|
- if (colorAttId != -1) {
|
|
|
- if (this.verbosity > 0) {
|
|
|
- console.log('Loaded color attribute.');
|
|
|
- }
|
|
|
- var colAttribute = decoder.GetAttribute(dracoGeometry, colorAttId);
|
|
|
- if (colAttribute.num_components() === 4) {
|
|
|
- numColorCoordinates = numPoints * 4;
|
|
|
- numColorCoordinateComponents = 4;
|
|
|
- }
|
|
|
- colAttributeData = new dracoDecoder.DracoFloat32Array();
|
|
|
- decoder.GetAttributeFloatForAllPoints(dracoGeometry, colAttribute,
|
|
|
- colAttributeData);
|
|
|
- }
|
|
|
-
|
|
|
- // Get normal attributes if exists.
|
|
|
- var normalAttId =
|
|
|
- decoder.GetAttributeId(dracoGeometry, dracoDecoder.NORMAL);
|
|
|
- var norAttributeData;
|
|
|
- if (normalAttId != -1) {
|
|
|
- if (this.verbosity > 0) {
|
|
|
- console.log('Loaded normal attribute.');
|
|
|
- }
|
|
|
- var norAttribute = decoder.GetAttribute(dracoGeometry, normalAttId);
|
|
|
- norAttributeData = new dracoDecoder.DracoFloat32Array();
|
|
|
- decoder.GetAttributeFloatForAllPoints(dracoGeometry, norAttribute,
|
|
|
- norAttributeData);
|
|
|
- }
|
|
|
-
|
|
|
- // Get texture coord attributes if exists.
|
|
|
- var texCoordAttId =
|
|
|
- decoder.GetAttributeId(dracoGeometry, dracoDecoder.TEX_COORD);
|
|
|
- var textCoordAttributeData;
|
|
|
- if (texCoordAttId != -1) {
|
|
|
- if (this.verbosity > 0) {
|
|
|
- console.log('Loaded texture coordinate attribute.');
|
|
|
- }
|
|
|
- var texCoordAttribute = decoder.GetAttribute(dracoGeometry,
|
|
|
- texCoordAttId);
|
|
|
- textCoordAttributeData = new dracoDecoder.DracoFloat32Array();
|
|
|
- decoder.GetAttributeFloatForAllPoints(dracoGeometry,
|
|
|
- texCoordAttribute,
|
|
|
- textCoordAttributeData);
|
|
|
- }
|
|
|
|
|
|
// Structure for converting to THREEJS geometry later.
|
|
|
- var geometryBuffer = {
|
|
|
- vertices: new Float32Array(numVertexCoordinates),
|
|
|
- normals: new Float32Array(numVertexCoordinates),
|
|
|
- uvs: new Float32Array(numTextureCoordinates),
|
|
|
- colors: new Float32Array(numColorCoordinates)
|
|
|
- };
|
|
|
-
|
|
|
- for (var i = 0; i < numVertexCoordinates; i += 3) {
|
|
|
- geometryBuffer.vertices[i] = posAttributeData.GetValue(i);
|
|
|
- geometryBuffer.vertices[i + 1] = posAttributeData.GetValue(i + 1);
|
|
|
- geometryBuffer.vertices[i + 2] = posAttributeData.GetValue(i + 2);
|
|
|
- // Add normal.
|
|
|
- if (normalAttId != -1) {
|
|
|
- geometryBuffer.normals[i] = norAttributeData.GetValue(i);
|
|
|
- geometryBuffer.normals[i + 1] = norAttributeData.GetValue(i + 1);
|
|
|
- geometryBuffer.normals[i + 2] = norAttributeData.GetValue(i + 2);
|
|
|
- }
|
|
|
- }
|
|
|
+ var geometryBuffer = {};
|
|
|
+ // Import data to Three JS geometry.
|
|
|
+ var geometry = new THREE.BufferGeometry();
|
|
|
|
|
|
- // Add color.
|
|
|
- for (var i = 0; i < numColorCoordinates; i += 1) {
|
|
|
- if (colorAttId != -1) {
|
|
|
- // Draco colors are already normalized.
|
|
|
- geometryBuffer.colors[i] = colAttributeData.GetValue(i);
|
|
|
- } else {
|
|
|
- // Default is white. This is faster than TypedArray.fill().
|
|
|
- geometryBuffer.colors[i] = 1.0;
|
|
|
+ // Add native Draco attribute type to geometry.
|
|
|
+ for (var attributeName in this.nativeAttributeMap) {
|
|
|
+ // The native attribute type is only used when no unique Id is
|
|
|
+ // provided. For example, loading .drc files.
|
|
|
+ if (this.attributeUniqueIdMap[attributeName] === undefined) {
|
|
|
+ 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, attribute, geometry, geometryBuffer);
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- // Add texture coordinates.
|
|
|
- if (texCoordAttId != -1) {
|
|
|
- for (var i = 0; i < numTextureCoordinates; i += 2) {
|
|
|
- geometryBuffer.uvs[i] = textCoordAttributeData.GetValue(i);
|
|
|
- geometryBuffer.uvs[i + 1] = textCoordAttributeData.GetValue(i + 1);
|
|
|
- }
|
|
|
+ // Add attributes of user specified unique id. E.g. GLTF models.
|
|
|
+ for (var attributeName in this.attributeUniqueIdMap) {
|
|
|
+ var attributeId = this.attributeUniqueIdMap[attributeName];
|
|
|
+ var attribute = decoder.GetAttributeByUniqueId(dracoGeometry,
|
|
|
+ attributeId);
|
|
|
+ this.addAttributeToGeometry(dracoDecoder, decoder, dracoGeometry,
|
|
|
+ attributeName, attribute, geometry, geometryBuffer);
|
|
|
}
|
|
|
|
|
|
- dracoDecoder.destroy(posAttributeData);
|
|
|
- if (colorAttId != -1)
|
|
|
- dracoDecoder.destroy(colAttributeData);
|
|
|
- if (normalAttId != -1)
|
|
|
- dracoDecoder.destroy(norAttributeData);
|
|
|
- if (texCoordAttId != -1)
|
|
|
- dracoDecoder.destroy(textCoordAttributeData);
|
|
|
-
|
|
|
// For mesh, we need to generate the faces.
|
|
|
if (geometryType == dracoDecoder.TRIANGULAR_MESH) {
|
|
|
if (this.drawMode === THREE.TriangleStripDrawMode) {
|
|
@@ -313,16 +285,12 @@ THREE.DRACOLoader.prototype = {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- // Import data to Three JS geometry.
|
|
|
- var geometry = new THREE.BufferGeometry();
|
|
|
geometry.drawMode = this.drawMode;
|
|
|
if (geometryType == dracoDecoder.TRIANGULAR_MESH) {
|
|
|
geometry.setIndex(new(geometryBuffer.indices.length > 65535 ?
|
|
|
THREE.Uint32BufferAttribute : THREE.Uint16BufferAttribute)
|
|
|
(geometryBuffer.indices, 1));
|
|
|
}
|
|
|
- geometry.addAttribute('position',
|
|
|
- new THREE.Float32BufferAttribute(geometryBuffer.vertices, 3));
|
|
|
var posTransform = new dracoDecoder.AttributeQuantizationTransform();
|
|
|
if (posTransform.InitFromAttribute(posAttribute)) {
|
|
|
// Quantized attribute. Store the quantization parameters into the
|
|
@@ -338,18 +306,6 @@ THREE.DRACOLoader.prototype = {
|
|
|
}
|
|
|
}
|
|
|
dracoDecoder.destroy(posTransform);
|
|
|
- geometry.addAttribute('color',
|
|
|
- new THREE.Float32BufferAttribute(geometryBuffer.colors,
|
|
|
- numColorCoordinateComponents));
|
|
|
- if (normalAttId != -1) {
|
|
|
- geometry.addAttribute('normal',
|
|
|
- new THREE.Float32BufferAttribute(geometryBuffer.normals, 3));
|
|
|
- }
|
|
|
- if (texCoordAttId != -1) {
|
|
|
- geometry.addAttribute('uv',
|
|
|
- new THREE.Float32BufferAttribute(geometryBuffer.uvs, 2));
|
|
|
- }
|
|
|
-
|
|
|
dracoDecoder.destroy(decoder);
|
|
|
dracoDecoder.destroy(dracoGeometry);
|
|
|
|
|
@@ -364,9 +320,9 @@ THREE.DRACOLoader.prototype = {
|
|
|
},
|
|
|
|
|
|
isVersionSupported: function(version, callback) {
|
|
|
- THREE.DRACOLoader.getDecoder(this,
|
|
|
- function(decoder) {
|
|
|
- callback(decoder.isVersionSupported(version));
|
|
|
+ THREE.DRACOLoader.getDecoderModule()
|
|
|
+ .then( function ( module ) {
|
|
|
+ callback( module.decoder.isVersionSupported( version ) );
|
|
|
});
|
|
|
},
|
|
|
|
|
@@ -377,119 +333,109 @@ THREE.DRACOLoader.prototype = {
|
|
|
}
|
|
|
};
|
|
|
|
|
|
-// This function loads a JavaScript file and adds it to the page. "path"
|
|
|
-// is the path to the JavaScript file. "onLoadFunc" is the function to be
|
|
|
-// called when the JavaScript file has been loaded.
|
|
|
-THREE.DRACOLoader.loadJavaScriptFile = function(path, onLoadFunc,
|
|
|
- dracoDecoder) {
|
|
|
- var head = document.getElementsByTagName('head')[0];
|
|
|
- var element = document.createElement('script');
|
|
|
- element.id = "decoder_script";
|
|
|
- element.type = 'text/javascript';
|
|
|
- element.src = path;
|
|
|
- if (onLoadFunc !== null) {
|
|
|
- element.onload = onLoadFunc(dracoDecoder);
|
|
|
- } else {
|
|
|
- element.onload = function(dracoDecoder) {
|
|
|
- dracoDecoder.timeLoaded = performance.now();
|
|
|
- };
|
|
|
- }
|
|
|
+THREE.DRACOLoader.decoderPath = './';
|
|
|
+THREE.DRACOLoader.decoderConfig = {};
|
|
|
+THREE.DRACOLoader.decoderModulePromise = null;
|
|
|
|
|
|
- var previous_decoder_script = document.getElementById("decoder_script");
|
|
|
- if (previous_decoder_script !== null) {
|
|
|
- previous_decoder_script.parentNode.removeChild(previous_decoder_script);
|
|
|
- }
|
|
|
- head.appendChild(element);
|
|
|
-}
|
|
|
-
|
|
|
-THREE.DRACOLoader.loadWebAssemblyDecoder = function(dracoDecoder) {
|
|
|
- dracoDecoder.dracoDecoderType['wasmBinaryFile'] =
|
|
|
- dracoDecoder.dracoSrcPath + 'draco_decoder.wasm';
|
|
|
- var xhr = new XMLHttpRequest();
|
|
|
- xhr.open('GET', dracoDecoder.dracoSrcPath + 'draco_decoder.wasm', true);
|
|
|
- xhr.responseType = 'arraybuffer';
|
|
|
- xhr.onload = function() {
|
|
|
- // draco_wasm_wrapper.js must be loaded before DracoDecoderModule is
|
|
|
- // created. The object passed into DracoDecoderModule() must contain a
|
|
|
- // property with the name of wasmBinary and the value must be an
|
|
|
- // ArrayBuffer containing the contents of the .wasm file.
|
|
|
- dracoDecoder.dracoDecoderType['wasmBinary'] = xhr.response;
|
|
|
- dracoDecoder.timeLoaded = performance.now();
|
|
|
- };
|
|
|
- xhr.send(null)
|
|
|
-}
|
|
|
-
|
|
|
-// This function will test if the browser has support for WebAssembly. If
|
|
|
-// it does it will download the WebAssembly Draco decoder, if not it will
|
|
|
-// download the asmjs Draco decoder.
|
|
|
-THREE.DRACOLoader.loadDracoDecoder = function(dracoDecoder) {
|
|
|
- if (typeof WebAssembly !== 'object' ||
|
|
|
- dracoDecoder.dracoDecoderType.type === 'js') {
|
|
|
- // No WebAssembly support
|
|
|
- THREE.DRACOLoader.loadJavaScriptFile(dracoDecoder.dracoSrcPath +
|
|
|
- 'draco_decoder.js', null, dracoDecoder);
|
|
|
+/**
|
|
|
+ * Sets the base path for decoder source files.
|
|
|
+ * @param {string} path
|
|
|
+ */
|
|
|
+THREE.DRACOLoader.setDecoderPath = function ( path ) {
|
|
|
+ THREE.DRACOLoader.decoderPath = path;
|
|
|
+};
|
|
|
+
|
|
|
+/**
|
|
|
+ * Sets decoder configuration and releases singleton decoder module. Module
|
|
|
+ * will be recreated with the next decoding call.
|
|
|
+ * @param {Object} config
|
|
|
+ */
|
|
|
+THREE.DRACOLoader.setDecoderConfig = function ( config ) {
|
|
|
+ var wasmBinary = THREE.DRACOLoader.decoderConfig.wasmBinary;
|
|
|
+ THREE.DRACOLoader.decoderConfig = config || {};
|
|
|
+ THREE.DRACOLoader.decoderModulePromise = null;
|
|
|
+
|
|
|
+ // Reuse WASM binary.
|
|
|
+ if ( wasmBinary ) THREE.DRACOLoader.decoderConfig.wasmBinary = wasmBinary;
|
|
|
+};
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 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}>}
|
|
|
+ */
|
|
|
+THREE.DRACOLoader.getDecoderModule = function () {
|
|
|
+ var scope = this;
|
|
|
+ var path = THREE.DRACOLoader.decoderPath;
|
|
|
+ var config = THREE.DRACOLoader.decoderConfig;
|
|
|
+ var promise = THREE.DRACOLoader.decoderModulePromise;
|
|
|
+
|
|
|
+ if ( promise ) return promise;
|
|
|
+
|
|
|
+ // Load source files.
|
|
|
+ if ( typeof DracoDecoderModule !== 'undefined' ) {
|
|
|
+ // Loaded externally.
|
|
|
+ promise = Promise.resolve();
|
|
|
+ } else if ( typeof WebAssembly !== 'object' || config.type === 'js' ) {
|
|
|
+ // Load with asm.js.
|
|
|
+ promise = THREE.DRACOLoader._loadScript( path + 'draco_decoder.js' );
|
|
|
} else {
|
|
|
- THREE.DRACOLoader.loadJavaScriptFile(dracoDecoder.dracoSrcPath +
|
|
|
- 'draco_wasm_wrapper.js',
|
|
|
- function (dracoDecoder) {
|
|
|
- THREE.DRACOLoader.loadWebAssemblyDecoder(dracoDecoder);
|
|
|
- }, dracoDecoder);
|
|
|
+ // Load with WebAssembly.
|
|
|
+ config.wasmBinaryFile = path + 'draco_decoder.wasm';
|
|
|
+ promise = THREE.DRACOLoader._loadScript( path + 'draco_wasm_wrapper.js' )
|
|
|
+ .then( function () {
|
|
|
+ return THREE.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 );
|
|
|
+ } );
|
|
|
+ } );
|
|
|
+
|
|
|
+ THREE.DRACOLoader.decoderModulePromise = promise;
|
|
|
+ return promise;
|
|
|
+};
|
|
|
|
|
|
/**
|
|
|
- * Creates and returns a singleton instance of the DracoDecoderModule.
|
|
|
- * The module loading is done asynchronously for WebAssembly. Initialized module
|
|
|
- * can be accessed through the callback function
|
|
|
- * |onDracoDecoderModuleLoadedCallback|.
|
|
|
+ * @param {string} src
|
|
|
+ * @return {Promise}
|
|
|
*/
|
|
|
-THREE.DRACOLoader.getDecoder = (function() {
|
|
|
- var decoder;
|
|
|
- var decoderCreationCalled = false;
|
|
|
-
|
|
|
- return function(dracoDecoder, onDracoDecoderModuleLoadedCallback) {
|
|
|
- if (typeof decoder !== 'undefined') {
|
|
|
- // Module already initialized.
|
|
|
- if (typeof onDracoDecoderModuleLoadedCallback !== 'undefined') {
|
|
|
- onDracoDecoderModuleLoadedCallback(decoder);
|
|
|
- }
|
|
|
- } else {
|
|
|
- if (typeof DracoDecoderModule === 'undefined') {
|
|
|
- // Wait until the Draco decoder is loaded before starting the error
|
|
|
- // timer.
|
|
|
- if (dracoDecoder.timeLoaded > 0) {
|
|
|
- var waitMs = performance.now() - dracoDecoder.timeLoaded;
|
|
|
-
|
|
|
- // After loading the Draco JavaScript decoder file, there is still
|
|
|
- // some time before the DracoDecoderModule is defined. So start a
|
|
|
- // loop to check when the DracoDecoderModule gets defined. If the
|
|
|
- // time is hit throw an error.
|
|
|
- if (waitMs > 5000) {
|
|
|
- throw new Error(
|
|
|
- 'THREE.DRACOLoader: DracoDecoderModule not found.');
|
|
|
- }
|
|
|
- }
|
|
|
- } else {
|
|
|
- if (!decoderCreationCalled) {
|
|
|
- decoderCreationCalled = true;
|
|
|
- dracoDecoder.dracoDecoderType['onModuleLoaded'] =
|
|
|
- function(module) {
|
|
|
- if (typeof onDracoDecoderModuleLoadedCallback ===
|
|
|
- 'function') {
|
|
|
- decoder = module;
|
|
|
- }
|
|
|
- };
|
|
|
- DracoDecoderModule(dracoDecoder.dracoDecoderType);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- // Either the DracoDecoderModule has not been defined or the decoder
|
|
|
- // has not been created yet. Call getDecoder() again.
|
|
|
- setTimeout(function() {
|
|
|
- THREE.DRACOLoader.getDecoder(dracoDecoder,
|
|
|
- onDracoDecoderModuleLoadedCallback);
|
|
|
- }, 10);
|
|
|
- }
|
|
|
- };
|
|
|
+THREE.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}
|
|
|
+ */
|
|
|
+THREE.DRACOLoader._loadArrayBuffer = function ( src ) {
|
|
|
+ var loader = new THREE.FileLoader();
|
|
|
+ loader.setResponseType( 'arraybuffer' );
|
|
|
+ return new Promise( function( resolve, reject ) {
|
|
|
+ loader.load( src, resolve, undefined, reject );
|
|
|
+ });
|
|
|
+};
|