diff --git a/javascript/example/DRACOLoader.js b/javascript/example/DRACOLoader.js
index 9ba2250..5669d9f 100644
--- a/javascript/example/DRACOLoader.js
+++ b/javascript/example/DRACOLoader.js
@@ -14,26 +14,16 @@
//
'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 = {};
- if (dracoDecoderType !== undefined) {
- THREE.DRACOLoader.dracoDecoderType = dracoDecoderType;
- }
this.drawMode = THREE.TrianglesDrawMode;
- this.dracoSrcPath = (dracoPath !== undefined) ? dracoPath : './';
- // If draco_decoder.js or wasm code is already loaded/included, then do
- // not dynamically load the decoder.
- 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.
@@ -45,8 +35,6 @@ THREE.DRACOLoader = function(dracoPath, dracoDecoderType, manager) {
};
};
-THREE.DRACOLoader.dracoDecoderType = {};
-
THREE.DRACOLoader.prototype = {
constructor: THREE.DRACOLoader,
@@ -116,12 +104,11 @@ THREE.DRACOLoader.prototype = {
*/
decodeDracoFile: function(rawBuffer, callback, attributeUniqueIdMap) {
var scope = this;
- this.attributeUniqueIdMap = (attributeUniqueIdMap !== undefined) ?
- attributeUniqueIdMap : {};
- THREE.DRACOLoader.getDecoderModule(
- 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) {
@@ -333,9 +320,9 @@ THREE.DRACOLoader.prototype = {
},
isVersionSupported: function(version, callback) {
- THREE.DRACOLoader.getDecoderModule(
- function(decoder) {
- callback(decoder.isVersionSupported(version));
+ THREE.DRACOLoader.getDecoderModule()
+ .then( function ( module ) {
+ callback( module.decoder.isVersionSupported( version ) );
});
},
@@ -346,131 +333,117 @@ 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 previous_decoder_script = document.getElementById("decoder_script");
- if (previous_decoder_script !== null) {
- return;
- }
- 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) {
- THREE.DRACOLoader.timeLoaded = performance.now();
- };
- }
- head.appendChild(element);
-}
-
-THREE.DRACOLoader.loadWebAssemblyDecoder = function(dracoDecoder) {
- THREE.DRACOLoader.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.
- THREE.DRACOLoader.dracoDecoderType['wasmBinary'] = xhr.response;
- THREE.DRACOLoader.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' ||
- THREE.DRACOLoader.dracoDecoderType.type === 'js') {
- // No WebAssembly support
- THREE.DRACOLoader.loadJavaScriptFile(dracoDecoder.dracoSrcPath +
- 'draco_decoder.js', null, dracoDecoder);
- } else {
- THREE.DRACOLoader.loadJavaScriptFile(dracoDecoder.dracoSrcPath +
- 'draco_wasm_wrapper.js',
- function (dracoDecoder) {
- THREE.DRACOLoader.loadWebAssemblyDecoder(dracoDecoder);
- }, dracoDecoder);
- }
-}
-
-THREE.DRACOLoader.decoderCreationCalled = false;
+THREE.DRACOLoader.decoderPath = './';
+THREE.DRACOLoader.decoderConfig = {};
+THREE.DRACOLoader.decoderModulePromise = null;
/**
- * 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|.
+ * Sets the base path for decoder source files.
+ * @param {string} path
*/
-THREE.DRACOLoader.getDecoderModule = (function() {
- return function(onDracoDecoderModuleLoadedCallback) {
- if (typeof THREE.DRACOLoader.decoderModule !== 'undefined') {
- // Module already initialized.
- if (typeof onDracoDecoderModuleLoadedCallback !== 'undefined') {
- onDracoDecoderModuleLoadedCallback(THREE.DRACOLoader.decoderModule);
- }
- } else {
- if (typeof DracoDecoderModule === 'undefined') {
- // Wait until the Draco decoder is loaded before starting the error
- // timer.
- if (THREE.DRACOLoader.timeLoaded > 0) {
- var waitMs = performance.now() - THREE.DRACOLoader.timeLoaded;
+THREE.DRACOLoader.setDecoderPath = function ( path ) {
+ THREE.DRACOLoader.decoderPath = path;
+};
- // 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 (!THREE.DRACOLoader.decoderCreationCalled) {
- THREE.DRACOLoader.decoderCreationCalled = true;
- THREE.DRACOLoader.dracoDecoderType['onModuleLoaded'] =
- function(module) {
- THREE.DRACOLoader.decoderModule = module;
- };
- DracoDecoderModule(THREE.DRACOLoader.dracoDecoderType);
- }
- }
+/**
+ * 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.releaseDecoderModule();
- // Either the DracoDecoderModule has not been defined or the decoder
- // has not been created yet. Call getDecoderModule() again.
- setTimeout(function() {
- THREE.DRACOLoader.getDecoderModule(
- onDracoDecoderModuleLoadedCallback);
- }, 10);
- }
- };
+ // Reuse WASM binary.
+ if ( wasmBinary ) THREE.DRACOLoader.decoderConfig.wasmBinary = wasmBinary;
+};
-})();
+/**
+ * Releases the singleton DracoDecoderModule instance. Module will be recreated
+ * with the next decoding call.
+ */
+THREE.DRACOLoader.releaseDecoderModule = function () {
+ THREE.DRACOLoader.decoderModulePromise = null;
+};
-// Releases the DracoDecoderModule instance associated with the draco loader.
-// The module will be automatically re-created the next time a new geometry is
-// loaded by THREE.DRACOLoader.
-THREE.DRACOLoader.releaseDecoderModule = function() {
- THREE.DRACOLoader.decoderModule = undefined;
- THREE.DRACOLoader.decoderCreationCalled = false;
- if (THREE.DRACOLoader.dracoDecoderType !== undefined &&
- THREE.DRACOLoader.dracoDecoderType.wasmBinary !== undefined) {
- // For WASM build we need to preserve the wasmBinary for future use.
- var wasmBinary = THREE.DRACOLoader.dracoDecoderType.wasmBinary;
- THREE.DRACOLoader.dracoDecoderType = {};
- THREE.DRACOLoader.dracoDecoderType.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.dracoDecoderType = {};
+ // 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;
+};
+
+/**
+ * @param {string} src
+ * @return {Promise}
+ */
+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 );
+ });
+};
diff --git a/javascript/example/README.md b/javascript/example/README.md
index bb71aff..349961b 100644
--- a/javascript/example/README.md
+++ b/javascript/example/README.md
@@ -38,7 +38,23 @@ Include Javascript decoder:
Create DracoLoader by setting the decoder type:
~~~~~ js
-var dracoDecoderType = {};
-dracoDecoderType.type = 'js';
-var dracoLoader = new THREE.DRACOLoader('path_to_decoder', dracoDecoderType);
+// (Optional) Change decoder source directory (defaults to './').
+THREE.DRACOLoader.setDecoderPath('./path/to/decoder/');
+
+// (Optional) Use JS decoder (defaults to WebAssembly if supported).
+THREE.DRACOLoader.setDecoderConfig({type: 'js'});
+
+// (Optional) Pre-fetch decoder source files (defaults to load on demand).
+THREE.DRACOLoader.getDecoderModule();
+
+var dracoLoader = new THREE.DRACOLoader();
+
+dracoLoader.load( 'model.drc', function ( geometry ) {
+
+ scene.add( new THREE.Mesh( geometry ) );
+
+ // (Optional) Release the cached decoder module.
+ THREE.DRACOLoader.releaseDecoderModule();
+
+} );
~~~~~
diff --git a/javascript/example/webgl_loader_draco.html b/javascript/example/webgl_loader_draco.html
index ccd9c0b..a40b7fb 100644
--- a/javascript/example/webgl_loader_draco.html
+++ b/javascript/example/webgl_loader_draco.html
@@ -37,17 +37,17 @@
three.js -
DRACO loader
-
+