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:
@@ -25,7 +25,8 @@ 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 {
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -27,30 +27,30 @@
|
|||||||
|
|
||||||
namespace Rendering::GPU {
|
namespace Rendering::GPU {
|
||||||
|
|
||||||
// Parámetros del postpro que el caller (SDLManager) pasa cada frame.
|
// Parámetros del postpro que el caller (SDLManager) pasa cada frame.
|
||||||
// Equivalente al lado "humano" del PostFxUniforms (sin paddings).
|
// Equivalente al lado "humano" del PostFxUniforms (sin paddings).
|
||||||
struct PostFxParams {
|
struct PostFxParams {
|
||||||
bool bloom_enabled{true};
|
bool bloom_enabled{true};
|
||||||
float bloom_intensity{0.6F};
|
float bloom_intensity{0.6F};
|
||||||
float bloom_threshold{0.4F};
|
float bloom_threshold{0.4F};
|
||||||
float bloom_radius_px{2.0F};
|
float bloom_radius_px{2.0F};
|
||||||
|
|
||||||
bool flicker_enabled{true};
|
bool flicker_enabled{true};
|
||||||
float flicker_amplitude{0.10F};
|
float flicker_amplitude{0.10F};
|
||||||
float flicker_frequency_hz{6.0F};
|
float flicker_frequency_hz{6.0F};
|
||||||
|
|
||||||
bool background_enabled{true};
|
bool background_enabled{true};
|
||||||
float background_min_r{0.0F};
|
float background_min_r{0.0F};
|
||||||
float background_min_g{0.02F};
|
float background_min_g{0.02F};
|
||||||
float background_min_b{0.0F};
|
float background_min_b{0.0F};
|
||||||
float background_max_r{0.0F};
|
float background_max_r{0.0F};
|
||||||
float background_max_g{0.06F};
|
float background_max_g{0.06F};
|
||||||
float background_max_b{0.0F};
|
float background_max_b{0.0F};
|
||||||
float background_pulse_freq_hz{6.0F};
|
float background_pulse_freq_hz{6.0F};
|
||||||
};
|
};
|
||||||
|
|
||||||
class GpuFrameRenderer {
|
class GpuFrameRenderer {
|
||||||
public:
|
public:
|
||||||
GpuFrameRenderer() = default;
|
GpuFrameRenderer() = default;
|
||||||
~GpuFrameRenderer();
|
~GpuFrameRenderer();
|
||||||
|
|
||||||
@@ -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; }
|
||||||
@@ -96,7 +102,7 @@ class GpuFrameRenderer {
|
|||||||
[[nodiscard]] auto device() -> GpuDevice& { return device_; }
|
[[nodiscard]] auto device() -> GpuDevice& { return device_; }
|
||||||
[[nodiscard]] auto isInsideFrame() const -> bool { return cmd_buffer_ != nullptr; }
|
[[nodiscard]] auto isInsideFrame() const -> bool { return cmd_buffer_ != nullptr; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
GpuDevice device_;
|
GpuDevice device_;
|
||||||
GpuLinePipeline line_pipeline_;
|
GpuLinePipeline line_pipeline_;
|
||||||
GpuPostFxPipeline postfx_pipeline_;
|
GpuPostFxPipeline postfx_pipeline_;
|
||||||
@@ -128,12 +134,15 @@ 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();
|
||||||
void flushBatch();
|
void flushBatch();
|
||||||
void compositePass();
|
void compositePass();
|
||||||
void applyFinalViewport();
|
void applyFinalViewport();
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Rendering::GPU
|
} // namespace Rendering::GPU
|
||||||
|
|||||||
@@ -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';
|
||||||
|
}
|
||||||
|
|||||||
@@ -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).
|
||||||
|
|||||||
@@ -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,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;
|
||||||
@@ -16,55 +16,59 @@ using SceneType = SceneContext::SceneType;
|
|||||||
|
|
||||||
namespace GlobalEvents {
|
namespace GlobalEvents {
|
||||||
|
|
||||||
auto handle(const SDL_Event& event, SDLManager& sdl, SceneContext& context) -> bool {
|
auto handle(const SDL_Event& event, SDLManager& sdl, SceneContext& context) -> bool {
|
||||||
// 1. Permitir que Input procese el evento (para hotplug de gamepads)
|
// 1. Permitir que Input procese el evento (para hotplug de gamepads)
|
||||||
auto event_msg = Input::get()->handleEvent(event);
|
auto event_msg = Input::get()->handleEvent(event);
|
||||||
if (!event_msg.empty()) {
|
if (!event_msg.empty()) {
|
||||||
std::cout << "[Input] " << event_msg << '\n';
|
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;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
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
|
} // namespace GlobalEvents
|
||||||
|
|||||||
Reference in New Issue
Block a user