Reverse-engineered from its PowerPC binary and checked against the original running under emulation: textures byte for byte and every triangle, over 3,600 frames. 25 fps like the plugin; its colour maps and wave images are extracted from its own code; tests/kaleidostrobe_golden.npz was recorded from the original.
46 lines
2.2 KiB
Python
46 lines
2.2 KiB
Python
import sys; sys.path.insert(0, __file__.rsplit('/',1)[0]); sys.path.insert(0, str(__import__('pathlib').Path(__file__).resolve().parents[2]))
|
|
import numpy as np
|
|
from plugin import Plugin
|
|
from lintunes.kaleidostrobe import engine as E
|
|
|
|
TEXIDX, CURTEX, CURFRAME, WAVEINC = 0x457f8, 0x13dbc, 0x13dc0, 0x257f0
|
|
p = Plugin(seed=1); k = p.k
|
|
rng = np.random.default_rng(3)
|
|
bad = 0
|
|
for n in E.DELTA_TABLE:
|
|
for tex in (0, 1):
|
|
state = {}
|
|
# the emulator's static counters may already have moved during
|
|
# Plugin(); sync by reading them is fiddly, so zero them first
|
|
k.u.mem_write(0x13b2c, b'\0' * (0x13be4 - 0x13b2c))
|
|
for it in range(4):
|
|
src = rng.integers(0, 256, (128, 128), dtype=np.uint8)
|
|
base = TEXIDX + tex * 0x8000
|
|
k.u.mem_write(base, src.tobytes())
|
|
k.w32(CURTEX, tex); k.w32(CURFRAME + 4 * tex, 1)
|
|
k.call(f'_calcDelta{n:03d}')
|
|
theirs = np.frombuffer(k.mem(base + 0x4000, 0x4000), np.uint8).reshape(128, 128)
|
|
ours = E.delta(n, src, state)
|
|
d = int((theirs != ours).sum())
|
|
if d:
|
|
bad += 1; print(f'delta {n:03d} tex {tex} iter {it}: {d} differ')
|
|
print('deltas checked')
|
|
for seed in (5, 99, 31337):
|
|
for idx in range(len(E.WAVE_TABLE)):
|
|
k.rng.srand(seed); r = E.ParkMiller(seed)
|
|
tex = idx % 2
|
|
k.w32(CURTEX, tex); k.w32(CURFRAME + 4 * tex, 0)
|
|
n = E.WAVE_TABLE[idx]
|
|
k.call(f'_initWaveShape{n:03d}')
|
|
theirs = np.frombuffer(k.mem(TEXIDX + tex * 0x8000, 0x4000), np.uint8).reshape(128, 128)
|
|
eng = E.Kaleidostrobe.__new__(E.Kaleidostrobe)
|
|
t = E.tables(); eng.waves, eng.wave_inc = t['waves'], t['wave_inc']
|
|
eng.rng = r; eng.buffers = np.zeros((2, 2, 128, 128), np.uint8)
|
|
eng.wave_scale = [0.0, 0.0]; eng.cur_wave = [idx, idx]
|
|
eng._init_wave(tex)
|
|
d = int((theirs != eng.buffers[tex, 0]).sum())
|
|
inc = k.rf(WAVEINC + 4 * tex)
|
|
if d or abs(inc - eng.wave_scale[tex]) > 1e-7 or k.rng.x != r.x:
|
|
bad += 1; print(f'wave {n:03d} seed {seed}: {d} differ, inc {inc} vs {eng.wave_scale[tex]}, rng {k.rng.x == r.x}')
|
|
print('waves checked; failures:', bad)
|