mylingo3d
Version:
Lingo3D is a React/Vue 3d game development framework that ships with a complete visual editor
133 lines (112 loc) • 4.19 kB
text/typescript
import { Box3, BufferAttribute, BufferGeometry } from "three"
import { MeshBVH } from "three-mesh-bvh"
import code from "./workerString"
import { Queue } from "@lincode/promiselikes"
const queue = new Queue()
export const geometryMeshMap = new WeakMap()
type Options = {
onProgress?: (progress: number) => void
}
export class GenerateMeshBVHWorker {
private worker: Worker | null
public constructor() {
const blob = new Blob([code], { type: "application/javascript" })
this.worker = new Worker(URL.createObjectURL(blob))
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."
)
}
}
}
public async generate(geom: BufferGeometry, options: Options = {}) {
await queue
if (this.worker === null) {
throw new Error("GenerateMeshBVHWorker: Worker has been disposed.")
}
const { worker } = this
const geometry = geom.clone()
geometry.dispose()
return new Promise<MeshBVH>((resolve, reject) => {
worker.onerror = (e) => {
reject(new Error(`GenerateMeshBVHWorker: ${e.message}`))
queue.resolve()
}
worker.onmessage = (e) => {
const { data } = e
if (data.error) {
reject(new Error(data.error))
queue.resolve()
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
)
//@ts-ignore
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)
queue.resolve()
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
const transferrables = [position]
if (index) {
transferrables.push(index)
}
worker.postMessage(
{
index,
position,
matrixWorld: geometryMeshMap.get(geom).matrixWorld,
options: {
...options,
onProgress: null,
includedProgressCallback: Boolean(options.onProgress),
groups: [...geometry.groups]
}
},
//@ts-ignore
transferrables.map((arr) => arr.buffer)
)
})
}
dispose() {
this.worker!.terminate()
this.worker = null
}
terminate() {
console.warn(
'GenerateMeshBVHWorker: "terminate" is deprecated. Use "dispose" instead.'
)
this.dispose()
}
}