From 90ee258d5f00fa46efc3263743b524423bffc1c5 Mon Sep 17 00:00:00 2001 From: Mugen87 Date: Wed, 3 Jul 2019 13:44:18 +0200 Subject: [PATCH] JSM: Added TS files for OBJLoader2 and fix style issues. --- examples/jsm/loaders/OBJLoader2.d.ts | 45 +++++++ examples/jsm/loaders/OBJLoader2.js | 50 +++++++- examples/jsm/loaders/OBJLoader2Parallel.d.ts | 17 +++ examples/jsm/loaders/OBJLoader2Parallel.js | 32 ++++- .../jsm/loaders/obj2/bridge/MtlObjBridge.d.ts | 4 + .../jsm/loaders/obj2/bridge/MtlObjBridge.js | 8 +- .../loaders/obj2/shared/MaterialHandler.d.ts | 22 ++++ .../loaders/obj2/shared/MaterialHandler.js | 25 +++- .../jsm/loaders/obj2/shared/MeshReceiver.d.ts | 22 ++++ .../jsm/loaders/obj2/shared/MeshReceiver.js | 29 ++++- .../loaders/obj2/utils/CodeSerializer.d.ts | 4 + .../jsm/loaders/obj2/utils/CodeSerializer.js | 11 +- .../loaders/obj2/utils/ObjectManipulator.d.ts | 3 + .../loaders/obj2/utils/ObjectManipulator.js | 6 +- .../worker/main/WorkerExecutionSupport.js | 83 ++++++++++++- .../obj2/worker/parallel/OBJLoader2Parser.js | 114 +++++++++++++++--- .../obj2/worker/parallel/WorkerRunner.js | 23 +++- 17 files changed, 449 insertions(+), 49 deletions(-) create mode 100644 examples/jsm/loaders/OBJLoader2.d.ts create mode 100644 examples/jsm/loaders/OBJLoader2Parallel.d.ts create mode 100644 examples/jsm/loaders/obj2/bridge/MtlObjBridge.d.ts create mode 100644 examples/jsm/loaders/obj2/shared/MaterialHandler.d.ts create mode 100644 examples/jsm/loaders/obj2/shared/MeshReceiver.d.ts create mode 100644 examples/jsm/loaders/obj2/utils/CodeSerializer.d.ts create mode 100644 examples/jsm/loaders/obj2/utils/ObjectManipulator.d.ts diff --git a/examples/jsm/loaders/OBJLoader2.d.ts b/examples/jsm/loaders/OBJLoader2.d.ts new file mode 100644 index 0000000000..5b50c42047 --- /dev/null +++ b/examples/jsm/loaders/OBJLoader2.d.ts @@ -0,0 +1,45 @@ +import { + LoadingManager, + Group +} from '../../../src/Three'; + +import { MaterialHandler } from './obj2/shared/MaterialHandler'; +import { MeshReceiver} from './obj2/shared/MeshReceiver'; + +export class OBJLoader2 { + constructor(manager?: LoadingManager); + manager: LoadingManager; + logging: { + enabled: boolean; + debug: boolean; + }; + modelName: string; + instanceNo: number; + path: string; + resourcePath: string; + useIndices: boolean; + disregardNormals: boolean; + materialPerSmoothingGroup: boolean; + useOAsMesh: boolean; + baseObject3d: Group; + callbacks: { + onParseProgress: Function; + genericErrorHandler: Function; + }; + materialHandler: MaterialHandler; + meshReceiver: MeshReceiver; + + addMaterials(materials: object): void; + load(url: string, onLoad: (group: Group) => void, onProgress?: (event: ProgressEvent) => void, onError?: (event: ErrorEvent) => void, onMeshAlter?: (meshData: object) => void): void; + parse(content: ArrayBuffer | string): void; + setLogging(enabled: boolean, debug: boolean): this; + setModelName(modelName: string): this; + setPath(path: string): this; + setResourcePath(path: string): this; + setBaseObject3d(baseObject3d: Object3D): this; + setUseIndices(useIndices: boolean): this; + setDisregardNormals(disregardNormals: boolean): this; + setMaterialPerSmoothingGroup(materialPerSmoothingGroup: boolean): this; + setUseOAsMesh(useOAsMesh: boolean): this; + setGenericErrorHandler(genericErrorHandler: Function): void; +} diff --git a/examples/jsm/loaders/OBJLoader2.js b/examples/jsm/loaders/OBJLoader2.js index 6ce071f22d..fb3edb5d73 100644 --- a/examples/jsm/loaders/OBJLoader2.js +++ b/examples/jsm/loaders/OBJLoader2.js @@ -20,6 +20,7 @@ import { MaterialHandler } from "./obj2/shared/MaterialHandler.js"; * @param {DefaultLoadingManager} [manager] The loadingManager for the loader to use. Default is {@link DefaultLoadingManager} */ const OBJLoader2 = function ( manager ) { + this.manager = ( manager !== undefined && manager !== null ) ? manager : DefaultLoadingManager; this.logging = { enabled: true, @@ -43,6 +44,7 @@ const OBJLoader2 = function ( manager ) { this.materialHandler = new MaterialHandler(); this.meshReceiver = new MeshReceiver( this.materialHandler ); + }; OBJLoader2.OBJLOADER2_VERSION = '3.0.0-beta2'; console.info( 'Using OBJLoader2 version: ' + OBJLoader2.OBJLOADER2_VERSION ); @@ -58,9 +60,11 @@ OBJLoader2.prototype = { * @param {boolean} debug True or false. */ setLogging: function ( enabled, debug ) { + this.logging.enabled = enabled === true; this.logging.debug = debug === true; return this; + }, /** @@ -69,8 +73,10 @@ OBJLoader2.prototype = { * @param {string} modelName */ setModelName: function ( modelName ) { + this.modelName = modelName ? modelName : this.modelName; return this; + }, /** @@ -79,8 +85,10 @@ OBJLoader2.prototype = { * @param {string} path URL */ setPath: function ( path ) { + this.path = path ? path : this.path; return this; + }, @@ -89,7 +97,9 @@ OBJLoader2.prototype = { * @param {string} resourcePath */ setResourcePath: function ( resourcePath ) { + this.resourcePath = resourcePath ? resourcePath : this.resourcePath; + }, /** @@ -98,8 +108,10 @@ OBJLoader2.prototype = { * @param {Object3D} baseObject3d Object already attached to scenegraph where new meshes will be attached to */ setBaseObject3d: function ( baseObject3d ) { + this.baseObject3d = ( baseObject3d === undefined || baseObject3d === null ) ? this.baseObject3d : baseObject3d; return this; + }, /** @@ -108,7 +120,9 @@ OBJLoader2.prototype = { * @param materials Object with named {@link Material} */ addMaterials: function ( materials ) { + this.materialHandler.addMaterials( materials ); + }, /** @@ -117,8 +131,10 @@ OBJLoader2.prototype = { * @param {boolean} useIndices=false */ setUseIndices: function ( useIndices ) { + this.useIndices = useIndices === true; return this; + }, /** @@ -127,8 +143,10 @@ OBJLoader2.prototype = { * @param {boolean} disregardNormals=false */ setDisregardNormals: function ( disregardNormals ) { + this.disregardNormals = disregardNormals === true; return this; + }, /** @@ -137,8 +155,10 @@ OBJLoader2.prototype = { * @param {boolean} materialPerSmoothingGroup=false */ setMaterialPerSmoothingGroup: function ( materialPerSmoothingGroup ) { + this.materialPerSmoothingGroup = materialPerSmoothingGroup === true; return this; + }, /** @@ -147,8 +167,10 @@ OBJLoader2.prototype = { * @param {boolean} useOAsMesh=false */ setUseOAsMesh: function ( useOAsMesh ) { + this.useOAsMesh = useOAsMesh === true; return this; + }, /** @@ -156,11 +178,13 @@ OBJLoader2.prototype = { * @param {Function} genericErrorHandler */ setGenericErrorHandler: function ( genericErrorHandler ) { + if ( genericErrorHandler !== undefined && genericErrorHandler !== null ) { this.callbacks.genericErrorHandler = genericErrorHandler; } + }, /** @@ -173,6 +197,7 @@ OBJLoader2.prototype = { * @private */ _setCallbacks: function ( onParseProgress, onMeshAlter, onLoadMaterials ) { + if ( onParseProgress !== undefined && onParseProgress !== null ) { this.callbacks.onParseProgress = onParseProgress; @@ -180,6 +205,7 @@ OBJLoader2.prototype = { } this.meshReceiver._setCallbacks( onParseProgress, onMeshAlter ); this.materialHandler._setCallbacks( onLoadMaterials ); + }, /** @@ -191,6 +217,7 @@ OBJLoader2.prototype = { * @param {number} numericalValue Numerical value describing the progress */ _onProgress: function ( type, text, numericalValue ) { + let message = text ? text : ''; let event = { detail: { @@ -211,6 +238,7 @@ OBJLoader2.prototype = { console.log( message ); } + }, /** @@ -220,6 +248,7 @@ OBJLoader2.prototype = { * @param {String} errorMessage The event containing the error */ _onError: function ( errorMessage ) { + if ( this.callbacks.genericErrorHandler ) { this.callbacks.genericErrorHandler( errorMessage ); @@ -243,6 +272,7 @@ OBJLoader2.prototype = { * @param {function} [onMeshAlter] Called after worker successfully delivered a single mesh */ load: function ( url, onLoad, onFileLoadProgress, onError, onMeshAlter ) { + let scope = this; if ( onError === null || onError === undefined ) { @@ -279,27 +309,32 @@ OBJLoader2.prototype = { let numericalValueRef = 0; let numericalValue = 0; onFileLoadProgress = function ( event ) { + if ( ! event.lengthComputable ) return; numericalValue = event.loaded / event.total; if ( numericalValue > numericalValueRef ) { numericalValueRef = numericalValue; - let output = 'Download of "' + url + '": ' + (numericalValue * 100).toFixed( 2 ) + '%'; + let output = 'Download of "' + url + '": ' + ( numericalValue * 100 ).toFixed( 2 ) + '%'; scope._onProgress( 'progressLoad', output, numericalValue ); } + }; } this._setCallbacks( null, onMeshAlter, null ); let fileLoaderOnLoad = function ( content ) { + onLoad( scope.parse( content ) ); + }; let fileLoader = new FileLoader( this.manager ); fileLoader.setPath( this.path || this.resourcePath ); fileLoader.setResponseType( 'arraybuffer' ); fileLoader.load( filename, fileLoaderOnLoad, onFileLoadProgress, onError ); + }, /** @@ -308,6 +343,7 @@ OBJLoader2.prototype = { * @param {arraybuffer|string} content OBJ data as Uint8Array or String */ parse: function ( content ) { + // fast-fail in case of illegal data if ( content === null || content === undefined ) { @@ -330,13 +366,19 @@ OBJLoader2.prototype = { let scope = this; let scopedOnAssetAvailable = function ( payload ) { + scope._onAssetAvailable( payload ); + }; let onProgressScoped = function ( text, numericalValue ) { + scope._onProgress( 'progressParse', text, numericalValue ); + }; let onErrorScoped = function ( message ) { + scope._onError( message ); + }; parser.setCallbackOnAssetAvailable( scopedOnAssetAvailable ); parser.setCallbackOnProgress( onProgressScoped ); @@ -346,7 +388,7 @@ OBJLoader2.prototype = { if ( this.logging.enabled ) console.info( 'Parsing arrayBuffer...' ); parser.parse( content ); - } else if ( typeof( content ) === 'string' || content instanceof String ) { + } else if ( typeof ( content ) === 'string' || content instanceof String ) { if ( this.logging.enabled ) console.info( 'Parsing text...' ); parser.parseText( content ); @@ -362,6 +404,7 @@ OBJLoader2.prototype = { } return this.baseObject3d; + }, _onAssetAvailable: function ( payload ) { @@ -372,7 +415,9 @@ OBJLoader2.prototype = { let meshes = this.meshReceiver.buildMeshes( payload ); for ( let mesh of meshes ) { + this.baseObject3d.add( mesh ); + } } else if ( payload.type === 'material' ) { @@ -380,6 +425,7 @@ OBJLoader2.prototype = { this.materialHandler.addPayloadMaterials( payload ); } + } }; diff --git a/examples/jsm/loaders/OBJLoader2Parallel.d.ts b/examples/jsm/loaders/OBJLoader2Parallel.d.ts new file mode 100644 index 0000000000..0912f866f8 --- /dev/null +++ b/examples/jsm/loaders/OBJLoader2Parallel.d.ts @@ -0,0 +1,17 @@ +import { + LoadingManager +} from '../../../src/Three'; +import { OBJLoader2 } from './OBJLoader2.js'; + +export class OBJLoader2Parallel extends OBJLoader2 { + constructor(manager?: LoadingManager); + preferJsmWorker: boolean; + executeParallel: boolean; + workerExecutionSupport: object; + + setPreferJsmWorker(preferJsmWorker: boolean): this; + setCallbackOnParseComplete(onParseComplete: Function): this; + setExecuteParallel(executeParallel: boolean): this; + getWorkerExecutionSupport(): object; + buildWorkerCode(): object; +} diff --git a/examples/jsm/loaders/OBJLoader2Parallel.js b/examples/jsm/loaders/OBJLoader2Parallel.js index 5b422252ea..5a30fbc37e 100644 --- a/examples/jsm/loaders/OBJLoader2Parallel.js +++ b/examples/jsm/loaders/OBJLoader2Parallel.js @@ -27,12 +27,14 @@ import { * @constructor */ const OBJLoader2Parallel = function ( manager ) { + OBJLoader2.call( this, manager ); this.preferJsmWorker = false; this.callbacks.onParseComplete = null; this.executeParallel = true; this.workerExecutionSupport = new WorkerExecutionSupport(); + }; OBJLoader2Parallel.prototype = Object.create( OBJLoader2.prototype ); OBJLoader2Parallel.prototype.constructor = OBJLoader2Parallel; @@ -42,8 +44,10 @@ console.info( 'Using OBJLoader2Parallel version: ' + OBJLoader2.OBJLOADER2_PARAL OBJLoader2Parallel.prototype.setPreferJsmWorker = function ( preferJsmWorker ) { + this.preferJsmWorker = preferJsmWorker === true; return this; + }; /** @@ -53,10 +57,14 @@ OBJLoader2Parallel.prototype.setPreferJsmWorker = function ( preferJsmWorker ) { * @return {OBJLoader2Parallel} */ OBJLoader2Parallel.prototype.setCallbackOnParseComplete = function ( onParseComplete ) { + if ( onParseComplete !== undefined && onParseComplete !== null ) { + this.callbacks.onParseComplete = onParseComplete; + } return this; + }; /** @@ -66,8 +74,10 @@ OBJLoader2Parallel.prototype.setCallbackOnParseComplete = function ( onParseComp * @return {OBJLoader2Parallel} */ OBJLoader2Parallel.prototype.setExecuteParallel = function ( executeParallel ) { + this.executeParallel = executeParallel === true; return this; + }; /** @@ -76,7 +86,9 @@ OBJLoader2Parallel.prototype.setExecuteParallel = function ( executeParallel ) { * @return {WorkerExecutionSupport|WorkerExecutionSupport} */ OBJLoader2Parallel.prototype.getWorkerExecutionSupport = function () { + return this.workerExecutionSupport; + }; /** @@ -85,6 +97,7 @@ OBJLoader2Parallel.prototype.getWorkerExecutionSupport = function () { * @return {CodeBuilderInstructions} */ OBJLoader2Parallel.prototype.buildWorkerCode = function () { + let codeBuilderInstructions = new CodeBuilderInstructions( true, true, this.preferJsmWorker ); if ( codeBuilderInstructions.isSupportsJsmWorker() ) { @@ -104,19 +117,23 @@ OBJLoader2Parallel.prototype.buildWorkerCode = function () { codeBuilderInstructions.addCodeFragment( codeWorkerRunner ); // allows to include full libraries as importScripts -// codeBuilderInstructions.addLibraryImport( '../../node_modules/three/build/three.js' ); + // codeBuilderInstructions.addLibraryImport( '../../node_modules/three/build/three.js' ); codeBuilderInstructions.addStartCode( 'new WorkerRunner( new DefaultWorkerPayloadHandler( new OBJLoader2Parser() ) );' ); } return codeBuilderInstructions; + }; /** * @private */ OBJLoader2Parallel.prototype._configure = function () { + if ( this.callbacks.onParseComplete === null ) { + throw "No callbackOnLoad was provided! Aborting!"; + } // check if worker is already available and if so, then fast-fail if ( this.workerExecutionSupport.isWorkerLoaded( this.preferJsmWorker ) ) return; @@ -125,10 +142,13 @@ OBJLoader2Parallel.prototype._configure = function () { let scope = this; let scopedOnAssetAvailable = function ( payload ) { + scope._onAssetAvailable( payload ); + }; this.workerExecutionSupport.updateCallbacks( scopedOnAssetAvailable, this.callbacks.onParseComplete ); + }; /** @@ -141,10 +161,12 @@ OBJLoader2Parallel.prototype._configure = function () { * @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 ) { +OBJLoader2Parallel.prototype.load = function ( content, onLoad, onFileLoadProgress, onError, onMeshAlter ) { + this.setCallbackOnParseComplete( onLoad ); OBJLoader2.prototype.load.call( this, content, function () {}, onFileLoadProgress, onError, onMeshAlter ); + }; /** @@ -152,7 +174,8 @@ OBJLoader2Parallel.prototype.load = function( content, onLoad, onFileLoadProgres * * @param {arraybuffer} content OBJ data as Uint8Array or String */ -OBJLoader2Parallel.prototype.parse = function( content ) { +OBJLoader2Parallel.prototype.parse = function ( content ) { + if ( this.executeParallel ) { this._configure(); @@ -183,6 +206,7 @@ OBJLoader2Parallel.prototype.parse = function( content ) { this.callbacks.onParseComplete( OBJLoader2.prototype.parse.call( this, content ) ); } + }; -export { OBJLoader2Parallel } +export { OBJLoader2Parallel }; diff --git a/examples/jsm/loaders/obj2/bridge/MtlObjBridge.d.ts b/examples/jsm/loaders/obj2/bridge/MtlObjBridge.d.ts new file mode 100644 index 0000000000..09e4fa33cc --- /dev/null +++ b/examples/jsm/loaders/obj2/bridge/MtlObjBridge.d.ts @@ -0,0 +1,4 @@ +export namespace MtlObjBridge { + export function link(processResult: object, assetLoader: object): void; + export function addMaterialsFromMtlLoader(materialCreator: object): void; +} diff --git a/examples/jsm/loaders/obj2/bridge/MtlObjBridge.js b/examples/jsm/loaders/obj2/bridge/MtlObjBridge.js index 0fccb28d2b..6544b2e1d9 100644 --- a/examples/jsm/loaders/obj2/bridge/MtlObjBridge.js +++ b/examples/jsm/loaders/obj2/bridge/MtlObjBridge.js @@ -13,12 +13,14 @@ const MtlObjBridge = { * @param processResult * @param assetLoader */ - link: function( processResult, assetLoader ) { + link: function ( processResult, assetLoader ) { + if ( typeof assetLoader.addMaterials === 'function' ) { assetLoader.addMaterials( this.addMaterialsFromMtlLoader( processResult ) ); } + }, /** @@ -27,6 +29,7 @@ const MtlObjBridge = { * @param Instance of {@link MTLLoader.MaterialCreator} */ addMaterialsFromMtlLoader: function ( materialCreator ) { + let newMaterials = {}; if ( materialCreator instanceof MTLLoader.MaterialCreator ) { @@ -35,7 +38,8 @@ const MtlObjBridge = { } return newMaterials; + } }; -export { MtlObjBridge } +export { MtlObjBridge }; diff --git a/examples/jsm/loaders/obj2/shared/MaterialHandler.d.ts b/examples/jsm/loaders/obj2/shared/MaterialHandler.d.ts new file mode 100644 index 0000000000..f4adb8b3b3 --- /dev/null +++ b/examples/jsm/loaders/obj2/shared/MaterialHandler.d.ts @@ -0,0 +1,22 @@ +import { + Material +} from '../../../../../src/Three'; + +export class MaterialHandler { + constructor(); + logging: { + enabled: boolean; + debug: boolean; + }; + callbacks: { + onLoadMaterials: Function; + }; + materials: object; + + addMaterials(materials: object, newMaterials: object): object; + addPayloadMaterials(materialPayload: object): object; + setLogging(enabled: boolean, debug: boolean): void; + getMaterials(): object; + getMaterial(materialName: string): Material; + getMaterialsJSON(): object; +} diff --git a/examples/jsm/loaders/obj2/shared/MaterialHandler.js b/examples/jsm/loaders/obj2/shared/MaterialHandler.js index 955f951179..bc6f58cb30 100644 --- a/examples/jsm/loaders/obj2/shared/MaterialHandler.js +++ b/examples/jsm/loaders/obj2/shared/MaterialHandler.js @@ -13,6 +13,7 @@ import { const MaterialHandler = function () { + this.logging = { enabled: true, debug: false @@ -23,6 +24,7 @@ const MaterialHandler = function () { }; this.materials = {}; this._createDefaultMaterials(); + }; MaterialHandler.prototype = { @@ -36,19 +38,24 @@ MaterialHandler.prototype = { * @param {boolean} debug True or false. */ setLogging: function ( enabled, debug ) { + this.logging.enabled = enabled === true; this.logging.debug = debug === true; + }, _setCallbacks: function ( onLoadMaterials ) { + if ( onLoadMaterials !== undefined && onLoadMaterials !== null ) { this.callbacks.onLoadMaterials = onLoadMaterials; } + }, _createDefaultMaterials: function () { + let defaultMaterial = new MeshStandardMaterial( { color: 0xDCF1FF } ); defaultMaterial.name = 'defaultMaterial'; @@ -69,6 +76,7 @@ MaterialHandler.prototype = { runtimeMaterials[ defaultPointMaterial.name ] = defaultPointMaterial; this.addMaterials( runtimeMaterials ); + }, /** @@ -78,6 +86,7 @@ MaterialHandler.prototype = { * @returns {Object} Map of {@link Material} */ addPayloadMaterials: function ( materialPayload ) { + let material, materialName; let materialCloneInstructions = materialPayload.materials.materialCloneInstructions; let newMaterials = {}; @@ -85,9 +94,10 @@ MaterialHandler.prototype = { if ( materialCloneInstructions !== undefined && materialCloneInstructions !== null ) { let materialNameOrg = materialCloneInstructions.materialNameOrg; - materialNameOrg = (materialNameOrg !== undefined && materialNameOrg !== null) ? materialNameOrg : ""; + materialNameOrg = ( materialNameOrg !== undefined && materialNameOrg !== null ) ? materialNameOrg : ""; let materialOrg = this.materials[ materialNameOrg ]; if ( materialOrg ) { + material = materialOrg.clone(); materialName = materialCloneInstructions.materialName; @@ -111,6 +121,7 @@ MaterialHandler.prototype = { console.info( 'Requested material "' + materialNameOrg + '" is not available!' ); } + } let materials = materialPayload.materials.serializedMaterials; @@ -137,6 +148,7 @@ MaterialHandler.prototype = { newMaterials = this.addMaterials( materials, newMaterials ); return newMaterials; + }, /** @@ -146,6 +158,7 @@ MaterialHandler.prototype = { * @param newMaterials [Object] with named {@link Material} */ addMaterials: function ( materials, newMaterials ) { + if ( newMaterials === undefined || newMaterials === null ) { newMaterials = {}; @@ -165,6 +178,7 @@ MaterialHandler.prototype = { } return newMaterials; + }, /** @@ -173,7 +187,9 @@ MaterialHandler.prototype = { * @returns {Object} Map of {@link Material} */ getMaterials: function () { + return this.materials; + }, /** @@ -182,7 +198,9 @@ MaterialHandler.prototype = { * @returns {Material} */ getMaterial: function ( materialName ) { + return this.materials[ materialName ]; + }, /** @@ -191,17 +209,20 @@ MaterialHandler.prototype = { * @returns {Object} Map of Materials in JSON representation */ getMaterialsJSON: function () { + let materialsJSON = {}; let material; for ( let materialName in this.materials ) { material = this.materials[ materialName ]; materialsJSON[ materialName ] = material.toJSON(); + } return materialsJSON; + } }; -export { MaterialHandler } +export { MaterialHandler }; diff --git a/examples/jsm/loaders/obj2/shared/MeshReceiver.d.ts b/examples/jsm/loaders/obj2/shared/MeshReceiver.d.ts new file mode 100644 index 0000000000..540021972c --- /dev/null +++ b/examples/jsm/loaders/obj2/shared/MeshReceiver.d.ts @@ -0,0 +1,22 @@ +import { + Mesh +} from '../../../../../src/Three'; + +import { MaterialHandler } from './MaterialHandler' + +export class MeshReceiver { + constructor(materialHandler: MaterialHandler); + logging: { + enabled: boolean; + debug: boolean; + }; + callbacks: { + onParseProgress: Function; + onMeshAlter: Function; + }; + materialHandler: MaterialHandler; + + buildMeshes(meshPayload: object): Mesh[]; + setLogging(enabled: boolean, debug: boolean): void; + +} diff --git a/examples/jsm/loaders/obj2/shared/MeshReceiver.js b/examples/jsm/loaders/obj2/shared/MeshReceiver.js index 98fb877dec..ed18b330fe 100644 --- a/examples/jsm/loaders/obj2/shared/MeshReceiver.js +++ b/examples/jsm/loaders/obj2/shared/MeshReceiver.js @@ -17,7 +17,8 @@ import { * @param {MaterialHandler} materialHandler * @constructor */ -const MeshReceiver = function( materialHandler ) { +const MeshReceiver = function ( materialHandler ) { + this.logging = { enabled: true, debug: false @@ -28,6 +29,7 @@ const MeshReceiver = function( materialHandler ) { onMeshAlter: null }; this.materialHandler = materialHandler; + }; MeshReceiver.prototype = { @@ -41,8 +43,10 @@ MeshReceiver.prototype = { * @param {boolean} debug True or false. */ setLogging: function ( enabled, debug ) { + this.logging.enabled = enabled === true; this.logging.debug = debug === true; + }, /** @@ -52,6 +56,7 @@ MeshReceiver.prototype = { * @private */ _setCallbacks: function ( onParseProgress, onMeshAlter ) { + if ( onParseProgress !== undefined && onParseProgress !== null ) { this.callbacks.onParseProgress = onParseProgress; @@ -62,6 +67,7 @@ MeshReceiver.prototype = { this.callbacks.onMeshAlter = onMeshAlter; } + }, /** @@ -71,6 +77,7 @@ MeshReceiver.prototype = { * @returns {Mesh[]} mesh Array of {@link Mesh} */ buildMeshes: function ( meshPayload ) { + let meshName = meshPayload.params.meshName; let bufferGeometry = new BufferGeometry(); @@ -80,7 +87,7 @@ MeshReceiver.prototype = { bufferGeometry.setIndex( new BufferAttribute( new Uint32Array( meshPayload.buffers.indices ), 1 ) ); } - let haveVertexColors = meshPayload.buffers.colors !== null; + let haveVertexColors = meshPayload.buffers.colors !== null; if ( haveVertexColors ) { bufferGeometry.addAttribute( 'color', new BufferAttribute( new Float32Array( meshPayload.buffers.colors ), 3 ) ); @@ -95,7 +102,7 @@ MeshReceiver.prototype = { bufferGeometry.computeVertexNormals(); } - if ( meshPayload.buffers.uvs !== null ) { + if ( meshPayload.buffers.uvs !== null ) { bufferGeometry.addAttribute( 'uv', new BufferAttribute( new Float32Array( meshPayload.buffers.uvs ), 2 ) ); @@ -155,6 +162,7 @@ MeshReceiver.prototype = { } } ); + } // here LoadedMeshUserOverride is required to be provided by the callback used to alter the results @@ -208,12 +216,12 @@ MeshReceiver.prototype = { } progressMessage += ': Adding mesh(es) (' + meshNames.length + ': ' + meshNames + ') from input mesh: ' + meshName; - progressMessage += ' (' + ( meshPayload.progress.numericalValue * 100).toFixed( 2 ) + '%)'; + progressMessage += ' (' + ( meshPayload.progress.numericalValue * 100 ).toFixed( 2 ) + '%)'; } else { progressMessage += ': Not adding mesh: ' + meshName; - progressMessage += ' (' + ( meshPayload.progress.numericalValue * 100).toFixed( 2 ) + '%)'; + progressMessage += ' (' + ( meshPayload.progress.numericalValue * 100 ).toFixed( 2 ) + '%)'; } let callbackOnParseProgress = this.callbacks.onParseProgress; @@ -224,6 +232,7 @@ MeshReceiver.prototype = { } return meshes; + } }; @@ -235,10 +244,12 @@ MeshReceiver.prototype = { * @param {boolean} disregardMesh=false Tell implementation to completely disregard this mesh * @param {boolean} disregardMesh=false Tell implementation that mesh(es) have been altered or added */ -const LoadedMeshUserOverride = function( disregardMesh, alteredMesh ) { +const LoadedMeshUserOverride = function ( disregardMesh, alteredMesh ) { + this.disregardMesh = disregardMesh === true; this.alteredMesh = alteredMesh === true; this.meshes = []; + }; @@ -252,8 +263,10 @@ LoadedMeshUserOverride.prototype = { * @param {Mesh} mesh */ addMesh: function ( mesh ) { + this.meshes.push( mesh ); this.alteredMesh = true; + }, /** @@ -262,7 +275,9 @@ LoadedMeshUserOverride.prototype = { * @returns {boolean} */ isDisregardMesh: function () { + return this.disregardMesh; + }, /** @@ -271,7 +286,9 @@ LoadedMeshUserOverride.prototype = { * @returns {boolean} */ providesAlteredMeshes: function () { + return this.alteredMesh; + } }; diff --git a/examples/jsm/loaders/obj2/utils/CodeSerializer.d.ts b/examples/jsm/loaders/obj2/utils/CodeSerializer.d.ts new file mode 100644 index 0000000000..73c0af6e26 --- /dev/null +++ b/examples/jsm/loaders/obj2/utils/CodeSerializer.d.ts @@ -0,0 +1,4 @@ +export namespace CodeSerializer { + export function serializeObject(fullName: string, object: object): string; + export function serializeClass(fullName: string, object: object, constructorName?: string, basePrototypeName?: string, ignoreFunctions?: string[], includeFunctions?: string[], overrideFunctions?: string[]): string; +} diff --git a/examples/jsm/loaders/obj2/utils/CodeSerializer.js b/examples/jsm/loaders/obj2/utils/CodeSerializer.js index 94e2525c14..a5c3d7d370 100644 --- a/examples/jsm/loaders/obj2/utils/CodeSerializer.js +++ b/examples/jsm/loaders/obj2/utils/CodeSerializer.js @@ -12,12 +12,13 @@ const CodeSerializer = { * @returns {string} */ serializeObject: function ( fullName, object ) { + let objectString = fullName + ' = {\n\n'; let part; for ( let name in object ) { part = object[ name ]; - if ( typeof( part ) === 'string' || part instanceof String ) { + if ( typeof ( part ) === 'string' || part instanceof String ) { part = part.replace( '\n', '\\n' ); part = part.replace( '\r', '\\r' ); @@ -42,6 +43,7 @@ const CodeSerializer = { objectString += '}\n\n'; return objectString; + }, /** @@ -53,6 +55,7 @@ const CodeSerializer = { * @returns {string} */ serializeClass: function ( fullName, object, constructorName, basePrototypeName, ignoreFunctions, includeFunctions, overrideFunctions ) { + let valueString, objectPart, constructorString, i, funcOverride; let prototypeFunctions = []; let objectProperties = []; @@ -90,6 +93,7 @@ const CodeSerializer = { prototypeFunctions.push( '\t' + name + ': ' + valueString + ',\n\n' ); } + } } @@ -119,7 +123,7 @@ const CodeSerializer = { } else { - if ( typeof( objectPart ) === 'string' || objectPart instanceof String) { + if ( typeof ( objectPart ) === 'string' || objectPart instanceof String ) { valueString = '\"' + objectPart.toString() + '\"'; @@ -172,7 +176,8 @@ const CodeSerializer = { objectString += '\n\n'; return objectString; + }, }; -export { CodeSerializer } +export { CodeSerializer }; diff --git a/examples/jsm/loaders/obj2/utils/ObjectManipulator.d.ts b/examples/jsm/loaders/obj2/utils/ObjectManipulator.d.ts new file mode 100644 index 0000000000..46332a72ba --- /dev/null +++ b/examples/jsm/loaders/obj2/utils/ObjectManipulator.d.ts @@ -0,0 +1,3 @@ +export namespace ObjectManipulator { + export function applyProperties(objToAlter: object, params: object, forceCreation: boolean): void; +} diff --git a/examples/jsm/loaders/obj2/utils/ObjectManipulator.js b/examples/jsm/loaders/obj2/utils/ObjectManipulator.js index 0f7f157523..190b427f08 100644 --- a/examples/jsm/loaders/obj2/utils/ObjectManipulator.js +++ b/examples/jsm/loaders/obj2/utils/ObjectManipulator.js @@ -12,11 +12,13 @@ const ObjectManipulator = { * @param {Object} params The parameter object */ applyProperties: function ( objToAlter, params, forceCreation ) { + // fast-fail if ( objToAlter === undefined || objToAlter === null || params === undefined || params === null ) return; var property, funcName, values; for ( property in params ) { + funcName = 'set' + property.substring( 0, 1 ).toLocaleUpperCase() + property.substring( 1 ); values = params[ property ]; @@ -29,8 +31,10 @@ const ObjectManipulator = { objToAlter[ property ] = values; } + } + } }; -export { ObjectManipulator } +export { ObjectManipulator }; diff --git a/examples/jsm/loaders/obj2/worker/main/WorkerExecutionSupport.js b/examples/jsm/loaders/obj2/worker/main/WorkerExecutionSupport.js index a6a2efdfa4..b378913a94 100644 --- a/examples/jsm/loaders/obj2/worker/main/WorkerExecutionSupport.js +++ b/examples/jsm/loaders/obj2/worker/main/WorkerExecutionSupport.js @@ -11,6 +11,7 @@ * @constructor */ const CodeBuilderInstructions = function ( supportsStandardWorker, supportsJsmWorker, preferJsmWorker ) { + this.supportsStandardWorker = supportsStandardWorker; this.supportsJsmWorker = supportsJsmWorker; this.preferJsmWorker = preferJsmWorker; @@ -20,6 +21,7 @@ const CodeBuilderInstructions = function ( supportsStandardWorker, supportsJsmWo this.jsmWorkerFile = null; this.defaultGeometryType = 0; + }; CodeBuilderInstructions.prototype = { @@ -27,15 +29,21 @@ CodeBuilderInstructions.prototype = { constructor: CodeBuilderInstructions, isSupportsStandardWorker: function () { + return this.supportsStandardWorker; + }, isSupportsJsmWorker: function () { + return this.supportsJsmWorker; + }, isPreferJsmWorker: function () { + return this.preferJsmWorker; + }, /** @@ -44,9 +52,13 @@ CodeBuilderInstructions.prototype = { * @param {String} jsmWorkerFile */ setJsmWorkerFile: function ( jsmWorkerFile ) { + if ( jsmWorkerFile !== undefined && jsmWorkerFile !== null ) { + this.jsmWorkerFile = jsmWorkerFile; + } + }, /** @@ -54,7 +66,9 @@ CodeBuilderInstructions.prototype = { * @param {String} startCode */ addStartCode: function ( startCode ) { + this.startCode = startCode; + }, /** @@ -62,7 +76,9 @@ CodeBuilderInstructions.prototype = { * @param {String} code */ addCodeFragment: function ( code ) { + this.codeFragments.push( code ); + }, /** @@ -70,21 +86,29 @@ CodeBuilderInstructions.prototype = { * @param {String} libraryPath */ addLibraryImport: function ( libraryPath ) { + let libraryUrl = new URL( libraryPath, window.location.href ).href; let code = 'importScripts( "' + libraryUrl + '" );'; this.importStatements.push( code ); + }, getImportStatements: function () { + return this.importStatements; + }, getCodeFragments: function () { + return this.codeFragments; + }, getStartCode: function () { + return this.startCode; + } }; @@ -94,12 +118,14 @@ CodeBuilderInstructions.prototype = { * @class */ const WorkerExecutionSupport = 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!"; this._reset(); + }; WorkerExecutionSupport.WORKER_SUPPORT_VERSION = '3.0.0-beta2'; console.info( 'Using WorkerSupport version: ' + WorkerExecutionSupport.WORKER_SUPPORT_VERSION ); @@ -110,14 +136,17 @@ WorkerExecutionSupport.prototype = { constructor: WorkerExecutionSupport, _reset: function () { + this.logging = { enabled: true, debug: false }; let scope = this; - let scopeTerminate = function ( ) { + let scopeTerminate = function ( ) { + scope._terminate(); + }; this.worker = { native: null, @@ -138,6 +167,7 @@ WorkerExecutionSupport.prototype = { terminate: scopeTerminate } }; + }, /** @@ -147,10 +177,12 @@ WorkerExecutionSupport.prototype = { * @param {boolean} debug True or false. */ setLogging: function ( enabled, debug ) { + this.logging.enabled = enabled === true; this.logging.debug = debug === true; this.worker.logging = enabled === true; return this; + }, /** @@ -159,8 +191,10 @@ WorkerExecutionSupport.prototype = { * @param {boolean} forceWorkerDataCopy True or false. */ setForceWorkerDataCopy: function ( forceWorkerDataCopy ) { + this.worker.forceWorkerDataCopy = forceWorkerDataCopy === true; return this; + }, /** @@ -169,6 +203,7 @@ WorkerExecutionSupport.prototype = { * @param {boolean} terminateWorkerOnLoad True or false. */ setTerminateWorkerOnLoad: function ( terminateWorkerOnLoad ) { + this.worker.terminateWorkerOnLoad = terminateWorkerOnLoad === true; if ( this.worker.terminateWorkerOnLoad && this.isWorkerLoaded( this.worker.jsmWorker ) && this.worker.queuedMessage === null && this.worker.started ) { @@ -182,6 +217,7 @@ WorkerExecutionSupport.prototype = { } return this; + }, /** @@ -191,6 +227,7 @@ WorkerExecutionSupport.prototype = { * @param {Function} [onLoad] The function that is called when parsing is complete. */ updateCallbacks: function ( onAssetAvailable, onLoad ) { + if ( onAssetAvailable !== undefined && onAssetAvailable !== null ) { this.worker.callbacks.onAssetAvailable = onAssetAvailable; @@ -202,14 +239,17 @@ WorkerExecutionSupport.prototype = { } this._verifyCallbacks(); + }, _verifyCallbacks: function () { + if ( this.worker.callbacks.onAssetAvailable === undefined || this.worker.callbacks.onAssetAvailable === null ) { throw 'Unable to run as no "onAssetAvailable" callback is set.'; } + }, /** @@ -219,10 +259,13 @@ WorkerExecutionSupport.prototype = { * @param {CodeBuilderInstructions} codeBuilderInstructions */ buildWorker: function ( codeBuilderInstructions ) { + let jsmSuccess = false; if ( codeBuilderInstructions.isSupportsJsmWorker() && codeBuilderInstructions.isPreferJsmWorker() ) { + jsmSuccess = this._buildWorkerJsm( codeBuilderInstructions ); + } if ( ! jsmSuccess && codeBuilderInstructions.isSupportsStandardWorker() ) { @@ -230,6 +273,7 @@ WorkerExecutionSupport.prototype = { this._buildWorkerStandard( codeBuilderInstructions ); } + }, /** @@ -239,6 +283,7 @@ WorkerExecutionSupport.prototype = { * @private */ _buildWorkerJsm: function ( codeBuilderInstructions ) { + let jsmSuccess = true; let timeLabel = 'buildWorkerJsm'; let workerAvailable = this._buildWorkerCheckPreconditions( true, timeLabel ); @@ -250,8 +295,7 @@ WorkerExecutionSupport.prototype = { let worker = new Worker( workerFileUrl, { type: "module" } ); this._configureWorkerCommunication( worker, true, codeBuilderInstructions.defaultGeometryType, timeLabel ); - } - catch ( e ) { + } catch ( e ) { jsmSuccess = false; // Chrome throws this exception, but Firefox currently does not complain, but can't execute the worker afterwards @@ -260,11 +304,13 @@ WorkerExecutionSupport.prototype = { console.error( "Modules are not supported in workers." ); } + } } return jsmSuccess; + }, /** @@ -279,17 +325,22 @@ WorkerExecutionSupport.prototype = { * @private */ _buildWorkerStandard: function ( codeBuilderInstructions ) { + let timeLabel = 'buildWorkerStandard'; let workerAvailable = this._buildWorkerCheckPreconditions( false, timeLabel ); if ( ! workerAvailable ) { let concatenateCode = ''; codeBuilderInstructions.getImportStatements().forEach( function ( element ) { + concatenateCode += element + '\n'; + } ); concatenateCode += '\n'; codeBuilderInstructions.getCodeFragments().forEach( function ( element ) { + concatenateCode += element + '\n'; + } ); concatenateCode += '\n'; concatenateCode += codeBuilderInstructions.getStartCode(); @@ -300,15 +351,18 @@ WorkerExecutionSupport.prototype = { this._configureWorkerCommunication( worker, false, codeBuilderInstructions.defaultGeometryType, timeLabel ); } + }, _buildWorkerCheckPreconditions: function ( requireJsmWorker, timeLabel ) { + let workerAvailable = false; if ( this.isWorkerLoaded( requireJsmWorker ) ) { workerAvailable = true; } else { + if ( this.logging.enabled ) { console.info( 'WorkerExecutionSupport: Building ' + ( requireJsmWorker ? 'jsm' : 'standard' ) + ' worker code...' ); @@ -318,20 +372,25 @@ WorkerExecutionSupport.prototype = { } return workerAvailable; + }, _configureWorkerCommunication: function ( worker, haveJsmWorker, defaultGeometryType, timeLabel ) { + this.worker.native = worker; this.worker.jsmWorker = haveJsmWorker; let scope = this; let scopedReceiveWorkerMessage = function ( event ) { + scope._receiveWorkerMessage( event ); + }; this.worker.native.onmessage = scopedReceiveWorkerMessage; if ( defaultGeometryType !== undefined && defaultGeometryType !== null ) { this.worker.workerRunner.defaultGeometryType = defaultGeometryType; + } if ( this.logging.enabled ) { @@ -339,6 +398,7 @@ WorkerExecutionSupport.prototype = { console.timeEnd( timeLabel ); } + }, /** @@ -347,18 +407,22 @@ WorkerExecutionSupport.prototype = { * @return {boolean|*} */ isWorkerLoaded: function ( requireJsmWorker ) { + return this.worker.native !== null && ( ( requireJsmWorker && this.worker.jsmWorker ) || ( ! requireJsmWorker && ! this.worker.jsmWorker ) ); + }, /** * Executed in worker scope */ _receiveWorkerMessage: function ( event ) { + let payload = event.data; let workerRunnerName = this.worker.workerRunner.name; switch ( payload.cmd ) { + case 'assetAvailable': this.worker.callbacks.onAssetAvailable( payload ); break; @@ -401,6 +465,7 @@ WorkerExecutionSupport.prototype = { break; } + }, /** @@ -408,16 +473,19 @@ WorkerExecutionSupport.prototype = { * * @param {Object} payload Raw mesh description (buffers, params, materials) used to build one to many meshes. */ - executeParallel: function( payload, transferables ) { + executeParallel: function ( payload, transferables ) { + payload.cmd = 'parse'; payload.usesMeshDisassembler = this.worker.workerRunner.usesMeshDisassembler; payload.defaultGeometryType = this.worker.workerRunner.defaultGeometryType; if ( ! this._verifyWorkerIsAvailable( payload, transferables ) ) return; this._postMessage(); + }, _verifyWorkerIsAvailable: function ( payload, transferables ) { + this._verifyCallbacks(); let ready = true; if ( this.worker.queuedMessage !== null ) { @@ -435,9 +503,11 @@ WorkerExecutionSupport.prototype = { } return ready; + }, _postMessage: function () { + if ( this.worker.queuedMessage !== null ) { if ( this.worker.queuedMessage.payload.data.input instanceof ArrayBuffer ) { @@ -466,15 +536,18 @@ WorkerExecutionSupport.prototype = { } } + }, _terminate: function () { + this.worker.native.terminate(); this._reset(); + } }; export { CodeBuilderInstructions, WorkerExecutionSupport -} +}; diff --git a/examples/jsm/loaders/obj2/worker/parallel/OBJLoader2Parser.js b/examples/jsm/loaders/obj2/worker/parallel/OBJLoader2Parser.js index c334eee829..20ccc506e9 100644 --- a/examples/jsm/loaders/obj2/worker/parallel/OBJLoader2Parser.js +++ b/examples/jsm/loaders/obj2/worker/parallel/OBJLoader2Parser.js @@ -6,7 +6,8 @@ * Parse OBJ data either from ArrayBuffer or string * @class */ -const OBJLoader2Parser = function() { +const OBJLoader2Parser = function () { + this.callbacks = { onProgress: null, onAssetAvailable: null, @@ -64,6 +65,7 @@ const OBJLoader2Parser = function() { enabled: true, debug: false }; + }; OBJLoader2Parser.prototype = { @@ -71,6 +73,7 @@ OBJLoader2Parser.prototype = { constructor: OBJLoader2Parser, resetRawMesh: function () { + // faces are stored according combined index of group, material and smoothingGroup (0 or not) this.rawMesh.subGroups = []; this.rawMesh.subGroupInUse = null; @@ -84,66 +87,88 @@ OBJLoader2Parser.prototype = { this.rawMesh.counts.faceCount = 0; this.rawMesh.counts.mtlCount = 0; this.rawMesh.counts.smoothingGroupCount = 0; + }, setMaterialPerSmoothingGroup: function ( materialPerSmoothingGroup ) { + this.materialPerSmoothingGroup = materialPerSmoothingGroup; + }, setUseOAsMesh: function ( useOAsMesh ) { + this.useOAsMesh = useOAsMesh; + }, setUseIndices: function ( useIndices ) { + this.useIndices = useIndices; + }, setDisregardNormals: function ( disregardNormals ) { + this.disregardNormals = disregardNormals; + }, setMaterials: function ( materials ) { + if ( materials === undefined || materials === null ) return; for ( let materialName in materials ) { + if ( materials.hasOwnProperty( materialName ) ) { this.materials[ materialName ] = materials[ materialName ]; } + } + }, setCallbackOnAssetAvailable: function ( onAssetAvailable ) { + if ( onAssetAvailable !== null && onAssetAvailable !== undefined ) { this.callbacks.onAssetAvailable = onAssetAvailable; } + }, setCallbackOnProgress: function ( onProgress ) { + if ( onProgress !== null && onProgress !== undefined ) { this.callbacks.onProgress = onProgress; } + }, setCallbackOnError: function ( onError ) { + if ( onError !== null && onError !== undefined ) { this.callbacks.onError = onError; } + }, setLogging: function ( enabled, debug ) { + this.logging.enabled = enabled === true; this.logging.debug = debug === true; + }, configure: function () { + if ( this.callbacks.onAssetAvailable === null ) { let errorMessage = 'Unable to run as no callback for building meshes is set.'; @@ -154,6 +179,7 @@ OBJLoader2Parser.prototype = { } else { throw errorMessage; + } } @@ -161,7 +187,7 @@ OBJLoader2Parser.prototype = { if ( this.logging.enabled ) { let matKeys = Object.keys( this.materials ); - let matNames = (matKeys.length > 0) ? '\n\tmaterialNames:\n\t\t- ' + matKeys.join( '\n\t\t- ' ) : '\n\tmaterialNames: None'; + let matNames = ( matKeys.length > 0 ) ? '\n\tmaterialNames:\n\t\t- ' + matKeys.join( '\n\t\t- ' ) : '\n\tmaterialNames: None'; let printedConfig = 'OBJLoader.Parser configuration:' + matNames + '\n\tmaterialPerSmoothingGroup: ' + this.materialPerSmoothingGroup @@ -169,17 +195,24 @@ OBJLoader2Parser.prototype = { + '\n\tuseIndices: ' + this.useIndices + '\n\tdisregardNormals: ' + this.disregardNormals; if ( this.callbacks.onProgress !== null ) { + printedConfig += '\n\tcallbacks.onProgress: ' + this.callbacks.onProgress.name; + } if ( this.callbacks.onAssetAvailable !== null ) { + printedConfig += '\n\tcallbacks.onAssetAvailable: ' + this.callbacks.onAssetAvailable.name; + } if ( this.callbacks.onError !== null ) { + printedConfig += '\n\tcallbacks.onError: ' + this.callbacks.onError.name; + } console.info( printedConfig ); } + }, /** @@ -188,6 +221,7 @@ OBJLoader2Parser.prototype = { * @param {Uint8Array} arrayBuffer OBJ data as Uint8Array */ parse: function ( arrayBuffer ) { + if ( this.logging.enabled ) console.time( 'OBJLoader.Parser.parse' ); this.configure(); @@ -201,6 +235,7 @@ OBJLoader2Parser.prototype = { code = arrayBufferView[ i ]; switch ( code ) { + // space case 32: if ( word.length > 0 ) buffer[ bufferPointer ++ ] = word; @@ -231,10 +266,13 @@ OBJLoader2Parser.prototype = { default: word += String.fromCharCode( code ); break; + } + } this.finalizeParsing(); if ( this.logging.enabled ) console.timeEnd( 'OBJLoader.Parser.parse' ); + }, /** @@ -243,6 +281,7 @@ OBJLoader2Parser.prototype = { * @param {string} text OBJ data as string */ parseText: function ( text ) { + if ( this.logging.enabled ) console.time( 'OBJLoader.Parser.parseText' ); this.configure(); this.legacyMode = true; @@ -255,6 +294,7 @@ OBJLoader2Parser.prototype = { char = text[ i ]; switch ( char ) { + case ' ': if ( word.length > 0 ) buffer[ bufferPointer ++ ] = word; word = ''; @@ -281,16 +321,21 @@ OBJLoader2Parser.prototype = { default: word += char; + } + } this.finalizeParsing(); if ( this.logging.enabled ) console.timeEnd( 'OBJLoader.Parser.parseText' ); + }, processLine: function ( buffer, bufferPointer, slashesCount ) { + if ( bufferPointer < 1 ) return; let reconstructString = function ( content, legacyMode, start, stop ) { + let line = ''; if ( stop > start ) { @@ -309,11 +354,13 @@ OBJLoader2Parser.prototype = { } return line; + }; let bufferLength, length, i, lineDesignation; - lineDesignation = buffer [ 0 ]; + lineDesignation = buffer[ 0 ]; switch ( lineDesignation ) { + case 'v': this.vertices.push( parseFloat( buffer[ 1 ] ) ); this.vertices.push( parseFloat( buffer[ 2 ] ) ); @@ -354,6 +401,7 @@ OBJLoader2Parser.prototype = { } // "f vertex/uv ..." + } else if ( bufferLength === slashesCount * 2 ) { this.checkFaceType( 1 ); @@ -366,6 +414,7 @@ OBJLoader2Parser.prototype = { } // "f vertex/uv/normal ..." + } else if ( bufferLength * 2 === slashesCount * 3 ) { this.checkFaceType( 2 ); @@ -378,6 +427,7 @@ OBJLoader2Parser.prototype = { } // "f vertex//normal ..." + } else { this.checkFaceType( 3 ); @@ -402,7 +452,7 @@ OBJLoader2Parser.prototype = { } else { - this.checkFaceType( (lineDesignation === 'l') ? 5 : 6 ); + this.checkFaceType( ( lineDesignation === 'l' ) ? 5 : 6 ); for ( i = 1, length = bufferLength + 1; i < length; i ++ ) this.buildFace( buffer[ i ] ); } @@ -441,17 +491,22 @@ OBJLoader2Parser.prototype = { default: break; + } + }, pushSmoothingGroup: function ( smoothingGroup ) { + let smoothingGroupInt = parseInt( smoothingGroup ); if ( isNaN( smoothingGroupInt ) ) { + smoothingGroupInt = smoothingGroup === "off" ? 0 : 1; + } let smoothCheck = this.rawMesh.smoothingGroup.normalized; - this.rawMesh.smoothingGroup.normalized = this.rawMesh.smoothingGroup.splitMaterials ? smoothingGroupInt : (smoothingGroupInt === 0) ? 0 : 1; + this.rawMesh.smoothingGroup.normalized = this.rawMesh.smoothingGroup.splitMaterials ? smoothingGroupInt : ( smoothingGroupInt === 0 ) ? 0 : 1; this.rawMesh.smoothingGroup.real = smoothingGroupInt; if ( smoothCheck !== smoothingGroupInt ) { @@ -460,6 +515,7 @@ OBJLoader2Parser.prototype = { this.checkSubGroup(); } + }, /** @@ -473,6 +529,7 @@ OBJLoader2Parser.prototype = { * faceType = 6: "p vertex ..." */ checkFaceType: function ( faceType ) { + if ( this.rawMesh.faceType !== faceType ) { this.processCompletedMesh(); @@ -480,9 +537,11 @@ OBJLoader2Parser.prototype = { this.checkSubGroup(); } + }, checkSubGroup: function () { + let index = this.rawMesh.activeMtlName + '|' + this.rawMesh.smoothingGroup.normalized; this.rawMesh.subGroupInUse = this.rawMesh.subGroups[ index ]; @@ -505,15 +564,17 @@ OBJLoader2Parser.prototype = { this.rawMesh.subGroups[ index ] = this.rawMesh.subGroupInUse; } + }, buildFace: function ( faceIndexV, faceIndexU, faceIndexN ) { + let subGroupInUse = this.rawMesh.subGroupInUse; let scope = this; let updateSubGroupInUse = function () { let faceIndexVi = parseInt( faceIndexV ); - let indexPointerV = 3 * (faceIndexVi > 0 ? faceIndexVi - 1 : faceIndexVi + scope.vertices.length / 3); + let indexPointerV = 3 * ( faceIndexVi > 0 ? faceIndexVi - 1 : faceIndexVi + scope.vertices.length / 3 ); let indexPointerC = scope.colors.length > 0 ? indexPointerV : null; let vertices = subGroupInUse.vertices; @@ -532,7 +593,7 @@ OBJLoader2Parser.prototype = { if ( faceIndexU ) { let faceIndexUi = parseInt( faceIndexU ); - let indexPointerU = 2 * (faceIndexUi > 0 ? faceIndexUi - 1 : faceIndexUi + scope.uvs.length / 2); + let indexPointerU = 2 * ( faceIndexUi > 0 ? faceIndexUi - 1 : faceIndexUi + scope.uvs.length / 2 ); let uvs = subGroupInUse.uvs; uvs.push( scope.uvs[ indexPointerU ++ ] ); uvs.push( scope.uvs[ indexPointerU ] ); @@ -541,13 +602,14 @@ OBJLoader2Parser.prototype = { if ( faceIndexN && ! scope.disregardNormals ) { let faceIndexNi = parseInt( faceIndexN ); - let indexPointerN = 3 * (faceIndexNi > 0 ? faceIndexNi - 1 : faceIndexNi + scope.normals.length / 3); + let indexPointerN = 3 * ( faceIndexNi > 0 ? faceIndexNi - 1 : faceIndexNi + scope.normals.length / 3 ); let normals = subGroupInUse.normals; normals.push( scope.normals[ indexPointerN ++ ] ); normals.push( scope.normals[ indexPointerN ++ ] ); normals.push( scope.normals[ indexPointerN ] ); } + }; if ( this.useIndices ) { @@ -560,11 +622,11 @@ OBJLoader2Parser.prototype = { indicesPointer = this.rawMesh.subGroupInUse.vertices.length / 3; updateSubGroupInUse(); subGroupInUse.indexMappings[ mappingName ] = indicesPointer; - subGroupInUse.indexMappingsCount++; + subGroupInUse.indexMappingsCount ++; } else { - this.rawMesh.counts.doubleIndicesCount++; + this.rawMesh.counts.doubleIndicesCount ++; } subGroupInUse.indices.push( indicesPointer ); @@ -575,9 +637,11 @@ OBJLoader2Parser.prototype = { } this.rawMesh.counts.faceCount ++; + }, createRawMeshReport: function ( inputObjectCount ) { + return 'Input Object number: ' + inputObjectCount + '\n\tObject name: ' + this.rawMesh.objectName + '\n\tGroup name: ' + this.rawMesh.groupName + @@ -588,12 +652,14 @@ OBJLoader2Parser.prototype = { '\n\tSmoothingGroup count: ' + this.rawMesh.counts.smoothingGroupCount + '\n\tMaterial count: ' + this.rawMesh.counts.mtlCount + '\n\tReal MeshOutputGroup count: ' + this.rawMesh.subGroups.length; + }, /** * Clear any empty subGroup and calculate absolute vertex, normal and uv counts */ finalizeRawMesh: function () { + let meshOutputGroupTemp = []; let meshOutputGroup; let absoluteVertexCount = 0; @@ -611,7 +677,7 @@ OBJLoader2Parser.prototype = { indices = meshOutputGroup.indices; if ( indices.length > 0 && absoluteIndexMappingsCount > 0 ) { - for ( let i = 0; i < indices.length; i++ ) { + for ( let i = 0; i < indices.length; i ++ ) { indices[ i ] = indices[ i ] + absoluteIndexMappingsCount; @@ -627,6 +693,7 @@ OBJLoader2Parser.prototype = { absoluteNormalCount += meshOutputGroup.normals.length; } + } // do not continue if no result @@ -647,9 +714,11 @@ OBJLoader2Parser.prototype = { } return result; + }, processCompletedMesh: function () { + let result = this.finalizeRawMesh(); let haveMesh = result !== null; if ( haveMesh ) { @@ -671,13 +740,14 @@ OBJLoader2Parser.prototype = { if ( this.callbacks.onProgress !== null ) { this.callbacks.onProgress( 'Completed [o: ' + this.rawMesh.objectName + ' g:' + this.rawMesh.groupName + '' + - '] Total progress: ' + (progressBytesPercent * 100).toFixed( 2 ) + '%', progressBytesPercent ); + '] Total progress: ' + ( progressBytesPercent * 100 ).toFixed( 2 ) + '%', progressBytesPercent ); } this.resetRawMesh(); } return haveMesh; + }, /** @@ -687,22 +757,23 @@ OBJLoader2Parser.prototype = { * @param result */ buildMesh: function ( result ) { + let meshOutputGroups = result.subGroups; let vertexFA = new Float32Array( result.absoluteVertexCount ); this.globalCounts.vertices += result.absoluteVertexCount / 3; this.globalCounts.faces += result.faceCount; this.globalCounts.doubleIndicesCount += result.doubleIndicesCount; - let indexUA = (result.absoluteIndexCount > 0) ? new Uint32Array( result.absoluteIndexCount ) : null; - let colorFA = (result.absoluteColorCount > 0) ? new Float32Array( result.absoluteColorCount ) : null; - let normalFA = (result.absoluteNormalCount > 0) ? new Float32Array( result.absoluteNormalCount ) : null; - let uvFA = (result.absoluteUvCount > 0) ? new Float32Array( result.absoluteUvCount ) : null; + let indexUA = ( result.absoluteIndexCount > 0 ) ? new Uint32Array( result.absoluteIndexCount ) : null; + let colorFA = ( result.absoluteColorCount > 0 ) ? new Float32Array( result.absoluteColorCount ) : null; + let normalFA = ( result.absoluteNormalCount > 0 ) ? new Float32Array( result.absoluteNormalCount ) : null; + let uvFA = ( result.absoluteUvCount > 0 ) ? new Float32Array( result.absoluteUvCount ) : null; let haveVertexColors = colorFA !== null; let meshOutputGroup; let materialNames = []; - let createMultiMaterial = (meshOutputGroups.length > 1); + let createMultiMaterial = ( meshOutputGroups.length > 1 ); let materialIndex = 0; let materialIndexMapping = []; let selectedMaterialIndex; @@ -727,7 +798,7 @@ OBJLoader2Parser.prototype = { materialNameOrg = meshOutputGroup.materialName; if ( this.rawMesh.faceType < 4 ) { - materialName = materialNameOrg + (haveVertexColors ? '_vertexColor' : '') + (meshOutputGroup.smoothingGroup === 0 ? '_flat' : ''); + materialName = materialNameOrg + ( haveVertexColors ? '_vertexColor' : '' ) + ( meshOutputGroup.smoothingGroup === 0 ? '_flat' : '' ); } else { @@ -883,17 +954,19 @@ OBJLoader2Parser.prototype = { uvs: uvFA }, // 0: mesh, 1: line, 2: point - geometryType: this.rawMesh.faceType < 4 ? 0 : (this.rawMesh.faceType === 6) ? 2 : 1 + geometryType: this.rawMesh.faceType < 4 ? 0 : ( this.rawMesh.faceType === 6 ) ? 2 : 1 }, [ vertexFA.buffer ], - indexUA !== null ? [ indexUA.buffer ] : null, + indexUA !== null ? [ indexUA.buffer ] : null, colorFA !== null ? [ colorFA.buffer ] : null, normalFA !== null ? [ normalFA.buffer ] : null, uvFA !== null ? [ uvFA.buffer ] : null ); + }, finalizeParsing: function () { + if ( this.logging.enabled ) console.info( 'Global output object count: ' + this.outputObjectCount ); if ( this.processCompletedMesh() && this.logging.enabled ) { @@ -904,6 +977,7 @@ OBJLoader2Parser.prototype = { console.info( parserFinalReport ); } + } }; diff --git a/examples/jsm/loaders/obj2/worker/parallel/WorkerRunner.js b/examples/jsm/loaders/obj2/worker/parallel/WorkerRunner.js index fc98f4c81a..7fe267690c 100644 --- a/examples/jsm/loaders/obj2/worker/parallel/WorkerRunner.js +++ b/examples/jsm/loaders/obj2/worker/parallel/WorkerRunner.js @@ -5,11 +5,13 @@ import { ObjectManipulator } from "../../utils/ObjectManipulator.js"; const DefaultWorkerPayloadHandler = function ( parser ) { + this.parser = parser; this.logging = { enabled: false, debug: false }; + }; DefaultWorkerPayloadHandler.prototype = { @@ -17,19 +19,26 @@ DefaultWorkerPayloadHandler.prototype = { constructor: DefaultWorkerPayloadHandler, handlePayload: function ( payload ) { + if ( payload.logging ) { + this.logging.enabled = payload.logging.enabled === true; this.logging.debug = payload.logging.debug === true; + } if ( payload.cmd === 'parse' ) { let scope = this; let callbacks = { callbackOnAssetAvailable: function ( payload ) { + self.postMessage( payload ); + }, callbackOnProgress: function ( text ) { + if ( scope.logging.enabled && scope.logging.debug ) console.debug( 'WorkerRunner: progress: ' + text ); + } }; @@ -44,7 +53,7 @@ DefaultWorkerPayloadHandler.prototype = { ObjectManipulator.applyProperties( parser, callbacks ); let arraybuffer; - if ( payload.params && payload.params.index !== undefined && payload.params.index !== null) { + if ( payload.params && payload.params.index !== undefined && payload.params.index !== null ) { arraybuffer = this.resourceDescriptors[ payload.params.index ].content; @@ -62,7 +71,7 @@ DefaultWorkerPayloadHandler.prototype = { } else { - parser[ parseFunctionName ] ( arraybuffer, payload.data.options ); + parser[ parseFunctionName ]( arraybuffer, payload.data.options ); } if ( this.logging.enabled ) console.log( 'WorkerRunner: Run complete!' ); @@ -87,14 +96,18 @@ DefaultWorkerPayloadHandler.prototype = { * @constructor */ const WorkerRunner = function ( payloadHandler ) { + this.resourceDescriptors = []; this.payloadHandler = payloadHandler; let scope = this; - let scopedRunner = function( event ) { + let scopedRunner = function ( event ) { + scope.processMessage( event.data ); + }; self.addEventListener( 'message', scopedRunner, false ); + }; WorkerRunner.prototype = { @@ -107,6 +120,7 @@ WorkerRunner.prototype = { * @param {Object} payload Raw mesh description (buffers, params, materials) used to build one to many meshes. */ processMessage: function ( payload ) { + if ( payload.data.resourceDescriptors && this.resourceDescriptors.length === 0 ) { for ( let name in payload.data.resourceDescriptors ) { @@ -118,6 +132,7 @@ WorkerRunner.prototype = { } this.payloadHandler.handlePayload( payload ); + } }; @@ -125,4 +140,4 @@ WorkerRunner.prototype = { export { WorkerRunner, DefaultWorkerPayloadHandler -} +}; -- GitLab