UNPKG

@polygonjs/polygonjs

Version:

node-based WebGL 3D engine https://polygonjs.com

234 lines (200 loc) 6.87 kB
import {BufferAttribute} from 'three'; import {BufferGeometry} from 'three'; import {LineSegments} from 'three'; import {Mesh} from 'three'; import {Points} from 'three'; /** * Development repository: https://github.com/kaisalmen/WWOBJLoader */ /** * * @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) { const meshName = meshPayload.params.meshName; const buffers = meshPayload.buffers; const 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; const materialNames = meshPayload.materials.materialNames; const createMultiMaterial = meshPayload.materials.multiMaterial; const multiMaterials = []; for (key in materialNames) { materialName = materialNames[key]; material = this.materialHandler.getMaterial(materialName); if (createMultiMaterial) multiMaterials.push(material); } if (createMultiMaterial) { material = multiMaterials; const materialGroups = meshPayload.materials.materialGroups; let materialGroup; for (key in materialGroups) { materialGroup = materialGroups[key]; bufferGeometry.addGroup(materialGroup.start, materialGroup.count, materialGroup.index); } } const meshes = []; let mesh; let callbackOnMeshAlterResult; let useOrgMesh = true; const 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 (const 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) { const meshNames = []; for (const 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};