#pragma once #include #include #include #include #include #include "core/rendering/shader_backend.hpp" #include "utils/defaults.hpp" class Screen { public: // Configuració typada de Screen. L'omple el Director des d'Options, // de manera que Screen no coneix YAML ni la capa Options directament. struct Config { int zoom{Defaults::Window::ZOOM}; bool fullscreen{Defaults::Window::FULLSCREEN}; bool vsync{Defaults::Video::VSYNC}; Defaults::ScalingMode scaling_mode{Defaults::Video::SCALING_MODE}; Defaults::TextureFilter texture_filter{Defaults::Video::TEXTURE_FILTER}; bool gpu_acceleration{Defaults::Video::GPU_ACCELERATION}; std::string preferred_driver{Defaults::Video::GPU_PREFERRED_DRIVER}; }; // Meyers singleton només per a l'accés (get()). El cicle de vida de SDL // el porta el Director: configure() i shutdown() s'han de cridar // explícitament, NO el destructor estàtic. El patró atexit + destructor // estàtic provoca segfaults a vkDestroyInstance en Wayland/Vulkan perquè // alguns recursos de SDL ja són inconsistents quan corre el destructor. static auto get() -> Screen&; Screen(const Screen&) = delete; Screen(Screen&&) = delete; auto operator=(const Screen&) -> Screen& = delete; auto operator=(Screen&&) -> Screen& = delete; // Inicialitza SDL_VIDEO i crea finestra + renderer o shader backend GPU // segons la config. Cal cridar-lo una vegada abans de qualsevol clear()/present(). void configure(const Config& config); // Destrueix tots els recursos SDL (finestra, GPU device, renderer, textura) // i tanca el subsistema de vídeo. El Director el crida ABANS de SDL_Quit. void shutdown(); void clear(std::uint8_t r = 0, std::uint8_t g = 0, std::uint8_t b = 0); void present(); [[nodiscard]] auto getRenderer() const -> SDL_Renderer* { return renderer_; } [[nodiscard]] auto getCanvasArgb() -> std::uint32_t* { return canvas_.data(); } [[nodiscard]] auto getCanvasWidth() const -> int { return canvas_width_; } [[nodiscard]] auto getCanvasHeight() const -> int { return canvas_height_; } private: Screen() = default; ~Screen() = default; void destroySdl(); void createSdl(); bool subsystem_initialized_{false}; Config config_{}; SDL_Window* window_{nullptr}; // Camí SDL_Renderer (fallback quan gpu_acceleration = false). SDL_Renderer* renderer_{nullptr}; SDL_Texture* game_texture_{nullptr}; // Camí SDL3 GPU (prioritari quan gpu_acceleration = true). std::unique_ptr shader_backend_; int canvas_width_{0}; int canvas_height_{0}; std::vector canvas_; };