Files
healer-man/scripts/dungeon-pipeline/build-shadowfang-selective-visual.test.mjs
2026-10-06 22:25:34 -04:00

86 lines
4.2 KiB
JavaScript

import assert from "node:assert/strict";
import sharp from "sharp";
import test from "node:test";
import { Document } from "@gltf-transform/core";
import { MeshoptSimplifier } from "meshoptimizer";
import { eligibleFallbackMaterial, simplifyEligibleFallbackPrimitive } from "./shadowfang-fallback-preprocess.mjs";
function gridPrimitive(document, buffer, material, name, segments = 20) {
const positions = new Float32Array((segments + 1) * (segments + 1) * 3);
const indices = new Uint16Array(segments * segments * 6);
let indexOffset = 0;
for (let row = 0; row <= segments; row += 1) {
for (let column = 0; column <= segments; column += 1) {
const vertex = row * (segments + 1) + column;
positions.set([column, row, Math.sin(column * 0.2) * Math.cos(row * 0.2) * 0.1], vertex * 3);
if (row < segments && column < segments) {
const topLeft = vertex;
const topRight = vertex + 1;
const bottomLeft = vertex + segments + 1;
const bottomRight = bottomLeft + 1;
indices.set([topLeft, bottomLeft, topRight, topRight, bottomLeft, bottomRight], indexOffset);
indexOffset += 6;
}
}
}
const primitive = document.createPrimitive()
.setAttribute("POSITION", document.createAccessor(`${name}-position`).setType("VEC3").setArray(positions).setBuffer(buffer))
.setIndices(document.createAccessor(`${name}-indices`).setType("SCALAR").setArray(indices).setBuffer(buffer))
.setMaterial(material);
return primitive;
}
function triangleCount(primitive) {
return (primitive.getIndices()?.getCount() ?? primitive.getAttribute("POSITION").getCount()) / 3;
}
function accessorHash(accessor) {
const array = accessor.getArray();
return Buffer.from(array.buffer, array.byteOffset, array.byteLength).toString("base64");
}
test("selective Shadowfang simplification skips textured lookalikes and unrelated materials", async () => {
await MeshoptSimplifier.ready;
const document = new Document();
const buffer = document.createBuffer();
const image = await sharp({
create: { width: 1, height: 1, channels: 4, background: { r: 160, g: 120, b: 80, alpha: 1 } },
}).png().toBuffer();
const texture = document.createTexture("fallback-test").setMimeType("image/png").setImage(image);
const texturedTerrain = document.createMaterial("ADT_Terrain").setBaseColorTexture(texture);
const untexturedTerrain = document.createMaterial("ADT_Terrain.001");
const unrelated = document.createMaterial("WMO_Wall");
const profile = {
materialNamePattern: "^ADT_(Terrain|Liquid_B2)(?:\\.\\d+)?$",
sourceExpandedTriangles: { ADT_Terrain: 800 },
targetExpandedTriangles: { ADT_Terrain: 160 },
simplifyError: 1,
lockBorder: false,
};
const textured = gridPrimitive(document, buffer, texturedTerrain, "textured-terrain");
const fallback = gridPrimitive(document, buffer, untexturedTerrain, "fallback-terrain");
const wall = gridPrimitive(document, buffer, unrelated, "unrelated-wall");
const texturedBefore = {
positions: accessorHash(textured.getAttribute("POSITION")),
indices: accessorHash(textured.getIndices()),
};
const texturedTrianglesBefore = triangleCount(textured);
const fallbackTrianglesBefore = triangleCount(fallback);
const wallTrianglesBefore = triangleCount(wall);
assert.equal(eligibleFallbackMaterial(texturedTerrain, profile), null);
assert.equal(eligibleFallbackMaterial(untexturedTerrain, profile), "ADT_Terrain");
assert.equal(eligibleFallbackMaterial(unrelated, profile), null);
assert.equal(simplifyEligibleFallbackPrimitive(textured, profile), false);
assert.equal(simplifyEligibleFallbackPrimitive(wall, profile), false);
assert.equal(simplifyEligibleFallbackPrimitive(fallback, profile), true);
assert.equal(triangleCount(textured), texturedTrianglesBefore);
assert.deepEqual({
positions: accessorHash(textured.getAttribute("POSITION")),
indices: accessorHash(textured.getIndices()),
}, texturedBefore, "the textured same-name primitive must keep every accessor byte");
assert.ok(triangleCount(fallback) < fallbackTrianglesBefore, "the allowed untextured terrain must simplify");
assert.equal(triangleCount(wall), wallTrianglesBefore, "the allowlist must leave unrelated geometry alone");
});