forked from phenom/healer-man
78 lines
2.8 KiB
JavaScript
78 lines
2.8 KiB
JavaScript
import test from "node:test";
|
|
import assert from "node:assert/strict";
|
|
import { composeWowAdtTerrainWeights, decodeWowAdtAlphaMap, wowAdtNormalizedUv } from "./wow-adt-terrain-material.mjs";
|
|
|
|
function layer(index, alphaMapEncoding, alphaMapDataOffset, alphaMapBytes, flags = 0x100) {
|
|
return {
|
|
index,
|
|
usesAlphaMap: (flags & 0x100) !== 0,
|
|
alphaMapCompressed: (flags & 0x200) !== 0,
|
|
alphaMapAvailable: true,
|
|
alphaMapEncoding,
|
|
alphaMapDataOffset,
|
|
alphaMapBytes,
|
|
alphaOffset: alphaMapDataOffset,
|
|
flags,
|
|
};
|
|
}
|
|
|
|
test("classic 4-bit maps expand and get deterministic edge repair", () => {
|
|
const bytes = Buffer.alloc(2048, 0x21);
|
|
const chunk = { indexX: 4, indexY: 7, flags: 0, layers: [] };
|
|
const decoded = decodeWowAdtAlphaMap(bytes, chunk, layer(1, "packed-4", 0, 2048));
|
|
assert.equal(decoded[0], 17);
|
|
assert.equal(decoded[1], 34);
|
|
assert.equal(decoded[63], decoded[62]);
|
|
assert.equal(decoded[63 * 64], decoded[62 * 64]);
|
|
|
|
chunk.flags = 0x8000;
|
|
const untouched = decodeWowAdtAlphaMap(bytes, chunk, layer(1, "packed-4", 0, 2048));
|
|
assert.equal(untouched[63], 34);
|
|
assert.equal(untouched[63 * 64], 17);
|
|
});
|
|
|
|
test("classic 4-bit opacity layers become ordered residual weights", () => {
|
|
const bytes = Buffer.alloc(4096, 0x88);
|
|
const chunk = {
|
|
indexX: 0,
|
|
indexY: 0,
|
|
flags: 0x8000,
|
|
layers: [
|
|
{ index: 0, usesAlphaMap: false },
|
|
layer(1, "packed-4", 0, 2048),
|
|
layer(2, "packed-4", 2048, 2048),
|
|
],
|
|
};
|
|
const weights = composeWowAdtTerrainWeights(bytes, chunk);
|
|
assert.equal(weights.sourcePolicy, "classic-nibble-to-big-alpha");
|
|
assert.deepEqual(weights.channelLayerIndices, [1, 2]);
|
|
assert.equal(weights.rgba[0], 63); // earlier overlay receives only remaining coverage
|
|
assert.equal(weights.rgba[1], 136); // last layer remains topmost
|
|
assert.equal(weights.rgba[2], 0);
|
|
assert.equal(weights.rgba[3], 255);
|
|
assert.equal(weights.maxWeightSum, 199);
|
|
});
|
|
|
|
test("compressed 8-bit MCAL fills exactly one 64x64 map", () => {
|
|
const packed = [];
|
|
let remaining = 4096;
|
|
while (remaining) {
|
|
const count = Math.min(127, remaining);
|
|
packed.push(0x80 | count, 37);
|
|
remaining -= count;
|
|
}
|
|
const bytes = Buffer.from(packed);
|
|
const chunk = { indexX: 1, indexY: 2, flags: 0x8000, layers: [] };
|
|
const decoded = decodeWowAdtAlphaMap(bytes, chunk, layer(1, "rle-8", 0, bytes.length, 0x300));
|
|
assert.equal(decoded.length, 4096);
|
|
assert.equal(decoded[0], 37);
|
|
assert.equal(decoded[4095], 37);
|
|
assert.throws(() => decodeWowAdtAlphaMap(Buffer.from([0x81]), chunk, layer(1, "rle-8", 0, 1, 0x300)), /truncated MCAL fill/);
|
|
});
|
|
|
|
test("normalized MCVT UVs follow source-positive local rows and stagger", () => {
|
|
assert.deepEqual(wowAdtNormalizedUv(0, 0), [0, 0]);
|
|
assert.deepEqual(wowAdtNormalizedUv(1, 0), [0.0625, 0.0625]);
|
|
assert.deepEqual(wowAdtNormalizedUv(16, 8), [1, 1]);
|
|
});
|