111 lines
3.9 KiB
C++
111 lines
3.9 KiB
C++
#pragma once
|
||
|
||
#include <SDL3/SDL.h>
|
||
|
||
#include <cstdint>
|
||
#include <memory>
|
||
|
||
#include "core/rendering/shader_backend.hpp"
|
||
|
||
class Screen {
|
||
public:
|
||
static void init();
|
||
static void destroy();
|
||
static auto get() -> Screen*;
|
||
|
||
// Presentació — rep el buffer ARGB de 320x200 de JD8
|
||
void present(Uint32* pixel_data);
|
||
|
||
// Gestió de finestra
|
||
void toggleFullscreen();
|
||
void incZoom();
|
||
void decZoom();
|
||
void setZoom(int zoom);
|
||
|
||
// Shaders i vídeo
|
||
// Mètodes que depenen d'una precondició (GPU present, shaders on, etc.)
|
||
// retornen `bool`: true si l'acció s'ha aplicat, false si la precondició
|
||
// no es complia. Els callers (F-keys, menú) poden suprimir notificacions
|
||
// o feedback quan la crida no ha tingut efecte.
|
||
void toggleShaders();
|
||
auto toggleSupersampling() -> bool; // false si GPU off / shaders off / actiu != POSTFX
|
||
void toggleAspectRatio();
|
||
void cycleScalingMode(int dir); // Cicla DISABLED/STRETCH/LETTERBOX/OVERSCAN/INTEGER
|
||
void toggleVSync();
|
||
void cycleTextureFilter(int dir); // Cicla NEAREST/LINEAR
|
||
void changeInternalResolution(int dir); // +/−1, clampat a [1, max_zoom_]
|
||
auto nextShaderType() -> bool; // false si GPU off / shaders off
|
||
auto prevShaderType() -> bool; // idem
|
||
auto nextPreset() -> bool; // false si GPU off / shaders off
|
||
auto prevPreset() -> bool; // idem
|
||
[[nodiscard]] auto getCurrentPresetName() const -> const char*;
|
||
void setActiveShader(Rendering::ShaderType type);
|
||
void applyCurrentPostFXPreset();
|
||
void applyCurrentCrtPiPreset();
|
||
|
||
// Getters
|
||
[[nodiscard]] auto isFullscreen() const -> bool { return fullscreen_; }
|
||
[[nodiscard]] auto getZoom() const -> int { return zoom_; }
|
||
[[nodiscard]] auto getMaxZoom() const -> int { return max_zoom_; }
|
||
[[nodiscard]] auto isHardwareAccelerated() const -> bool;
|
||
[[nodiscard]] auto getActiveShaderName() const -> const char*;
|
||
[[nodiscard]] auto getWindow() -> SDL_Window* { return window_; }
|
||
[[nodiscard]] auto getRenderer() -> SDL_Renderer* { return renderer_; }
|
||
|
||
#ifdef __EMSCRIPTEN__
|
||
// Sincronització amb el canvas HTML quan el navegador canvia la mida
|
||
// (fullscreen entrant/eixint, rotació de mòbil). Cridat pels callbacks
|
||
// natius d'Emscripten registrats al constructor.
|
||
void handleCanvasResized();
|
||
void syncFullscreenFlagFromBrowser(bool is_fullscreen);
|
||
#endif
|
||
|
||
private:
|
||
Screen();
|
||
~Screen();
|
||
|
||
void adjustWindowSize();
|
||
void calculateMaxZoom();
|
||
void initShaders();
|
||
void applyFallbackPresentation(); // Logical presentation + scale mode per al path SDL_Renderer
|
||
void ensureFallbackInternalTexture(); // Recrea internal_texture_sdl_ si cal (fallback path)
|
||
|
||
static Screen* instance_;
|
||
|
||
SDL_Window* window_{nullptr};
|
||
SDL_Renderer* renderer_{nullptr};
|
||
SDL_Texture* texture_{nullptr}; // 320x200 streaming, ABGR8888 (fallback SDL_Renderer)
|
||
SDL_Texture* internal_texture_sdl_{nullptr}; // 320·N x 200·N TARGET (fallback path, només si N>1)
|
||
int internal_texture_mult_{0}; // Multiplicador amb què es va crear internal_texture_sdl_
|
||
|
||
// Backend GPU (nullptr si no disponible o desactivat)
|
||
std::unique_ptr<Rendering::ShaderBackend> shader_backend_;
|
||
|
||
void updateRenderInfo();
|
||
|
||
struct FPS {
|
||
Uint32 ticks{0};
|
||
int frame_count{0};
|
||
int last_value{0};
|
||
|
||
void increment() { frame_count++; }
|
||
auto calculate(Uint32 current_ticks) -> int {
|
||
if (current_ticks - ticks >= 1000) {
|
||
last_value = frame_count;
|
||
frame_count = 0;
|
||
ticks = current_ticks;
|
||
}
|
||
return last_value;
|
||
}
|
||
};
|
||
|
||
int zoom_{3};
|
||
int max_zoom_{6};
|
||
bool fullscreen_{false};
|
||
FPS fps_;
|
||
std::string gpu_driver_;
|
||
|
||
static constexpr int GAME_WIDTH = 320;
|
||
static constexpr int GAME_HEIGHT = 200;
|
||
};
|