Spaces:
Running
Running
| import loadWasm from "../../../wasm/data"; | |
| // eslint-disable-next-line @typescript-eslint/no-explicit-any | |
| let wasmModule: any; | |
| async function initWasm() { | |
| wasmModule = await loadWasm(); | |
| } | |
| class Splat { | |
| offset: number = 0; | |
| position: Float32Array = new Float32Array(3); | |
| rotation: Float32Array = new Float32Array(4); | |
| scale: Float32Array = new Float32Array(3); | |
| selected: boolean = false; | |
| vertexCount: number = 0; | |
| positions: Float32Array = new Float32Array(0); | |
| rotations: Float32Array = new Float32Array(0); | |
| scales: Float32Array = new Float32Array(0); | |
| colors: Uint8Array = new Uint8Array(0); | |
| selection: Uint8Array = new Uint8Array(0); | |
| } | |
| let allocatedVertexCount: number = 0; | |
| const updateQueue = new Array<Splat>(); | |
| let running = false; | |
| let loading = false; | |
| let positionsPtr: number; | |
| let rotationsPtr: number; | |
| let scalesPtr: number; | |
| let colorsPtr: number; | |
| let selectionPtr: number; | |
| let dataPtr: number; | |
| let worldPositionsPtr: number; | |
| let worldRotationsPtr: number; | |
| let worldScalesPtr: number; | |
| const pack = async (splat: Splat) => { | |
| while (loading) { | |
| await new Promise((resolve) => setTimeout(resolve, 0)); | |
| } | |
| if (!wasmModule) { | |
| loading = true; | |
| await initWasm(); | |
| loading = false; | |
| } | |
| const targetAllocatedVertexCount = Math.pow(2, Math.ceil(Math.log2(splat.vertexCount))); | |
| if (targetAllocatedVertexCount > allocatedVertexCount) { | |
| if (allocatedVertexCount > 0) { | |
| wasmModule._free(positionsPtr); | |
| wasmModule._free(rotationsPtr); | |
| wasmModule._free(scalesPtr); | |
| wasmModule._free(colorsPtr); | |
| wasmModule._free(selectionPtr); | |
| wasmModule._free(dataPtr); | |
| wasmModule._free(worldPositionsPtr); | |
| wasmModule._free(worldRotationsPtr); | |
| wasmModule._free(worldScalesPtr); | |
| } | |
| allocatedVertexCount = targetAllocatedVertexCount; | |
| positionsPtr = wasmModule._malloc(3 * allocatedVertexCount * 4); | |
| rotationsPtr = wasmModule._malloc(4 * allocatedVertexCount * 4); | |
| scalesPtr = wasmModule._malloc(3 * allocatedVertexCount * 4); | |
| colorsPtr = wasmModule._malloc(4 * allocatedVertexCount); | |
| selectionPtr = wasmModule._malloc(allocatedVertexCount); | |
| dataPtr = wasmModule._malloc(8 * allocatedVertexCount * 4); | |
| worldPositionsPtr = wasmModule._malloc(3 * allocatedVertexCount * 4); | |
| worldRotationsPtr = wasmModule._malloc(4 * allocatedVertexCount * 4); | |
| worldScalesPtr = wasmModule._malloc(3 * allocatedVertexCount * 4); | |
| } | |
| wasmModule.HEAPF32.set(splat.positions, positionsPtr / 4); | |
| wasmModule.HEAPF32.set(splat.rotations, rotationsPtr / 4); | |
| wasmModule.HEAPF32.set(splat.scales, scalesPtr / 4); | |
| wasmModule.HEAPU8.set(splat.colors, colorsPtr); | |
| wasmModule.HEAPU8.set(splat.selection, selectionPtr); | |
| wasmModule._pack( | |
| splat.selected, | |
| splat.vertexCount, | |
| positionsPtr, | |
| rotationsPtr, | |
| scalesPtr, | |
| colorsPtr, | |
| selectionPtr, | |
| dataPtr, | |
| worldPositionsPtr, | |
| worldRotationsPtr, | |
| worldScalesPtr, | |
| ); | |
| const outData = new Uint32Array(wasmModule.HEAPU32.buffer, dataPtr, splat.vertexCount * 8); | |
| const detachedData = new Uint32Array(outData.slice().buffer); | |
| const worldPositions = new Float32Array(wasmModule.HEAPF32.buffer, worldPositionsPtr, splat.vertexCount * 3); | |
| const detachedWorldPositions = new Float32Array(worldPositions.slice().buffer); | |
| const worldRotations = new Float32Array(wasmModule.HEAPF32.buffer, worldRotationsPtr, splat.vertexCount * 4); | |
| const detachedWorldRotations = new Float32Array(worldRotations.slice().buffer); | |
| const worldScales = new Float32Array(wasmModule.HEAPF32.buffer, worldScalesPtr, splat.vertexCount * 3); | |
| const detachedWorldScales = new Float32Array(worldScales.slice().buffer); | |
| const response = { | |
| data: detachedData, | |
| worldPositions: detachedWorldPositions, | |
| worldRotations: detachedWorldRotations, | |
| worldScales: detachedWorldScales, | |
| offset: splat.offset, | |
| vertexCount: splat.vertexCount, | |
| positions: splat.positions.buffer, | |
| rotations: splat.rotations.buffer, | |
| scales: splat.scales.buffer, | |
| colors: splat.colors.buffer, | |
| selection: splat.selection.buffer, | |
| }; | |
| self.postMessage({ response: response }, [ | |
| response.data.buffer, | |
| response.worldPositions.buffer, | |
| response.worldRotations.buffer, | |
| response.worldScales.buffer, | |
| response.positions, | |
| response.rotations, | |
| response.scales, | |
| response.colors, | |
| response.selection, | |
| ]); | |
| running = false; | |
| }; | |
| const packThrottled = () => { | |
| if (updateQueue.length === 0) return; | |
| if (!running) { | |
| running = true; | |
| const splat = updateQueue.shift() as Splat; | |
| pack(splat); | |
| setTimeout(() => { | |
| running = false; | |
| packThrottled(); | |
| }, 0); | |
| } | |
| }; | |
| self.onmessage = (e) => { | |
| if (e.data.splat) { | |
| const splat = e.data.splat as Splat; | |
| for (const [index, existing] of updateQueue.entries()) { | |
| if (existing.offset === splat.offset) { | |
| updateQueue[index] = splat; | |
| return; | |
| } | |
| } | |
| updateQueue.push(splat); | |
| packThrottled(); | |
| } | |
| }; | |