#pragma once #include #include #include #include "core/rendering/shader_backend.hpp" class Screen { public: static void init(); static void destroy(); static auto get() -> Screen*; ~Screen(); // públic per a std::unique_ptr // 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(); 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 std::unique_ptr 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 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; };