fps: overlay debug a dalt-dreta del canvas (verd, F10 toggle, 8bithud, alineat amb notificacions i overscan-aware)

This commit is contained in:
2026-05-19 20:59:35 +02:00
parent 73f210bc2c
commit fa2dc9bbf3
5 changed files with 73 additions and 1 deletions
+4
View File
@@ -127,6 +127,10 @@ namespace GlobalInputs {
notifyPresentationMode();
return true;
}
if (Input::get()->checkInput(Input::Action::TOGGLE_FPS, Input::Repeat::OFF)) {
Screen::get()->toggleFps();
return true;
}
// F5/F6 només actuen quan el post-procesado està actiu.
if (Screen::isShaderEnabled()) {
if (Input::get()->checkInput(Input::Action::TOGGLE_SHADER_TYPE, Input::Repeat::OFF)) {
+1
View File
@@ -54,6 +54,7 @@ class Input {
SHOW_VERSION,
TOGGLE_VSYNC,
NEXT_PRESENTATION_MODE,
TOGGLE_FPS,
// Centinela final (usar para sizing)
NUMBER_OF_INPUTS
+53 -1
View File
@@ -169,9 +169,12 @@ void Screen::start() {
// Vuelca el contenido del renderizador en pantalla
void Screen::blit() {
// Dibuja la notificación activa sobre el gameCanvas antes de presentar
updateFps();
// Dibuja la notificación activa i, si toca, l'overlay de FPS sobre el gameCanvas
SDL_SetRenderTarget(renderer_, game_canvas_);
renderNotification();
renderFps();
#ifndef NO_SHADERS
// Si el backend GPU està viu i accelerat, passem sempre per ell (tant amb
@@ -525,6 +528,55 @@ void Screen::renderNotification() {
notification_outline_color_);
}
// Alterna la visibilitat de l'overlay de FPS. No persisteix a config.
void Screen::toggleFps() {
fps_visible_ = !fps_visible_;
if (fps_visible_) {
fps_window_start_ticks_ = SDL_GetTicks();
fps_frame_count_ = 0;
fps_value_ = 0;
}
}
auto Screen::isFpsVisible() const -> bool {
return fps_visible_;
}
// Acumula frames i recalcula el FPS cada segon real (no afectat per dt del joc).
// Cridat des de blit() una vegada per frame.
void Screen::updateFps() {
if (!fps_visible_) { return; }
++fps_frame_count_;
const Uint32 NOW = SDL_GetTicks();
const Uint32 ELAPSED = NOW - fps_window_start_ticks_;
if (ELAPSED >= 1000) {
fps_value_ = static_cast<int>((static_cast<Uint64>(fps_frame_count_) * 1000) / ELAPSED);
fps_frame_count_ = 0;
fps_window_start_ticks_ = NOW;
}
}
// Dibuixa "NN FPS" a dalt a la dreta del canvas, mateixa Y que les notificacions
// (incloent l'ajust per overscan) i amb la mateixa font 8bithud.
void Screen::renderFps() {
if (!fps_visible_ || notification_text_ == nullptr) { return; }
constexpr int RIGHT_MARGIN = 2;
const Color FPS_COLOR{0x60, 0xD0, 0x70}; // verd (mateix to que SUCCESS de notificacions)
const Color FPS_OUTLINE{0x26, 0x53, 0x2C}; // ~40% darken del verd
const std::string MSG = std::to_string(fps_value_) + " FPS";
const int TEXT_W = notification_text_->lenght(MSG, 1);
const int X = game_canvas_width_ - TEXT_W - RIGHT_MARGIN;
const int Y = notification_y_ + safeNotificationY();
notification_text_->writeDX(Text::FLAG_COLOR | Text::FLAG_STROKE,
X,
Y,
MSG,
1,
FPS_COLOR,
1,
FPS_OUTLINE);
}
// Y minima del canvas visible. Solo no zero quan estem en overscan i l'aspect
// de finestra obliga a escalar mes ample que alt (el canvas vertical desborda
// i la franja superior es retalla). En cas contrari (qualsevol altre mode, o
+14
View File
@@ -73,6 +73,10 @@ class Screen {
void notify(const std::string &text, Color text_color, Color outline_color, Uint32 duration_ms); // Muestra una notificación en la línea superior del canvas durante durationMs. Sobrescribe cualquier notificación activa (sin apilación).
void clearNotification(); // Limpia la notificación actual
// FPS overlay (debug, no persistent)
void toggleFps(); // Alterna la visibilitat de l'overlay de FPS
[[nodiscard]] auto isFpsVisible() const -> bool; // Estat actual
// GPU / shaders (post-procesado). En builds con NO_SHADERS (Emscripten) son no-op.
void initShaders(); // Crea el backend GPU si no existe y lo inicializa
void shutdownShaders(); // Libera el backend GPU
@@ -115,6 +119,10 @@ class Screen {
void renderNotification(); // Dibuja la notificación activa (si la hay) sobre el gameCanvas
[[nodiscard]] auto safeNotificationY() const -> int; // Y minima dins del canvas que segueix sent visible en overscan (segons aspect ratio finestra/canvas)
// FPS overlay
void updateFps(); // Acumula temps i recalcula fps cada segon (a cridar des de blit)
void renderFps(); // Dibuixa "NN FPS" a dalt a la dreta del canvas
#ifndef NO_SHADERS
// Aplica els paràmetres actuals del shader al backend segons options
// (pass-through si `videoShaderEnabled==false`, preset per defecte si true).
@@ -142,6 +150,12 @@ class Screen {
Uint32 notification_end_time_; // SDL_GetTicks() hasta el cual se muestra
int notification_y_; // Fila vertical en el canvas virtual
// FPS overlay (debug, no persistent)
bool fps_visible_{false}; // F10 toggle
int fps_value_{0}; // Ultim valor calculat (frames per segon)
int fps_frame_count_{0}; // Frames acumulats durant la finestra actual
Uint32 fps_window_start_ticks_{0}; // Inici de la finestra d'1s actual (SDL_GetTicks)
#ifndef NO_SHADERS
// GPU / shaders
std::unique_ptr<Rendering::ShaderBackend> shader_backend_; // Backend GPU (nullptr si inactivo)
+1
View File
@@ -234,6 +234,7 @@ void Director::initInput() {
Input::get()->bindKey(Input::Action::NEXT_SHADER_PRESET, SDL_SCANCODE_F6);
Input::get()->bindKey(Input::Action::TOGGLE_VSYNC, SDL_SCANCODE_F7);
Input::get()->bindKey(Input::Action::NEXT_PRESENTATION_MODE, SDL_SCANCODE_F8);
Input::get()->bindKey(Input::Action::TOGGLE_FPS, SDL_SCANCODE_F10);
Input::get()->bindKey(Input::Action::SHOW_VERSION, SDL_SCANCODE_F11);
// Mando - Movimiento del jugador