From fdd34eb94348fa895e11e557e6062b2f01189254 Mon Sep 17 00:00:00 2001 From: Sergio Valor Date: Wed, 20 May 2026 19:35:35 +0200 Subject: [PATCH] refactor(#28): SDLManager rep Config::EngineConfig + on_persist callback MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Pas 4/N del hallazgo #28. SDLManager deixa d'incloure game/options.hpp. El ctor accepta ara una Config::EngineConfig& (per llegir/mutar window i rendering) i un opcional std::function on_persist callback. Canvis funcionals: - Es mantenen les mutacions de window.{width,height,zoom_factor,fullscreen} però ara sobre cfg_->window en lloc d'Options::window. Comportament idèntic perquè Options::window és un alias a engine_config.window. - toggleVSync deixa de cridar Options::saveToFile() directament i invoca on_persist_ si està connectat. El Director li passa una lambda que fa la persistència (mantenint sdl_manager agnòstic). - initWindowAndGpu (free function) rep el vsync inicial per paràmetre. - Eliminat el ctor per defecte (SDLManager()) que no era cridat des de cap call-site del projecte. Cleanup preexistent surfat per clang-tidy en treure el ctor default: - finestra_, max_width_, max_height_, max_zoom_ passen a tindre default member initializers; eliminat el seu ctor mem-init redundant. Co-Authored-By: Claude Opus 4.7 (1M context) --- source/core/rendering/sdl_manager.cpp | 148 +++++++++++--------------- source/core/rendering/sdl_manager.hpp | 94 ++++++++-------- source/core/system/director.cpp | 6 +- 3 files changed, 114 insertions(+), 134 deletions(-) diff --git a/source/core/rendering/sdl_manager.cpp b/source/core/rendering/sdl_manager.cpp index 22d2b86..47c5416 100644 --- a/source/core/rendering/sdl_manager.cpp +++ b/source/core/rendering/sdl_manager.cpp @@ -13,95 +13,65 @@ #include "core/defaults.hpp" #include "core/input/mouse.hpp" #include "core/rendering/coordinate_transform.hpp" -#include "game/options.hpp" #include "project.h" namespace { -auto initWindowAndGpu(SDL_Window** out_window, - Rendering::Renderer& gpu_renderer, - int width, int height, bool fullscreen) -> bool { - // Título estático estilo CCAE. El FPS y el estado de VSync los muestra - // el DebugOverlay (toggle F11), no la barra de título. - const std::string TITLE = std::format("© 2026 {} — JailDesigner", - Project::LONG_NAME); + auto initWindowAndGpu(SDL_Window** out_window, + Rendering::Renderer& gpu_renderer, + int width, + int height, + bool fullscreen, + int initial_vsync) -> bool { + // Título estático estilo CCAE. El FPS y el estado de VSync los muestra + // el DebugOverlay (toggle F11), no la barra de título. + const std::string TITLE = std::format("© 2026 {} — JailDesigner", + Project::LONG_NAME); - SDL_WindowFlags flags = SDL_WINDOW_RESIZABLE; - if (fullscreen) { - flags = static_cast(flags | SDL_WINDOW_FULLSCREEN); + SDL_WindowFlags flags = SDL_WINDOW_RESIZABLE; + if (fullscreen) { + flags = static_cast(flags | SDL_WINDOW_FULLSCREEN); + } + + SDL_Window* window = SDL_CreateWindow(TITLE.c_str(), width, height, flags); + if (window == nullptr) { + std::cerr << "Error creant finestra: " << SDL_GetError() << '\n'; + return false; + } + + if (!fullscreen) { + SDL_SetWindowPosition(window, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED); + } + + // Inicializar el FrameRenderer (claim del window + pipeline de líneas). + if (!gpu_renderer.init(window, + static_cast(Defaults::Game::WIDTH), + static_cast(Defaults::Game::HEIGHT))) { + std::cerr << "Error inicialitzant GpuFrameRenderer\n"; + SDL_DestroyWindow(window); + return false; + } + + gpu_renderer.setVSync(initial_vsync != 0); + + // Cargar parámetros del postpro desde el resource pack. Si el YAML falta + // o falla, el loader devuelve los defaults built-in (bloom suave + flicker + // sutil + background verde tenue). + gpu_renderer.setPostFx(Config::PostFx::load("config/postfx.yaml")); + + *out_window = window; + return true; } - - SDL_Window* window = SDL_CreateWindow(TITLE.c_str(), width, height, flags); - if (window == nullptr) { - std::cerr << "Error creant finestra: " << SDL_GetError() << '\n'; - return false; - } - - if (!fullscreen) { - SDL_SetWindowPosition(window, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED); - } - - // Inicializar el FrameRenderer (claim del window + pipeline de líneas). - if (!gpu_renderer.init(window, - static_cast(Defaults::Game::WIDTH), - static_cast(Defaults::Game::HEIGHT))) { - std::cerr << "Error inicialitzant GpuFrameRenderer\n"; - SDL_DestroyWindow(window); - return false; - } - - gpu_renderer.setVSync(Options::rendering.vsync != 0); - - // Cargar parámetros del postpro desde el resource pack. Si el YAML falta - // o falla, el loader devuelve los defaults built-in (bloom suave + flicker - // sutil + background verde tenue). - gpu_renderer.setPostFx(Config::PostFx::load("config/postfx.yaml")); - - *out_window = window; - return true; -} } // namespace -SDLManager::SDLManager() - : finestra_(nullptr), - current_width_(Defaults::Window::WIDTH), - current_height_(Defaults::Window::HEIGHT), - is_fullscreen_(false), - max_width_(1920), - max_height_(1080), - zoom_factor_(Defaults::Window::BASE_ZOOM), - windowed_width_(Defaults::Window::WIDTH), - windowed_height_(Defaults::Window::HEIGHT), - max_zoom_(1.0F) { - if (!SDL_Init(SDL_INIT_VIDEO)) { - std::cerr << "Error inicialitzant SDL3: " << SDL_GetError() << '\n'; - return; - } - - calculateMaxWindowSize(); - - if (!initWindowAndGpu(&finestra_, gpu_renderer_, current_width_, current_height_, false)) { - SDL_Quit(); - return; - } - - updateViewport(); - - std::cout << "SDL3 inicialitzat: " << current_width_ << "x" << current_height_ - << " (logic: " << Defaults::Game::WIDTH << "x" - << Defaults::Game::HEIGHT << ")" << '\n'; -} - -SDLManager::SDLManager(int width, int height, bool fullscreen) - : finestra_(nullptr), +SDLManager::SDLManager(int width, int height, bool fullscreen, Config::EngineConfig& cfg, std::function on_persist) + : cfg_(&cfg), + on_persist_(std::move(on_persist)), current_width_(width), current_height_(height), is_fullscreen_(fullscreen), - max_width_(1920), - max_height_(1080), zoom_factor_(static_cast(width) / Defaults::Window::WIDTH), windowed_width_(width), - windowed_height_(height), - max_zoom_(1.0F) { + windowed_height_(height) { if (!SDL_Init(SDL_INIT_VIDEO)) { std::cerr << "Error inicialitzant SDL3: " << SDL_GetError() << '\n'; return; @@ -109,7 +79,7 @@ SDLManager::SDLManager(int width, int height, bool fullscreen) calculateMaxWindowSize(); - if (!initWindowAndGpu(&finestra_, gpu_renderer_, current_width_, current_height_, is_fullscreen_)) { + if (!initWindowAndGpu(&finestra_, gpu_renderer_, current_width_, current_height_, is_fullscreen_, cfg_->rendering.vsync)) { SDL_Quit(); return; } @@ -194,9 +164,9 @@ void SDLManager::applyZoom(float new_zoom) { windowed_width_ = new_width; windowed_height_ = new_height; - Options::window.width = new_width; - Options::window.height = new_height; - Options::window.zoom_factor = zoom_factor_; + cfg_->window.width = new_width; + cfg_->window.height = new_height; + cfg_->window.zoom_factor = zoom_factor_; std::cout << "Zoom: " << zoom_factor_ << "x (" << new_width << "x" << new_height << ")" << '\n'; @@ -216,9 +186,9 @@ void SDLManager::updateViewport() { offset_y = std::max(offset_y, 0); gpu_renderer_.setViewport(static_cast(offset_x), - static_cast(offset_y), - static_cast(scaled_width), - static_cast(scaled_height)); + static_cast(offset_y), + static_cast(scaled_width), + static_cast(scaled_height)); std::cout << "Viewport: " << scaled_width << "x" << scaled_height << " @ (" << offset_x << "," << offset_y << ") [scale=" << scale << "]" @@ -288,7 +258,7 @@ void SDLManager::toggleFullscreen() { << windowed_width_ << "x" << windowed_height_ << ")" << '\n'; } - Options::window.fullscreen = is_fullscreen_; + cfg_->window.fullscreen = is_fullscreen_; Mouse::setForceHidden(is_fullscreen_); } @@ -334,7 +304,9 @@ void SDLManager::present() { } void SDLManager::toggleVSync() { - Options::rendering.vsync = (Options::rendering.vsync == 1) ? 0 : 1; - gpu_renderer_.setVSync(Options::rendering.vsync != 0); - Options::saveToFile(); + cfg_->rendering.vsync = (cfg_->rendering.vsync == 1) ? 0 : 1; + gpu_renderer_.setVSync(cfg_->rendering.vsync != 0); + if (on_persist_) { + on_persist_(); + } } diff --git a/source/core/rendering/sdl_manager.hpp b/source/core/rendering/sdl_manager.hpp index 86052e7..a1273c7 100644 --- a/source/core/rendering/sdl_manager.hpp +++ b/source/core/rendering/sdl_manager.hpp @@ -11,61 +11,67 @@ #include #include +#include +#include "core/config/engine_config.hpp" #include "core/rendering/render_context.hpp" class SDLManager { - public: - SDLManager(); // Constructor per defecte (usa Defaults::) - SDLManager(int width, int height, bool fullscreen); // Constructor con configuración - ~SDLManager(); + public: + // `cfg` ha de viure tant com el manager (el posseeix el Director). + // `on_persist` es crida després de mutar la config (per exemple a + // toggleVSync) per delegar la persistència en una capa externa + // (game/Options::saveToFile), mantenint sdl_manager agnòstic. + SDLManager(int width, int height, bool fullscreen, Config::EngineConfig& cfg, std::function on_persist = {}); + ~SDLManager(); - // No permetre còpia ni assignació - SDLManager(const SDLManager&) = delete; - auto operator=(const SDLManager&) -> SDLManager& = delete; + // No permetre còpia ni assignació + SDLManager(const SDLManager&) = delete; + auto operator=(const SDLManager&) -> SDLManager& = delete; - // [NUEVO] Gestió de finestra dinàmica - void increaseWindowSize(); // F2: +100px - void decreaseWindowSize(); // F1: -100px - void toggleFullscreen(); // F3 - void toggleVSync(); // F4 - auto handleWindowEvent(const SDL_Event& event) -> bool; // Per a SDL_EVENT_WINDOW_RESIZED + // [NUEVO] Gestió de finestra dinàmica + void increaseWindowSize(); // F2: +100px + void decreaseWindowSize(); // F1: -100px + void toggleFullscreen(); // F3 + void toggleVSync(); // F4 + auto handleWindowEvent(const SDL_Event& event) -> bool; // Per a SDL_EVENT_WINDOW_RESIZED - // Funciones principals (renderizado). - // clear() devuelve false si la swapchain no está disponible (p.ej. - // ventana minimizada). El caller debe saltarse draw+present ese frame. - [[nodiscard]] auto clear(uint8_t r = 0, uint8_t g = 0, uint8_t b = 0) -> bool; - void present(); + // Funciones principals (renderizado). + // clear() devuelve false si la swapchain no está disponible (p.ej. + // ventana minimizada). El caller debe saltarse draw+present ese frame. + [[nodiscard]] auto clear(uint8_t r = 0, uint8_t g = 0, uint8_t b = 0) -> bool; + void present(); - // Getters - auto getRenderer() -> Rendering::Renderer* { return &gpu_renderer_; } - [[nodiscard]] auto getScaleFactor() const -> float { return zoom_factor_; } + // Getters + auto getRenderer() -> Rendering::Renderer* { return &gpu_renderer_; } + [[nodiscard]] auto getScaleFactor() const -> float { return zoom_factor_; } - // [NUEVO] Actualitzar context de renderizado (factor de scale global) - void updateRenderingContext() const; + // [NUEVO] Actualitzar context de renderizado (factor de scale global) + void updateRenderingContext() const; - private: - SDL_Window* finestra_; - Rendering::Renderer gpu_renderer_; // GpuFrameRenderer (SDL3 GPU) + private: + SDL_Window* finestra_{nullptr}; + Rendering::Renderer gpu_renderer_; // GpuFrameRenderer (SDL3 GPU) + Config::EngineConfig* cfg_; // Propietat del Director, sobreviu al manager + std::function on_persist_; // Opcional: persistència delegada - // [NUEVO] Estat de la finestra - int current_width_; // Mida física actual - int current_height_; - bool is_fullscreen_; - int max_width_; // Calculat des del display - int max_height_; + // [NUEVO] Estat de la finestra + int current_width_; // Mida física actual + int current_height_; + bool is_fullscreen_; + int max_width_{1920}; // Fallback si no es pot llegir del display + int max_height_{1080}; - // [ZOOM SYSTEM] - float zoom_factor_; // Current zoom (0.5x to max_zoom_) - int windowed_width_; // Saved size before fullscreen - int windowed_height_; // Saved size before fullscreen - float max_zoom_; // Maximum zoom (calculated from display) - - // [NUEVO] Funciones internes - void calculateMaxWindowSize(); // Llegir resolució del display - void calculateMaxZoom(); // Calculate max zoom from display - void applyZoom(float new_zoom); // Apply zoom and resize window - void applyWindowSize(int width, int height); // Canviar mida + centrar - void updateViewport(); // Configurar viewport con letterbox + // [ZOOM SYSTEM] + float zoom_factor_; // Current zoom (0.5x to max_zoom_) + int windowed_width_; // Saved size before fullscreen + int windowed_height_; // Saved size before fullscreen + float max_zoom_{1.0F}; // Maximum zoom (calculated from display) + // [NUEVO] Funciones internes + void calculateMaxWindowSize(); // Llegir resolució del display + void calculateMaxZoom(); // Calculate max zoom from display + void applyZoom(float new_zoom); // Apply zoom and resize window + void applyWindowSize(int width, int height); // Canviar mida + centrar + void updateViewport(); // Configurar viewport con letterbox }; diff --git a/source/core/system/director.cpp b/source/core/system/director.cpp index 2296db9..29d1a18 100644 --- a/source/core/system/director.cpp +++ b/source/core/system/director.cpp @@ -220,8 +220,10 @@ auto Director::run() -> int { int initial_height = static_cast(std::round( Defaults::Window::HEIGHT * Options::window.zoom_factor)); - // Crear gestor SDL con configuración de Options - SDLManager sdl(initial_width, initial_height, Options::window.fullscreen); + // Crear gestor SDL con configuración de Options. + // Inyectamos la engine_config + un callback per persistir-la quan + // toggleVSync (F4) muti vsync, sense que sdl_manager conegui Options. + SDLManager sdl(initial_width, initial_height, Options::window.fullscreen, Options::engine_config, [] { Options::saveToFile(); }); // CRÍTIC: Forçar ocultació del cursor DESPRÉS de toda la inicialización SDL // Això evita que SDL mostre el cursor automàticament durante la creació de la finestra