import assert from "node:assert/strict"; import { mkdtemp, rm } from "node:fs/promises"; import os from "node:os"; import path from "node:path"; import sharp from "sharp"; import test from "node:test"; import { Document, NodeIO } from "@gltf-transform/core"; import { ALL_EXTENSIONS } from "@gltf-transform/extensions"; import { MeshoptDecoder } from "meshoptimizer"; import { auditGeometry } from "./audit-wow-visual-quality.mjs"; function addTriangle(document, buffer, { name, offset, material = null, textured = false, uvValues = null }) { const positions = document.createAccessor(`${name}-positions`) .setType("VEC3") .setArray(new Float32Array([ offset, 0, 0, offset + 1, 0, 0, offset, 1, 0, ])) .setBuffer(buffer); const primitive = document.createPrimitive().setAttribute("POSITION", positions); if (textured) { const texcoords = document.createAccessor(`${name}-uvs`) .setType("VEC2") .setArray(new Float32Array(uvValues ?? [0, 0, 1, 0, 0, 1])) .setBuffer(buffer); primitive.setAttribute("TEXCOORD_0", texcoords); } if (material) primitive.setMaterial(material); const mesh = document.createMesh(`${name}-mesh`).addPrimitive(primitive); return document.createNode(name).setMesh(mesh); } test("WoW visual audit counts untextured and material-free surfaces safely", async (context) => { const workingDirectory = await mkdtemp(path.join(os.tmpdir(), "wow-visual-audit-")); context.after(async () => rm(workingDirectory, { recursive: true, force: true })); const visualFile = path.join(workingDirectory, "coverage-fixture.glb"); const io = new NodeIO() .registerExtensions(ALL_EXTENSIONS) .registerDependencies({ "meshopt.decoder": MeshoptDecoder }); const document = new Document(); const buffer = document.createBuffer(); const image = await sharp({ create: { width: 1, height: 1, channels: 4, background: { r: 180, g: 140, b: 90, alpha: 1 } }, }).png().toBuffer(); const texture = document.createTexture("textured-surface").setMimeType("image/png").setImage(image); const texturedMaterial = document.createMaterial("textured").setBaseColorTexture(texture); const plainMaterial = document.createMaterial("plain").setBaseColorFactor([0.35, 0.31, 0.24, 1]); const scene = document.createScene("coverage-fixture") .addChild(addTriangle(document, buffer, { name: "textured", offset: 0, material: texturedMaterial, textured: true })) .addChild(addTriangle(document, buffer, { name: "plain", offset: 3, material: plainMaterial })) .addChild(addTriangle(document, buffer, { name: "no-material", offset: 6 })) .addChild(addTriangle(document, buffer, { name: "degenerate-uv", offset: 9, material: texturedMaterial, textured: true, uvValues: [0, 0, 0, 0, 1, 1], })); document.getRoot().setDefaultScene(scene); await io.write(visualFile, document); const result = await auditGeometry(visualFile, [[1, 1]], "coverage fixture"); assert.equal(result.materialCoverage.totalTriangles, 4); assert.equal(result.materialCoverage.baseColorTexturedTriangles, 2); assert.equal(result.materialCoverage.untexturedTriangles, 2); assert.equal(result.materialCoverage.baseColorTexturedAreaM2, 1); assert.equal(result.materialCoverage.untexturedAreaM2, 1); assert.deepEqual(Object.keys(result.materialCoverage.untexturedMaterials).sort(), ["(no material)", "plain"]); assert.equal(result.materialCoverage.untexturedMaterials.plain.triangles, 1); assert.deepEqual(result.materialCoverage.untexturedMaterials.plain.baseColorFactor, [0.35, 0.31, 0.24, 1]); assert.equal(result.materialCoverage.untexturedMaterials["(no material)"].triangles, 1); const hotspotResult = await auditGeometry(visualFile, [[1, 1]], "coverage hotspot fixture", { hotspotCellSizeM: 2 }); assert.equal(hotspotResult.uvHotspots.length, 1); assert.deepEqual(hotspotResult.uvHotspots[0].center, [9, 0.33, 1]); assert.equal(hotspotResult.uvHotspots[0].uvDegenerateTriangles, 1); assert.equal(hotspotResult.uvHotspots[0].rankCollapsedAreaM2, 0.5); });