<?phpnamespace App\Engine;/** * Every picture of the game (assets/data/art.pak, made by tools/make-art.php): wall textures (column-major), * flats (64 x 64 row-major), sprites (column-major, index 255 transparent), first-person weapons, status bar. * Darkened copies are made on demand with strtr() and kept: the renderer then reads plain bytes. */final class Art{ public array $walls; public array $flats; public array $sprites; public array $weapons; public array $hud; public array $sky; /** @var array<string, array<int, string>> */ private array $wallShades = []; private array $flatShades = []; private array $spriteShades = []; /** animated flats: base name => current frame name */ public array $flatFrame = []; private static ?self $instance = null; public function __construct(string $pakFile) { $pak = unserialize((string)file_get_contents($pakFile)); if (!is_array($pak)) { throw new \RuntimeException("Cannot read $pakFile"); } $this->walls = $pak['walls']; $this->flats = $pak['flats']; $this->sprites = $pak['sprites']; $this->weapons = $pak['weapons']; $this->hud = $pak['hud']; $this->sky = $pak['sky']; foreach ($this->walls as &$w) { $w['wmask'] = $w['w'] - 1; $w['hmask'] = $w['h'] - 1; } unset($w); } /** One instance for the whole program: the pack is read once. */ public static function get(string $pakFile): self { return self::$instance ??= new self($pakFile); } public function wall(string $name, int $level): string { return $this->wallShades[$name][$level] ??= Palette::darken($this->walls[$name]['px'] ?? $this->walls['TECH']['px'], $level); } public function flat(string $name, int $level): string { $name = $this->flatFrame[$name] ?? $name; return $this->flatShades[$name][$level] ??= Palette::darken($this->flats[$name] ?? $this->flats['FLOOR1'], $level); } /** The shaded column-major pixels of a sprite picture. */ public function spritePixels(array $pic, string $key, int $level): string { return $this->spriteShades[$key][$level] ??= Palette::darken($pic['px'], $level); } /** Animated flats: ACID1 -> ACID1..3, a frame every 8 tics (p_spec.c's anims). */ public function animate(int $tic): void { $k = intdiv($tic, 8) % 3 + 1; foreach (['ACID', 'LAVA', 'BLOOD'] as $base) { for ($i = 1; $i <= 3; $i++) { $this->flatFrame[$base . $i] = $base . ((($i - 1 + $k - 1) % 3) + 1); } } } /** * The picture of a sprite frame for a view rotation 1..8 (0 = the same for every angle). * @return array{0: array, 1: string}|null the picture and its cache key */ public function spriteFrame(string $sprite, string $frame, int $rot): ?array { $f = $this->sprites[$sprite][$frame] ?? null; if ($f === null) { return null; } if (isset($f[0])) { return [$f[0], "$sprite$frame" . '0']; } return [$f[$rot], "$sprite$frame$rot"]; }}