75 lines
3.7 KiB
JavaScript
75 lines
3.7 KiB
JavaScript
import fs from "node:fs";
|
|
import factory from "../../web/app/src/vendor/blender/web_engine.js";
|
|
|
|
const wasmBinary = fs.readFileSync(new URL("../../web/app/src/vendor/blender/web_engine.wasm", import.meta.url));
|
|
const blend = fs.readFileSync(new URL("../../tests/files/web/basic_scene.blend", import.meta.url));
|
|
const expected = JSON.parse(fs.readFileSync(new URL("../../tests/golden/W-079/basic-scene-decimate.json", import.meta.url), "utf8"));
|
|
|
|
function readSnapshot(engine, handle) {
|
|
const dataOut = engine._malloc(4);
|
|
const lengthOut = engine._malloc(4);
|
|
try {
|
|
if (engine._web_engine_get_scene_snapshot(handle, dataOut, lengthOut) !== 0) throw new Error("golden snapshot request failed");
|
|
const pointer = engine.HEAPU32[dataOut >>> 2];
|
|
const length = engine.HEAPU32[lengthOut >>> 2];
|
|
return JSON.parse(new TextDecoder().decode(engine.HEAPU8.slice(pointer, pointer + length)));
|
|
}
|
|
finally {
|
|
engine._free(dataOut);
|
|
engine._free(lengthOut);
|
|
}
|
|
}
|
|
|
|
function open(engine, handle) {
|
|
const pointer = engine._malloc(blend.byteLength);
|
|
engine.HEAPU8.set(blend, pointer);
|
|
const result = engine._web_engine_open_blend(handle, pointer, blend.byteLength);
|
|
engine._free(pointer);
|
|
if (result !== 0) throw new Error(`golden fixture open failed: ${engine.UTF8ToString(engine._web_engine_last_error_message())}`);
|
|
}
|
|
|
|
function apply(engine, handle, command) {
|
|
const bytes = new TextEncoder().encode(JSON.stringify(command));
|
|
const pointer = engine._malloc(bytes.byteLength);
|
|
engine.HEAPU8.set(bytes, pointer);
|
|
const result = engine._web_engine_apply_command(handle, pointer, bytes.byteLength);
|
|
engine._free(pointer);
|
|
if (result !== 0) throw new Error(`golden command failed: ${engine.UTF8ToString(engine._web_engine_last_error_message())}`);
|
|
}
|
|
|
|
function sourceSummary(snapshot) {
|
|
const meshById = new Map(snapshot.meshes.map((mesh) => [mesh.id, mesh]));
|
|
return {
|
|
frame: [snapshot.frame.start, snapshot.frame.end],
|
|
objects: snapshot.nodes.map((node) => {
|
|
const mesh = node.dataId ? meshById.get(node.dataId) : undefined;
|
|
return { name: node.name, type: node.type, vertices: mesh?.vertexCount ?? 0, polygons: mesh?.faceCount ?? 0, materials: mesh?.materialSlotIds?.length ?? 0 };
|
|
}).sort((left, right) => left.name.localeCompare(right.name)),
|
|
};
|
|
}
|
|
|
|
const sourceEngine = await factory({ wasmBinary });
|
|
const sourceHandle = sourceEngine._web_engine_create();
|
|
open(sourceEngine, sourceHandle);
|
|
const source = sourceSummary(readSnapshot(sourceEngine, sourceHandle));
|
|
sourceEngine._web_engine_destroy(sourceHandle);
|
|
|
|
const collapse = {};
|
|
for (const ratio of [1, 0.9, 0.8, 0.75, 0.7, 0.65, 0.5, 0.25]) {
|
|
const engine = await factory({ wasmBinary });
|
|
const handle = engine._web_engine_create();
|
|
open(engine, handle);
|
|
const snapshot = readSnapshot(engine, handle);
|
|
const mesh = snapshot.meshes.find((candidate) => candidate.id === "mesh:Cube.001");
|
|
apply(engine, handle, { type: "decimateMesh", meshId: mesh.id, profile: { schemaVersion: 1, sourceMeshRevision: snapshot.revision, attributePolicy: "PRESERVE", mode: "COLLAPSE", ratio, triangulate: false, useSymmetry: false } });
|
|
const output = readSnapshot(engine, handle).meshes.find((candidate) => candidate.id === mesh.id);
|
|
collapse[String(ratio)] = { vertices: output.vertexCount, triangles: output.triangleCount ?? Math.floor((output.indices?.length ?? 0) / 3) };
|
|
engine._web_engine_destroy(handle);
|
|
}
|
|
|
|
const actual = { fixture: expected.fixture, source, collapse };
|
|
if (JSON.stringify(actual) !== JSON.stringify(expected)) {
|
|
throw new Error(`Blender golden mismatch\nexpected=${JSON.stringify(expected)}\nactual=${JSON.stringify(actual)}`);
|
|
}
|
|
console.log(`blender-golden-ok fixture=${expected.fixture} ratios=${Object.keys(collapse).join(",")}`);
|