Files
XgridConverter/public/workers/converter.worker.js
Andreas Wilms 9b5f2d0814 test
2026-03-09 12:25:43 +01:00

110 lines
3.0 KiB
JavaScript

import {
WebPCodec,
readFile,
writeFile,
MemoryReadFileSystem,
MemoryFileSystem,
} from "@playcanvas/splat-transform";
// 1. Configure WASM path for the browser environment
WebPCodec.config({ wasmUrl: "/webp.wasm" });
/**
* Converts Xgrids LCI binary data to a standard PLY
* Parses 12-byte float chunks (X, Y, Z) from the binary buffer.
*/
function convertLciToPly(lciBuffer) {
const view = new DataView(lciBuffer);
// Xgrids LCI files usually start with a 4-byte point count
const numPoints = view.getUint32(0, true);
const points = [];
let offset = 4;
for (let i = 0; i < numPoints; i++) {
if (offset + 12 > lciBuffer.byteLength) break;
const x = view.getFloat32(offset, true);
const y = view.getFloat32(offset + 4, true);
const z = view.getFloat32(offset + 8, true);
points.push(`${x} ${y} ${z}`);
offset += 12;
}
const header = [
"ply",
"format ascii 1.0",
`element vertex ${points.length}`,
"property float x",
"property float y",
"property float z",
"end_header",
].join("\n");
return header + "\n" + points.join("\n");
}
self.onmessage = async (e) => {
const { type, lccBuffer, lciBuffer, fileName } = e.data;
if (type === "START_CONVERSION") {
try {
// --- STEP 1: GENERATE COLLISION MESH (.PLY) ---
self.postMessage({ type: "LOG", message: "Parsing LCI Geometry..." });
const plyData = convertLciToPly(lciBuffer);
const plyBlob = new Blob([plyData], { type: "text/plain" });
// --- STEP 2: GENERATE HIGHEST QUALITY .SOG ---
self.postMessage({
type: "LOG",
message: "Loading LCC into Splat Engine...",
});
const readFs = new MemoryReadFileSystem();
readFs.add(`${fileName}.lcc`, new Uint8Array(lccBuffer));
// splat-transform handles LCC containers natively
const dataTable = await readFile(`${fileName}.lcc`, { fs: readFs });
self.postMessage({
type: "LOG",
message: "Compiling High Quality SOG (WASM)...",
});
const writeFsSog = new MemoryFileSystem();
await writeFile(dataTable, `${fileName}.sog`, { fs: writeFsSog });
const sogBlob = new Blob([writeFsSog.get(`${fileName}.sog`)]);
// --- STEP 3: GENERATE LODs (UNBUNDLED TILES) ---
self.postMessage({
type: "LOG",
message: "Generating LOD Tiled Structure...",
});
const writeFsLod = new MemoryFileSystem();
// 'unbundled' creates the tiled WebP/JSON structure for streaming
await writeFile(dataTable, "lods/meta.json", {
fs: writeFsLod,
unbundled: true,
});
// --- STEP 4: RETURN ALL ASSETS ---
self.postMessage({
type: "DONE",
data: {
sog: sogBlob,
ply: plyBlob,
lods: writeFsLod.files, // This contains the meta.json and .webp tiles
fileName: fileName,
},
});
} catch (err) {
self.postMessage({
type: "LOG",
message: `CRITICAL ERROR: ${err.message}`,
});
console.error(err);
}
}
};