import fs from "node:fs"; import factory from "../../web/app/src/vendor/blender/web_engine.js"; const ratio = Number(process.argv[2]); if (!Number.isFinite(ratio) || ratio <= 0 || ratio > 1) throw new Error("usage: probe-collapse-ratio.mjs RATIO"); 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 engine = await factory({ wasmBinary }); const handle = engine._web_engine_create(); const text = new TextEncoder(); function open() { 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); return result; } function snapshot() { const dataOut = engine._malloc(4); const lengthOut = engine._malloc(4); try { const result = engine._web_engine_get_scene_snapshot(handle, dataOut, lengthOut); if (result !== 0) throw new Error("snapshot 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 apply(meshId, revision) { const command = text.encode(JSON.stringify({ type: "decimateMesh", meshId, profile: { schemaVersion: 1, sourceMeshRevision: revision, attributePolicy: "PRESERVE", mode: "COLLAPSE", ratio, triangulate: false, useSymmetry: false }, })); const pointer = engine._malloc(command.byteLength); engine.HEAPU8.set(command, pointer); const result = engine._web_engine_apply_command(handle, pointer, command.byteLength); engine._free(pointer); return result; } const opened = open(); if (opened !== 0) throw new Error(`open failed code=${opened} message=${engine.UTF8ToString(engine._web_engine_last_error_message())}`); const source = snapshot(); const mesh = source.meshes.find((candidate) => candidate.id === "mesh:Cube.001") ?? source.meshes.find((candidate) => candidate.geometryStatus === "available"); if (!mesh) throw new Error("cube mesh not found"); const result = apply(mesh.id, source.revision); const message = engine.UTF8ToString(engine._web_engine_last_error_message()); let output = null; if (result === 0) output = snapshot().meshes.find((candidate) => candidate.id === mesh.id); console.log(JSON.stringify({ ratio, result, message, allocatedBytes: engine._web_engine_get_allocated_bytes(), output: output && { vertexCount: output.vertexCount, triangleCount: output.triangleCount, faceCount: output.faceCount } })); engine._web_engine_destroy(handle);