87 lines
3.7 KiB
JavaScript
87 lines
3.7 KiB
JavaScript
import crypto from "node:crypto";
|
|
import fs from "node:fs";
|
|
import os from "node:os";
|
|
import path from "node:path";
|
|
import { spawnSync } from "node:child_process";
|
|
import { fileURLToPath } from "node:url";
|
|
|
|
const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "../..");
|
|
const resourceRoot = path.resolve(process.env.VDB_RESOURCE_ROOT ?? path.join(os.homedir(), "resource-library/blender-web-vdb"));
|
|
const source = path.join(resourceRoot, "generated", "generated-smoke.vdb");
|
|
const generator = path.join(root, "build_vdb_tools", "vdb_volume_golden");
|
|
const committedRoot = path.join(root, "tests", "golden", "M8-19");
|
|
const check = process.argv.includes("--check");
|
|
const outputRoot = check ? fs.mkdtempSync(path.join(os.tmpdir(), "vdb-volume-golden-")) : committedRoot;
|
|
const outputPrefix = path.join(outputRoot, "generated-smoke");
|
|
const sha256 = (file) => crypto.createHash("sha256").update(fs.readFileSync(file)).digest("hex");
|
|
|
|
if (!fs.existsSync(generator)) throw new Error(`VDB_VOLUME_GOLDEN_TOOL_MISSING: ${generator}`);
|
|
if (!fs.existsSync(source)) throw new Error(`VDB_VOLUME_GOLDEN_SOURCE_MISSING: ${source}`);
|
|
fs.mkdirSync(outputRoot, { recursive: true });
|
|
|
|
try {
|
|
const result = spawnSync(generator, [source, outputPrefix], { encoding: "utf8" });
|
|
if (result.status !== 0) throw new Error(result.stderr || `vdb_volume_golden exited ${result.status}`);
|
|
const native = JSON.parse(result.stdout.trim());
|
|
const axes = ["X", "Y", "Z"];
|
|
const images = axes.map((axis) => {
|
|
const fileName = `generated-smoke-${axis.toLowerCase()}.rgba`;
|
|
const file = path.join(outputRoot, fileName);
|
|
const bytes = fs.readFileSync(file);
|
|
let alphaPixels = 0;
|
|
for (let index = 3; index < bytes.byteLength; index += 4) if (bytes[index] > 0) alphaPixels++;
|
|
return { axis, file: fileName, byteLength: bytes.byteLength, sha256: sha256(file), alphaPixels };
|
|
});
|
|
const manifest = {
|
|
schemaVersion: 1,
|
|
taskId: "M8-19",
|
|
source: {
|
|
resourceId: "generated-smoke-vdb",
|
|
sha256: sha256(source),
|
|
grid: native.grid,
|
|
activeVoxelCount: native.activeVoxelCount,
|
|
indexBounds: native.indexBounds,
|
|
},
|
|
native: {
|
|
openVDBVersion: native.openVDBVersion,
|
|
generatorSourceSha256: sha256(path.join(root, "tools", "vdb", "vdb_volume_golden.cc")),
|
|
},
|
|
renderContract: {
|
|
shaderSemanticVersion: "volume-wgsl-v1",
|
|
width: native.width,
|
|
height: native.height,
|
|
format: "RGBA8_UNORM",
|
|
interpolation: "LINEAR",
|
|
densityScale: 1,
|
|
emissionScale: 0,
|
|
anisotropy: 0,
|
|
color: [0.72, 0.78, 0.86],
|
|
axes,
|
|
thresholds: {
|
|
maxChannelError: 2,
|
|
meanAbsoluteError: 0.1,
|
|
rmsError: 0.5,
|
|
alphaCoverageDeltaRatio: 0.002,
|
|
},
|
|
},
|
|
images,
|
|
};
|
|
const manifestText = `${JSON.stringify(manifest, null, 2)}\n`;
|
|
const manifestFile = path.join(outputRoot, "manifest.json");
|
|
fs.writeFileSync(manifestFile, manifestText);
|
|
|
|
if (check) {
|
|
for (const image of images) {
|
|
const expected = fs.readFileSync(path.join(committedRoot, image.file));
|
|
const actual = fs.readFileSync(path.join(outputRoot, image.file));
|
|
if (!expected.equals(actual)) throw new Error(`VDB_VOLUME_GOLDEN_MISMATCH: ${image.file}`);
|
|
}
|
|
const expectedManifest = fs.readFileSync(path.join(committedRoot, "manifest.json"), "utf8");
|
|
if (expectedManifest !== manifestText) throw new Error("VDB_VOLUME_GOLDEN_MISMATCH: manifest.json");
|
|
}
|
|
process.stdout.write(`vdb-volume-golden-${check ? "check" : "generated"} axes=3 bytes=${images.reduce((total, image) => total + image.byteLength, 0)} sha256=${images.map((image) => image.sha256).join(",")}\n`);
|
|
}
|
|
finally {
|
|
if (check) fs.rmSync(outputRoot, { recursive: true, force: true });
|
|
}
|