108 lines
3.6 KiB
JavaScript
108 lines
3.6 KiB
JavaScript
import fs from "fs";
|
|
import path from "path";
|
|
import { NodeIO } from "@gltf-transform/core";
|
|
import { ALL_EXTENSIONS } from "@gltf-transform/extensions";
|
|
import { dedup, prune, resample, weld, quantize } from "@gltf-transform/functions";
|
|
import { BACKUP_SUFFIX, needsConversion } from "../../utils/gltf.js";
|
|
import { convert } from "../convert/service.js";
|
|
|
|
const io = new NodeIO().registerExtensions(ALL_EXTENSIONS);
|
|
|
|
const QUANTIZE_PRESETS = {
|
|
high: { position: 16, normal: 12, texcoord: 14, color: 10, generic: 12 },
|
|
balanced: { position: 14, normal: 10, texcoord: 12, color: 8, generic: 12 },
|
|
aggressive: { position: 12, normal: 8, texcoord: 10, color: 8, generic: 10 },
|
|
light: { position: 10, normal: 8, texcoord: 10, color: 8, generic: 10 }
|
|
};
|
|
|
|
export const buildTransforms = (config) => {
|
|
const transforms = [];
|
|
const selected = new Set(config.commands);
|
|
if (selected.has("dedup")) transforms.push(dedup());
|
|
if (selected.has("prune")) transforms.push(prune());
|
|
if (selected.has("resample")) transforms.push(resample());
|
|
if (selected.has("weld")) transforms.push(weld());
|
|
if (selected.has("quantize")) {
|
|
const preset = QUANTIZE_PRESETS[config.quantizePreset] || QUANTIZE_PRESETS.balanced;
|
|
transforms.push(quantize({
|
|
quantizePosition: preset.position,
|
|
quantizeNormal: preset.normal,
|
|
quantizeTexcoord: preset.texcoord,
|
|
quantizeColor: preset.color,
|
|
quantizeGeneric: preset.generic
|
|
}));
|
|
}
|
|
return transforms;
|
|
};
|
|
|
|
const resolveOutput = (file, config) => {
|
|
const cwd = process.cwd();
|
|
const originalExt = path.extname(file).toLowerCase() || ".gltf";
|
|
const baseName = originalExt ? file.slice(0, -originalExt.length) : file;
|
|
const isConvertible = needsConversion(file);
|
|
|
|
const targetExt = config.outputFormat === "gltf" ? ".gltf"
|
|
: (config.outputFormat === "glb" || isConvertible) ? ".glb"
|
|
: originalExt;
|
|
|
|
const wantsCopy = config.outputOptions.includes("copy");
|
|
const wantsOverwrite = config.outputOptions.includes("overwrite");
|
|
const mode = wantsCopy ? "copy" : (wantsOverwrite ? "overwrite" : "copy");
|
|
const backup = config.outputOptions.includes("backup") && mode === "overwrite";
|
|
|
|
const targetName = mode === "copy"
|
|
? `${baseName}_compressed${targetExt}`
|
|
: `${baseName}${targetExt}`;
|
|
|
|
return {
|
|
cwd,
|
|
mode,
|
|
backup,
|
|
sourcePath: path.join(cwd, file),
|
|
sourceExt: originalExt,
|
|
targetExt,
|
|
targetPath: path.join(cwd, targetName),
|
|
baseName,
|
|
needsConversion: isConvertible
|
|
};
|
|
};
|
|
|
|
export const processFile = async (file, config, transforms) => {
|
|
const output = resolveOutput(file, config);
|
|
if (!fs.existsSync(output.sourcePath)) {
|
|
return { ok: false, file, reason: "missing" };
|
|
}
|
|
|
|
if (!transforms.length) {
|
|
return { ok: false, file, reason: "no-transform" };
|
|
}
|
|
|
|
if (output.backup) {
|
|
const backupName = `${output.baseName}${BACKUP_SUFFIX}${output.sourceExt}`;
|
|
const backupPath = path.join(output.cwd, backupName);
|
|
fs.copyFileSync(output.sourcePath, backupPath);
|
|
}
|
|
|
|
let inputPath = output.sourcePath;
|
|
|
|
if (output.needsConversion) {
|
|
const tempPath = path.join(output.cwd, `${output.baseName}_temp.glb`);
|
|
await convert(output.sourcePath, tempPath, { binary: true });
|
|
inputPath = tempPath;
|
|
}
|
|
|
|
const document = io.read(inputPath);
|
|
await document.transform(...transforms);
|
|
io.write(output.targetPath, document);
|
|
|
|
if (output.needsConversion) {
|
|
fs.rmSync(inputPath, { force: true });
|
|
}
|
|
|
|
if (output.mode === "overwrite" && output.targetPath !== output.sourcePath) {
|
|
fs.rmSync(output.sourcePath, { force: true });
|
|
}
|
|
|
|
return { ok: true, file, output: output.targetPath };
|
|
};
|