/** * @author Kai Salmen / https://kaisalmen.de * 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/worker/parallel/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.executeParallel = true; this.workerExecutionSupport = new WorkerExecutionSupport(); }; OBJLoader2Parallel.OBJLOADER2_PARALLEL_VERSION = '3.1.2'; console.info( 'Using OBJLoader2Parallel version: ' + OBJLoader2Parallel.OBJLOADER2_PARALLEL_VERSION ); 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 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 preferJsmWorker True or False * @return {OBJLoader2Parallel} */ setPreferJsmWorker: function ( preferJsmWorker ) { this.preferJsmWorker = preferJsmWorker === true; 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 () { let codeBuilderInstructions = new CodeBuilderInstructions( true, true, this.preferJsmWorker ); if ( codeBuilderInstructions.isSupportsJsmWorker() ) { codeBuilderInstructions.setJsmWorkerFile( '../examples/loaders/jsm/obj2/worker/parallel/jsm/OBJLoader2Worker.js' ); } if ( codeBuilderInstructions.isSupportsStandardWorker() ) { let codeOBJLoader2Parser = CodeSerializer.serializeClass( 'OBJLoader2Parser', OBJLoader2Parser ); let codeObjectManipulator = CodeSerializer.serializeObject( 'ObjectManipulator', ObjectManipulator ); let codeParserPayloadHandler = CodeSerializer.serializeClass( 'DefaultWorkerPayloadHandler', DefaultWorkerPayloadHandler ); let codeWorkerRunner = CodeSerializer.serializeClass( 'WorkerRunner', WorkerRunner ); codeBuilderInstructions.addCodeFragment( codeOBJLoader2Parser ); codeBuilderInstructions.addCodeFragment( codeObjectManipulator ); codeBuilderInstructions.addCodeFragment( codeParserPayloadHandler ); codeBuilderInstructions.addCodeFragment( codeWorkerRunner ); codeBuilderInstructions.addStartCode( 'new WorkerRunner( new DefaultWorkerPayloadHandler( new OBJLoader2Parser() ) );' ); } return codeBuilderInstructions; }, /** * See {@link OBJLoader2.load} */ load: function ( content, onLoad, onFileLoadProgress, onError, onMeshAlter ) { let 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() ); let scope = this; let 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 } } ); let dummy = new Object3D(); dummy.name = 'OBJLoader2ParallelDummy'; return dummy; } else { return OBJLoader2.prototype.parse.call( this, content ); } }, } ); export { OBJLoader2Parallel };