Files
yawn/addons/handles/test/import-gltf.test.ts

146 lines
4.3 KiB
TypeScript

import assert from "node:assert/strict";
import test from "node:test";
import { importGltf } from "../src/importers/gltf";
import { createScene, latestGraph, testCore } from "./scene-helpers";
function close(actual: ArrayLike<number>, expected: ArrayLike<number>) {
assert.equal(actual.length, expected.length);
for (let index = 0; index < actual.length; index++)
assert.ok(Math.abs(actual[index] - expected[index]) < 1e-5);
}
test("importGltf hydrates worker output into one batched scene update", async () => {
const previousWorker = globalThis.Worker;
const previousImageBitmap = globalThis.ImageBitmap;
const previousCreateImageBitmap = globalThis.createImageBitmap;
class MockImageBitmap {
readonly width = 1;
readonly height = 1;
}
const workerResult = {
camera: { direction: [0, 0, 1], fov: 1.1 },
textures: [
{
image: new MockImageBitmap(),
sampler: {
magFilter: "linear",
minFilter: "linear",
mipmapFilter: "linear",
addressModeU: "repeat",
addressModeV: "repeat",
},
},
],
materials: [
{
baseColor: [0.2, 0.4, 0.6, 1],
metallic: 0.3,
roughness: 0.7,
flags: 0,
baseColorTexture: 0,
metallicRoughnessTexture: -1,
normalTexture: -1,
emissiveTexture: -1,
occlusionTexture: -1,
transmissionTexture: -1,
thicknessTexture: -1,
clearcoatTexture: -1,
iridescenceTexture: -1,
iridescenceThicknessTexture: -1,
anisotropyTexture: -1,
specularTexture: -1,
specularColorTexture: -1,
},
],
primitives: [
{
positions: new Float32Array([0, 0, 0, 1, 0, 0, 0, 1, 0]),
normals: new Float32Array([0, 0, 1, 0, 0, 1, 0, 0, 1]),
uvs: new Float32Array([0, 0, 1, 0, 0, 1]),
indices: new Uint32Array([0, 1, 2]),
material: 0,
position: [2, 3, 4],
rotor: [0, 0, 0, 1],
scale: [1, 1, 1],
},
],
lights: [
{
type: "point",
color: [1, 0.5, 0.25],
intensity: 6,
range: 12,
position: [4, 5, 6],
},
],
};
class MockWorker {
#listeners = new Map<string, (event: any) => void>();
addEventListener(type: string, listener: (event: any) => void) {
this.#listeners.set(type, listener);
}
postMessage(message: { request: number }) {
queueMicrotask(() =>
this.#listeners.get("message")?.({
data: { request: message.request, result: workerResult },
}),
);
}
}
Object.defineProperties(globalThis, {
Worker: { configurable: true, value: MockWorker },
ImageBitmap: { configurable: true, value: MockImageBitmap },
createImageBitmap: {
configurable: true,
value: async () => new MockImageBitmap(),
},
});
try {
const scene = await createScene();
const core = testCore(scene);
const compiled = core.graphs.length;
const meshes = await importGltf(scene, "https://example.test/model.glb");
assert.equal(meshes.length, 1);
assert.deepEqual(meshes.camera, workerResult.camera);
assert.deepEqual(meshes[0].position.toArray(), [2, 3, 4]);
assert.deepEqual(
Array.from(scene.geometryData(meshes[0].geometryId, "indices")!),
[0, 1, 2],
);
close(
scene.array("materials").row(meshes[0].materialId).slice(0, 6),
[0.2, 0.4, 0.6, 1, 0.3, 0.7],
);
assert.equal(
scene.array("materialTextures").row(meshes[0].materialId)[0],
1,
);
assert.deepEqual(
Array.from(scene.array("pointLights").row(1)),
[1, 0.5, 0.25, 6, 12, 1, 0, 0],
);
const texture = latestGraph(scene).resources.textures.find(
(resource: any) => resource.id.startsWith("texture-"),
);
assert.equal(texture.format, "rgba8unorm-srgb");
assert.equal(core.uploadedTextures.length, 1);
assert.equal(core.graphs.length - compiled, 1);
} finally {
for (const [name, previous] of [
["Worker", previousWorker],
["ImageBitmap", previousImageBitmap],
["createImageBitmap", previousCreateImageBitmap],
] as const)
if (previous === undefined) delete (globalThis as any)[name];
else
Object.defineProperty(globalThis, name, {
configurable: true,
value: previous,
});
}
});