138 lines
6.4 KiB
JavaScript
138 lines
6.4 KiB
JavaScript
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/modifier_grease_pencil_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 output(engine, handle, fn, owned = false) {
|
|
const dataOut = engine._malloc(4);
|
|
const lengthOut = engine._malloc(4);
|
|
try {
|
|
assert.equal(fn(handle, dataOut, lengthOut), 0, engine.UTF8ToString(engine._web_engine_last_error_message()));
|
|
const pointer = engine.HEAPU32[dataOut >>> 2];
|
|
const length = engine.HEAPU32[lengthOut >>> 2];
|
|
const bytes = engine.HEAPU8.slice(pointer, pointer + length);
|
|
if (owned) engine._web_engine_free_buffer(pointer);
|
|
return bytes;
|
|
}
|
|
finally {
|
|
engine._free(dataOut);
|
|
engine._free(lengthOut);
|
|
}
|
|
}
|
|
|
|
function snapshot(engine, handle) {
|
|
return JSON.parse(new TextDecoder().decode(output(engine, handle, engine._web_engine_get_scene_snapshot)));
|
|
}
|
|
|
|
function command(engine, handle, payload) {
|
|
const bytes = new TextEncoder().encode(JSON.stringify(payload));
|
|
const pointer = engine._malloc(bytes.byteLength);
|
|
try {
|
|
engine.HEAPU8.set(bytes, pointer);
|
|
assert.equal(engine._web_engine_apply_command(handle, pointer, bytes.byteLength), 0,
|
|
`${payload.type}: ${engine.UTF8ToString(engine._web_engine_last_error_message())}`);
|
|
}
|
|
finally { engine._free(pointer); }
|
|
}
|
|
|
|
function close(actual, expected, label) {
|
|
assert.ok(Math.abs(actual - expected) <= 1e-6, `${label}: ${actual} != ${expected}`);
|
|
}
|
|
|
|
function assertFixture(scene) {
|
|
const node = scene.nodes.find((candidate) => candidate.name === "GreasePencilObject");
|
|
const data = scene.greasePencils?.find((candidate) => candidate.name === "GreasePencilData");
|
|
assert.equal(node?.type, "GREASE_PENCIL");
|
|
assert.equal(node?.dataId, data?.id);
|
|
assert.equal(data?.geometryStatus, "available");
|
|
assert.equal(data?.layerCount, 1);
|
|
assert.equal(data?.frameCount, 1);
|
|
assert.equal(data?.strokeCount, 1);
|
|
assert.equal(data?.pointCount, 4);
|
|
const layer = data.layers[0];
|
|
const stroke = layer.frames[0].drawing.strokes[0];
|
|
assert.equal(layer.name, "Lines");
|
|
assert.equal(layer.visible, true);
|
|
assert.equal(layer.locked, false);
|
|
assert.equal(stroke.cyclic, false);
|
|
assert.equal(stroke.materialIndex, 0);
|
|
assert.deepEqual(stroke.points[0].position, [-1.5, 0, 0]);
|
|
close(stroke.points[0].radius, 0.05, "radius");
|
|
close(stroke.points[0].opacity, 0.9, "opacity");
|
|
assert.equal(data.attributes.length, 6);
|
|
}
|
|
|
|
const engine = await factory({ wasmBinary: wasmBinary.slice() });
|
|
const handle = engine._web_engine_create();
|
|
open(engine, handle, fixture);
|
|
assertFixture(snapshot(engine, handle));
|
|
const original = snapshot(engine, handle).greasePencils[0];
|
|
const dataId = original.id;
|
|
command(engine, handle, { type: "createGreasePencilLayer", dataId, name: "Web Drafts" });
|
|
let edited = snapshot(engine, handle).greasePencils[0];
|
|
assert.equal(edited.layerCount, 2);
|
|
const layerId = edited.layers.find((layer) => layer.name === "Web Drafts").id;
|
|
command(engine, handle, { type: "moveGreasePencilLayer", dataId, layerId, direction: "BOTTOM" });
|
|
edited = snapshot(engine, handle).greasePencils[0];
|
|
assert.equal(edited.layers[0].id, layerId);
|
|
command(engine, handle, { type: "insertGreasePencilFrame", dataId, layerId, frame: 10, duration: 4 });
|
|
const webStrokes = [{
|
|
cyclic: true,
|
|
materialIndex: 0,
|
|
points: [
|
|
{ position: [0, 0, 0], radius: 0.1, opacity: 0.7, vertexColor: [1, 0, 0, 1] },
|
|
{ position: [1, 1, 0], radius: 0.2, opacity: 0.8, vertexColor: [0, 1, 0, 1] },
|
|
{ position: [2, 0, 0], radius: 0.3, opacity: 0.9, vertexColor: [0, 0, 1, 1] },
|
|
],
|
|
}];
|
|
command(engine, handle, { type: "setGreasePencilStrokes", dataId, layerId, frame: 10, strokes: webStrokes });
|
|
edited = snapshot(engine, handle).greasePencils[0];
|
|
assert.equal(edited.frameCount, 2);
|
|
assert.equal(edited.strokeCount, 2);
|
|
assert.equal(edited.pointCount, 7);
|
|
assert.equal(edited.layers.find((layer) => layer.id === layerId).frames[0].drawing.strokes[0].cyclic, true);
|
|
assert.equal(engine._web_engine_undo(handle), 0, engine.UTF8ToString(engine._web_engine_last_error_message()));
|
|
assert.equal(snapshot(engine, handle).greasePencils[0].strokeCount, 1);
|
|
assert.equal(engine._web_engine_redo(handle), 0, engine.UTF8ToString(engine._web_engine_last_error_message()));
|
|
assert.equal(snapshot(engine, handle).greasePencils[0].pointCount, 7);
|
|
command(engine, handle, { type: "removeGreasePencilFrame", dataId, layerId, frame: 10 });
|
|
assert.equal(snapshot(engine, handle).greasePencils[0].frameCount, 1);
|
|
assert.equal(engine._web_engine_undo(handle), 0, engine.UTF8ToString(engine._web_engine_last_error_message()));
|
|
assert.equal(snapshot(engine, handle).greasePencils[0].frameCount, 2);
|
|
command(engine, handle, { type: "removeGreasePencilLayer", dataId, layerId });
|
|
assert.equal(snapshot(engine, handle).greasePencils[0].layerCount, 1);
|
|
assert.equal(engine._web_engine_undo(handle), 0, engine.UTF8ToString(engine._web_engine_last_error_message()));
|
|
edited = snapshot(engine, handle).greasePencils[0];
|
|
assert.equal(edited.layerCount, 2);
|
|
assert.equal(edited.pointCount, 7);
|
|
const saved = output(engine, handle, engine._web_engine_save_blend, true);
|
|
engine._web_engine_destroy(handle);
|
|
|
|
const reopened = engine._web_engine_create();
|
|
open(engine, reopened, saved);
|
|
const reopenedScene = snapshot(engine, reopened);
|
|
const reopenedData = reopenedScene.greasePencils[0];
|
|
assert.equal(reopenedData.layerCount, 2);
|
|
assert.equal(reopenedData.frameCount, 2);
|
|
assert.equal(reopenedData.strokeCount, 2);
|
|
assert.equal(reopenedData.pointCount, 7);
|
|
const reopenedStroke = reopenedData.layers.find((layer) => layer.name === "Web Drafts").frames[0].drawing.strokes[0];
|
|
assert.equal(reopenedStroke.cyclic, true);
|
|
assert.deepEqual(reopenedStroke.points[2].position, [2, 0, 0]);
|
|
close(reopenedStroke.points[2].radius, 0.3, "reopened radius");
|
|
engine._web_engine_destroy(reopened);
|
|
process.stdout.write("grease-pencil-roundtrip-ok layer-frame-stroke=passed undo-redo=passed save-reopen=passed\n");
|