94 lines
4.0 KiB
JavaScript
94 lines
4.0 KiB
JavaScript
import assert from "node:assert/strict";
|
|
import test from "node:test";
|
|
|
|
import { buildNativeWaterGeometry } from "./native-water-geometry.mjs";
|
|
|
|
const primaryPlacement = {
|
|
translation: [2, 3, 4],
|
|
rotation: [0, 0, 0, 1],
|
|
scale: [1, 1, 1],
|
|
};
|
|
|
|
function fixtureLayer({ flags = [0xff, 0xdf, 0x9f, 0xbf, 0x80, 0x00, 0xff, 0x9f, 0xbf] } = {}) {
|
|
const colors = [
|
|
0xff112233, 0xff445566, 0xff778899,
|
|
0xffaabbcc, 0xffddeeff, 0xff010203,
|
|
0xff102030, 0xff405060, 0xff708090,
|
|
];
|
|
return {
|
|
classGuid: "test-water",
|
|
version: 3,
|
|
waterBodyGuid: "exact-body-guid",
|
|
transform: { scale: [2, 1, 1], rotation: [0, 0, 0, 1], translation: [100, 5, 200] },
|
|
height: {
|
|
origin: [0, 0, 0], spacing: 10, overlap: 0, width: 3, height: 3,
|
|
values: Float32Array.from([1, 2, 3, 4, 5, 6, 7, 8, 9]),
|
|
},
|
|
color: {
|
|
present: true, origin: [0, 0, 0], spacing: 10, overlap: 0, width: 3, height: 3,
|
|
values: Uint32Array.from(colors),
|
|
},
|
|
flags: {
|
|
origin: [0, 0, 0], spacing: 10, overlap: 0, width: 3, height: 3,
|
|
values: Uint8Array.from(flags),
|
|
},
|
|
descriptorJoin: {
|
|
strategy: "exact serialized body GUID bytes",
|
|
status: "matched",
|
|
descriptorKeys: ["body-row"],
|
|
descriptors: [{ key: "body-row", guid: "exact-body-guid", effectType: 4 }],
|
|
},
|
|
unbuildableReason: null,
|
|
};
|
|
}
|
|
|
|
function assertClose(actual, expected, epsilon = 1e-6) {
|
|
assert.equal(actual.length, expected.length);
|
|
for (let index = 0; index < expected.length; index += 1) {
|
|
assert.ok(Math.abs(actual[index] - expected[index]) <= epsilon, `value[${index}] ${actual[index]} != ${expected[index]}`);
|
|
}
|
|
}
|
|
|
|
test("native water geometry expands even and odd pair patterns with one reflected-Z winding reversal", () => {
|
|
const built = buildNativeWaterGeometry([fixtureLayer()], primaryPlacement, 0.1);
|
|
const [water] = built.layers;
|
|
|
|
assert.equal(water.summary.consideredTwoCellQuadPairs, 2);
|
|
assert.equal(water.summary.emittedTwoCellQuadPairs, 2);
|
|
assert.equal(water.summary.emittedTriangles, 8);
|
|
assert.deepEqual(Array.from(water.indices.slice(0, 12)), [0, 4, 3, 0, 1, 4, 1, 2, 4, 2, 5, 4]);
|
|
assert.deepEqual(Array.from(water.indices.slice(12, 24)), [3, 4, 6, 4, 7, 6, 4, 5, 8, 4, 8, 7]);
|
|
assertClose(Array.from(water.positions.slice(0, 3)), [9.8, 0.3, -19.6]);
|
|
assert.equal(water.summary.sourceSplitPlaneHeight, 6);
|
|
assertClose(Array.from(water.positions.slice(3, 6)), [11.8, 0.4, -19.6]);
|
|
assertClose(Array.from(water.sourceWorldXZ.slice(0, 6)), [100, 200, 120, 200, 140, 200]);
|
|
assertClose(Array.from(water.sourceWorldXZ.slice(6, 12)), [100, 210, 120, 210, 140, 210]);
|
|
assert.deepEqual(Array.from(water.normals.slice(0, 3)), [0, 1, 0]);
|
|
assertClose(Array.from(water.colors.slice(0, 4)), [17 / 255, 34 / 255, 51 / 255, 1]);
|
|
assertClose([water.colors[1 * 4 + 3]], [125 / 255]);
|
|
assert.equal(water.layer.descriptorJoin.descriptors[0].effectType, 4);
|
|
});
|
|
|
|
test("water visibility bit masks pair geometry while preserving per-vertex diffuse alpha", () => {
|
|
const hidden = buildNativeWaterGeometry([fixtureLayer({ flags: new Array(9).fill(0x3f) })], primaryPlacement, 0.1);
|
|
assert.equal(hidden.layers[0].indices.length, 0);
|
|
assert.equal(hidden.layers[0].colors[3], 1);
|
|
|
|
const visibleFromOneVertex = buildNativeWaterGeometry([fixtureLayer({ flags: [0x80, 0, 0, 0, 0, 0, 0, 0, 0] })], primaryPlacement, 0.1);
|
|
assert.equal(visibleFromOneVertex.layers[0].summary.emittedTriangles, 4);
|
|
assert.equal(visibleFromOneVertex.layers[0].colors[3], 0);
|
|
});
|
|
|
|
test("native water builder refuses non-exact material joins and missing source color bytes", () => {
|
|
const unmatched = fixtureLayer();
|
|
unmatched.descriptorJoin.status = "missing";
|
|
assert.throws(() => buildNativeWaterGeometry([unmatched], primaryPlacement, 0.1), /descriptor GUID join is missing/);
|
|
|
|
const v1 = fixtureLayer();
|
|
v1.color = { present: false };
|
|
v1.unbuildableReason = "native v1 color absent";
|
|
const result = buildNativeWaterGeometry([v1], primaryPlacement, 0.1);
|
|
assert.equal(result.layers.length, 0);
|
|
assert.equal(result.skipped[0].reason, "native v1 color absent");
|
|
});
|