Files
Battle-for-Tismo/tests/fog_test.js
T

90 lines
3.8 KiB
JavaScript

import { TestCase } from "./framework/test_case.js";
import { MapTopology, mapToLocal } from "../shared/hex.js";
import { GLMapRenderer } from "../client/js/map_view/webgl.js";
import {
FOG_EXPLORED_OPACITY,
FOG_EXPLORED_RGB,
FOG_UNEXPLORED_OPACITY,
FOG_UNEXPLORED_RGB,
blurFog,
fogLevel,
isFogged,
} from "../client/js/map_view/fog.js";
// Two samples on opposite sides of a shared hex edge, halfway between the two
// tile centres.
const edgeSamples = (a, b) => [
{ level: a, dx: -23.625, dy: -14 },
{ level: b, dx: 23.625, dy: 14 },
];
export class FogTest extends TestCase {
test_levels_describe_visible_explored_and_unexplored_ground() {
this.assertFalse(isFogged(fogLevel(true, true)), "visible ground has no fog");
this.assertEqual(fogLevel(false, true).opacity, FOG_EXPLORED_OPACITY);
this.assertEqual(fogLevel(false, false).opacity, FOG_UNEXPLORED_OPACITY);
this.assertEqual(fogLevel(false, true).rgb, FOG_EXPLORED_RGB);
this.assertEqual(fogLevel(false, false).rgb, FOG_UNEXPLORED_RGB);
}
test_the_frontier_fades_instead_of_stepping() {
const explored = fogLevel(false, true);
const visible = fogLevel(true, true);
const blend = blurFog(edgeSamples(explored, visible));
// Half the kernel is over fogged ground, so the edge is about half as opaque
// as the explored tile rather than jumping straight to clear.
this.assertApprox(blend.opacity, FOG_EXPLORED_OPACITY / 2, 1e-6, "faded opacity");
this.assertEqual(blend.rgb, FOG_EXPLORED_RGB, "the fog keeps its colour");
}
test_a_tile_centre_keeps_its_own_fog() {
const unexplored = fogLevel(false, false);
const clear = fogLevel(true, true);
const blur = blurFog([
{ level: unexplored, dx: 0, dy: 0 },
{ level: clear, dx: 47.25, dy: 28 },
]);
this.assertGreater(blur.opacity, 0.9, "the middle of the fog stays opaque");
}
test_explored_and_unexplored_colours_mix() {
const blend = blurFog(edgeSamples(fogLevel(false, true), fogLevel(false, false)));
this.assertGreater(blend.opacity, FOG_EXPLORED_OPACITY, "between the two fog levels");
this.assertLess(blend.opacity, FOG_UNEXPLORED_OPACITY);
for (let i = 0; i < 3; i++) {
const low = Math.min(FOG_EXPLORED_RGB[i], FOG_UNEXPLORED_RGB[i]);
const high = Math.max(FOG_EXPLORED_RGB[i], FOG_UNEXPLORED_RGB[i]);
this.assertTrue(blend.rgb[i] >= low - 1e-9 && blend.rgb[i] <= high + 1e-9, `channel ${i} mixed`);
}
}
test_the_blur_agrees_from_both_sides_of_an_edge() {
// The renderer builds one ring per tile; both tiles on a shared edge must
// produce the same blurred fog there, or the frontier would seam.
const topology = new MapTopology({ x: 5, y: 5 }, false);
const renderer = Object.create(GLMapRenderer.prototype);
const levelAt = (x, y) => fogLevel(false, !(x === 0 && y === 0));
const centreA = mapToLocal(0, 0);
const centreB = mapToLocal(1, 0);
const ringA = renderer._fogRing(topology, 0, 0, centreA, levelAt);
const ringB = renderer._fogRing(topology, 1, 0, centreB, levelAt);
const px = (centreA.x + centreB.x) / 2;
const py = (centreA.y + centreB.y) / 2;
const samples = (ring) => ring.map((s) => ({ level: s.level, dx: s.x - px, dy: s.y - py }));
const a = blurFog(samples(ringA));
const b = blurFog(samples(ringB));
this.assertApprox(a.opacity, b.opacity, 1e-12, "the shared edge fades identically");
for (let i = 0; i < 3; i++) {
this.assertApprox(a.rgb[i], b.rgb[i], 1e-12, `channel ${i} agrees`);
}
}
test_off_map_neighbours_are_ignored() {
const blend = blurFog([
{ level: fogLevel(false, false), dx: 0, dy: 0 },
{ level: null, dx: 47.25, dy: 28 },
]);
this.assertApprox(blend.opacity, FOG_UNEXPLORED_OPACITY, 1e-6, "a missing tile does not dilute the fog");
}
}