import { Box3, BufferAttribute } from 'three'; import { MeshBVH } from 'three-mesh-bvh'; import GenerateAsyncWorkerUrl from './generateAsync.worker.js?worker&url'; export class GenerateMeshBVHWorker { constructor() { this.running = false; this.worker = new Worker(GenerateAsyncWorkerUrl, { type: 'module' }); this.worker.onerror = e => { if ( e.message ) { throw new Error( `GenerateMeshBVHWorker: Could not create Web Worker with error "${ e.message }"` ); } else { throw new Error( 'GenerateMeshBVHWorker: Could not create Web Worker.' ); } }; } generate( geometry, options = {} ) { if (this.running) { throw new Error( 'GenerateMeshBVHWorker: Already running job.' ); } if (this.worker === null) { throw new Error( 'GenerateMeshBVHWorker: Worker has been disposed.' ); } const { worker } = this; this.running = true; return new Promise((resolve, reject) => { worker.onerror = e => { reject( new Error( `GenerateMeshBVHWorker: ${ e.message }` ) ); this.running = false; }; worker.onmessage = e => { this.running = false; const { data } = e; if (data.error) { reject( new Error( data.error ) ); worker.onmessage = null; } else if ( data.serialized ) { const { serialized, position } = data; const bvh = MeshBVH.deserialize( serialized, geometry, { setIndex: false } ); const boundsOptions = Object.assign( { setBoundingBox: true, }, options ); // we need to replace the arrays because they're neutered entirely by the // webworker transfer. geometry.attributes.position.array = position; if ( geometry.index ) { geometry.index.array = serialized.index; } else { const newIndex = new BufferAttribute( serialized.index, 1, false ); geometry.setIndex( newIndex ); } if ( boundsOptions.setBoundingBox ) { geometry.boundingBox = bvh.getBoundingBox( new Box3() ); } resolve( bvh ); worker.onmessage = null; } else if ( options.onProgress ) { options.onProgress( data.progress ); } }; const index = geometry.index ? geometry.index.array : null; const position = geometry.attributes.position.array; if (position.isInterleavedBufferAttribute || index && index.isInterleavedBufferAttribute) { throw new Error( 'GenerateMeshBVHWorker: InterleavedBufferAttribute are not supported for the geometry attributes.' ); } const transferable = [ position ]; if (index) { transferable.push( index ); } worker.postMessage({ index, position, options: { ...options, onProgress: null, includedProgressCallback: Boolean( options.onProgress ), groups: [ ... geometry.groups ], }, }, transferable.map(arr => arr.buffer)); }); } dispose() { this.worker.terminate(); this.worker = null; } terminate() { console.warn( 'GenerateMeshBVHWorker: "terminate" is deprecated. Use "dispose" instead.' ); this.dispose(); } }