pike/val Public Public: anyone can read this; nobody can change it.

forked from benjivers/val

workbenchthis machine
Files 674c40ddee5c18295fdc6a04cd14d0d0c8bbfce9
1
/**
2
 * The wall batching, as arithmetic: columns in, runs out. What matters is
3
 * that the runs say the same thing the columns did — every column covered
4
 * exactly once, in order — while there are far fewer of them.
5
 */
6
7
import { expect, test } from "bun:test";
8
import { covered, GEOM, hazeStep, makeColumns, SKY, wallRuns } from "../../static/engine/slices.js";
9
10
type Col = { level: number; side?: number; top?: number; high?: number; haze?: number };
11
12
/** Columns from a list, so a case reads as the picture it describes. */
13
function columns(list: Col[]) {
14
  const cols = makeColumns(list.length);
15
  list.forEach((c, i) => {
16
    cols.level[i] = c.level;
17
    cols.side[i] = c.side ?? 0;
18
    cols.top[i] = c.top ?? 100;
19
    cols.high[i] = c.high ?? 200;
20
    cols.haze[i] = c.haze ?? 0;
21
  });
22
  return cols;
23
}
24
25
const flat = (n: number, over: Col = { level: 7 }) => columns(Array.from({ length: n }, () => over));
26
27
test("a run of equal levels is one rectangle, however long it is", () => {
28
  const out: never[] = [];
29
  const used = wallRuns(flat(1280), out);
30
  expect(used).toBe(1);
31
  expect(out[0]).toMatchObject({ from: 0, to: 1279, level: 7 });
32
});
33
34
test("the picture's column count is unchanged: every column covered once", () => {
35
  const cols = columns([
36
    { level: 3 },
37
    { level: 3 },
38
    { level: 4 },
39
    { level: 4 },
40
    { level: 4 },
41
    { level: 9, side: 1 },
42
  ]);
43
  const out: { from: number; to: number }[] = [];
44
  const used = wallRuns(cols, out);
45
  expect(used).toBe(3);
46
  expect(covered(out, used)).toBe(6);
47
  // In order, end to end, no gaps and no overlap.
48
  expect(out.slice(0, used).map((r) => [r.from, r.to])).toEqual([
49
    [0, 1],
50
    [2, 4],
51
    [5, 5],
52
  ]);
53
});
54
55
test("each column its own level is one rectangle each: no picture is lost", () => {
56
  const cols = columns(Array.from({ length: 40 }, (_, i) => ({ level: i })));
57
  const out: never[] = [];
58
  const used = wallRuns(cols, out);
59
  expect(used).toBe(40);
60
  expect(covered(out, used)).toBe(40);
61
});
62
63
test("the same level on a different face is a different run", () => {
64
  const cols = columns([{ level: 5, side: 0 }, { level: 5, side: 1 }, { level: 5, side: 1 }]);
65
  const out: { side: number }[] = [];
66
  const used = wallRuns(cols, out);
67
  expect(used).toBe(2);
68
  expect(out[1]!.side).toBe(1);
69
});
70
71
test("sky ends a run and is covered by nothing", () => {
72
  const cols = columns([{ level: 2 }, { level: SKY }, { level: 2 }, { level: 2 }]);
73
  const out: { from: number; to: number }[] = [];
74
  const used = wallRuns(cols, out);
75
  expect(used).toBe(2);
76
  expect(covered(out, used)).toBe(3);
77
  expect(out[1]).toMatchObject({ from: 2, to: 3 });
78
});
79
80
test("slices that differ in height by more than half a pixel do not merge", () => {
81
  const near = columns([
82
    { level: 6, top: 100, high: 200 },
83
    { level: 6, top: 100 + GEOM / 2, high: 200 },
84
  ]);
85
  const far = columns([
86
    { level: 6, top: 100, high: 200 },
87
    { level: 6, top: 100, high: 200 + GEOM * 4 },
88
  ]);
89
  expect(wallRuns(near, [])).toBe(1);
90
  expect(wallRuns(far, [])).toBe(2);
91
});
92
93
test("haze joins the run's identity, quantised, so fog is batched too", () => {
94
  expect(hazeStep(0)).toBe(0);
95
  expect(hazeStep(1)).toBe(16);
96
  expect(hazeStep(2)).toBe(16); // clamped: nothing is fogged past opaque
97
  const cols = columns([
98
    { level: 6, haze: 0.5 },
99
    { level: 6, haze: 0.51 }, // the same step: one rectangle
100
    { level: 6, haze: 0.9 },
101
  ]);
102
  const out: { haze: number }[] = [];
103
  const used = wallRuns(cols, out);
104
  expect(used).toBe(2);
105
  expect(out[0]!.haze).toBeCloseTo(0.5, 5);
106
});
107
108
test("the run buffer is reused: a smaller frame allocates nothing new", () => {
109
  const out: unknown[] = [];
110
  wallRuns(columns(Array.from({ length: 30 }, (_, i) => ({ level: i }))), out);
111
  const grown = out.length;
112
  expect(grown).toBe(30);
113
  const used = wallRuns(flat(30), out);
114
  expect(used).toBe(1);
115
  expect(out.length).toBe(grown);
116
});
↑↓ navigate ↵ open esc close
↑↓ navigate ↵ open esc close

Keyboard shortcuts