diff --git a/source/core/config/engine_config.hpp b/source/core/config/engine_config.hpp index 32f91c8..3890dfe 100644 --- a/source/core/config/engine_config.hpp +++ b/source/core/config/engine_config.hpp @@ -25,7 +25,8 @@ namespace Config { }; struct RenderingConfig { - int vsync{1}; // 0=disabled, 1=enabled + int vsync{1}; // 0=disabled, 1=enabled + int antialias{1}; // 0=disabled, 1=enabled (AA geomètric a les línies, toggle F5) }; struct KeyboardBindings { diff --git a/source/core/defaults/rendering.hpp b/source/core/defaults/rendering.hpp index b6a636f..819b1fd 100644 --- a/source/core/defaults/rendering.hpp +++ b/source/core/defaults/rendering.hpp @@ -5,6 +5,7 @@ namespace Defaults::Rendering { - constexpr int VSYNC_DEFAULT = 1; // 0=disabled, 1=enabled + constexpr int VSYNC_DEFAULT = 1; // 0=disabled, 1=enabled + constexpr int ANTIALIAS_DEFAULT = 1; // 0=disabled, 1=enabled (AA geomètric a les línies) } // namespace Defaults::Rendering diff --git a/source/core/input/input.cpp b/source/core/input/input.cpp index 5009840..f7d2d95 100644 --- a/source/core/input/input.cpp +++ b/source/core/input/input.cpp @@ -39,6 +39,7 @@ Input::Input(std::string game_controller_db_path) {Action::WINDOW_INC_ZOOM, KeyState{.scancode = SDL_SCANCODE_F2}}, {Action::TOGGLE_FULLSCREEN, KeyState{.scancode = SDL_SCANCODE_F3}}, {Action::TOGGLE_VSYNC, KeyState{.scancode = SDL_SCANCODE_F4}}, + {Action::TOGGLE_ANTIALIAS, KeyState{.scancode = SDL_SCANCODE_F5}}, {Action::EXIT, KeyState{.scancode = SDL_SCANCODE_ESCAPE}}}; initSDLGamePad(); // Inicializa el subsistema SDL_INIT_GAMEPAD diff --git a/source/core/input/input_types.hpp b/source/core/input/input_types.hpp index 92f7a0f..a32f6d1 100644 --- a/source/core/input/input_types.hpp +++ b/source/core/input/input_types.hpp @@ -21,6 +21,7 @@ enum class InputAction : std::uint8_t { // Acciones de entrada posibles en el j WINDOW_DEC_ZOOM, // F1 TOGGLE_FULLSCREEN, // F3 TOGGLE_VSYNC, // F4 + TOGGLE_ANTIALIAS, // F5 EXIT, // ESC // Input obligatorio diff --git a/source/core/rendering/gpu/gpu_frame_renderer.cpp b/source/core/rendering/gpu/gpu_frame_renderer.cpp index 6c296be..16d9a27 100644 --- a/source/core/rendering/gpu/gpu_frame_renderer.cpp +++ b/source/core/rendering/gpu/gpu_frame_renderer.cpp @@ -243,21 +243,23 @@ namespace Rendering::GPU { return; } - // Antialias geomètric: extruim 0.5 píxel extra a cada banda del gruix - // demanat, i el fragment shader fa fade als bords usant edge_dist (±1 - // als laterals, 0 al centre). Així el gruix "ple" coincideix amb el - // demanat i el píxel extra només aporta la transició suau. - const float AA_PADDING = 0.5F; + // Antialias geomètric: quan està ON, extruim 0.5 píxel extra a cada + // banda del gruix demanat i posem edge_dist = ±1 als laterals; el + // fragment shader fa fade als bords. Quan està OFF, geometria nua + // (thickness exacte) i edge_dist = 0 a tots els vèrtexs → el + // smoothstep del shader produeix alpha=1 sempre. + const float AA_PADDING = antialias_enabled_ ? 0.5F : 0.0F; const float HALF = (thickness * 0.5F) + AA_PADDING; const float NX = -DY / LEN * HALF; const float NY = DX / LEN * HALF; + const float EDGE = antialias_enabled_ ? 1.0F : 0.0F; const auto BASE_INDEX = static_cast(vertices_.size()); - vertices_.push_back({x1 + NX, y1 + NY, r, g, b, a, +1.0F}); - vertices_.push_back({x1 - NX, y1 - NY, r, g, b, a, -1.0F}); - vertices_.push_back({x2 + NX, y2 + NY, r, g, b, a, +1.0F}); - vertices_.push_back({x2 - NX, y2 - NY, r, g, b, a, -1.0F}); + vertices_.push_back({x1 + NX, y1 + NY, r, g, b, a, +EDGE}); + vertices_.push_back({x1 - NX, y1 - NY, r, g, b, a, -EDGE}); + vertices_.push_back({x2 + NX, y2 + NY, r, g, b, a, +EDGE}); + vertices_.push_back({x2 - NX, y2 - NY, r, g, b, a, -EDGE}); indices_.push_back(BASE_INDEX + 0); indices_.push_back(BASE_INDEX + 1); diff --git a/source/core/rendering/gpu/gpu_frame_renderer.hpp b/source/core/rendering/gpu/gpu_frame_renderer.hpp index 376c1c5..2b2174d 100644 --- a/source/core/rendering/gpu/gpu_frame_renderer.hpp +++ b/source/core/rendering/gpu/gpu_frame_renderer.hpp @@ -27,30 +27,30 @@ namespace Rendering::GPU { -// Parámetros del postpro que el caller (SDLManager) pasa cada frame. -// Equivalente al lado "humano" del PostFxUniforms (sin paddings). -struct PostFxParams { - bool bloom_enabled{true}; - float bloom_intensity{0.6F}; - float bloom_threshold{0.4F}; - float bloom_radius_px{2.0F}; + // Parámetros del postpro que el caller (SDLManager) pasa cada frame. + // Equivalente al lado "humano" del PostFxUniforms (sin paddings). + struct PostFxParams { + bool bloom_enabled{true}; + float bloom_intensity{0.6F}; + float bloom_threshold{0.4F}; + float bloom_radius_px{2.0F}; - bool flicker_enabled{true}; - float flicker_amplitude{0.10F}; - float flicker_frequency_hz{6.0F}; + bool flicker_enabled{true}; + float flicker_amplitude{0.10F}; + float flicker_frequency_hz{6.0F}; - bool background_enabled{true}; - float background_min_r{0.0F}; - float background_min_g{0.02F}; - float background_min_b{0.0F}; - float background_max_r{0.0F}; - float background_max_g{0.06F}; - float background_max_b{0.0F}; - float background_pulse_freq_hz{6.0F}; -}; + bool background_enabled{true}; + float background_min_r{0.0F}; + float background_min_g{0.02F}; + float background_min_b{0.0F}; + float background_max_r{0.0F}; + float background_max_g{0.06F}; + float background_max_b{0.0F}; + float background_pulse_freq_hz{6.0F}; + }; -class GpuFrameRenderer { - public: + class GpuFrameRenderer { + public: GpuFrameRenderer() = default; ~GpuFrameRenderer(); @@ -72,8 +72,7 @@ class GpuFrameRenderer { [[nodiscard]] auto beginFrame(float clear_r, float clear_g, float clear_b) -> bool; // Encola una línea con grosor configurable (px). Color RGBA en [0..1]. - void pushLine(float x1, float y1, float x2, float y2, float thickness, - float r, float g, float b, float a); + void pushLine(float x1, float y1, float x2, float y2, float thickness, float r, float g, float b, float a); // endFrame: flush del batch de líneas → composite postpro → submit + presenta. void endFrame(); @@ -87,6 +86,13 @@ class GpuFrameRenderer { // Activa/desactiva VSync. true = SDL_GPU_PRESENTMODE_VSYNC, false = IMMEDIATE. void setVSync(bool enabled); + // Activa/desactiva l'antialias geomètric a les línies. Quan està OFF, + // pushLine no extrudeix píxel extra ni emet edge_dist (geometria com + // abans del commit d'AA-1). Quan està ON, l'extrusió i el fade del + // fragment shader produeixen bords suavitzats. + void setAntialias(bool enabled) { antialias_enabled_ = enabled; } + [[nodiscard]] auto isAntialiasEnabled() const -> bool { return antialias_enabled_; } + // Parámetros del postpro que se aplican en endFrame. Por defecto = // valores de Defaults (bloom moderado, flicker suave, fondo verde tenue). void setPostFx(const PostFxParams& params) { postfx_params_ = params; } @@ -96,7 +102,7 @@ class GpuFrameRenderer { [[nodiscard]] auto device() -> GpuDevice& { return device_; } [[nodiscard]] auto isInsideFrame() const -> bool { return cmd_buffer_ != nullptr; } - private: + private: GpuDevice device_; GpuLinePipeline line_pipeline_; GpuPostFxPipeline postfx_pipeline_; @@ -128,12 +134,15 @@ class GpuFrameRenderer { // Parámetros del postpro (configurables vía YAML). PostFxParams postfx_params_{}; + // Estat de l'antialias geomètric a les línies (toggle F5). + bool antialias_enabled_{true}; + // Helpers internos. [[nodiscard]] auto createOffscreen() -> bool; void destroyOffscreen(); void flushBatch(); void compositePass(); void applyFinalViewport(); -}; + }; } // namespace Rendering::GPU diff --git a/source/core/rendering/sdl_manager.cpp b/source/core/rendering/sdl_manager.cpp index f0b1b32..3bf8060 100644 --- a/source/core/rendering/sdl_manager.cpp +++ b/source/core/rendering/sdl_manager.cpp @@ -84,6 +84,9 @@ SDLManager::SDLManager(int width, int height, bool fullscreen, Config::EngineCon return; } + // Aplica l'estat inicial d'antialias des de la config (per defecte ON). + gpu_renderer_.setAntialias(cfg_->rendering.antialias != 0); + updateViewport(); // En fullscreen: forzar ocultació permanent del cursor. @@ -323,3 +326,11 @@ void SDLManager::toggleVSync() { on_persist_(); } } + +void SDLManager::toggleAntialias() { + cfg_->rendering.antialias = (cfg_->rendering.antialias == 1) ? 0 : 1; + gpu_renderer_.setAntialias(cfg_->rendering.antialias != 0); + // No persistim: l'AA és toggleable runtime però el seu estat no es + // guarda al YAML de moment (decisió volgudament conservadora). + std::cout << "F5: AA " << (cfg_->rendering.antialias != 0 ? "ON" : "OFF") << '\n'; +} diff --git a/source/core/rendering/sdl_manager.hpp b/source/core/rendering/sdl_manager.hpp index f5b0dfe..ca71bee 100644 --- a/source/core/rendering/sdl_manager.hpp +++ b/source/core/rendering/sdl_manager.hpp @@ -34,6 +34,7 @@ class SDLManager { void decreaseWindowSize(); // F1: -100px void toggleFullscreen(); // F3 void toggleVSync(); // F4 + void toggleAntialias(); // F5 auto handleWindowEvent(const SDL_Event& event) -> bool; // Per a SDL_EVENT_WINDOW_RESIZED // Funciones principals (renderizado). diff --git a/source/core/system/debug_overlay.cpp b/source/core/system/debug_overlay.cpp index 5e81d09..e8f2577 100644 --- a/source/core/system/debug_overlay.cpp +++ b/source/core/system/debug_overlay.cpp @@ -44,6 +44,7 @@ namespace System { const std::string FPS_TEXT = "FPS: " + std::to_string(fps_display_); const std::string VSYNC_TEXT = std::string("VSYNC: ") + (rendering_cfg_->vsync == 1 ? "ON" : "OFF"); + const std::string AA_TEXT = std::string("AA: ") + (rendering_cfg_->antialias == 1 ? "ON" : "OFF"); text_.render(FPS_TEXT, Vec2{.x = OVERLAY_X, .y = OVERLAY_Y_FPS}, @@ -55,6 +56,11 @@ namespace System { OVERLAY_SCALE, OVERLAY_SPACING, OVERLAY_BRIGHTNESS); + text_.render(AA_TEXT, + Vec2{.x = OVERLAY_X, .y = OVERLAY_Y_FPS + (2.0F * OVERLAY_LINE_HEIGHT)}, + OVERLAY_SCALE, + OVERLAY_SPACING, + OVERLAY_BRIGHTNESS); } } // namespace System diff --git a/source/core/system/global_events.cpp b/source/core/system/global_events.cpp index 1eb4fcc..3615126 100644 --- a/source/core/system/global_events.cpp +++ b/source/core/system/global_events.cpp @@ -5,10 +5,10 @@ #include -#include "scene_context.hpp" #include "core/input/input.hpp" #include "core/input/mouse.hpp" #include "core/rendering/sdl_manager.hpp" +#include "scene_context.hpp" // Using declarations per simplificar el codi using SceneManager::SceneContext; @@ -16,55 +16,59 @@ using SceneType = SceneContext::SceneType; namespace GlobalEvents { -auto handle(const SDL_Event& event, SDLManager& sdl, SceneContext& context) -> bool { - // 1. Permitir que Input procese el evento (para hotplug de gamepads) - auto event_msg = Input::get()->handleEvent(event); - if (!event_msg.empty()) { - std::cout << "[Input] " << event_msg << '\n'; - } - - // 2. Procesar SDL_EVENT_QUIT directamente (no es input de juego) - if (event.type == SDL_EVENT_QUIT) { - context.setNextScene(SceneType::EXIT); - SceneManager::actual = SceneType::EXIT; - return true; - } - - // 3. Gestió del ratolí (auto-ocultar) - Mouse::handleEvent(event); - - // 4. Procesar acciones globales directamente desde eventos SDL - // (NO usar Input::checkAction() para evitar desfase de timing) - if (event.type == SDL_EVENT_KEY_DOWN) { - switch (event.key.scancode) { - case SDL_SCANCODE_F1: - sdl.decreaseWindowSize(); - return true; - - case SDL_SCANCODE_F2: - sdl.increaseWindowSize(); - return true; - - case SDL_SCANCODE_F3: - sdl.toggleFullscreen(); - return true; - - case SDL_SCANCODE_F4: - sdl.toggleVSync(); - return true; - - case SDL_SCANCODE_ESCAPE: - context.setNextScene(SceneType::EXIT); - SceneManager::actual = SceneType::EXIT; - return true; - - default: - // Tecla no global - break; + auto handle(const SDL_Event& event, SDLManager& sdl, SceneContext& context) -> bool { + // 1. Permitir que Input procese el evento (para hotplug de gamepads) + auto event_msg = Input::get()->handleEvent(event); + if (!event_msg.empty()) { + std::cout << "[Input] " << event_msg << '\n'; } - } - return false; // Event no processat -} + // 2. Procesar SDL_EVENT_QUIT directamente (no es input de juego) + if (event.type == SDL_EVENT_QUIT) { + context.setNextScene(SceneType::EXIT); + SceneManager::actual = SceneType::EXIT; + return true; + } + + // 3. Gestió del ratolí (auto-ocultar) + Mouse::handleEvent(event); + + // 4. Procesar acciones globales directamente desde eventos SDL + // (NO usar Input::checkAction() para evitar desfase de timing) + if (event.type == SDL_EVENT_KEY_DOWN) { + switch (event.key.scancode) { + case SDL_SCANCODE_F1: + sdl.decreaseWindowSize(); + return true; + + case SDL_SCANCODE_F2: + sdl.increaseWindowSize(); + return true; + + case SDL_SCANCODE_F3: + sdl.toggleFullscreen(); + return true; + + case SDL_SCANCODE_F4: + sdl.toggleVSync(); + return true; + + case SDL_SCANCODE_F5: + sdl.toggleAntialias(); + return true; + + case SDL_SCANCODE_ESCAPE: + context.setNextScene(SceneType::EXIT); + SceneManager::actual = SceneType::EXIT; + return true; + + default: + // Tecla no global + break; + } + } + + return false; // Event no processat + } } // namespace GlobalEvents