73 lines
2.6 KiB
JavaScript
73 lines
2.6 KiB
JavaScript
import { spawn } from "node:child_process";
|
|
import { mkdtemp, readFile, rm, writeFile } from "node:fs/promises";
|
|
import { tmpdir } from "node:os";
|
|
import path from "node:path";
|
|
import { NodeIO } from "@gltf-transform/core";
|
|
import { ALL_EXTENSIONS, EXTTextureWebP, KHRTextureBasisu } from "@gltf-transform/extensions";
|
|
import { MeshoptDecoder, MeshoptEncoder } from "meshoptimizer";
|
|
import sharp from "sharp";
|
|
|
|
export const TOKTX_COMMAND = process.env.TOKTX ?? "toktx";
|
|
|
|
export async function createGameAssetIO() {
|
|
await MeshoptDecoder.ready;
|
|
await MeshoptEncoder.ready;
|
|
return new NodeIO()
|
|
.registerExtensions(ALL_EXTENSIONS)
|
|
.registerDependencies({
|
|
"meshopt.decoder": MeshoptDecoder,
|
|
"meshopt.encoder": MeshoptEncoder,
|
|
});
|
|
}
|
|
|
|
function run(command, args) {
|
|
return new Promise((resolve, reject) => {
|
|
const child = spawn(command, args, { stdio: "inherit" });
|
|
child.once("error", reject);
|
|
child.once("exit", (code) => {
|
|
if (code === 0) resolve();
|
|
else reject(new Error(`${command} exited with code ${code ?? "unknown"}.`));
|
|
});
|
|
});
|
|
}
|
|
|
|
export async function convertDocumentTexturesToKtx2(document, temporaryPrefix) {
|
|
const textures = document.getRoot().listTextures();
|
|
if (textures.length === 0) throw new Error("Asset contains no textures to convert.");
|
|
|
|
const temporaryDirectory = await mkdtemp(path.join(tmpdir(), temporaryPrefix));
|
|
try {
|
|
for (const [index, texture] of textures.entries()) {
|
|
const sourceImage = texture.getImage();
|
|
if (!sourceImage) throw new Error(`Texture ${texture.getName() || index} contains no image data.`);
|
|
|
|
const pngPath = path.join(temporaryDirectory, `texture-${index}.png`);
|
|
const ktx2Path = path.join(temporaryDirectory, `texture-${index}.ktx2`);
|
|
await writeFile(pngPath, await sharp(sourceImage).png().toBuffer());
|
|
await run(TOKTX_COMMAND, [
|
|
"--t2",
|
|
"--encode", "uastc",
|
|
"--uastc_quality", "4",
|
|
"--zcmp", "18",
|
|
"--threads", process.env.TOKTX_THREADS ?? "4",
|
|
"--genmipmap",
|
|
"--assign_oetf", "srgb",
|
|
"--assign_primaries", "bt709",
|
|
ktx2Path,
|
|
pngPath,
|
|
]);
|
|
|
|
texture
|
|
.setName(`${texture.getName() || `texture_${index}`}_uastc`)
|
|
.setMimeType("image/ktx2")
|
|
.setImage(new Uint8Array(await readFile(ktx2Path)));
|
|
}
|
|
document.getRoot().listExtensionsUsed()
|
|
.find((extension) => extension.extensionName === EXTTextureWebP.EXTENSION_NAME)
|
|
?.dispose();
|
|
document.createExtension(KHRTextureBasisu).setRequired(true);
|
|
} finally {
|
|
await rm(temporaryDirectory, { recursive: true, force: true });
|
|
}
|
|
}
|