Add Chromium-only Blender WebEngine parity work
This commit is contained in:
146
tools/web/check-lighting-roundtrip.mjs
Normal file
146
tools/web/check-lighting-roundtrip.mjs
Normal file
@@ -0,0 +1,146 @@
|
||||
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/basic_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 reject(engine, handle, payload, code) {
|
||||
const bytes = new TextEncoder().encode(JSON.stringify(payload));
|
||||
const pointer = engine._malloc(bytes.byteLength);
|
||||
try {
|
||||
engine.HEAPU8.set(bytes, pointer);
|
||||
assert.notEqual(engine._web_engine_apply_command(handle, pointer, bytes.byteLength), 0);
|
||||
assert.match(engine.UTF8ToString(engine._web_engine_last_error_message()), new RegExp(code));
|
||||
}
|
||||
finally { engine._free(pointer); }
|
||||
}
|
||||
|
||||
function close(actual, expected, label) {
|
||||
assert.ok(Math.abs(actual - expected) <= 1e-5, `${label}: ${actual} != ${expected}`);
|
||||
}
|
||||
|
||||
function assertLighting(scene) {
|
||||
const camera = scene.cameras.find((item) => item.id === "camera:Camera.001");
|
||||
const light = scene.lights.find((item) => item.id === "light:Area");
|
||||
const world = scene.worlds.find((item) => item.id === "world:World");
|
||||
const definition = scene.scenes.find((item) => item.id === "scene:Scene");
|
||||
assert.equal(camera.projection, "PERSPECTIVE");
|
||||
assert.equal(camera.depthOfField.enabled, false);
|
||||
assert.equal(camera.depthOfField.focusDistance, 10);
|
||||
assert.equal(light.energy, 800);
|
||||
assert.equal(light.exposure, 0);
|
||||
assert.equal(light.castsShadow, true);
|
||||
assert.equal(light.temperature, 6500);
|
||||
assert.equal(world.mist.enabled, false);
|
||||
assert.equal(world.mist.type, "QUADRATIC");
|
||||
assert.equal(definition.renderEngine, "BLENDER_EEVEE");
|
||||
assert.equal(definition.colorManagement.displayDevice, "sRGB");
|
||||
assert.equal(definition.colorManagement.viewTransform, "AgX");
|
||||
assert.equal(definition.colorManagement.look, "None");
|
||||
assert.equal(definition.colorManagement.exposure, 0);
|
||||
assert.equal(definition.colorManagement.whiteBalanceStatus, "AVAILABLE");
|
||||
close(definition.colorManagement.temperature, 6500, "scene temperature");
|
||||
close(definition.colorManagement.tint, 10, "scene tint");
|
||||
return { camera, light, world, definition };
|
||||
}
|
||||
|
||||
function assertEdited(scene) {
|
||||
const camera = scene.cameras.find((item) => item.id === "camera:Camera.001");
|
||||
const light = scene.lights.find((item) => item.id === "light:Area");
|
||||
const world = scene.worlds.find((item) => item.id === "world:World");
|
||||
const definition = scene.scenes.find((item) => item.id === "scene:Scene");
|
||||
assert.equal(camera.projection, "PERSPECTIVE");
|
||||
assert.equal(camera.depthOfField.enabled, false);
|
||||
close(light.energy, 400, "light energy");
|
||||
close(light.exposure, 1, "light exposure");
|
||||
assert.equal(light.castsShadow, false);
|
||||
assert.equal(light.useTemperature, true);
|
||||
close(light.temperature, 5000, "light temperature");
|
||||
assert.deepEqual(light.color, [0.25, 0.5, 0.75]);
|
||||
assert.equal(world.mist.enabled, true);
|
||||
assert.equal(world.mist.type, "LINEAR");
|
||||
close(world.mist.start, 2, "mist start");
|
||||
close(world.mist.depth, 50, "mist depth");
|
||||
close(world.mist.intensity, 0.2, "mist intensity");
|
||||
close(definition.colorManagement.exposure, 0, "preserved scene exposure");
|
||||
close(definition.colorManagement.gamma, 1, "preserved scene gamma");
|
||||
assert.equal(definition.colorManagement.whiteBalanceStatus, "BLOCKED");
|
||||
assert.equal(definition.colorManagement.temperature, undefined);
|
||||
assert.equal(definition.colorManagement.tint, undefined);
|
||||
return { camera, light, world, definition };
|
||||
}
|
||||
|
||||
const engine = await factory({ wasmBinary: wasmBinary.slice() });
|
||||
const handle = engine._web_engine_create();
|
||||
open(engine, handle, fixture);
|
||||
const before = assertLighting(snapshot(engine, handle));
|
||||
command(engine, handle, { type: "setObjectVisibility", objectId: "object:BasicCube", visible: true });
|
||||
assert.equal(snapshot(engine, handle).scenes.find((item) => item.id === before.definition.id).colorManagement.whiteBalanceStatus, "AVAILABLE");
|
||||
command(engine, handle, { type: "setLightProperties", dataId: before.light.id, properties: {
|
||||
color: [0.25, 0.5, 0.75], energy: 400, exposure: 1, castsShadow: false,
|
||||
temperature: 5000, useTemperature: true,
|
||||
} });
|
||||
assert.equal(snapshot(engine, handle).scenes.find((item) => item.id === before.definition.id).colorManagement.whiteBalanceStatus, "BLOCKED");
|
||||
command(engine, handle, { type: "setWorldProperties", dataId: before.world.id, properties: {
|
||||
color: [0.1, 0.2, 0.3], exposure: 0.5,
|
||||
mist: { enabled: true, type: "LINEAR", start: 2, depth: 50, intensity: 0.2, height: 3 },
|
||||
} });
|
||||
assert.equal(snapshot(engine, handle).scenes.find((item) => item.id === before.definition.id).colorManagement.whiteBalanceStatus, "BLOCKED");
|
||||
assertEdited(snapshot(engine, handle));
|
||||
assert.equal(engine._web_engine_undo(handle), 0, engine.UTF8ToString(engine._web_engine_last_error_message()));
|
||||
assert.equal(snapshot(engine, handle).worlds.find((item) => item.id === before.world.id).mist.enabled, false);
|
||||
assert.equal(engine._web_engine_redo(handle), 0, engine.UTF8ToString(engine._web_engine_last_error_message()));
|
||||
assertEdited(snapshot(engine, handle));
|
||||
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);
|
||||
assertEdited(snapshot(engine, reopened));
|
||||
engine._web_engine_destroy(reopened);
|
||||
|
||||
process.stdout.write("lighting-roundtrip-ok camera-dof=passed light-shadow-exposure=passed world-mist=passed color-management-reader=passed white-balance-gate=passed undo-redo=passed save-reopen=passed\n");
|
||||
Reference in New Issue
Block a user