183 lines
5.0 KiB
TypeScript
183 lines
5.0 KiB
TypeScript
const originalFetch = globalThis.fetch;
|
|
globalThis.fetch = async (input, init) => {
|
|
const url = input instanceof Request ? input.url : input.toString();
|
|
self.postMessage({ type: "LOG", message: `FETCH: ${url}` });
|
|
|
|
if (url.includes("webp.wasm")) {
|
|
self.postMessage({
|
|
type: "LOG",
|
|
message: `INTERCEPTED → /workers/webp.wasm`,
|
|
});
|
|
const res = await originalFetch("/workers/webp.wasm", init);
|
|
self.postMessage({
|
|
type: "LOG",
|
|
message: `WASM response status: ${res.status}`,
|
|
});
|
|
return res;
|
|
}
|
|
return originalFetch(input, init);
|
|
};
|
|
|
|
// Intercept XMLHttpRequest (Emscripten uses this in Workers)
|
|
if (typeof XMLHttpRequest !== "undefined") {
|
|
const originalOpen = XMLHttpRequest.prototype.open;
|
|
// @ts-ignore
|
|
XMLHttpRequest.prototype.open = function (
|
|
method: string,
|
|
url: string | URL,
|
|
...rest: any[]
|
|
) {
|
|
if (typeof url === "string" && url.includes("webp.wasm")) {
|
|
url = "/workers/webp.wasm";
|
|
}
|
|
return originalOpen.apply(this, [method, url, ...rest] as any);
|
|
};
|
|
}
|
|
|
|
self.onmessage = async (e: MessageEvent) => {
|
|
const { type, filesData, mainLccName, fileName } = e.data;
|
|
|
|
if (type === "START_CONVERSION") {
|
|
try {
|
|
self.postMessage({ type: "LOG", message: "Initialisiere..." });
|
|
|
|
// Emscripten's native locateFile hook
|
|
// @ts-ignore
|
|
globalThis.Module = globalThis.Module || {};
|
|
// @ts-ignore
|
|
globalThis.Module.locateFile = function (path: string) {
|
|
if (path.endsWith(".wasm")) {
|
|
return new URL("/webp.wasm", self.location.origin).href;
|
|
}
|
|
return path;
|
|
};
|
|
|
|
const {
|
|
readFile,
|
|
writeFile,
|
|
MemoryReadFileSystem,
|
|
MemoryFileSystem,
|
|
getInputFormat,
|
|
} = await import("@playcanvas/splat-transform");
|
|
|
|
const readFs = new MemoryReadFileSystem();
|
|
|
|
self.postMessage({
|
|
type: "LOG",
|
|
message: "Lade Dateien in den virtuellen Speicher...",
|
|
});
|
|
|
|
for (const file of filesData) {
|
|
readFs.set(file.name, new Uint8Array(file.buffer));
|
|
}
|
|
|
|
const readOptions = {
|
|
iterations: 0,
|
|
lodSelect: [0, 1, 2, 3, 4], // we have captured a total level of 5
|
|
unbundled: false,
|
|
lodChunkCount: 0,
|
|
lodChunkExtent: 0,
|
|
};
|
|
|
|
self.postMessage({ type: "LOG", message: "Lese LCC und Binärdaten..." });
|
|
|
|
const tables = await readFile({
|
|
filename: mainLccName,
|
|
fileSystem: readFs,
|
|
inputFormat: getInputFormat(mainLccName),
|
|
params: [],
|
|
options: readOptions,
|
|
});
|
|
|
|
const mainTable = tables[0];
|
|
if (!mainTable) throw new Error("Keine Splat-Daten gefunden.");
|
|
|
|
const generatedFiles: { name: string; blob: Blob }[] = [];
|
|
|
|
// PASS 1: Generate Single High-Quality SOG
|
|
self.postMessage({ type: "LOG", message: "Kompiliere Single SOG..." });
|
|
|
|
const writeFsSingle = new MemoryFileSystem();
|
|
const singleOutputName = `${fileName}.sog`;
|
|
const singleOptions = {
|
|
...readOptions,
|
|
iterations: 10,
|
|
unbundled: false,
|
|
};
|
|
|
|
await writeFile(
|
|
{
|
|
filename: singleOutputName,
|
|
outputFormat: "sog",
|
|
dataTable: mainTable,
|
|
options: singleOptions,
|
|
},
|
|
writeFsSingle,
|
|
);
|
|
|
|
const singleSogData = writeFsSingle.results.get(singleOutputName);
|
|
if (singleSogData) {
|
|
generatedFiles.push({
|
|
name: singleOutputName,
|
|
blob: new Blob([new Uint8Array(singleSogData).slice().buffer], {
|
|
type: "application/octet-stream",
|
|
}),
|
|
});
|
|
}
|
|
|
|
// ==========================================
|
|
// PASS 2: Generate Unbundled LOD SOGs + JSON
|
|
// ==========================================
|
|
self.postMessage({ type: "LOG", message: "Kompiliere LOD Chunks..." });
|
|
|
|
const writeFsLods = new MemoryFileSystem();
|
|
|
|
// MUST be exactly "meta.json" for unbundled SOG format
|
|
const lodsOutputName = "meta.json";
|
|
|
|
const lodOptions = {
|
|
...readOptions,
|
|
iterations: 10,
|
|
unbundled: true,
|
|
lodChunkCount: 512,
|
|
lodChunkExtent: 16,
|
|
};
|
|
|
|
await writeFile(
|
|
{
|
|
filename: lodsOutputName,
|
|
outputFormat: "sog",
|
|
dataTable: mainTable,
|
|
options: lodOptions,
|
|
},
|
|
writeFsLods,
|
|
);
|
|
|
|
// Jetzt iterieren wir über alle generierten Dateien im System
|
|
for (const [generatedName, data] of writeFsLods.results.entries()) {
|
|
const mimeType = generatedName.endsWith(".json")
|
|
? "application/json"
|
|
: "application/octet-stream";
|
|
|
|
generatedFiles.push({
|
|
name: generatedName,
|
|
blob: new Blob([new Uint8Array(data).slice().buffer], {
|
|
type: mimeType,
|
|
}),
|
|
});
|
|
}
|
|
|
|
// Send all Data to Frontend
|
|
self.postMessage({
|
|
type: "DONE",
|
|
data: {
|
|
files: generatedFiles,
|
|
},
|
|
});
|
|
} catch (err: any) {
|
|
self.postMessage({ type: "LOG", message: `Fehler: ${err.message}` });
|
|
console.error(err);
|
|
}
|
|
}
|
|
};
|