From 3405ccbf99e34f2f3fbac02ecc5ab6cdf8948790 Mon Sep 17 00:00:00 2001 From: Kai Salmen Date: Mon, 14 Jun 2021 21:54:03 +0200 Subject: [PATCH] Align code with latest code from three-wtm (1.0.0-beta.6) --- .../workerTaskManager/WorkerTaskManager.js | 88 ++++++++++++------- .../workerTaskManager/utils/MaterialStore.js | 3 +- .../workerTaskManager/utils/MaterialUtils.js | 10 ++- .../workerTaskManager/utils/TransportUtils.js | 83 ++++++++++++++--- .../worker/defaultRouting.js | 9 +- .../workerTaskManager/worker/tmOBJLoader.js | 35 ++++---- examples/webgl_loader_workertaskmanager.html | 46 +++++----- 7 files changed, 179 insertions(+), 95 deletions(-) diff --git a/examples/jsm/loaders/workerTaskManager/WorkerTaskManager.js b/examples/jsm/loaders/workerTaskManager/WorkerTaskManager.js index fff8888fcb3848..5eb45f7a7c1a6c 100644 --- a/examples/jsm/loaders/workerTaskManager/WorkerTaskManager.js +++ b/examples/jsm/loaders/workerTaskManager/WorkerTaskManager.js @@ -1,6 +1,6 @@ /** - * Development repository: https://github.com/kaisalmen/WWOBJLoader - * Proposed by Don McCurdy / https://www.donmccurdy.com + * Development repository: https://github.com/kaisalmen/three-wtm + * Initial idea by Don McCurdy / https://www.donmccurdy.com */ import { FileLoader } from "../../../../build/three.module.js"; @@ -86,9 +86,9 @@ class WorkerTaskManager { * Registers functions and dependencies for a new task type. * * @param {string} taskType The name to be used for registration. - * @param {function} initFunction The function to be called when the worker is initialised - * @param {function} executeFunction The function to be called when the worker is executed - * @param {function} comRoutingFunction The function that should handle communication, leave undefined for default behavior + * @param {Function} initFunction The function to be called when the worker is initialised + * @param {Function} executeFunction The function to be called when the worker is executed + * @param {Function} comRoutingFunction The function that should handle communication, leave undefined for default behavior * @param {boolean} fallback Set to true if execution should be performed in main * @param {Object[]} [dependencyDescriptions] * @return {boolean} Tells if registration is possible (new=true) or if task was already registered (existing=false) @@ -147,17 +147,17 @@ class WorkerTaskManager { if ( workerTypeDefinition.isWorkerModule() ) { await workerTypeDefinition.createWorkerModules() - .then( instances => workerTypeDefinition.initWorkers( config, transferables ) ) - .then( y => workerTypeDefinition.status.initComplete = true ) - .catch( x => console.error( x ) ); + .then( () => workerTypeDefinition.initWorkers( config, transferables ) ) + .then( () => workerTypeDefinition.status.initComplete = true ) + .catch( e => console.error( e ) ); } else { await workerTypeDefinition.loadDependencies() - .then( code => workerTypeDefinition.createWorkers() ) - .then( instances => workerTypeDefinition.initWorkers( config, transferables ) ) - .then( y => workerTypeDefinition.status.initComplete = true ) - .catch( x => console.error( x ) ); + .then( () => workerTypeDefinition.createWorkers() ) + .then( () => workerTypeDefinition.initWorkers( config, transferables ) ) + .then( () => workerTypeDefinition.status.initComplete = true ) + .catch( e => console.error( e ) ); } @@ -222,26 +222,25 @@ class WorkerTaskManager { this.actualExecutionCount ++; let promiseWorker = new Promise( ( resolveWorker, rejectWorker ) => { - taskWorker.onmessage = function ( e ) { + taskWorker.onmessage = message => { // allow intermediate asset provision before flagging execComplete - if ( e.data.cmd === 'assetAvailable' ) { + if ( message.data.cmd === 'assetAvailable' ) { if ( storedExecution.assetAvailableFunction instanceof Function ) { - storedExecution.assetAvailableFunction( e.data ); + storedExecution.assetAvailableFunction( message.data ); } } else { - resolveWorker( e ); + resolveWorker( message ); } }; taskWorker.onerror = rejectWorker; - taskWorker.postMessage( { cmd: "execute", workerId: taskWorker.getId(), @@ -249,10 +248,10 @@ class WorkerTaskManager { }, storedExecution.transferables ); } ); - promiseWorker.then( ( e ) => { + promiseWorker.then( ( message ) => { workerTypeDefinition.returnAvailableTask( taskWorker ); - storedExecution.resolve( e.data ); + storedExecution.resolve( message.data ); this.actualExecutionCount --; this._depleteExecutions(); @@ -309,11 +308,11 @@ class WorkerTypeDefinition { this.verbose = verbose === true; this.initialised = false; this.functions = { - /** @type {function} */ + /** @type {Function} */ init: null, - /** @type {function} */ + /** @type {Function} */ execute: null, - /** @type {function} */ + /** @type {Function} */ comRouting: null, dependencies: { /** @type {Object[]} */ @@ -354,9 +353,9 @@ class WorkerTypeDefinition { * Set the three functions. A default comRouting function is used if it is not passed here. * Then it creates the code fr. * - * @param {function} initFunction The function to be called when the worker is initialised - * @param {function} executeFunction The function to be called when the worker is executed - * @param {function} [comRoutingFunction] The function that should handle communication, leave undefined for default behavior + * @param {Function} initFunction The function to be called when the worker is initialised + * @param {Function} executeFunction The function to be called when the worker is executed + * @param {Function} [comRoutingFunction] The function that should handle communication, leave undefined for default behavior */ setFunctions ( initFunction, executeFunction, comRoutingFunction ) { @@ -368,13 +367,32 @@ class WorkerTypeDefinition { this.functions.comRouting = WorkerTaskManagerDefaultRouting.comRouting; } - this.workers.code.push( 'const init = ' + this.functions.init.toString() + ';\n\n' ); - this.workers.code.push( 'const execute = ' + this.functions.execute.toString() + ';\n\n' ); - this.workers.code.push( 'const comRouting = ' + this.functions.comRouting.toString() + ';\n\n' ); + this._addWorkerCode( 'init', this.functions.init.toString() ); + this._addWorkerCode( 'execute', this.functions.execute.toString() ); + this._addWorkerCode( 'comRouting', this.functions.comRouting.toString() ); this.workers.code.push( 'self.addEventListener( "message", message => comRouting( self, message, null, init, execute ), false );' ); } + /** + * + * @param {string} functionName Name of the function + * @param {string} functionString A function as string + * @private + */ + _addWorkerCode ( functionName, functionString ) { + if ( functionString.startsWith('function') ) { + + this.workers.code.push( 'const ' + functionName + ' = ' + functionString + ';\n\n' ); + + } else { + + this.workers.code.push( 'function ' + functionString + ';\n\n' ); + + } + + } + /** * Set the url of all dependent libraries (only used in non-module case). * @@ -415,7 +433,7 @@ class WorkerTypeDefinition { /** * Loads all dependencies and stores each as {@link ArrayBuffer} into the array. Returns if all loading is completed. * - * @return {} + * @return {String[]} */ async loadDependencies () { @@ -502,7 +520,12 @@ class WorkerTypeDefinition { let taskWorkerPromise = new Promise( ( resolveWorker, rejectWorker ) => { - taskWorker.onmessage = resolveWorker; + taskWorker.onmessage = message => { + + if ( this.verbose ) console.log( 'Init Complete: ' + message.data.id ); + resolveWorker( message ); + + } taskWorker.onerror = rejectWorker; // ensure all transferables are copies to all workers on init! @@ -524,6 +547,7 @@ class WorkerTypeDefinition { promises.push( taskWorkerPromise ); } + if ( this.verbose ) console.log( 'Task: ' + this.getTaskType() + ': Waiting for completion of initialization of all workers.'); await Promise.all( promises ); this.workers.available = this.workers.instances; @@ -652,8 +676,8 @@ class MockedTaskWorker { * Creates a new instance. * * @param {number} id - * @param {function} initFunction - * @param {function} executeFunction + * @param {Function} initFunction + * @param {Function} executeFunction */ constructor( id, initFunction, executeFunction ) { diff --git a/examples/jsm/loaders/workerTaskManager/utils/MaterialStore.js b/examples/jsm/loaders/workerTaskManager/utils/MaterialStore.js index 2cff736dc290b9..55bdfb928a0e04 100644 --- a/examples/jsm/loaders/workerTaskManager/utils/MaterialStore.js +++ b/examples/jsm/loaders/workerTaskManager/utils/MaterialStore.js @@ -1,9 +1,8 @@ /** - * Development repository: https://github.com/kaisalmen/WWOBJLoader + * Development repository: https://github.com/kaisalmen/three-wtm */ import { - Material, MeshStandardMaterial, LineBasicMaterial, PointsMaterial, diff --git a/examples/jsm/loaders/workerTaskManager/utils/MaterialUtils.js b/examples/jsm/loaders/workerTaskManager/utils/MaterialUtils.js index 15e783f9f7a9b7..a80250e29b3f15 100644 --- a/examples/jsm/loaders/workerTaskManager/utils/MaterialUtils.js +++ b/examples/jsm/loaders/workerTaskManager/utils/MaterialUtils.js @@ -1,9 +1,7 @@ /** - * Development repository: https://github.com/kaisalmen/WWOBJLoader + * Development repository: https://github.com/kaisalmen/three-wtm */ -import { Material } from "../../../../../build/three.module.js"; - /** * Static functions useful in the context of handling materials. */ @@ -62,7 +60,11 @@ class MaterialUtils { for ( const materialName in materialsObject ) { material = materialsObject[ materialName ]; - if ( material instanceof Material ) materialsJSON[ materialName ] = material.toJSON(); + if ( typeof material.toJSON === 'function' ) { + + materialsJSON[ materialName ] = material.toJSON(); + + } } return materialsJSON; diff --git a/examples/jsm/loaders/workerTaskManager/utils/TransportUtils.js b/examples/jsm/loaders/workerTaskManager/utils/TransportUtils.js index eba5e1fdd0ad09..5f0e8e4e21174c 100644 --- a/examples/jsm/loaders/workerTaskManager/utils/TransportUtils.js +++ b/examples/jsm/loaders/workerTaskManager/utils/TransportUtils.js @@ -1,5 +1,5 @@ /** - * Development repository: https://github.com/kaisalmen/WWOBJLoader + * Development repository: https://github.com/kaisalmen/three-wtm */ import { @@ -8,12 +8,72 @@ import { Box3, Sphere, Texture, - Material, MaterialLoader } from "../../../../../build/three.module.js"; -import { - MaterialUtils -} from './MaterialUtils.js'; +import { MaterialUtils } from './MaterialUtils.js'; + +class DeUglify { + + static buildThreeConst () { + return 'const EventDispatcher = THREE.EventDispatcher;\n' + + 'const BufferGeometry = THREE.BufferGeometry;\n' + + 'const BufferAttribute = THREE.BufferAttribute;\n' + + 'const Box3 = THREE.Box3;\n' + + 'const Sphere = THREE.Sphere;\n' + + 'const Texture = THREE.Texture;\n' + + 'const MaterialLoader = THREE.MaterialLoader;\n'; + } + + static buildUglifiedThreeMapping () { + function _BufferGeometry() { return BufferGeometry; } + function _BufferAttribute () { return BufferAttribute; } + function _Box3 () { return Box3; } + function _Sphere () { return Sphere; } + function _Texture () { return Texture; } + function _MaterialLoader () { return MaterialLoader; } + + return DeUglify.buildUglifiedNameAssignment( _BufferGeometry, 'BufferGeometry', /_BufferGeometry/, false ) + + DeUglify.buildUglifiedNameAssignment( _BufferAttribute, 'BufferAttribute', /_BufferAttribute/, false ) + + DeUglify.buildUglifiedNameAssignment( _Box3, 'Box3', /_Box3/, false ) + + DeUglify.buildUglifiedNameAssignment( _Sphere, 'Sphere', /_Sphere/, false ) + + DeUglify.buildUglifiedNameAssignment( _Texture, 'Texture', /_Texture/, false ) + + DeUglify.buildUglifiedNameAssignment( _MaterialLoader, 'MaterialLoader', /_MaterialLoader/, false ); + } + + static buildUglifiedThreeWtmMapping () { + function _DataTransport () { return DataTransport; } + function _GeometryTransport () { return GeometryTransport; } + function _MeshTransport () { return MeshTransport; } + function _MaterialsTransport () { return MaterialsTransport; } + function _MaterialUtils () { return MaterialUtils; } + + return DeUglify.buildUglifiedNameAssignment( _DataTransport, 'DataTransport', /_DataTransport/, true ) + + DeUglify.buildUglifiedNameAssignment( _GeometryTransport, 'GeometryTransport', /_GeometryTransport/, true ) + + DeUglify.buildUglifiedNameAssignment( _MeshTransport, 'MeshTransport', /_MeshTransport/, true ) + + DeUglify.buildUglifiedNameAssignment( _MaterialsTransport, 'MaterialsTransport', /_MaterialsTransport/, true ) + + DeUglify.buildUglifiedNameAssignment( _MaterialUtils, 'MaterialUtils', /_MaterialUtils/, true ); + } + + static buildUglifiedNameAssignment(func, name, methodPattern, invert) { + let funcStr = func.toString(); + // remove the method name and any line breaks (rollup lib creation, non-uglify case + funcStr = funcStr.replace(methodPattern, "").replace(/[\r\n]+/gm, ""); + // remove return and any semi-colons + funcStr = funcStr.replace(/.*return/, "").replace(/\}/, "").replace(/;/gm, ""); + const retrieveNamed = funcStr.trim() + // return non-empty string in uglified case (name!=retrieveNamed); e.g. "const BufferGeometry = e"; + // return empty string in case of non-uglified lib/src + let output = ""; + if (retrieveNamed !== name) { + const left = invert ? name : retrieveNamed; + const right = invert ? retrieveNamed : name; + output = "const " + left + " = " + right + ";\n"; + } + return output; + } +} + + /** * Define a base structure that is used to ship data in between main and workers. @@ -181,7 +241,7 @@ class DataTransport { /** * Return all transferable in one array. - * @return {[]|ArrayBuffer[]} + * @return {ArrayBuffer[]} */ getTransferables() { @@ -314,7 +374,7 @@ class MaterialsTransport extends DataTransport { let clonedMaterial; for ( let material of Object.values( this.main.materials ) ) { - if ( material instanceof Material ) { + if ( typeof material.clone === 'function' ) { clonedMaterial = material.clone(); clonedMaterials[ clonedMaterial.name ] = this._cleanMaterial( clonedMaterial ); @@ -424,10 +484,8 @@ class GeometryTransport extends DataTransport { super( cmd, id ); this.main.type = 'GeometryTransport'; - /** - * @type {number} - * 0: mesh, 1: line, 2: point - */ + // 0: mesh, 1: line, 2: point + /** @type {number} */ this.main.geometryType = 0; /** @type {object} */ this.main.geometry = {}; @@ -808,5 +866,6 @@ export { MeshTransport, MaterialsTransport, ObjectUtils, - ObjectManipulator + ObjectManipulator, + DeUglify } diff --git a/examples/jsm/loaders/workerTaskManager/worker/defaultRouting.js b/examples/jsm/loaders/workerTaskManager/worker/defaultRouting.js index 2f25c430d91744..0c21fc9c9d0f1a 100644 --- a/examples/jsm/loaders/workerTaskManager/worker/defaultRouting.js +++ b/examples/jsm/loaders/workerTaskManager/worker/defaultRouting.js @@ -1,10 +1,10 @@ /** - * Development repository: https://github.com/kaisalmen/WWOBJLoader + * Development repository: https://github.com/kaisalmen/three-wtm */ -const WorkerTaskManagerDefaultRouting = { +class WorkerTaskManagerDefaultRouting { - comRouting: function ( context, message, object, initFunction, executeFunction ) { + static comRouting ( context, message, object, initFunction, executeFunction ) { let payload = message.data; if ( payload.cmd === 'init' ) { @@ -12,6 +12,7 @@ const WorkerTaskManagerDefaultRouting = { if ( object !== undefined && object !== null ) { object[ initFunction ]( context, payload.workerId, payload.config ); + } else { initFunction( context, payload.workerId, payload.config ); @@ -34,6 +35,6 @@ const WorkerTaskManagerDefaultRouting = { } -}; +} export { WorkerTaskManagerDefaultRouting } diff --git a/examples/jsm/loaders/workerTaskManager/worker/tmOBJLoader.js b/examples/jsm/loaders/workerTaskManager/worker/tmOBJLoader.js index b7656879669574..ac772d35db7fad 100644 --- a/examples/jsm/loaders/workerTaskManager/worker/tmOBJLoader.js +++ b/examples/jsm/loaders/workerTaskManager/worker/tmOBJLoader.js @@ -1,27 +1,24 @@ +import { OBJLoader } from '../../OBJLoader.js'; import { DataTransport, MaterialsTransport, GeometryTransport, MeshTransport, ObjectUtils, -} from "../utils/TransportUtils.js"; -import { - MaterialUtils -} from '../utils/MaterialUtils.js'; -import { OBJLoader } from "../../OBJLoader.js"; + DeUglify +} from '../utils/TransportUtils.js'; +import { MaterialUtils } from '../utils/MaterialUtils.js';; import { WorkerTaskManagerDefaultRouting } from "./defaultRouting.js"; -const OBJLoaderWorker = { +class OBJLoaderWorker { - buildStandardWorkerDependencies: function ( threeJsLocation, objLoaderLocation ) { + static buildStandardWorkerDependencies ( threeJsLocation, objLoaderLocation ) { return [ { url: threeJsLocation }, { code: '\n\n' }, - { code: 'const MaterialLoader = THREE.MaterialLoader;\n' }, - { code: 'const Material = THREE.Material;\n' }, - { code: 'const Texture = THREE.Texture;\n' }, - { code: 'const BufferGeometry = THREE.BufferGeometry;\n' }, - { code: 'const EventDispatcher = THREE.EventDispatcher;\n' }, + { code: DeUglify.buildThreeConst() }, + { code: '\n\n' }, + { code: DeUglify.buildUglifiedThreeMapping() }, { code: '\n\n' }, { url: objLoaderLocation }, { code: '\n\nconst OBJLoader = THREE.OBJLoader;\n\n' }, @@ -30,11 +27,13 @@ const OBJLoaderWorker = { { code: ObjectUtils.serializeClass( MaterialsTransport ) }, { code: ObjectUtils.serializeClass( MaterialUtils ) }, { code: ObjectUtils.serializeClass( GeometryTransport ) }, - { code: ObjectUtils.serializeClass( MeshTransport ) } + { code: ObjectUtils.serializeClass( MeshTransport ) }, + { code: DeUglify.buildUglifiedThreeWtmMapping() }, + { code: '\n\n' } ] - }, + } - init: function ( context, id, config ) { + static init ( context, id, config ) { const materialsTransport = new MaterialsTransport().loadData( config ); context.objLoader = { @@ -50,9 +49,9 @@ const OBJLoaderWorker = { cmd: "init", id: id } ); - }, + } - execute: function ( context, id, config ) { + static execute ( context, id, config ) { context.objLoader.loader = new OBJLoader(); const dataTransport = new DataTransport().loadData( config ); @@ -85,7 +84,7 @@ const OBJLoaderWorker = { } -}; +} self.addEventListener( 'message', message => WorkerTaskManagerDefaultRouting.comRouting( self, message, OBJLoaderWorker, 'init', 'execute' ), false ); diff --git a/examples/webgl_loader_workertaskmanager.html b/examples/webgl_loader_workertaskmanager.html index 4d99270a32e1e3..f5279f0bad8f57 100644 --- a/examples/webgl_loader_workertaskmanager.html +++ b/examples/webgl_loader_workertaskmanager.html @@ -20,20 +20,20 @@ 'use strict'; import * as THREE from '../build/three.module.js'; - import { TrackballControls } from "./jsm/controls/TrackballControls.js"; + import { WorkerTaskManager } from "./jsm/loaders/workerTaskManager/WorkerTaskManager.js"; import { DataTransport, GeometryTransport, MeshTransport, MaterialsTransport, - ObjectUtils + ObjectUtils, + DeUglify } from "./jsm/loaders/workerTaskManager/utils/TransportUtils.js" import { MaterialUtils } from "./jsm/loaders/workerTaskManager/utils/MaterialUtils.js" import { MaterialStore } from "./jsm/loaders/workerTaskManager/utils/MaterialStore.js" - import { FileLoader } from "../src/loaders/FileLoader.js"; - import { OBJLoaderWorker } from "./jsm/loaders/workerTaskManager/worker/tmOBJLoader.js"; + import { OBJLoaderWorker } from "./jsm/loaders/workerTaskManager/worker/tmOBJLoader.js" /** * The aim of this example is to show two possible ways how to use the {@link WorkerTaskManager}: @@ -66,7 +66,7 @@ this.objectsUsed = new Map(); - this.workerTaskManager = new WorkerTaskManager( 4 ).setVerbose( true ); + this.workerTaskManager = new WorkerTaskManager( 8 ).setVerbose( true ); this.tasksToUse = []; this.materialStore = new MaterialStore( true ); @@ -108,16 +108,16 @@ async initContent () { /** Simplest way to define a worker for {@link WorkerTaskManager} */ - const InlineWorker = { + class InlineWorker { - workerStandardInit: function ( context, id, config ) { + static init ( context, id, config ) { context.storage = { whoami: config.id }; context.postMessage( { cmd: "init", id: id } ); - }, + } - workerStandardExec: function ( context, id, config ) { + static execute ( context, id, config ) { let bufferGeometry = new THREE.SphereBufferGeometry( 40, 64, 64 ); bufferGeometry.name = 'InlineWorker' + config.id; @@ -128,19 +128,23 @@ .package( false ) .postMessage( context ); - }, - - buildStandardWorkerDependencies( threeJsLocation ) { + } + static buildStandardWorkerDependencies( threeJsLocation ) { return [ { url: threeJsLocation }, - { code: 'const BufferGeometry = THREE.BufferGeometry;\n' }, - { code: 'const EventDispatcher = THREE.EventDispatcher;\n' }, + { code: '\n\n' }, + { code: DeUglify.buildThreeConst() }, + { code: '\n\n' }, + { code: DeUglify.buildUglifiedThreeMapping() }, + { code: '\n\n' }, { code: ObjectUtils.serializeClass( DataTransport ) }, { code: ObjectUtils.serializeClass( GeometryTransport ) }, { code: ObjectUtils.serializeClass( MaterialUtils ) }, { code: ObjectUtils.serializeClass( MaterialsTransport ) }, - { code: ObjectUtils.serializeClass( MeshTransport ) } + { code: ObjectUtils.serializeClass( MeshTransport ) }, + { code: DeUglify.buildUglifiedThreeWtmMapping() }, + { code: '\n\n' } ]; } @@ -150,9 +154,9 @@ let awaiting = []; let taskDescr = { name: 'InlineWorker', - funcInit: InlineWorker.workerStandardInit, - funcExec: InlineWorker.workerStandardExec, - dependencies: InlineWorker.buildStandardWorkerDependencies( "../build/three.min.js" ) + funcInit: InlineWorker.init, + funcExec: InlineWorker.execute, + dependencies: InlineWorker.buildStandardWorkerDependencies( '../build/three.min.js' ) }; this.tasksToUse.push( taskDescr ); this.workerTaskManager.registerTaskType( taskDescr.name, taskDescr.funcInit, taskDescr.funcExec, null, false, taskDescr.dependencies ); @@ -168,7 +172,7 @@ this.tasksToUse.push( taskDescrObj ); this.workerTaskManager.registerTaskType( taskDescrObj.name, taskDescrObj.funcInit, taskDescrObj.funcExec, null, false, taskDescrObj.dependencies ); const loadObj = async function ( filenameObj ) { - let fileLoader = new FileLoader(); + let fileLoader = new THREE.FileLoader(); fileLoader.setResponseType( 'arraybuffer' ); return await fileLoader.loadAsync( filenameObj ); } @@ -181,7 +185,6 @@ .package( false ); awaiting.push( this.workerTaskManager.initTaskType( taskDescrObj.name, mt.getMain(), mt.getTransferables() ).catch( e => console.error( e ) ) ); } ); - return await Promise.all( awaiting ); } @@ -227,9 +230,6 @@ */ _processMessage ( payload ) { switch ( payload.cmd ) { - case 'init': - console.log( 'Init Completed: ' + payload.id ); - break; case 'assetAvailable': case 'execComplete':