import fs from "node:fs"; import factory from "../../web/app/src/vendor/blender/web_engine.js"; const fixtures = process.argv.slice(2); const fixtureNames = fixtures.length > 0 ? fixtures : [ "empty.blend", "basic_scene.blend", "rigged_shape_scene.blend", ]; function readFixture(name) { if (name.includes("/")) return fs.readFileSync(name); return fs.readFileSync(new URL(`../../tests/files/web/${name}`, import.meta.url)); } function openBlend(engine, handle, bytes) { const pointer = engine._malloc(bytes.byteLength); try { engine.HEAPU8.set(bytes, pointer); return engine._web_engine_open_blend(handle, pointer, bytes.byteLength); } finally { engine._free(pointer); } } function evaluate(engine, handle) { const dataOut = engine._malloc(4); const lengthOut = engine._malloc(4); try { const result = engine._web_engine_evaluate_depsgraph(handle, dataOut, lengthOut); const messagePointer = engine._web_engine_last_error_message(); const message = messagePointer ? engine.UTF8ToString(messagePointer) : ""; if (result !== 0) return { result, message }; const pointer = engine.HEAPU32[dataOut >>> 2]; const length = engine.HEAPU32[lengthOut >>> 2]; return { result, report: JSON.parse(new TextDecoder().decode(engine.HEAPU8.slice(pointer, pointer + length))) }; } finally { engine._free(dataOut); engine._free(lengthOut); } } function snapshot(engine, handle) { const dataOut = engine._malloc(4); const lengthOut = engine._malloc(4); try { if (engine._web_engine_get_scene_snapshot(handle, dataOut, lengthOut) !== 0) return null; 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); } } for (const fixtureName of fixtureNames) { process.stdout.write(`depsgraph-diagnostic fixture=${fixtureName} stage=create\n`); try { const engine = await factory({ wasmBinary: fs.readFileSync(new URL("../../web/app/src/vendor/blender/web_engine.wasm", import.meta.url)) }); const handle = engine._web_engine_create(); process.stdout.write(`depsgraph-diagnostic fixture=${fixtureName} stage=open\n`); const openResult = openBlend(engine, handle, readFixture(fixtureName)); if (openResult !== 0) { process.stdout.write(`depsgraph-diagnostic fixture=${fixtureName} open=${openResult} message=${engine.UTF8ToString(engine._web_engine_last_error_message())}\n`); engine._web_engine_destroy(handle); continue; } if (process.env.DIAGNOSE_SNAPSHOT === "1") { const scene = snapshot(engine, handle); process.stdout.write(`depsgraph-diagnostic fixture=${fixtureName} snapshot=${JSON.stringify(scene?.meshes?.map((mesh) => ({ id: mesh.id, modifiers: mesh.modifierStack })) ?? [])}\n`); } process.stdout.write(`depsgraph-diagnostic fixture=${fixtureName} stage=evaluate\n`); const evaluation = evaluate(engine, handle); process.stdout.write(`depsgraph-diagnostic fixture=${fixtureName} result=${JSON.stringify(evaluation)}\n`); engine._web_engine_destroy(handle); } catch (error) { const message = error instanceof Error ? error.message : String(error); process.stdout.write(`depsgraph-diagnostic fixture=${fixtureName} exception=${message}\n`); if (error instanceof Error && error.stack) { const wasmFrames = error.stack.split("\n") .filter((line) => line.includes("wasm-function") || line.trimStart().startsWith("at ")) .filter((line) => !line.includes("web_engine.js:9")) .slice(0, 16); for (const frame of wasmFrames) process.stdout.write(`depsgraph-diagnostic stack=${frame.trim()}\n`); } } }