feat(antialias): toggle F5 i indicador AA al debug overlay

Permet alternar l'AA geomètric en runtime:

- Action::TOGGLE_ANTIALIAS bound a F5.
- GlobalEvents::handle reacciona al scancode F5 cridant sdl.toggleAntialias().
- SDLManager::toggleAntialias muta cfg_->rendering.antialias i propaga a
  gpu_renderer_.setAntialias().
- GpuFrameRenderer manté l'estat antialias_enabled_ (true per defecte) i
  pushLine adapta extrusió i edge_dist en funció del flag — geometria nua
  quan està OFF, fade als bords quan està ON.
- RenderingConfig guanya el camp `antialias{1}` per coherència amb vsync;
  l'estat NO es persisteix al YAML de moment (decisió volgudament conservadora,
  podem afegir-ho en un commit a part si cal).
- DebugOverlay (F11) mostra una tercera línia "AA: ON/OFF" sota VSYNC per
  poder comparar a temps real.
This commit is contained in:
2026-05-20 21:39:24 +02:00
parent b10f2da647
commit 1ef9ca551f
10 changed files with 122 additions and 85 deletions
+1
View File
@@ -26,6 +26,7 @@ namespace Config {
struct RenderingConfig { 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 { struct KeyboardBindings {
+1
View File
@@ -6,5 +6,6 @@
namespace Defaults::Rendering { 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 } // namespace Defaults::Rendering
+1
View File
@@ -39,6 +39,7 @@ Input::Input(std::string game_controller_db_path)
{Action::WINDOW_INC_ZOOM, KeyState{.scancode = SDL_SCANCODE_F2}}, {Action::WINDOW_INC_ZOOM, KeyState{.scancode = SDL_SCANCODE_F2}},
{Action::TOGGLE_FULLSCREEN, KeyState{.scancode = SDL_SCANCODE_F3}}, {Action::TOGGLE_FULLSCREEN, KeyState{.scancode = SDL_SCANCODE_F3}},
{Action::TOGGLE_VSYNC, KeyState{.scancode = SDL_SCANCODE_F4}}, {Action::TOGGLE_VSYNC, KeyState{.scancode = SDL_SCANCODE_F4}},
{Action::TOGGLE_ANTIALIAS, KeyState{.scancode = SDL_SCANCODE_F5}},
{Action::EXIT, KeyState{.scancode = SDL_SCANCODE_ESCAPE}}}; {Action::EXIT, KeyState{.scancode = SDL_SCANCODE_ESCAPE}}};
initSDLGamePad(); // Inicializa el subsistema SDL_INIT_GAMEPAD initSDLGamePad(); // Inicializa el subsistema SDL_INIT_GAMEPAD
+1
View File
@@ -21,6 +21,7 @@ enum class InputAction : std::uint8_t { // Acciones de entrada posibles en el j
WINDOW_DEC_ZOOM, // F1 WINDOW_DEC_ZOOM, // F1
TOGGLE_FULLSCREEN, // F3 TOGGLE_FULLSCREEN, // F3
TOGGLE_VSYNC, // F4 TOGGLE_VSYNC, // F4
TOGGLE_ANTIALIAS, // F5
EXIT, // ESC EXIT, // ESC
// Input obligatorio // Input obligatorio
@@ -243,21 +243,23 @@ namespace Rendering::GPU {
return; return;
} }
// Antialias geomètric: extruim 0.5 píxel extra a cada banda del gruix // Antialias geomètric: quan està ON, extruim 0.5 píxel extra a cada
// demanat, i el fragment shader fa fade als bords usant edge_dist (±1 // banda del gruix demanat i posem edge_dist = ±1 als laterals; el
// als laterals, 0 al centre). Així el gruix "ple" coincideix amb el // fragment shader fa fade als bords. Quan està OFF, geometria nua
// demanat i el píxel extra només aporta la transició suau. // (thickness exacte) i edge_dist = 0 a tots els vèrtexs → el
const float AA_PADDING = 0.5F; // 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 HALF = (thickness * 0.5F) + AA_PADDING;
const float NX = -DY / LEN * HALF; const float NX = -DY / LEN * HALF;
const float NY = DX / LEN * HALF; const float NY = DX / LEN * HALF;
const float EDGE = antialias_enabled_ ? 1.0F : 0.0F;
const auto BASE_INDEX = static_cast<uint16_t>(vertices_.size()); const auto BASE_INDEX = static_cast<uint16_t>(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, +EDGE});
vertices_.push_back({x1 - NX, y1 - NY, r, g, b, a, -1.0F}); vertices_.push_back({x1 - NX, y1 - NY, r, g, b, a, -EDGE});
vertices_.push_back({x2 + NX, y2 + NY, r, g, b, a, +1.0F}); vertices_.push_back({x2 + NX, y2 + NY, r, g, b, a, +EDGE});
vertices_.push_back({x2 - NX, y2 - NY, r, g, b, a, -1.0F}); vertices_.push_back({x2 - NX, y2 - NY, r, g, b, a, -EDGE});
indices_.push_back(BASE_INDEX + 0); indices_.push_back(BASE_INDEX + 0);
indices_.push_back(BASE_INDEX + 1); indices_.push_back(BASE_INDEX + 1);
@@ -72,8 +72,7 @@ class GpuFrameRenderer {
[[nodiscard]] auto beginFrame(float clear_r, float clear_g, float clear_b) -> bool; [[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]. // 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, void pushLine(float x1, float y1, float x2, float y2, float thickness, float r, float g, float b, float a);
float r, float g, float b, float a);
// endFrame: flush del batch de líneas → composite postpro → submit + presenta. // endFrame: flush del batch de líneas → composite postpro → submit + presenta.
void endFrame(); void endFrame();
@@ -87,6 +86,13 @@ class GpuFrameRenderer {
// Activa/desactiva VSync. true = SDL_GPU_PRESENTMODE_VSYNC, false = IMMEDIATE. // Activa/desactiva VSync. true = SDL_GPU_PRESENTMODE_VSYNC, false = IMMEDIATE.
void setVSync(bool enabled); 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 = // Parámetros del postpro que se aplican en endFrame. Por defecto =
// valores de Defaults (bloom moderado, flicker suave, fondo verde tenue). // valores de Defaults (bloom moderado, flicker suave, fondo verde tenue).
void setPostFx(const PostFxParams& params) { postfx_params_ = params; } void setPostFx(const PostFxParams& params) { postfx_params_ = params; }
@@ -128,6 +134,9 @@ class GpuFrameRenderer {
// Parámetros del postpro (configurables vía YAML). // Parámetros del postpro (configurables vía YAML).
PostFxParams postfx_params_{}; PostFxParams postfx_params_{};
// Estat de l'antialias geomètric a les línies (toggle F5).
bool antialias_enabled_{true};
// Helpers internos. // Helpers internos.
[[nodiscard]] auto createOffscreen() -> bool; [[nodiscard]] auto createOffscreen() -> bool;
void destroyOffscreen(); void destroyOffscreen();
+11
View File
@@ -84,6 +84,9 @@ SDLManager::SDLManager(int width, int height, bool fullscreen, Config::EngineCon
return; return;
} }
// Aplica l'estat inicial d'antialias des de la config (per defecte ON).
gpu_renderer_.setAntialias(cfg_->rendering.antialias != 0);
updateViewport(); updateViewport();
// En fullscreen: forzar ocultació permanent del cursor. // En fullscreen: forzar ocultació permanent del cursor.
@@ -323,3 +326,11 @@ void SDLManager::toggleVSync() {
on_persist_(); 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';
}
+1
View File
@@ -34,6 +34,7 @@ class SDLManager {
void decreaseWindowSize(); // F1: -100px void decreaseWindowSize(); // F1: -100px
void toggleFullscreen(); // F3 void toggleFullscreen(); // F3
void toggleVSync(); // F4 void toggleVSync(); // F4
void toggleAntialias(); // F5
auto handleWindowEvent(const SDL_Event& event) -> bool; // Per a SDL_EVENT_WINDOW_RESIZED auto handleWindowEvent(const SDL_Event& event) -> bool; // Per a SDL_EVENT_WINDOW_RESIZED
// Funciones principals (renderizado). // Funciones principals (renderizado).
+6
View File
@@ -44,6 +44,7 @@ namespace System {
const std::string FPS_TEXT = "FPS: " + std::to_string(fps_display_); 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 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, text_.render(FPS_TEXT,
Vec2{.x = OVERLAY_X, .y = OVERLAY_Y_FPS}, Vec2{.x = OVERLAY_X, .y = OVERLAY_Y_FPS},
@@ -55,6 +56,11 @@ namespace System {
OVERLAY_SCALE, OVERLAY_SCALE,
OVERLAY_SPACING, OVERLAY_SPACING,
OVERLAY_BRIGHTNESS); 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 } // namespace System
+5 -1
View File
@@ -5,10 +5,10 @@
#include <iostream> #include <iostream>
#include "scene_context.hpp"
#include "core/input/input.hpp" #include "core/input/input.hpp"
#include "core/input/mouse.hpp" #include "core/input/mouse.hpp"
#include "core/rendering/sdl_manager.hpp" #include "core/rendering/sdl_manager.hpp"
#include "scene_context.hpp"
// Using declarations per simplificar el codi // Using declarations per simplificar el codi
using SceneManager::SceneContext; using SceneManager::SceneContext;
@@ -53,6 +53,10 @@ auto handle(const SDL_Event& event, SDLManager& sdl, SceneContext& context) -> b
sdl.toggleVSync(); sdl.toggleVSync();
return true; return true;
case SDL_SCANCODE_F5:
sdl.toggleAntialias();
return true;
case SDL_SCANCODE_ESCAPE: case SDL_SCANCODE_ESCAPE:
context.setNextScene(SceneType::EXIT); context.setNextScene(SceneType::EXIT);
SceneManager::actual = SceneType::EXIT; SceneManager::actual = SceneType::EXIT;