Release v0.1.9 2026-07-13
This commit is contained in:
@@ -0,0 +1,72 @@
|
||||
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 });
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user