/** * @author Kai Salmen / https://kaisalmen.de * Development repository: https://github.com/kaisalmen/WWOBJLoader */ import { BufferAttribute, BufferGeometry, LineSegments, Mesh, Points } from "../../../../../build/three.module.js"; /** * * @param {MaterialHandler} materialHandler * @constructor */ const MeshReceiver = function ( materialHandler ) { this.logging = { enabled: false, debug: false }; this.callbacks = { onProgress: null, onMeshAlter: null }; this.materialHandler = materialHandler; }; MeshReceiver.prototype = { constructor: MeshReceiver, /** * Enable or disable logging in general (except warn and error), plus enable or disable debug logging. * * @param {boolean} enabled True or false. * @param {boolean} debug True or false. */ setLogging: function ( enabled, debug ) { this.logging.enabled = enabled === true; this.logging.debug = debug === true; }, /** * * @param {Function} onProgress * @param {Function} onMeshAlter * @private */ _setCallbacks: function ( onProgress, onMeshAlter ) { if ( onProgress !== null && onProgress !== undefined && onProgress instanceof Function ) { this.callbacks.onProgress = onProgress; } if ( onMeshAlter !== null && onMeshAlter !== undefined && onMeshAlter instanceof Function ) { this.callbacks.onMeshAlter = onMeshAlter; } }, /** * Builds one or multiple meshes from the data described in the payload (buffers, params, material info). * * @param {Object} meshPayload Raw mesh description (buffers, params, materials) used to build one to many meshes. * @returns {Mesh[]} mesh Array of {@link Mesh} */ buildMeshes: function ( meshPayload ) { let meshName = meshPayload.params.meshName; let buffers = meshPayload.buffers; let bufferGeometry = new BufferGeometry(); if ( buffers.vertices !== undefined && buffers.vertices !== null ) { bufferGeometry.setAttribute( 'position', new BufferAttribute( new Float32Array( buffers.vertices ), 3 ) ); } if ( buffers.indices !== undefined && buffers.indices !== null ) { bufferGeometry.setIndex( new BufferAttribute( new Uint32Array( buffers.indices ), 1 ) ); } if ( buffers.colors !== undefined && buffers.colors !== null ) { bufferGeometry.setAttribute( 'color', new BufferAttribute( new Float32Array( buffers.colors ), 3 ) ); } if ( buffers.normals !== undefined && buffers.normals !== null ) { bufferGeometry.setAttribute( 'normal', new BufferAttribute( new Float32Array( buffers.normals ), 3 ) ); } else { bufferGeometry.computeVertexNormals(); } if ( buffers.uvs !== undefined && buffers.uvs !== null ) { bufferGeometry.setAttribute( 'uv', new BufferAttribute( new Float32Array( buffers.uvs ), 2 ) ); } if ( buffers.skinIndex !== undefined && buffers.skinIndex !== null ) { bufferGeometry.setAttribute( 'skinIndex', new BufferAttribute( new Uint16Array( buffers.skinIndex ), 4 ) ); } if ( buffers.skinWeight !== undefined && buffers.skinWeight !== null ) { bufferGeometry.setAttribute( 'skinWeight', new BufferAttribute( new Float32Array( buffers.skinWeight ), 4 ) ); } let material, materialName, key; let materialNames = meshPayload.materials.materialNames; let createMultiMaterial = meshPayload.materials.multiMaterial; let multiMaterials = []; for ( key in materialNames ) { materialName = materialNames[ key ]; material = this.materialHandler.getMaterial( materialName ); if ( createMultiMaterial ) multiMaterials.push( material ); } if ( createMultiMaterial ) { material = multiMaterials; let materialGroups = meshPayload.materials.materialGroups; let materialGroup; for ( key in materialGroups ) { materialGroup = materialGroups[ key ]; bufferGeometry.addGroup( materialGroup.start, materialGroup.count, materialGroup.index ); } } let meshes = []; let mesh; let callbackOnMeshAlterResult; let useOrgMesh = true; let geometryType = meshPayload.geometryType === null ? 0 : meshPayload.geometryType; if ( this.callbacks.onMeshAlter ) { callbackOnMeshAlterResult = this.callbacks.onMeshAlter( { detail: { meshName: meshName, bufferGeometry: bufferGeometry, material: material, geometryType: geometryType } } ); } // here LoadedMeshUserOverride is required to be provided by the callback used to alter the results if ( callbackOnMeshAlterResult ) { if ( callbackOnMeshAlterResult.isDisregardMesh() ) { useOrgMesh = false; } else if ( callbackOnMeshAlterResult.providesAlteredMeshes() ) { for ( let i in callbackOnMeshAlterResult.meshes ) { meshes.push( callbackOnMeshAlterResult.meshes[ i ] ); } useOrgMesh = false; } } if ( useOrgMesh ) { if ( meshPayload.computeBoundingSphere ) bufferGeometry.computeBoundingSphere(); if ( geometryType === 0 ) { mesh = new Mesh( bufferGeometry, material ); } else if ( geometryType === 1 ) { mesh = new LineSegments( bufferGeometry, material ); } else { mesh = new Points( bufferGeometry, material ); } mesh.name = meshName; meshes.push( mesh ); } let progressMessage = meshPayload.params.meshName; if ( meshes.length > 0 ) { let meshNames = []; for ( let i in meshes ) { mesh = meshes[ i ]; meshNames[ i ] = mesh.name; } progressMessage += ': Adding mesh(es) (' + meshNames.length + ': ' + meshNames + ') from input mesh: ' + meshName; progressMessage += ' (' + ( meshPayload.progress.numericalValue * 100 ).toFixed( 2 ) + '%)'; } else { progressMessage += ': Not adding mesh: ' + meshName; progressMessage += ' (' + ( meshPayload.progress.numericalValue * 100 ).toFixed( 2 ) + '%)'; } if ( this.callbacks.onProgress ) { this.callbacks.onProgress( 'progress', progressMessage, meshPayload.progress.numericalValue ); } return meshes; } }; /** * Object to return by callback onMeshAlter. Used to disregard a certain mesh or to return one to many meshes. * @class * * @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 ) { this.disregardMesh = disregardMesh === true; this.alteredMesh = alteredMesh === true; this.meshes = []; }; LoadedMeshUserOverride.prototype = { constructor: LoadedMeshUserOverride, /** * Add a mesh created within callback. * * @param {Mesh} mesh */ addMesh: function ( mesh ) { this.meshes.push( mesh ); this.alteredMesh = true; }, /** * Answers if mesh shall be disregarded completely. * * @returns {boolean} */ isDisregardMesh: function () { return this.disregardMesh; }, /** * Answers if new mesh(es) were created. * * @returns {boolean} */ providesAlteredMeshes: function () { return this.alteredMesh; } }; export { MeshReceiver, LoadedMeshUserOverride };