diff --git a/docs/examples/loaders/LoaderSupport.html b/docs/examples/loaders/LoaderSupport.html
index 5479a6bb9c5abb41dd6461c8db4a83a61bb8b732..4e3fd7918f1947cca5d622b93b45442efb573c51 100644
--- a/docs/examples/loaders/LoaderSupport.html
+++ b/docs/examples/loaders/LoaderSupport.html
@@ -156,10 +156,9 @@
[page:Function functionCodeBuilder] - Function that is invoked with funcBuildObject and funcBuildSingelton that allows stringification of objects and singletons.
- [page:Boolean forceWorkerReload] - Force re-build of the worker code.
Array of [page:String libLocations] - URL of libraries that shall be added to worker code relative to libPath.
[page:String libPath] - Base path used for loading libraries.
[page:LoaderSupport.WorkerRunnerRefImpl runnerImpl] - The default worker parser wrapper implementation (communication and execution). An extended class could be passed here.
@@ -178,12 +177,6 @@
-
[page:Function builder] - The builder function. Default is [page:LoaderSupport.Builder].
@@ -251,7 +244,7 @@
- prepareWorkers
- enqueueForRun
- processQueue
- - deregister
+ - tearDown
@@ -283,7 +276,10 @@
-
+ [page:Function callbackOnFinishedProcessing] - Function called once all workers finished processing.
+
@@ -543,7 +544,7 @@
Methods
-
[method:null isValid]( [page:Object input] )
+
[method:Boolean isValid]( [page:Object input] )
[page:Object input] - Can be anything
diff --git a/examples/js/loaders/LoaderSupport.js b/examples/js/loaders/LoaderSupport.js
index d9effa2a49b5e23828a2673281640de4e809b09f..d3bd7051608ac2345adffc0561a24c653cc73bbc 100644
--- a/examples/js/loaders/LoaderSupport.js
+++ b/examples/js/loaders/LoaderSupport.js
@@ -941,13 +941,8 @@ THREE.LoaderSupport.WorkerRunnerRefImpl = (function () {
* @param {Object} payload Raw mesh description (buffers, params, materials) used to build one to many meshes.
*/
WorkerRunnerRefImpl.prototype.processMessage = function ( payload ) {
- var logger = new ConsoleLogger();
- if ( Validator.isValid( payload.logger ) ) {
-
- logger.setEnabled( payload.logger.enabled );
- logger.setDebug( payload.logger.debug );
-
- }
+ var logEnabled = payload.logger.enabled;
+ var logDebug = payload.logger.enabled;
if ( payload.cmd === 'run' ) {
var callbacks = {
@@ -955,19 +950,20 @@ THREE.LoaderSupport.WorkerRunnerRefImpl = (function () {
self.postMessage( payload );
},
callbackProgress: function ( text ) {
- logger.logDebug( 'WorkerRunner: progress: ' + text );
+ if ( logEnabled && logDebug ) console.debug( 'WorkerRunner: progress: ' + text );
}
};
// Parser is expected to be named as such
- var parser = new Parser( logger );
+ var parser = new Parser();
+ if ( typeof parser[ 'setLogConfig' ] === 'function' ) parser.setLogConfig( logEnabled, logDebug );
this.applyProperties( parser, payload.params );
this.applyProperties( parser, payload.materials );
this.applyProperties( parser, callbacks );
parser.workerScope = self;
parser.parse( payload.data.input, payload.data.options );
- logger.logInfo( 'WorkerRunner: Run complete!' );
+ if ( logEnabled ) console.log( 'WorkerRunner: Run complete!' );
callbacks.callbackBuilder( {
cmd: 'complete',
@@ -976,7 +972,7 @@ THREE.LoaderSupport.WorkerRunnerRefImpl = (function () {
} else {
- logger.logError( 'WorkerRunner: Received unknown command: ' + payload.cmd );
+ console.error( 'WorkerRunner: Received unknown command: ' + payload.cmd );
}
};
@@ -993,170 +989,226 @@ THREE.LoaderSupport.WorkerRunnerRefImpl = (function () {
*/
THREE.LoaderSupport.WorkerSupport = (function () {
- var WORKER_SUPPORT_VERSION = '1.1.1';
+ var WORKER_SUPPORT_VERSION = '2.0.0';
var Validator = THREE.LoaderSupport.Validator;
- function WorkerSupport( logger ) {
- this.logger = Validator.verifyInput( logger, new THREE.LoaderSupport.ConsoleLogger() );
- this.logger.logInfo( 'Using THREE.LoaderSupport.WorkerSupport version: ' + WORKER_SUPPORT_VERSION );
+ var LoaderWorker = (function () {
- // check worker support first
- if ( window.Worker === undefined ) throw "This browser does not support web workers!";
- if ( window.Blob === undefined ) throw "This browser does not support Blob!";
- if ( typeof window.URL.createObjectURL !== 'function' ) throw "This browser does not support Object creation from URL!";
+ function LoaderWorker( logger ) {
+ this.logger = Validator.verifyInput( logger, new THREE.LoaderSupport.ConsoleLogger() );
+ this._reset();
+ }
+
+ LoaderWorker.prototype._reset = function () {
+ this.worker = null;
+ this.runnerImplName = null;
+ this.callbacks = {
+ builder: null,
+ onLoad: null
+ };
+ this.terminateRequested = false;
+ this.queuedMessage = null;
+ this.started = false;
+ };
+
+ LoaderWorker.prototype.initWorker = function ( code, runnerImplName ) {
+ this.runnerImplName = runnerImplName;
+ var blob = new Blob( [ code ], { type: 'application/javascript' } );
+ this.worker = new Worker( window.URL.createObjectURL( blob ) );
+ this.worker.onmessage = this._receiveWorkerMessage;
- this.worker = null;
- this.workerCode = null;
- this.loading = true;
- this.queuedMessage = null;
- this.running = false;
- this.terminateRequested = false;
+ // set referemce to this, then processing in worker scope within "_receiveWorkerMessage" can access members
+ this.worker.runtimeRef = this;
- this.callbacks = {
- builder: null,
- onLoad: null
+ // process stored queuedMessage
+ this._postMessage();
};
- }
- /**
- * Validate the status of worker code and the derived worker.
- * @memberOf THREE.LoaderSupport.WorkerSupport
- *
- * @param {Function} functionCodeBuilder Function that is invoked with funcBuildObject and funcBuildSingelton that allows stringification of objects and singletons.
- * @param {boolean} forceWorkerReload Force re-build of the worker code.
- * @param {String[]} libLocations URL of libraries that shall be added to worker code relative to libPath
- * @param {String} libPath Base path used for loading libraries
- * @param {THREE.LoaderSupport.WorkerRunnerRefImpl} runnerImpl The default worker parser wrapper implementation (communication and execution). An extended class could be passed here.
- */
- WorkerSupport.prototype.validate = function ( functionCodeBuilder, forceWorkerReload, libLocations, libPath, runnerImpl ) {
- this.running = false;
- if ( forceWorkerReload ) {
+ /**
+ * Executed in worker scope
+ */
+ LoaderWorker.prototype._receiveWorkerMessage = function ( e ) {
+ var payload = e.data;
+ switch ( payload.cmd ) {
+ case 'meshData':
+ case 'materialData':
+ case 'imageData':
+ this.runtimeRef.callbacks.builder( payload );
+ break;
- this.worker = null;
- this.workerCode = null;
- this.loading = true;
- this.queuedMessage = null;
- this.callbacks.builder = null;
- this.callbacks.onLoad = null;
+ case 'complete':
+ this.runtimeRef.queuedMessage = null;
+ this.started = false;
+ this.runtimeRef.callbacks.onLoad( payload.msg );
- }
+ if ( this.runtimeRef.terminateRequested ) {
+
+ this.runtimeRef.logger.logInfo( 'WorkerSupport [' + this.runtimeRef.runnerImplName + ']: Run is complete. Terminating application on request!' );
+ this.runtimeRef._terminate();
+
+ }
+ break;
+
+ case 'error':
+ this.runtimeRef.logger.logError( 'WorkerSupport [' + this.runtimeRef.runnerImplName + ']: Reported error: ' + payload.msg );
+ this.runtimeRef.queuedMessage = null;
+ this.started = false;
+ this.runtimeRef.callbacks.onLoad( payload.msg );
- if ( ! Validator.isValid( this.worker ) ) {
+ if ( this.runtimeRef.terminateRequested ) {
- this.logger.logInfo( 'WorkerSupport: Building worker code...' );
- this.logger.logTimeStart( 'buildWebWorkerCode' );
+ this.runtimeRef.logger.logInfo( 'WorkerSupport [' + this.runtimeRef.runnerImplName + ']: Run reported error. Terminating application on request!' );
+ this.runtimeRef._terminate();
- var workerRunner;
- if ( Validator.isValid( runnerImpl ) ) {
+ }
+ break;
- this.logger.logInfo( 'WorkerSupport: Using "' + runnerImpl.name + '" as Runncer class for worker.' );
- workerRunner = runnerImpl;
+ default:
+ this.runtimeRef.logger.logError( 'WorkerSupport [' + this.runtimeRef.runnerImplName + ']: Received unknown command: ' + payload.cmd );
+ break;
+
+ }
+ };
+
+ LoaderWorker.prototype.setCallbacks = function ( builder, onLoad ) {
+ this.callbacks.builder = Validator.verifyInput( builder, this.callbacks.builder );
+ this.callbacks.onLoad = Validator.verifyInput( onLoad, this.callbacks.onLoad );
+ };
+
+ LoaderWorker.prototype.run = function( payload ) {
+ if ( Validator.isValid( this.queuedMessage ) ) {
+
+ console.warn( 'Already processing message. Rejecting new run instruction' );
+ return;
} else {
- this.logger.logInfo( 'WorkerSupport: Using DEFAULT "THREE.LoaderSupport.WorkerRunnerRefImpl" as Runncer class for worker.' );
- workerRunner = THREE.LoaderSupport.WorkerRunnerRefImpl;
+ this.queuedMessage = payload;
+ this.started = true;
}
+ if ( ! Validator.isValid( this.callbacks.builder ) ) throw 'Unable to run as no "builder" callback is set.';
+ if ( ! Validator.isValid( this.callbacks.onLoad ) ) throw 'Unable to run as no "onLoad" callback is set.';
+ if ( payload.cmd !== 'run' ) payload.cmd = 'run';
+ if ( Validator.isValid( payload.logger ) ) {
- var scope = this;
- var buildWorkerCode = function ( baseWorkerCode ) {
- scope.workerCode = baseWorkerCode;
- if ( workerRunner == THREE.LoaderSupport.WorkerRunnerRefImpl ) {
+ payload.logger.enabled = Validator.verifyInput( payload.logger.enabled, true );
+ payload.logger.debug = Validator.verifyInput( payload.logger.debug, false );
- scope.workerCode += buildObject( 'Validator', THREE.LoaderSupport.Validator );
- scope.workerCode += buildSingelton( 'ConsoleLogger', 'ConsoleLogger', THREE.LoaderSupport.ConsoleLogger );
+ } else {
+ payload.logger = {
+ enabled: true,
+ debug: false
}
- scope.workerCode += functionCodeBuilder( buildObject, buildSingelton );
- scope.workerCode += buildSingelton( workerRunner.name, workerRunner.name, workerRunner );
- scope.workerCode += 'new ' + workerRunner.name + '();\n\n';
- var blob = new Blob( [ scope.workerCode ], { type: 'application/javascript' } );
- scope.worker = new Worker( window.URL.createObjectURL( blob ) );
- scope.logger.logTimeEnd( 'buildWebWorkerCode' );
+ }
+ this._postMessage();
+ };
- var receiveWorkerMessage = function ( e ) {
- var payload = e.data;
+ LoaderWorker.prototype._postMessage = function () {
+ if ( Validator.isValid( this.queuedMessage ) && Validator.isValid( this.worker ) ) {
- switch ( payload.cmd ) {
- case 'meshData':
- case 'materialData':
- case 'imageData':
- scope.callbacks.builder( payload );
- break;
+ this.worker.postMessage( this.queuedMessage );
- case 'complete':
- scope.callbacks.onLoad( payload.msg );
- scope.running = false;
+ }
+ };
- if ( scope.terminateRequested ) {
+ LoaderWorker.prototype.setTerminateRequested = function ( terminateRequested ) {
+ this.terminateRequested = terminateRequested === true;
+ if ( this.terminateRequested && Validator.isValid( this.worker ) && ! Validator.isValid( this.queuedMessage ) && this.started ) {
- scope.logger.logInfo( 'WorkerSupport [' + workerRunner + ']: Run is complete. Terminating application on request!' );
- scope.terminateWorker();
+ this.logger.logInfo( 'Worker is terminated immediately as it is not running!' );
+ this._terminate();
- }
- break;
+ }
+ };
- case 'error':
- scope.logger.logError( 'WorkerSupport [' + workerRunner + ']: Reported error: ' + payload.msg );
- break;
+ LoaderWorker.prototype._terminate = function () {
+ this.worker.terminate();
+ this._reset();
+ };
- default:
- scope.logger.logError( 'WorkerSupport [' + workerRunner + ']: Received unknown command: ' + payload.cmd );
- break;
+ return LoaderWorker;
- }
- };
- scope.worker.addEventListener( 'message', receiveWorkerMessage, false );
- scope.loading = false;
- scope._postMessage();
- };
+ })();
- if ( Validator.isValid( libLocations ) && libLocations.length > 0 ) {
+ function WorkerSupport( logger ) {
+ this.logger = Validator.verifyInput( logger, new THREE.LoaderSupport.ConsoleLogger() );
+ this.logger.logInfo( 'Using THREE.LoaderSupport.WorkerSupport version: ' + WORKER_SUPPORT_VERSION );
- var libsContent = '';
- var loadAllLibraries = function ( path, locations ) {
- if ( locations.length === 0 ) {
+ // check worker support first
+ if ( window.Worker === undefined ) throw "This browser does not support web workers!";
+ if ( window.Blob === undefined ) throw "This browser does not support Blob!";
+ if ( typeof window.URL.createObjectURL !== 'function' ) throw "This browser does not support Object creation from URL!";
- buildWorkerCode( libsContent );
+ this.loaderWorker = new LoaderWorker( this.logger );
+ }
- } else {
+ /**
+ * Validate the status of worker code and the derived worker.
+ * @memberOf THREE.LoaderSupport.WorkerSupport
+ *
+ * @param {Function} functionCodeBuilder Function that is invoked with funcBuildObject and funcBuildSingelton that allows stringification of objects and singletons.
+ * @param {String[]} libLocations URL of libraries that shall be added to worker code relative to libPath
+ * @param {String} libPath Base path used for loading libraries
+ * @param {THREE.LoaderSupport.WorkerRunnerRefImpl} runnerImpl The default worker parser wrapper implementation (communication and execution). An extended class could be passed here.
+ */
+ WorkerSupport.prototype.validate = function ( functionCodeBuilder, libLocations, libPath, runnerImpl ) {
+ if ( Validator.isValid( this.loaderWorker.worker ) ) return;
- var loadedLib = function ( contentAsString ) {
- libsContent += contentAsString;
- loadAllLibraries( path, locations );
- };
+ this.logger.logInfo( 'WorkerSupport: Building worker code...' );
+ this.logger.logTimeStart( 'buildWebWorkerCode' );
- var fileLoader = new THREE.FileLoader();
- fileLoader.setPath( path );
- fileLoader.setResponseType( 'text' );
- fileLoader.load( locations[ 0 ], loadedLib );
- locations.shift();
+ if ( Validator.isValid( runnerImpl ) ) {
- }
- };
- loadAllLibraries( libPath, libLocations );
+ this.logger.logInfo( 'WorkerSupport: Using "' + runnerImpl.name + '" as Runncer class for worker.' );
- } else {
+ } else {
- buildWorkerCode( '' );
+ runnerImpl = THREE.LoaderSupport.WorkerRunnerRefImpl;
+ this.logger.logInfo( 'WorkerSupport: Using DEFAULT "THREE.LoaderSupport.WorkerRunnerRefImpl" as Runncer class for worker.' );
- }
}
- };
- /**
- * Terminate the worker and the code.
- * @memberOf THREE.LoaderSupport.WorkerSupport
- */
- WorkerSupport.prototype.terminateWorker = function () {
- if ( Validator.isValid( this.worker ) ) {
- this.worker.terminate();
+ var userWorkerCode = functionCodeBuilder( buildObject, buildSingelton );
+ userWorkerCode += buildSingelton( runnerImpl.name, runnerImpl.name, runnerImpl );
+ userWorkerCode += 'new ' + runnerImpl.name + '();\n\n';
+
+ var scope = this;
+ if ( Validator.isValid( libLocations ) && libLocations.length > 0 ) {
+
+ var libsContent = '';
+ var loadAllLibraries = function ( path, locations ) {
+ if ( locations.length === 0 ) {
+
+ scope.loaderWorker.initWorker( libsContent + userWorkerCode, scope.logger, runnerImpl.name );
+ scope.logger.logTimeEnd( 'buildWebWorkerCode' );
+
+ } else {
+
+ var loadedLib = function ( contentAsString ) {
+ libsContent += contentAsString;
+ loadAllLibraries( path, locations );
+ };
+
+ var fileLoader = new THREE.FileLoader();
+ fileLoader.setPath( path );
+ fileLoader.setResponseType( 'text' );
+ fileLoader.load( locations[ 0 ], loadedLib );
+ locations.shift();
+
+ }
+ };
+ loadAllLibraries( libPath, libLocations );
+
+ } else {
+
+ this.loaderWorker.initWorker( userWorkerCode, this.logger, runnerImpl.name );
+ this.logger.logTimeEnd( 'buildWebWorkerCode' );
+
}
- this.worker = null;
- this.workerCode = null;
};
/**
@@ -1167,10 +1219,27 @@ THREE.LoaderSupport.WorkerSupport = (function () {
* @param {Function} onLoad The function that is called when parsing is complete.
*/
WorkerSupport.prototype.setCallbacks = function ( builder, onLoad ) {
- this.callbacks = {
- builder: builder,
- onLoad: onLoad
- };
+ this.loaderWorker.setCallbacks( builder, onLoad );
+ };
+
+ /**
+ * Runs the parser with the provided configuration.
+ * @memberOf THREE.LoaderSupport.WorkerSupport
+ *
+ * @param {Object} payload Raw mesh description (buffers, params, materials) used to build one to many meshes.
+ */
+ WorkerSupport.prototype.run = function ( payload ) {
+ this.loaderWorker.run( payload );
+ };
+
+ /**
+ * Request termination of worker once parser is finished.
+ * @memberOf THREE.LoaderSupport.WorkerSupport
+ *
+ * @param {boolean} terminateRequested True or false.
+ */
+ WorkerSupport.prototype.setTerminateRequested = function ( terminateRequested ) {
+ this.loaderWorker.setTerminateRequested( terminateRequested );
};
var buildObject = function ( fullName, object ) {
@@ -1229,41 +1298,8 @@ THREE.LoaderSupport.WorkerSupport = (function () {
return objectString;
};
- /**
- * Request termination of worker once parser is finished.
- * @memberOf THREE.LoaderSupport.WorkerSupport
- *
- * @param {boolean} terminateRequested True or false.
- */
- WorkerSupport.prototype.setTerminateRequested = function ( terminateRequested ) {
- this.terminateRequested = terminateRequested === true;
- };
-
- /**
- * Runs the parser with the provided configuration.
- * @memberOf THREE.LoaderSupport.WorkerSupport
- *
- * @param {Object} payload Raw mesh description (buffers, params, materials) used to build one to many meshes.
- */
- WorkerSupport.prototype.run = function ( payload ) {
- if ( ! Validator.isValid( this.callbacks.builder ) ) throw 'Unable to run as no "builder" callback is set.';
- if ( ! Validator.isValid( this.callbacks.onLoad ) ) throw 'Unable to run as no "onLoad" callback is set.';
- if ( Validator.isValid( this.worker ) || this.loading ) {
- if ( payload.cmd !== 'run' ) payload.cmd = 'run';
- this.queuedMessage = payload;
- this.running = true;
- this._postMessage();
-
- }
- };
-
- WorkerSupport.prototype._postMessage = function () {
- if ( ! this.loading && Validator.isValid( this.queuedMessage ) ) {
- this.worker.postMessage( this.queuedMessage );
- }
- };
-
return WorkerSupport;
+
})();
/**
@@ -1272,7 +1308,7 @@ THREE.LoaderSupport.WorkerSupport = (function () {
* prepareWorkers
* enqueueForRun
* processQueue
- * deregister
+ * tearDown (to force stop)
*
* @class
*
@@ -1281,7 +1317,7 @@ THREE.LoaderSupport.WorkerSupport = (function () {
*/
THREE.LoaderSupport.WorkerDirector = (function () {
- var LOADER_WORKER_DIRECTOR_VERSION = '2.0.0';
+ var LOADER_WORKER_DIRECTOR_VERSION = '2.1.0';
var Validator = THREE.LoaderSupport.Validator;
@@ -1301,10 +1337,13 @@ THREE.LoaderSupport.WorkerDirector = (function () {
this.workerDescription = {
classDef: classDef,
globalCallbacks: {},
- workerSupports: []
+ workerSupports: {}
};
this.objectsCompleted = 0;
this.instructionQueue = [];
+ this.instructionQueuePointer = 0;
+
+ this.callbackOnFinishedProcessing = null;
}
/**
@@ -1349,30 +1388,21 @@ THREE.LoaderSupport.WorkerDirector = (function () {
if ( Validator.isValid( globalCallbacks ) ) this.workerDescription.globalCallbacks = globalCallbacks;
this.maxQueueSize = Math.min( maxQueueSize, MAX_QUEUE_SIZE );
this.maxWebWorkers = Math.min( maxWebWorkers, MAX_WEB_WORKER );
+ this.maxWebWorkers = Math.min( this.maxWebWorkers, this.maxQueueSize );
this.objectsCompleted = 0;
this.instructionQueue = [];
+ this.instructionQueuePointer = 0;
- var start = this.workerDescription.workerSupports.length;
- var i;
- if ( start < this.maxWebWorkers ) {
-
- for ( i = start; i < this.maxWebWorkers; i++ ) {
-
- this.workerDescription.workerSupports[ i ] = {
- workerSupport: new THREE.LoaderSupport.WorkerSupport( this.logger ),
- loader: null
- };
-
- }
-
- } else {
+ for ( var instanceNo = 0; instanceNo < this.maxWebWorkers; instanceNo++ ) {
- for ( i = start - 1; i >= this.maxWebWorkers; i-- ) {
+ this.workerDescription.workerSupports[ instanceNo ] = {
+ instanceNo: instanceNo,
+ inUse: false,
+ terminateRequested: false,
+ workerSupport: new THREE.LoaderSupport.WorkerSupport( this.logger ),
+ loader: null
+ };
- this.workerDescription.workerSupports[ i ].workerSupport.setRequestTerminate( true );
- this.workerDescription.workerSupports.pop();
-
- }
}
};
@@ -1388,47 +1418,68 @@ THREE.LoaderSupport.WorkerDirector = (function () {
}
};
+ /**
+ * Returns if any workers are running.
+ *
+ * @memberOf THREE.LoaderSupport.WorkerDirector
+ * @returns {boolean}
+ */
+ WorkerDirector.prototype.isRunning = function () {
+ var wsKeys = Object.keys( this.workerDescription.workerSupports );
+ return ( ( this.instructionQueue.length > 0 && this.instructionQueuePointer < this.instructionQueue.length ) || wsKeys.length > 0 );
+ };
+
/**
* Process the instructionQueue until it is depleted.
* @memberOf THREE.LoaderSupport.WorkerDirector
*/
WorkerDirector.prototype.processQueue = function () {
- if ( this.instructionQueue.length === 0 ) return;
+ var prepData, supportDesc;
+ for ( var instanceNo in this.workerDescription.workerSupports ) {
- var length = Math.min( this.maxWebWorkers, this.instructionQueue.length );
- for ( var i = 0; i < length; i++ ) {
+ supportDesc = this.workerDescription.workerSupports[ instanceNo ];
+ if ( ! supportDesc.inUse ) {
- this._kickWorkerRun( this.instructionQueue[ 0 ], i );
- this.instructionQueue.shift();
+ if ( this.instructionQueuePointer < this.instructionQueue.length ) {
- }
- };
+ prepData = this.instructionQueue[ this.instructionQueuePointer ];
+ this._kickWorkerRun( prepData, supportDesc );
+ this.instructionQueuePointer++;
- WorkerDirector.prototype._kickWorkerRun = function( prepData, workerInstanceNo ) {
- var scope = this;
- var directorOnLoad = function ( event ) {
- scope.objectsCompleted++;
+ } else {
- var nextPrepData = scope.instructionQueue[ 0 ];
- if ( Validator.isValid( nextPrepData ) ) {
+ this._deregister( supportDesc );
- scope.instructionQueue.shift();
- scope.logger.logInfo( '\nAssigning next item from queue to worker (queue length: ' + scope.instructionQueue.length + ')\n\n' );
- scope._kickWorkerRun( nextPrepData, event.detail.instanceNo );
+ }
- } else if ( scope.instructionQueue.length === 0 ) {
+ }
- scope.deregister();
+ }
- }
- };
+ if ( ! this.isRunning() && this.callbackOnFinishedProcessing !== null ) {
+
+ this.callbackOnFinishedProcessing();
+ this.callbackOnFinishedProcessing = null;
+ }
+ };
+
+ WorkerDirector.prototype._kickWorkerRun = function( prepData, supportDesc ) {
+ supportDesc.inUse = true;
+ supportDesc.workerSupport.setTerminateRequested( supportDesc.terminateRequested );
+
+ this.logger.logInfo( '\nAssigning next item from queue to worker (queue length: ' + this.instructionQueue.length + ')\n\n' );
+
+ var scope = this;
var prepDataCallbacks = prepData.getCallbacks();
var globalCallbacks = this.workerDescription.globalCallbacks;
var wrapperOnLoad = function ( event ) {
if ( Validator.isValid( globalCallbacks.onLoad ) ) globalCallbacks.onLoad( event );
if ( Validator.isValid( prepDataCallbacks.onLoad ) ) prepDataCallbacks.onLoad( event );
- directorOnLoad( event );
+ scope.objectsCompleted++;
+ supportDesc.inUse = false;
+
+ scope.processQueue();
};
var wrapperOnProgress = function ( event ) {
@@ -1441,8 +1492,7 @@ THREE.LoaderSupport.WorkerDirector = (function () {
if ( Validator.isValid( prepDataCallbacks.onMeshAlter ) ) prepDataCallbacks.onMeshAlter( event );
};
- var supportTuple = this.workerDescription.workerSupports[ workerInstanceNo ];
- supportTuple.loader = this._buildLoader( workerInstanceNo );
+ supportDesc.loader = this._buildLoader( supportDesc.instanceNo );
var updatedCallbacks = new THREE.LoaderSupport.Callbacks();
updatedCallbacks.setCallbackOnLoad( wrapperOnLoad );
@@ -1450,13 +1500,13 @@ THREE.LoaderSupport.WorkerDirector = (function () {
updatedCallbacks.setCallbackOnMeshAlter( wrapperOnMeshAlter );
prepData.callbacks = updatedCallbacks;
- supportTuple.loader.run( prepData, supportTuple.workerSupport );
+ supportDesc.loader.run( prepData, supportDesc.workerSupport );
};
WorkerDirector.prototype._buildLoader = function ( instanceNo ) {
var classDef = this.workerDescription.classDef;
var loader = Object.create( classDef.prototype );
- this.workerDescription.classDef.call( loader, null, this.logger );
+ this.workerDescription.classDef.call( loader, THREE.DefaultLoadingManager, this.logger );
// verify that all required functions are implemented
if ( ! loader.hasOwnProperty( 'instanceNo' ) ) throw classDef.name + ' has no property "instanceNo".';
@@ -1466,36 +1516,47 @@ THREE.LoaderSupport.WorkerDirector = (function () {
throw classDef.name + ' has no property "workerSupport".';
- } else if ( ! classDef.workerSupport instanceof THREE.LoaderSupport.WorkerSupport ) {
-
- throw classDef.name + '.workerSupport is not of type "THREE.LoaderSupport.WorkerSupport".';
-
}
if ( typeof loader.run !== 'function' ) throw classDef.name + ' has no function "run".';
+ if ( ! loader.hasOwnProperty( 'callbacks' ) || ! Validator.isValid( loader.callbacks ) ) {
+
+ this.logger.logWarn( classDef.name + ' has an invalid property "callbacks". Will change to "THREE.LoaderSupport.Callbacks"' );
+ loader.callbacks = new THREE.LoaderSupport.Callbacks();
+ }
return loader;
};
+ WorkerDirector.prototype._deregister = function ( supportDesc ) {
+ if ( Validator.isValid( supportDesc ) ) {
+
+ supportDesc.workerSupport.setTerminateRequested( true );
+ this.logger.logInfo( 'Requested termination of worker #' + supportDesc.instanceNo + '.' );
+
+ var loaderCallbacks = supportDesc.loader.callbacks;
+ if ( Validator.isValid( loaderCallbacks.onProgress ) ) loaderCallbacks.onProgress( { detail: { text: '' } } );
+ delete this.workerDescription.workerSupports[ supportDesc.instanceNo ];
+
+ }
+ };
+
/**
* Terminate all workers.
* @memberOf THREE.LoaderSupport.WorkerDirector
+ *
+ * @param {callback} callbackOnFinishedProcessing Function called once all workers finished processing.
*/
- WorkerDirector.prototype.deregister = function () {
+ WorkerDirector.prototype.tearDown = function ( callbackOnFinishedProcessing ) {
this.logger.logInfo( 'WorkerDirector received the deregister call. Terminating all workers!' );
- for ( var i = 0, length = this.workerDescription.workerSupports.length; i < length; i++ ) {
+ this.instructionQueuePointer = this.instructionQueue.length;
+ this.callbackOnFinishedProcessing = Validator.verifyInput( callbackOnFinishedProcessing, null );
- var supportTuple = this.workerDescription.workerSupports[ i ];
- supportTuple.workerSupport.setTerminateRequested( true );
- this.logger.logInfo( 'Requested termination of worker.' );
+ for ( var name in this.workerDescription.workerSupports ) {
- var loaderCallbacks = supportTuple.loader.callbacks;
- if ( Validator.isValid( loaderCallbacks.onProgress ) ) loaderCallbacks.onProgress( { detail: { text: '' } } );
+ this.workerDescription.workerSupports[ name ].terminateRequested = true;
}
-
- this.workerDescription.workerSupports = [];
- this.instructionQueue = [];
};
return WorkerDirector;
diff --git a/examples/js/loaders/OBJLoader2.js b/examples/js/loaders/OBJLoader2.js
index 322e3e1ca7dd223293dcdd5127b996721e8523a2..f3b71ef569ade8d5782b5b2335cfe928b4db5141 100644
--- a/examples/js/loaders/OBJLoader2.js
+++ b/examples/js/loaders/OBJLoader2.js
@@ -7,6 +7,8 @@
if ( THREE.OBJLoader2 === undefined ) { THREE.OBJLoader2 = {} }
+if ( THREE.LoaderSupport === undefined ) console.error( '"THREE.LoaderSupport" is not available. "THREE.OBJLoader2" requires it. Please include "LoaderSupport.js" in your HTML.' );
+
/**
* Use this class to load OBJ data from files or to parse OBJ data from an arraybuffer
* @class
@@ -16,9 +18,10 @@ if ( THREE.OBJLoader2 === undefined ) { THREE.OBJLoader2 = {} }
*/
THREE.OBJLoader2 = (function () {
- var OBJLOADER2_VERSION = '2.1.2';
+ var OBJLOADER2_VERSION = '2.2.0';
var LoaderBase = THREE.LoaderSupport.LoaderBase;
var Validator = THREE.LoaderSupport.Validator;
+ var ConsoleLogger = THREE.LoaderSupport.ConsoleLogger;
OBJLoader2.prototype = Object.create( THREE.LoaderSupport.LoaderBase.prototype );
OBJLoader2.prototype.constructor = OBJLoader2;
@@ -126,10 +129,6 @@ THREE.OBJLoader2 = (function () {
this.workerSupport = workerSupportExternal;
this.logger = workerSupportExternal.logger;
- } else {
-
- this.terminateWorkerOnLoad = true;
-
}
var scope = this;
var onMaterialsLoaded = function ( materials ) {
@@ -176,7 +175,8 @@ THREE.OBJLoader2 = (function () {
OBJLoader2.prototype.parse = function ( content ) {
this.logger.logTimeStart( 'OBJLoader2 parse: ' + this.modelName );
- var parser = new Parser( this.logger );
+ var parser = new Parser();
+ parser.setLogConfig( this.logger.enabled, this.logger.debug );
parser.setMaterialPerSmoothingGroup( this.materialPerSmoothingGroup );
parser.setUseIndices( this.useIndices );
parser.setDisregardNormals( this.disregardNormals );
@@ -239,7 +239,6 @@ THREE.OBJLoader2 = (function () {
}
}
);
- if ( scope.terminateWorkerOnLoad ) scope.workerSupport.terminateWorker();
scope.logger.logTimeEnd( 'OBJLoader2 parseAsync: ' + scope.modelName );
};
var scopedOnMeshLoaded = function ( payload ) {
@@ -257,6 +256,8 @@ THREE.OBJLoader2 = (function () {
workerCode += '/**\n';
workerCode += ' * This code was constructed by OBJLoader2 buildCode.\n';
workerCode += ' */\n\n';
+ workerCode += funcBuildObject( 'Validator', Validator );
+ workerCode += funcBuildSingelton( 'ConsoleLogger', 'ConsoleLogger', ConsoleLogger );
workerCode += funcBuildSingelton( 'LoaderBase', 'LoaderBase', LoaderBase );
workerCode += funcBuildObject( 'Consts', Consts );
workerCode += funcBuildSingelton( 'Parser', 'Parser', Parser );
@@ -267,6 +268,7 @@ THREE.OBJLoader2 = (function () {
};
this.workerSupport.validate( buildCode, false );
this.workerSupport.setCallbacks( scopedOnMeshLoaded, scopedOnLoad );
+ if ( scope.terminateWorkerOnLoad ) this.workerSupport.setTerminateRequested( true );
var materialNames = {};
var materials = this.builder.getMaterials();
@@ -330,7 +332,9 @@ THREE.OBJLoader2 = (function () {
*/
var Parser = (function () {
- function Parser( logger ) {
+ var ConsoleLogger = THREE.LoaderSupport.ConsoleLogger;
+
+ function Parser() {
this.callbackProgress = null;
this.callbackBuilder = null;
@@ -348,7 +352,7 @@ THREE.OBJLoader2 = (function () {
faces: 0,
doubleIndicesCount: 0
};
- this.logger = logger;
+ this.logger = new ConsoleLogger();
this.totalBytes = 0;
this.reachedFaces = false;
};
@@ -383,6 +387,11 @@ THREE.OBJLoader2 = (function () {
this.callbackProgress = callbackProgress;
};
+ Parser.prototype.setLogConfig = function ( enabled, debug ) {
+ this.logger.setEnabled( enabled );
+ this.logger.setDebug( debug );
+ };
+
Parser.prototype.configure = function () {
this.rawMesh = new RawMesh( this.materialPerSmoothingGroup, this.useIndices, this.disregardNormals );
@@ -1359,6 +1368,7 @@ THREE.OBJLoader2 = (function () {
* @param {string} [crossOrigin] CORS value
*/
OBJLoader2.prototype._loadMtl = function ( resource, callbackOnLoad, crossOrigin ) {
+ if ( THREE.MTLLoader === undefined ) console.error( '"THREE.MTLLoader" is not available. "THREE.OBJLoader2" requires it for loading MTL files.' );
if ( Validator.isValid( resource ) ) this.logger.logTimeStart( 'Loading MTL: ' + resource.name );
var materials = [];
diff --git a/examples/webgl_loader_obj2_meshspray.html b/examples/webgl_loader_obj2_meshspray.html
index 83bc557e81dfd6970868fc346d6a58a8018294e6..9aabc86e00e9fa81b4f9c1a0d3bccb16259209c1 100644
--- a/examples/webgl_loader_obj2_meshspray.html
+++ b/examples/webgl_loader_obj2_meshspray.html
@@ -142,12 +142,14 @@
workerCode += '/**\n';
workerCode += ' * This code was constructed by MeshSpray buildCode.\n';
workerCode += ' */\n\n';
+ workerCode += funcBuildObject( 'Validator', Validator );
+ workerCode += funcBuildSingelton( 'ConsoleLogger', 'ConsoleLogger', ConsoleLogger );
workerCode += funcBuildSingelton( 'Parser', 'Parser', Parser );
return workerCode;
};
var libs2Load = [ 'build/three.min.js' ];
- this.workerSupport.validate( buildCode, false, libs2Load, '../' );
+ this.workerSupport.validate( buildCode, libs2Load, '../' );
this.workerSupport.setCallbacks( scopeBuilderFunc, scopeFuncComplete );
this.workerSupport.run(
{
@@ -173,7 +175,9 @@
var Parser = ( function () {
- function Parser( logger ) {
+ var ConsoleLogger = THREE.LoaderSupport.ConsoleLogger;
+
+ function Parser() {
this.sizeFactor = 0.5;
this.localOffsetFactor = 1.0;
this.globalObjectCount = 0;
@@ -181,10 +185,16 @@
this.dimension = 200;
this.quantity = 1;
this.callbackBuilder = null;
- this.logger = logger;
+ this.callbackProgress = null;
+ this.logger = new ConsoleLogger();
this.serializedMaterials = null;
};
+ Parser.prototype.setLogConfig = function ( enabled, debug ) {
+ this.logger.setEnabled( enabled );
+ this.logger.setDebug( debug );
+ };
+
Parser.prototype.parse = function () {
var baseTriangle = [ 1.0, 1.0, 1.0, -1.0, 1.0, 1.0, 0.0, -1.0, 1.0 ];
var vertices = [];
@@ -389,12 +399,11 @@
var maxWebWorkers = 4;
var radius = 640;
var logger = new THREE.LoaderSupport.ConsoleLogger( false );
- this.workerDirector = new THREE.LoaderSupport.WorkerDirector( MeshSpray, logger );
- this.workerDirector.setCrossOrigin( 'anonymous' );
+ var workerDirector = new THREE.LoaderSupport.WorkerDirector( MeshSpray, logger );
+ workerDirector.setCrossOrigin( 'anonymous' );
- var scope = this;
var callbackOnLoad = function ( event ) {
- logger.logInfo( 'Worker #' + event.detail.instanceNo + ': Completed loading. (#' + scope.workerDirector.objectsCompleted + ')' );
+ logger.logInfo( 'Worker #' + event.detail.instanceNo + ': Completed loading. (#' + workerDirector.objectsCompleted + ')' );
};
var reportProgress = function( event ) {
document.getElementById( 'feedback' ).innerHTML = event.detail.text;
@@ -416,7 +425,7 @@
callbacks.setCallbackOnMeshAlter( callbackMeshAlter );
callbacks.setCallbackOnLoad( callbackOnLoad );
callbacks.setCallbackOnProgress( reportProgress );
- this.workerDirector.prepareWorkers( callbacks, maxQueueSize, maxWebWorkers );
+ workerDirector.prepareWorkers( callbacks, maxQueueSize, maxWebWorkers );
var prepData;
var pivot;
@@ -440,9 +449,9 @@
prepData.dimension = Math.max( Math.random() * 500, 100 );
prepData.globalObjectCount = globalObjectCount++;
- this.workerDirector.enqueueForRun( prepData );
+ workerDirector.enqueueForRun( prepData );
}
- this.workerDirector.processQueue();
+ workerDirector.processQueue();
};
MeshSprayApp.prototype.resizeDisplayGL = function () {
diff --git a/examples/webgl_loader_obj2_options.html b/examples/webgl_loader_obj2_options.html
index 7d801ebbf44f1243791d288cdea28e7ed3fa7949..c57df9814202c5863b578868c70b782636ad1f49 100644
--- a/examples/webgl_loader_obj2_options.html
+++ b/examples/webgl_loader_obj2_options.html
@@ -1,7 +1,7 @@
-
three.js webgl - WWOBJLoader2
+
three.js webgl - OBJLoader2 usage options
@@ -243,6 +243,8 @@
var scope = this;
var objLoader = new THREE.OBJLoader2();
var callbackOnLoad = function ( event ) {
+ objLoader.workerSupport.setTerminateRequested( true );
+
var local = new THREE.Object3D();
local.name = 'Pivot_WaltHead';
local.position.set( -125, 50, 0 );
@@ -257,6 +259,7 @@
var onLoadMtl = function ( materials ) {
objLoader.setModelName( modelName );
objLoader.setMaterials( materials );
+ objLoader.terminateWorkerOnLoad = false;
objLoader.load( 'obj/walt/WaltHead.obj', callbackOnLoad, null, null, null, true );
};
objLoader.loadMtl( 'obj/walt//WaltHead.mtl', 'WaltHead.mtl', null, onLoadMtl );
diff --git a/examples/webgl_loader_obj2_run_director.html b/examples/webgl_loader_obj2_run_director.html
index c046b0bae14d5af74d4fddf2cdd9df380dcca422..86a4a2465578ddff88b9383a79a7a755a7d4bd1d 100644
--- a/examples/webgl_loader_obj2_run_director.html
+++ b/examples/webgl_loader_obj2_run_director.html
@@ -113,7 +113,7 @@
this.logger = new THREE.LoaderSupport.ConsoleLogger();
this.logger.setEnabled( false );
- this.workerDirector = new THREE.LoaderSupport.WorkerDirector( THREE.OBJLoader2, this.logger );
+ this.workerDirector = new THREE.LoaderSupport.WorkerDirector( THREE.OBJLoader2, this.logger );
this.workerDirector.setCrossOrigin( 'anonymous' );
this.controls = null;
@@ -380,7 +380,24 @@
};
WWParallels.prototype.terminateManager = function () {
- this.workerDirector.deregister();
+ this.workerDirector.tearDown();
+ this.running = false;
+ };
+
+ WWParallels.prototype.terminateManagerAndClearScene = function () {
+ var scope = this;
+ var scopedClearAllAssests = function (){
+ scope.clearAllAssests();
+ };
+ if ( this.workerDirector.isRunning() ) {
+
+ this.workerDirector.tearDown( scopedClearAllAssests );
+
+ } else {
+
+ scopedClearAllAssests();
+ }
+
this.running = false;
};
@@ -402,8 +419,7 @@
app.terminateManager();
},
clearAllAssests: function () {
- app.terminateManager();
- app.clearAllAssests();
+ app.terminateManagerAndClearScene();
}
};
var gui = new dat.GUI( {