233 lines
6.6 KiB
JavaScript
233 lines
6.6 KiB
JavaScript
/**
|
|
* Development repository: https://github.com/kaisalmen/WWOBJLoader
|
|
*/
|
|
|
|
// Imports only related to wrapper
|
|
import {
|
|
Object3D
|
|
} from '../../../build/three.module.js';
|
|
import {
|
|
CodeBuilderInstructions,
|
|
WorkerExecutionSupport
|
|
} from './obj2/worker/main/WorkerExecutionSupport.js';
|
|
import { CodeSerializer } from './obj2/utils/CodeSerializer.js';
|
|
import { OBJLoader2 } from './OBJLoader2.js';
|
|
|
|
// Imports only related to worker (when standard workers (modules aren't supported) are used)
|
|
import { OBJLoader2Parser } from './obj2/OBJLoader2Parser.js';
|
|
import {
|
|
WorkerRunner,
|
|
DefaultWorkerPayloadHandler,
|
|
ObjectManipulator
|
|
} from './obj2/worker/parallel/WorkerRunner.js';
|
|
|
|
|
|
/**
|
|
* Creates a new OBJLoader2Parallel. Use it to load OBJ data from files or to parse OBJ data from arraybuffer.
|
|
* It extends {@link OBJLoader2} with the capability to run the parser in a web worker.
|
|
*
|
|
* @param [LoadingManager] manager The loadingManager for the loader to use. Default is {@link LoadingManager}
|
|
* @constructor
|
|
*/
|
|
const OBJLoader2Parallel = function ( manager ) {
|
|
|
|
OBJLoader2.call( this, manager );
|
|
this.preferJsmWorker = false;
|
|
this.jsmWorkerUrl = null;
|
|
|
|
this.executeParallel = true;
|
|
this.workerExecutionSupport = new WorkerExecutionSupport();
|
|
|
|
};
|
|
|
|
OBJLoader2Parallel.OBJLOADER2_PARALLEL_VERSION = '3.2.0';
|
|
console.info( 'Using OBJLoader2Parallel version: ' + OBJLoader2Parallel.OBJLOADER2_PARALLEL_VERSION );
|
|
OBJLoader2Parallel.DEFAULT_JSM_WORKER_PATH = './jsm/loaders/obj2/worker/parallel/OBJLoader2JsmWorker.js';
|
|
|
|
OBJLoader2Parallel.prototype = Object.assign( Object.create( OBJLoader2.prototype ), {
|
|
|
|
constructor: OBJLoader2Parallel,
|
|
|
|
/**
|
|
* Execution of parse in parallel via Worker is default, but normal {OBJLoader2} parsing can be enforced via false here.
|
|
*
|
|
* @param {boolean} executeParallel True or False
|
|
* @return {OBJLoader2Parallel}
|
|
*/
|
|
setExecuteParallel: function ( executeParallel ) {
|
|
|
|
this.executeParallel = executeParallel === true;
|
|
return this;
|
|
|
|
},
|
|
|
|
/**
|
|
* Set whether jsm modules in workers should be used. This requires browser support which is currently only experimental.
|
|
* @param {boolean} preferJsmWorker True or False
|
|
* @param {URL} jsmWorkerUrl Provide complete jsm worker URL otherwise relative path to this module may not be correct
|
|
* @return {OBJLoader2Parallel}
|
|
*/
|
|
setJsmWorker: function ( preferJsmWorker, jsmWorkerUrl ) {
|
|
|
|
this.preferJsmWorker = preferJsmWorker === true;
|
|
|
|
if ( jsmWorkerUrl === undefined || jsmWorkerUrl === null ) {
|
|
|
|
throw 'The url to the jsm worker is not valid. Aborting...';
|
|
|
|
}
|
|
|
|
this.jsmWorkerUrl = jsmWorkerUrl;
|
|
|
|
return this;
|
|
|
|
},
|
|
|
|
/**
|
|
* Allow to get hold of {@link WorkerExecutionSupport} for configuration purposes.
|
|
* @return {WorkerExecutionSupport}
|
|
*/
|
|
getWorkerExecutionSupport: function () {
|
|
|
|
return this.workerExecutionSupport;
|
|
|
|
},
|
|
|
|
/**
|
|
* Provide instructions on what is to be contained in the worker.
|
|
* @return {CodeBuilderInstructions}
|
|
*/
|
|
buildWorkerCode: function () {
|
|
|
|
const codeBuilderInstructions = new CodeBuilderInstructions( true, true, this.preferJsmWorker );
|
|
|
|
if ( codeBuilderInstructions.isSupportsJsmWorker() ) {
|
|
|
|
codeBuilderInstructions.setJsmWorkerUrl( this.jsmWorkerUrl );
|
|
|
|
}
|
|
|
|
if ( codeBuilderInstructions.isSupportsStandardWorker() ) {
|
|
|
|
const objectManipulator = new ObjectManipulator();
|
|
const defaultWorkerPayloadHandler = new DefaultWorkerPayloadHandler( this.parser );
|
|
const workerRunner = new WorkerRunner( {} );
|
|
codeBuilderInstructions.addCodeFragment( CodeSerializer.serializeClass( OBJLoader2Parser, this.parser ) );
|
|
codeBuilderInstructions.addCodeFragment( CodeSerializer.serializeClass( ObjectManipulator, objectManipulator ) );
|
|
codeBuilderInstructions.addCodeFragment( CodeSerializer.serializeClass( DefaultWorkerPayloadHandler, defaultWorkerPayloadHandler ) );
|
|
codeBuilderInstructions.addCodeFragment( CodeSerializer.serializeClass( WorkerRunner, workerRunner ) );
|
|
|
|
const startCode = 'new ' + workerRunner.constructor.name + '( new ' + defaultWorkerPayloadHandler.constructor.name + '( new ' + this.parser.constructor.name + '() ) );';
|
|
codeBuilderInstructions.addStartCode( startCode );
|
|
|
|
}
|
|
|
|
return codeBuilderInstructions;
|
|
|
|
},
|
|
|
|
/**
|
|
* See {@link OBJLoader2.load}
|
|
*/
|
|
load: function ( content, onLoad, onFileLoadProgress, onError, onMeshAlter ) {
|
|
|
|
const scope = this;
|
|
function interceptOnLoad( object3d, message ) {
|
|
|
|
if ( object3d.name === 'OBJLoader2ParallelDummy' ) {
|
|
|
|
if ( scope.parser.logging.enabled && scope.parser.logging.debug ) {
|
|
|
|
console.debug( 'Received dummy answer from OBJLoader2Parallel#parse' );
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
onLoad( object3d, message );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
OBJLoader2.prototype.load.call( this, content, interceptOnLoad, onFileLoadProgress, onError, onMeshAlter );
|
|
|
|
},
|
|
|
|
/**
|
|
* See {@link OBJLoader2.parse}
|
|
* The callback onLoad needs to be set to be able to receive the content if used in parallel mode.
|
|
* Fallback is possible via {@link OBJLoader2Parallel#setExecuteParallel}.
|
|
*/
|
|
parse: function ( content ) {
|
|
|
|
if ( this.executeParallel ) {
|
|
|
|
if ( this.parser.callbacks.onLoad === this.parser._onLoad ) {
|
|
|
|
throw 'No callback other than the default callback was provided! Aborting!';
|
|
|
|
}
|
|
|
|
// check if worker has been initialize before. If yes, skip init
|
|
if ( ! this.workerExecutionSupport.isWorkerLoaded( this.preferJsmWorker ) ) {
|
|
|
|
this.workerExecutionSupport.buildWorker( this.buildWorkerCode() );
|
|
|
|
const scope = this;
|
|
const scopedOnAssetAvailable = function ( payload ) {
|
|
|
|
scope._onAssetAvailable( payload );
|
|
|
|
};
|
|
|
|
function scopedOnLoad( message ) {
|
|
|
|
scope.parser.callbacks.onLoad( scope.baseObject3d, message );
|
|
|
|
}
|
|
|
|
this.workerExecutionSupport.updateCallbacks( scopedOnAssetAvailable, scopedOnLoad );
|
|
|
|
}
|
|
|
|
// Create default materials beforehand, but do not override previously set materials (e.g. during init)
|
|
this.materialHandler.createDefaultMaterials( false );
|
|
|
|
this.workerExecutionSupport.executeParallel(
|
|
{
|
|
params: {
|
|
modelName: this.modelName,
|
|
instanceNo: this.instanceNo,
|
|
useIndices: this.parser.useIndices,
|
|
disregardNormals: this.parser.disregardNormals,
|
|
materialPerSmoothingGroup: this.parser.materialPerSmoothingGroup,
|
|
useOAsMesh: this.parser.useOAsMesh,
|
|
materials: this.materialHandler.getMaterialsJSON()
|
|
},
|
|
data: {
|
|
input: content,
|
|
options: null
|
|
},
|
|
logging: {
|
|
enabled: this.parser.logging.enabled,
|
|
debug: this.parser.logging.debug
|
|
}
|
|
} );
|
|
|
|
const dummy = new Object3D();
|
|
dummy.name = 'OBJLoader2ParallelDummy';
|
|
return dummy;
|
|
|
|
} else {
|
|
|
|
return OBJLoader2.prototype.parse.call( this, content );
|
|
|
|
}
|
|
|
|
},
|
|
|
|
} );
|
|
|
|
export { OBJLoader2Parallel };
|