import assert from "node:assert/strict"; import fs from "node:fs"; import factory from "../../web/app/src/vendor/blender/web_engine.js"; const root = new URL("../../", import.meta.url); const wasmBinary = fs.readFileSync(new URL("web/app/src/vendor/blender/web_engine.wasm", root)); const fixture = fs.readFileSync(new URL("tests/files/web/mask_scene.blend", root)); function open(engine, handle, bytes) { const pointer = engine._malloc(bytes.byteLength); try { engine.HEAPU8.set(bytes, pointer); assert.equal(engine._web_engine_open_blend(handle, pointer, bytes.byteLength), 0, engine.UTF8ToString(engine._web_engine_last_error_message())); } finally { engine._free(pointer); } } function snapshot(engine, handle) { const dataOut = engine._malloc(4), lengthOut = engine._malloc(4); try { assert.equal(engine._web_engine_get_scene_snapshot(handle, dataOut, lengthOut), 0, engine.UTF8ToString(engine._web_engine_last_error_message())); const pointer = engine.HEAPU32[dataOut >>> 2], length = engine.HEAPU32[lengthOut >>> 2]; return JSON.parse(new TextDecoder().decode(engine.HEAPU8.slice(pointer, pointer + length))); } finally { engine._free(dataOut); engine._free(lengthOut); } } const close = (actual, expected, label) => assert.ok(Math.abs(actual - expected) < 1e-6, `${label}: ${actual} != ${expected}`); const engine = await factory({ wasmBinary: wasmBinary.slice() }); const handle = engine._web_engine_create(); open(engine, handle, fixture); const scene = snapshot(engine, handle); assert.equal(scene.trackingMaskStatus, "AVAILABLE"); const project = scene.trackingMasks; assert.equal(project.schemaVersion, 1); assert.equal(project.clips.length, 0); assert.equal(project.bindings.length, 0); assert.equal(project.masks.length, 1); const mask = project.masks[0]; assert.equal(mask.id, "mask:WebMask"); assert.equal(mask.layers.length, 1); const layer = mask.layers[0]; assert.equal(layer.name, "WebMaskLayer"); assert.equal(layer.locked, true); close(layer.opacity, 0.625, "layer opacity"); const spline = layer.splines[0]; assert.equal(spline.cyclic, true); assert.equal(spline.fill, false); assert.equal(spline.points.length, 3); assert.deepEqual(spline.points.map((point) => point.handleType), ["ALIGNED", "VECTOR", "FREE"]); for (const [label, actual, expected] of [ ["point co", spline.points[0].co, [0.1, 0.2]], ["left handle", spline.points[0].handleLeft, [0.2, 0.2]], ["right handle", spline.points[0].handleRight, [0, 0.2]], ]) { actual.forEach((value, index) => close(value, expected[index], `${label}[${index}]`)); } close(spline.points[2].feather, 0.75, "point feather"); assert.deepEqual(spline.points.map((point) => point.selected), [true, false, true]); engine._web_engine_destroy(handle); process.stdout.write("mask-main-reader-ok layers-splines=passed handles-feather=passed selection=passed\n");