<?phpnamespace App\Engine;use JumPHP\Kernel\Engine;use JumPHP\Renderer\Renderer;/** * Puts the 8-bit frame on the screen: palette -> RGBA in one strtr() (C speed), uploaded as one OpenGL / WebGL * texture and stretched over the view. Without GL (rare: a software SDL renderer) a BMP goes through GD. */final class Screen{ private int $texture = 0; private ?array $map = null; private ?array $wideMap = null; private ?array $tint = null; private ?bool $gl = null; private int $fallbackFrame = 0; public function __construct(private Engine $engine) { } /** Damage (red) / pickup (yellow) flash: [r, g, b, amount 0..1], or null. Rebuilds the colour map. */ public function setTint(?array $tint): void { if ($tint === $this->tint) { return; } $this->tint = $tint; $this->map = null; $this->wideMap = null; } /** * $view: palette frame of $vw x $vh ($vw = 320 or 160: low detail, each pixel doubled), $bar: 320 x n status bar. */ public function present(Renderer $r, string $view, int $vw, int $vh, string $bar, int $barH): void { $this->map ??= Palette::rgbaMap($this->tint); if ($vw === 160) { if ($this->wideMap === null) { $this->wideMap = []; foreach ($this->map as $k => $v) { $this->wideMap[$k] = $v . $v; } } $rgba = strtr($view, $this->wideMap); } else { $rgba = strtr($view, $this->map); } if ($barH > 0) { $rgba .= strtr($bar, $this->map); } $h = $vh + $barH; $gl = $this->engine->opengl(); $this->gl ??= $gl->isAvailable(); if ($this->gl) { // GL textures start at the bottom row $rgba = implode('', array_reverse(str_split($rgba, 320 * 4))); $this->texture = $gl->textureFromRgba(320, $h, $rgba, false, false, $this->texture ?: null); if ($gl->begin(null)) { $gl->blit($this->texture); $gl->end(); } return; } $this->fallback($r, $rgba, 320, $h); } private function fallback(Renderer $r, string $rgba, int $w, int $h): void { // RGBA -> BGRA, a top-down 32-bit BMP, read by GD $bgra = ''; $n = strlen($rgba); $bgra = $rgba; for ($i = 0; $i < $n; $i += 4) { $bgra[$i] = $rgba[$i + 2]; $bgra[$i + 2] = $rgba[$i]; } $bmp = 'BM' . pack('VvvV', 54 + $n, 0, 0, 54) . pack('VVVvvVVVVVV', 40, $w, (-$h) & 0xFFFFFFFF, 1, 32, 0, $n, 2835, 2835, 0, 0) . $bgra; $img = @imagecreatefromstring($bmp); if ($img === false) { return; } $name = 'frame' . ($this->fallbackFrame++ % 2); $sdl = $this->engine->sdl; $sdl->createTextureFromGd($name, $img); $r->copy($sdl->getTexture($name)['texture'], null, 0, 0, $r->getWidth(), $r->getHeight()); }}