import assert from "node:assert/strict"; import { spawnSync } from "node:child_process"; import { mkdtemp, readFile, rm } from "node:fs/promises"; import os from "node:os"; import path from "node:path"; import test from "node:test"; import { fileURLToPath } from "node:url"; import { Document, NodeIO } from "@gltf-transform/core"; import { ALL_EXTENSIONS, KHRMaterialsVariants } from "@gltf-transform/extensions"; import sharp from "sharp"; import { MeshoptDecoder } from "meshoptimizer"; import { environmentOptimizationArguments } from "../lib/environment-optimization.mjs"; const projectRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "../../.."); const gltfTransformCli = path.join(projectRoot, "node_modules/@gltf-transform/cli/bin/cli.js"); const io = new NodeIO() .registerExtensions(ALL_EXTENSIONS) .registerDependencies({ "meshopt.decoder": MeshoptDecoder }); test("real glTF Transform optimize preserves opted-in material variant carriers and UVs", async (context) => { await MeshoptDecoder.ready; const workingDirectory = await mkdtemp(path.join(os.tmpdir(), "runewaker-water-variant-opt-")); context.after(async () => rm(workingDirectory, { recursive: true, force: true })); const sourceFile = path.join(workingDirectory, "water-variant-source.glb"); const outputFile = path.join(workingDirectory, "water-variant-optimized.glb"); const document = new Document(); const buffer = document.createBuffer("fixture"); const variants = document.createExtension(KHRMaterialsVariants).setRequired(false); const normalPng = await sharp({ create: { width: 4, height: 4, channels: 4, background: { r: 128, g: 128, b: 255, alpha: 1 } }, }).png().toBuffer(); const normalTexture = document.createTexture("native-normal-frame") .setImage(normalPng) .setMimeType("image/png"); const regularMaterial = document.createMaterial("source-water").setAlphaMode("BLEND"); const frameMaterial = document.createMaterial("normal-frame-00") .setNormalTexture(normalTexture) .setAlphaMode("OPAQUE"); frameMaterial.getNormalTextureInfo().setWrapS(10497).setWrapT(10497); const variant = variants.createVariant("native-frame-00"); const mapping = variants.createMappingList().addMapping( variants.createMapping().setMaterial(frameMaterial).addVariant(variant), ); const primitive = document.createPrimitive() .setAttribute("POSITION", document.createAccessor("positions", buffer) .setType("VEC3") .setArray(new Float32Array([0, 0, 0, 1, 0, 0, 0, 0, 1]))) .setAttribute("NORMAL", document.createAccessor("normals", buffer) .setType("VEC3") .setArray(new Float32Array([0, 1, 0, 0, 1, 0, 0, 1, 0]))) .setAttribute("TEXCOORD_0", document.createAccessor("source-world-xz", buffer) .setType("VEC2") .setArray(new Float32Array([100, 200, 110, 200, 100, 210]))) .setIndices(document.createAccessor("indices", buffer).setArray(new Uint16Array([0, 1, 2]))) .setMaterial(regularMaterial) .setExtension(KHRMaterialsVariants.EXTENSION_NAME, mapping); const mesh = document.createMesh("native-water").addPrimitive(primitive); const scene = document.createScene("scene").addChild(document.createNode("water-layer").setMesh(mesh)); document.getRoot().setDefaultScene(scene); await io.write(sourceFile, document); const args = environmentOptimizationArguments(sourceFile, outputFile, { preserveMaterialVariantCarriers: true }); assert.equal(args[args.indexOf("--join") + 1], "false"); assert.equal(args[args.indexOf("--prune") + 1], "false"); assert.equal(args[args.indexOf("--prune-attributes") + 1], "false"); const waterArgs = environmentOptimizationArguments(sourceFile, outputFile, { preserveNativeWaterLayers: true }); assert.equal(waterArgs[waterArgs.indexOf("--join") + 1], "false", "native water keeps its existing carrier-preservation behavior"); const optimized = spawnSync(process.execPath, [gltfTransformCli, ...args], { cwd: projectRoot, encoding: "utf8", windowsHide: true, }); assert.equal(optimized.status, 0, `${optimized.stdout}\n${optimized.stderr}`); const output = await io.read(outputFile); const outputMesh = output.getRoot().listMeshes().find((candidate) => candidate.getName() === "native-water"); const outputPrimitive = outputMesh?.listPrimitives()[0]; assert.ok(outputPrimitive, "optimized water primitive must remain present"); const texcoords = outputPrimitive.getAttribute("TEXCOORD_0"); assert.ok(texcoords, "normal-texture variant must retain its required UV0 attribute"); assert.equal(texcoords.getType(), "VEC2"); assert.deepEqual(Array.from(texcoords.getArray()), [100, 200, 110, 200, 100, 210]); const outputMapping = outputPrimitive.getExtension(KHRMaterialsVariants.EXTENSION_NAME)?.listMappings()[0]; assert.ok(outputMapping, "KHR_materials_variants mapping must survive optimize"); assert.equal(outputMapping.getMaterial()?.getNormalTexture()?.getName(), "native-normal-frame"); assert.deepEqual(outputMapping.listVariants().map((item) => item.getName()), ["native-frame-00"]); assert.ok((await readFile(outputFile)).length > 0); });