提交 05a07fbb 编写于 作者: K Kai Salmen

OBJLoader2Parallel: isolated build function and added code docs

WorkerExecutionSupport: buildWorker uses CodeBuilderInstructions to decide how to internally build the worker (standard or jsm based)
上级 f42bb736
......@@ -20,69 +20,83 @@ import {
} from "./obj2/worker/parallel/WorkerRunner.js";
/**
* Extends {OBJLoader2} with the capability to run the parser {OBJLoader2Parser} in web worker
* with help of {WorkerExecutionSupport}.
*
* @param [LoadingManager] manager
* @constructor
*/
const OBJLoader2Parallel = function ( manager ) {
OBJLoader2.call( this, manager );
this.useJsmWorker = false;
this.preferJsmWorker = false;
this.callbackOnLoad = null;
this.callbacks.onParseComplete = null;
this.executeParallel = true;
this.workerExecutionSupport = new WorkerExecutionSupport();
};
OBJLoader2.OBJLOADER2_PARALLEL_VERSION = '3.0.0-beta2';
console.info( 'Using OBJLoader2Parallel version: ' + OBJLoader2.OBJLOADER2PARALLEL_VERSION );
OBJLoader2Parallel.prototype = Object.create( OBJLoader2.prototype );
OBJLoader2Parallel.prototype.constructor = OBJLoader2Parallel;
OBJLoader2Parallel.prototype.setUseJsmWorker = function ( useJsmWorker ) {
this.useJsmWorker = useJsmWorker === true;
OBJLoader2.OBJLOADER2_PARALLEL_VERSION = '3.0.0-beta2';
console.info( 'Using OBJLoader2Parallel version: ' + OBJLoader2.OBJLOADER2_PARALLEL_VERSION );
OBJLoader2Parallel.prototype.setPreferJsmWorker = function ( preferJsmWorker ) {
this.preferJsmWorker = preferJsmWorker === true;
return this;
};
OBJLoader2Parallel.prototype.setCallbackOnLoad = function ( callbackOnLoad ) {
if ( callbackOnLoad !== undefined && callbackOnLoad !== null ) {
this.callbackOnLoad = callbackOnLoad;
/**
* If this call back is not set, then the completion message from worker will not be received.
*
* @param {function} onParseComplete
* @return {OBJLoader2Parallel}
*/
OBJLoader2Parallel.prototype.setCallbackOnParseComplete = function ( onParseComplete ) {
if ( onParseComplete !== undefined && onParseComplete !== null ) {
this.callbacks.onParseComplete = onParseComplete;
}
else {
throw "No callbackOnLoad was provided! Aborting!"
throw "No callbackOnLoad was provided! Aborting!";
}
return this;
};
/**
* Execution of parse in parallel via Worker is default, but normal {OBJLoader2} parsing can be enforced via false here.
*
* @param executeParallel
* @return {OBJLoader2Parallel}
*/
OBJLoader2Parallel.prototype.setExecuteParallel = function ( executeParallel ) {
this.executeParallel = executeParallel === true;
return this;
};
/**
* Allow to get hold of {WorkerExecutionSupport} for configuratin purposes
*
* @return {WorkerExecutionSupport|WorkerExecutionSupport}
*/
OBJLoader2Parallel.prototype.getWorkerExecutionSupport = function () {
return this.workerExecutionSupport;
};
OBJLoader2Parallel.prototype._configure = function () {
if ( this.callbackOnLoad === null ) {
"No callbackOnLoad was provided! Aborting!"
}
// check if worker is already available and if so, then fast-fail
if ( this.workerExecutionSupport.isWorkerLoaded( this.useJsmWorker ) ) return;
let codeBuilderInstructions = new CodeBuilderInstructions();
let jsmSuccess = false;
if ( this.useJsmWorker ) {
/**
* Provides instructions on what is to be contained in the worker
*
* @return {CodeBuilderInstructions}
*/
OBJLoader2Parallel.prototype.buildWorkerCode = function () {
let codeBuilderInstructions = new CodeBuilderInstructions( true, true, this.preferJsmWorker );
if ( codeBuilderInstructions.isSupportsJsmWorker() ) {
codeBuilderInstructions.setJsmWorkerFile( '../../src/loaders/worker/parallel/jsm/OBJLoader2Worker.js' );
jsmSuccess = this.workerExecutionSupport.buildWorkerJsm( codeBuilderInstructions );
}
if ( ! jsmSuccess ) {
}
if ( codeBuilderInstructions.isSupportsStandardWorker() ) {
let codeOBJLoader2Parser = CodeSerializer.serializeClass( 'OBJLoader2Parser', OBJLoader2Parser );
let codeObjectManipulator = CodeSerializer.serializeObject( 'ObjectManipulator', ObjectManipulator );
......@@ -94,33 +108,54 @@ OBJLoader2Parallel.prototype._configure = function () {
codeBuilderInstructions.addCodeFragment( codeParserPayloadHandler );
codeBuilderInstructions.addCodeFragment( codeWorkerRunner );
// allows to include full libraries as importScripts
// codeBuilderInstructions.addLibraryImport( '../../node_modules/three/build/three.js' );
codeBuilderInstructions.addStartCode( 'new WorkerRunner( new DefaultWorkerPayloadHandler( new OBJLoader2Parser() ) );' );
this.workerExecutionSupport.buildWorkerStandard( codeBuilderInstructions );
}
return codeBuilderInstructions;
};
/**
* @private
*/
OBJLoader2Parallel.prototype._configure = function () {
if ( this.callbacks.onParseComplete === null ) {
"No callbackOnLoad was provided! Aborting!"
}
// check if worker is already available and if so, then fast-fail
if ( this.workerExecutionSupport.isWorkerLoaded( this.preferJsmWorker ) ) return;
this.workerExecutionSupport.buildWorker( this.buildWorkerCode() );
let scope = this;
let scopedOnAssetAvailable = function ( payload ) {
scope._onAssetAvailable( payload );
};
this.workerExecutionSupport.updateCallbacks( scopedOnAssetAvailable, this.callbackOnLoad );
this.workerExecutionSupport.updateCallbacks( scopedOnAssetAvailable, this.callbacks.onParseComplete );
};
/**
* Load is intercepted from OBJLoader2.
* @inheritDoc
* Load is intercepted from {OBJLoader2}. It replaces the regular onLoad callback as the final worker result will be
* returned later by its own callbackOnLoad.
*
* @param {string} url A string containing the path/URL of the file to be loaded.
* @param {function} onLoad A function to be called after loading is successfully completed. The function receives loaded Object3D as an argument.
* @param {function} [onFileLoadProgress] A function to be called while the loading is in progress. The argument will be the XMLHttpRequest instance, which contains total and Integer bytes.
* @param {function} [onError] A function to be called if an error occurs during loading. The function receives the error as an argument.
* @param {function} [onMeshAlter] Called after worker successfully delivered a single mesh
*/
OBJLoader2Parallel.prototype.load = function( content, onLoad, onFileLoadProgress, onError, onMeshAlter ) {
this.setCallbackOnLoad( onLoad );
this.setCallbackOnParseComplete( onLoad );
OBJLoader2.prototype.load.call( this, content, function () {}, onFileLoadProgress, onError, onMeshAlter );
};
/**
* @inheritDoc
* Parses OBJ data in parallel with web worker.
*
* @param {arraybuffer} content OBJ data as Uint8Array or String
*/
OBJLoader2Parallel.prototype.parse = function( content ) {
if ( this.executeParallel ) {
......@@ -150,7 +185,7 @@ OBJLoader2Parallel.prototype.parse = function( content ) {
} else {
this.callbackOnLoad( OBJLoader2.prototype.parse.call( this, content ) );
this.callbacks.onParseComplete( OBJLoader2.prototype.parse.call( this, content ) );
}
};
......
......@@ -3,12 +3,22 @@
* Development repository: https://github.com/kaisalmen/WWOBJLoader
*/
const CodeBuilderInstructions = function () {
/**
* These instructions are used by {WorkerExecutionSupport} to build code for the web worker or to assign code
*
* @param {boolean} supportsStandardWorker
* @param {boolean} supportsJsmWorker
* @constructor
*/
const CodeBuilderInstructions = function ( supportsStandardWorker, supportsJsmWorker, preferJsmWorker ) {
this.supportsStandardWorker = supportsStandardWorker;
this.supportsJsmWorker = supportsJsmWorker;
this.preferJsmWorker = preferJsmWorker;
this.startCode = '';
this.codeFragments = [];
this.importStatements = [];
this.jsmWorkerFile;
this.jsmWorker = false;
this.defaultGeometryType = 0;
};
......@@ -16,16 +26,20 @@ CodeBuilderInstructions.prototype = {
constructor: CodeBuilderInstructions,
setJsmWorkerFile: function ( jsmWorkerFile ) {
this.jsmWorkerFile = jsmWorkerFile;
isSupportsStandardWorker: function () {
return this.supportsStandardWorker;
},
isSupportsJsmWorker: function () {
return this.supportsJsmWorker;
},
setJsmWorker: function ( jsmWorker ) {
this.jsmWorker = jsmWorker;
isPreferJsmWorker: function () {
return this.preferJsmWorker;
},
isJsmWorker: function () {
return this.jsmWorker;
setJsmWorkerFile: function ( jsmWorkerFile ) {
this.jsmWorkerFile = jsmWorkerFile;
},
addStartCode: function ( startCode ) {
......@@ -68,7 +82,7 @@ const WorkerExecutionSupport = function () {
this._reset();
};
WorkerExecutionSupport.WORKER_SUPPORT_VERSION = '3.0.0-beta2';
WorkerExecutionSupport.WORKER_SUPPORT_VERSION = '3.0.0-preview';
console.info( 'Using WorkerSupport version: ' + WorkerExecutionSupport.WORKER_SUPPORT_VERSION );
......@@ -95,7 +109,7 @@ WorkerExecutionSupport.prototype = {
usesMeshDisassembler: false,
defaultGeometryType: 0
},
terminateWorkerOnLoad: false,
terminateWorkerOnLoad: true,
forceWorkerDataCopy: false,
started: false,
queuedMessage: null,
......@@ -179,7 +193,33 @@ WorkerExecutionSupport.prototype = {
}
},
buildWorkerJsm: function ( codeBuilderInstructions ) {
/**
* Builds the worker code according the provided Instructions.
* If jsm worker code shall be built, then function may fall back to standard if lag is set
*
* @param {CodeBuilderInstructions} codeBuilderInstructions
*/
buildWorker: function ( codeBuilderInstructions ) {
let jsmSuccess = false;
if ( codeBuilderInstructions.isSupportsJsmWorker() && codeBuilderInstructions.isPreferJsmWorker() ) {
jsmSuccess = this._buildWorkerJsm( codeBuilderInstructions );
}
if ( ! jsmSuccess && codeBuilderInstructions.isSupportsStandardWorker() ) {
this._buildWorkerStandard( codeBuilderInstructions );
}
},
/**
*
* @param {CodeBuilderInstructions} codeBuilderInstructions
* @return {boolean} Whether loading of jsm worker was successful
* @private
*/
_buildWorkerJsm: function ( codeBuilderInstructions ) {
let jsmSuccess = true;
this._buildWorkerCheckPreconditions( true, 'buildWorkerJsm' );
......@@ -187,9 +227,7 @@ WorkerExecutionSupport.prototype = {
try {
let worker = new Worker( workerFileUrl, { type: "module" } );
codeBuilderInstructions.setJsmWorker( true );
this._configureWorkerCommunication( worker, codeBuilderInstructions, 'buildWorkerJsm' );
this._configureWorkerCommunication( worker, true, codeBuilderInstructions.defaultGeometryType, 'buildWorkerJsm' );
}
catch ( e ) {
......@@ -201,7 +239,6 @@ WorkerExecutionSupport.prototype = {
}
}
return jsmSuccess;
},
......@@ -210,7 +247,13 @@ WorkerExecutionSupport.prototype = {
*
* @param {CodeBuilderIns} buildWorkerCode The function that is invoked to create the worker code of the parser.
*/
buildWorkerStandard: function ( codeBuilderInstructions ) {
/**
*
* @param {CodeBuilderInstructions} codeBuilderInstructions
* @private
*/
_buildWorkerStandard: function ( codeBuilderInstructions ) {
this._buildWorkerCheckPreconditions( false,'buildWorkerStandard' );
let concatenateCode = '';
......@@ -226,9 +269,8 @@ WorkerExecutionSupport.prototype = {
let blob = new Blob( [ concatenateCode ], { type: 'application/javascript' } );
let worker = new Worker( window.URL.createObjectURL( blob ) );
codeBuilderInstructions.setJsmWorker( false );
this._configureWorkerCommunication( worker, codeBuilderInstructions, 'buildWorkerStandard' );
this._configureWorkerCommunication( worker, false, codeBuilderInstructions.defaultGeometryType, 'buildWorkerStandard' );
},
_buildWorkerCheckPreconditions: function ( requireJsmWorker, timeLabel ) {
......@@ -242,18 +284,18 @@ WorkerExecutionSupport.prototype = {
}
},
_configureWorkerCommunication: function ( worker, codeBuilderInstructions, timeLabel ) {
_configureWorkerCommunication: function ( worker, haveJsmWorker, defaultGeometryType, timeLabel ) {
this.worker.native = worker;
this.worker.jsmWorker = codeBuilderInstructions.isJsmWorker();
this.worker.jsmWorker = haveJsmWorker;
let scope = this;
let scopedReceiveWorkerMessage = function ( event ) {
scope._receiveWorkerMessage( event );
};
this.worker.native.onmessage = scopedReceiveWorkerMessage;
if ( codeBuilderInstructions.defaultGeometryType !== undefined && codeBuilderInstructions.defaultGeometryType !== null ) {
if ( defaultGeometryType !== undefined && defaultGeometryType !== null ) {
this.worker.workerRunner.defaultGeometryType = codeBuilderInstructions.defaultGeometryType;
this.worker.workerRunner.defaultGeometryType = defaultGeometryType;
}
if ( this.logging.enabled ) {
......@@ -263,6 +305,11 @@ WorkerExecutionSupport.prototype = {
}
},
/**
* Returns if Worker code is available and complies with expectation.
* @param {boolean} requireJsmWorker
* @return {boolean|*}
*/
isWorkerLoaded: function ( requireJsmWorker ) {
return this.worker.native !== null &&
( ( requireJsmWorker && this.worker.jsmWorker ) || ( ! requireJsmWorker && ! this.worker.jsmWorker ) );
......
......@@ -284,8 +284,8 @@
.setModelName( local.name )
.setBaseObject3d( local );
// Configure WorkerExecutionSupport to disregard worker after execution
objLoader2Parallel.getWorkerExecutionSupport().setTerminateWorkerOnLoad( true );
// Configure WorkerExecutionSupport to not disregard worker after execution
objLoader2Parallel.getWorkerExecutionSupport().setTerminateWorkerOnLoad( false );
function callbackMeshAlter ( event ) {
let override = new LoadedMeshUserOverride( false, true );
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册