From d4fc7c0ee86114dd8ae2d3775c0022df022a5cc6 Mon Sep 17 00:00:00 2001 From: Sergio Valor Date: Sat, 4 Apr 2026 20:14:11 +0200 Subject: [PATCH] - renderInfo - fix: no guardava el preset actual --- CMakeLists.txt | 3 ++ source/core/input/global_inputs.cpp | 9 +++++ source/core/jail/jinput.cpp | 3 +- source/core/rendering/overlay.cpp | 36 ++++++++++++++++++++ source/core/rendering/overlay.hpp | 4 +++ source/core/rendering/screen.cpp | 51 ++++++++++++++++++++++++++--- source/core/rendering/screen.hpp | 20 +++++++++++ source/game/defaults.hpp | 1 + source/game/options.cpp | 44 +++++++++++++++++++++++++ source/game/options.hpp | 17 ++++++++++ source/utils/utils.cpp | 10 ++++++ source/utils/utils.hpp | 5 +++ 12 files changed, 197 insertions(+), 6 deletions(-) create mode 100644 source/utils/utils.cpp create mode 100644 source/utils/utils.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index bb55a5b..589299f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -43,6 +43,9 @@ set(APP_SOURCES source/game/prota.cpp source/game/sprite.cpp + # Utils + source/utils/utils.cpp + # Main source/main.cpp ) diff --git a/source/core/input/global_inputs.cpp b/source/core/input/global_inputs.cpp index e80aa26..c347b9b 100644 --- a/source/core/input/global_inputs.cpp +++ b/source/core/input/global_inputs.cpp @@ -19,6 +19,7 @@ namespace GlobalInputs { static bool next_shader_prev = false; static bool next_preset_prev = false; static bool stretch_filter_prev = false; + static bool render_info_prev = false; auto handle() -> bool { bool consumed = false; @@ -112,6 +113,14 @@ namespace GlobalInputs { if (stretch_filter) consumed = true; stretch_filter_prev = stretch_filter; + // F10 — Toggle render info (FPS, driver, shader) + bool render_info = JI_KeyPressed(Options::keys_gui.toggle_render_info); + if (render_info && !render_info_prev) { + Overlay::toggleRenderInfo(); + } + if (render_info) consumed = true; + render_info_prev = render_info; + return consumed; } diff --git a/source/core/jail/jinput.cpp b/source/core/jail/jinput.cpp index 6e8146f..ca0918b 100644 --- a/source/core/jail/jinput.cpp +++ b/source/core/jail/jinput.cpp @@ -22,7 +22,8 @@ static bool isGuiKey(SDL_Scancode sc) { sc == Options::keys_gui.toggle_supersampling || sc == Options::keys_gui.next_shader || sc == Options::keys_gui.next_shader_preset || - sc == Options::keys_gui.toggle_stretch_filter; + sc == Options::keys_gui.toggle_stretch_filter || + sc == Options::keys_gui.toggle_render_info; } void JI_DisableKeyboard(Uint32 time) { diff --git a/source/core/rendering/overlay.cpp b/source/core/rendering/overlay.cpp index 6998e02..81442eb 100644 --- a/source/core/rendering/overlay.cpp +++ b/source/core/rendering/overlay.cpp @@ -6,6 +6,7 @@ #include #include "core/rendering/text.hpp" +#include "game/options.hpp" namespace Overlay { @@ -46,6 +47,9 @@ namespace Overlay { static std::vector notifications_; static Uint32 last_ticks_ = 0; + // --- Render info --- + static std::string render_info_text_; + void init() { font_ = std::make_unique("fonts/8bithud.fnt", "fonts/8bithud.gif"); last_ticks_ = SDL_GetTicks(); @@ -120,6 +124,19 @@ namespace Overlay { font_->draw(pixel_data, box_x + NOTIF_PADDING_H, box_y + NOTIF_PADDING_V, notif.message.c_str(), NOTIF_TEXT_COLOR); } + // Render info (FPS, driver, shader) — centrat, posició configurable + if (Options::render_info.position != Options::RenderInfoPosition::OFF && !render_info_text_.empty()) { + int info_w = font_->width(render_info_text_.c_str()); + int info_x = (SCREEN_W - info_w) / 2; + int info_y = (Options::render_info.position == Options::RenderInfoPosition::TOP) + ? 1 + : SCREEN_H - font_->charHeight() - 1; + // Ombra (1px desplaçat) + font_->draw(pixel_data, info_x + 1, info_y + 1, render_info_text_.c_str(), Options::render_info.shadow_color); + // Text + font_->draw(pixel_data, info_x, info_y, render_info_text_.c_str(), Options::render_info.text_color); + } + // Elimina les acabades notifications_.erase( std::remove_if(notifications_.begin(), notifications_.end(), [](const Notification& n) { return n.status == Status::FINISHED; }), @@ -139,4 +156,23 @@ namespace Overlay { notifications_.push_back(notif); } + void toggleRenderInfo() { + // Cicla: OFF → TOP → BOTTOM → OFF + switch (Options::render_info.position) { + case Options::RenderInfoPosition::OFF: + Options::render_info.position = Options::RenderInfoPosition::TOP; + break; + case Options::RenderInfoPosition::TOP: + Options::render_info.position = Options::RenderInfoPosition::BOTTOM; + break; + case Options::RenderInfoPosition::BOTTOM: + Options::render_info.position = Options::RenderInfoPosition::OFF; + break; + } + } + + void setRenderInfoText(const char* text) { + render_info_text_ = text; + } + } // namespace Overlay diff --git a/source/core/rendering/overlay.hpp b/source/core/rendering/overlay.hpp index 225e800..7845bff 100644 --- a/source/core/rendering/overlay.hpp +++ b/source/core/rendering/overlay.hpp @@ -11,4 +11,8 @@ namespace Overlay { // Mostra una notificació amb animació slide-in/stay/slide-out void showNotification(const char* text, float duration_seconds = 2.0F); + + // Activa/desactiva la info de renderitzat (FPS, driver, shader, preset) + void toggleRenderInfo(); + void setRenderInfoText(const char* text); } // namespace Overlay diff --git a/source/core/rendering/screen.cpp b/source/core/rendering/screen.cpp index 5b7543d..48699e4 100644 --- a/source/core/rendering/screen.cpp +++ b/source/core/rendering/screen.cpp @@ -1,11 +1,13 @@ #include "core/rendering/screen.hpp" +#include #include #include "core/rendering/overlay.hpp" #include "core/rendering/sdl3gpu/sdl3gpu_shader.hpp" #include "game/defines.hpp" #include "game/options.hpp" +#include "utils/utils.hpp" Screen* Screen::instance_ = nullptr; @@ -81,10 +83,8 @@ void Screen::initShaders() { return; } - auto* gpu = dynamic_cast(shader_backend_.get()); - if (gpu) { - std::cout << "GPU driver: " << gpu->getDriverName() << '\n'; - } + gpu_driver_ = shader_backend_->getDriverName(); + std::cout << "GPU driver: " << gpu_driver_ << '\n'; // Aplica opcions de vídeo shader_backend_->setScaleMode(Options::video.integer_scale); @@ -97,12 +97,35 @@ void Screen::initShaders() { shader_backend_->setOversample(3); } - // Aplica presets per defecte (de moment hardcoded, futur: YAML) + // Resol el shader actiu des del config + if (Options::video.current_shader == "crtpi") { + shader_backend_->setActiveShader(Rendering::ShaderType::CRTPI); + } else { + shader_backend_->setActiveShader(Rendering::ShaderType::POSTFX); + } + + // Resol presets per nom + for (int i = 0; i < static_cast(Options::postfx_presets.size()); i++) { + if (Options::postfx_presets[i].name == Options::video.current_postfx_preset) { + Options::current_postfx_preset = i; + break; + } + } + for (int i = 0; i < static_cast(Options::crtpi_presets.size()); i++) { + if (Options::crtpi_presets[i].name == Options::video.current_crtpi_preset) { + Options::current_crtpi_preset = i; + break; + } + } + applyCurrentPostFXPreset(); applyCurrentCrtPiPreset(); } void Screen::present(Uint32* pixel_data) { + fps_.increment(); + fps_.calculate(SDL_GetTicks()); + updateRenderInfo(); Overlay::render(pixel_data); if (shader_backend_ && shader_backend_->isHardwareAccelerated() && Options::video.shader_enabled) { @@ -192,9 +215,11 @@ void Screen::nextShaderType() { if (shader_backend_->getActiveShader() == Rendering::ShaderType::POSTFX) { shader_backend_->setActiveShader(Rendering::ShaderType::CRTPI); + Options::video.current_shader = "crtpi"; applyCurrentCrtPiPreset(); } else { shader_backend_->setActiveShader(Rendering::ShaderType::POSTFX); + Options::video.current_shader = "postfx"; applyCurrentPostFXPreset(); } } @@ -205,10 +230,12 @@ void Screen::nextPreset() { if (shader_backend_->getActiveShader() == Rendering::ShaderType::POSTFX) { if (Options::postfx_presets.empty()) return; Options::current_postfx_preset = (Options::current_postfx_preset + 1) % static_cast(Options::postfx_presets.size()); + Options::video.current_postfx_preset = Options::postfx_presets[Options::current_postfx_preset].name; applyCurrentPostFXPreset(); } else { if (Options::crtpi_presets.empty()) return; Options::current_crtpi_preset = (Options::current_crtpi_preset + 1) % static_cast(Options::crtpi_presets.size()); + Options::video.current_crtpi_preset = Options::crtpi_presets[Options::current_crtpi_preset].name; applyCurrentCrtPiPreset(); } } @@ -276,6 +303,20 @@ auto Screen::getActiveShaderName() const -> const char* { return shader_backend_->getActiveShader() == Rendering::ShaderType::POSTFX ? "POSTFX" : "CRT-PI"; } +void Screen::updateRenderInfo() { + std::string driver = gpu_driver_.empty() ? "sdl" : toLower(gpu_driver_); + std::string info = std::to_string(fps_.last_value) + " fps - " + driver; + + if (Options::video.shader_enabled) { + std::string shader_name = toLower(getActiveShaderName()); + std::string preset_name = toLower(getCurrentPresetName()); + info += " - " + shader_name + " " + preset_name; + if (Options::video.supersampling) info += " (ss)"; + } + + Overlay::setRenderInfoText(info.c_str()); +} + void Screen::adjustWindowSize() { int w = GAME_WIDTH * zoom_; // Si 4:3 actiu, l'alçada visual és 240 per zoom (200 * 1.2) diff --git a/source/core/rendering/screen.hpp b/source/core/rendering/screen.hpp index 5b12cac..efe5911 100644 --- a/source/core/rendering/screen.hpp +++ b/source/core/rendering/screen.hpp @@ -60,9 +60,29 @@ class Screen { // Backend GPU (nullptr si no disponible o desactivat) std::unique_ptr shader_backend_; + void updateRenderInfo(); + + struct FPS { + Uint32 ticks{0}; + int frame_count{0}; + int last_value{0}; + + void increment() { frame_count++; } + auto calculate(Uint32 current_ticks) -> int { + if (current_ticks - ticks >= 1000) { + last_value = frame_count; + frame_count = 0; + ticks = current_ticks; + } + return last_value; + } + }; + int zoom_{3}; int max_zoom_{6}; bool fullscreen_{false}; + FPS fps_; + std::string gpu_driver_; static constexpr int GAME_WIDTH = 320; static constexpr int GAME_HEIGHT = 200; diff --git a/source/game/defaults.hpp b/source/game/defaults.hpp index 189909d..282dd1a 100644 --- a/source/game/defaults.hpp +++ b/source/game/defaults.hpp @@ -13,6 +13,7 @@ namespace Defaults::KeysGUI { constexpr SDL_Scancode NEXT_SHADER = SDL_SCANCODE_F7; constexpr SDL_Scancode NEXT_SHADER_PRESET = SDL_SCANCODE_F8; constexpr SDL_Scancode TOGGLE_STRETCH_FILTER = SDL_SCANCODE_F9; + constexpr SDL_Scancode TOGGLE_RENDER_INFO = SDL_SCANCODE_F10; } // namespace Defaults::KeysGUI // Tecles de joc (moviment del personatge, accions) diff --git a/source/game/options.cpp b/source/game/options.cpp index 2a1f3f6..15ea7c7 100644 --- a/source/game/options.cpp +++ b/source/game/options.cpp @@ -61,6 +61,31 @@ namespace Options { video.downscale_algo = node["downscale_algo"].get_value(); if (node.contains("linear_upscale")) video.linear_upscale = node["linear_upscale"].get_value(); + if (node.contains("current_shader")) + video.current_shader = node["current_shader"].get_value(); + if (node.contains("current_postfx_preset")) + video.current_postfx_preset = node["current_postfx_preset"].get_value(); + if (node.contains("current_crtpi_preset")) + video.current_crtpi_preset = node["current_crtpi_preset"].get_value(); + } + + static void loadRenderInfoFromYaml(const fkyaml::node& yaml) { + if (!yaml.contains("render_info")) return; + const auto& node = yaml["render_info"]; + + if (node.contains("position")) { + auto pos = node["position"].get_value(); + if (pos == "top") + render_info.position = RenderInfoPosition::TOP; + else if (pos == "bottom") + render_info.position = RenderInfoPosition::BOTTOM; + else + render_info.position = RenderInfoPosition::OFF; + } + if (node.contains("text_color")) + render_info.text_color = static_cast(node["text_color"].get_value()); + if (node.contains("shadow_color")) + render_info.shadow_color = static_cast(node["shadow_color"].get_value()); } static void loadWindowConfigFromYaml(const fkyaml::node& yaml) { @@ -117,6 +142,7 @@ namespace Options { } loadVideoConfigFromYaml(yaml); + loadRenderInfoFromYaml(yaml); loadWindowConfigFromYaml(yaml); loadAudioConfigFromYaml(yaml); loadGameConfigFromYaml(yaml); @@ -163,6 +189,24 @@ namespace Options { file << " stretch_filter_linear: " << (video.stretch_filter_linear ? "true" : "false") << " # filtre 4:3: false=nearest, true=linear\n"; file << " downscale_algo: " << video.downscale_algo << " # 0=bilinear, 1=Lanczos2, 2=Lanczos3\n"; file << " linear_upscale: " << (video.linear_upscale ? "true" : "false") << "\n"; + file << " current_shader: " << video.current_shader << "\n"; + file << " current_postfx_preset: " << video.current_postfx_preset << "\n"; + file << " current_crtpi_preset: " << video.current_crtpi_preset << "\n"; + file << "\n"; + + // RENDER INFO + file << "# RENDER INFO\n"; + file << "render_info:\n"; + { + const char* pos = "off"; + if (render_info.position == RenderInfoPosition::TOP) + pos = "top"; + else if (render_info.position == RenderInfoPosition::BOTTOM) + pos = "bottom"; + file << " position: " << pos << " # off/top/bottom\n"; + } + file << " text_color: " << render_info.text_color << "\n"; + file << " shadow_color: " << render_info.shadow_color << "\n"; file << "\n"; // WINDOW diff --git a/source/game/options.hpp b/source/game/options.hpp index 690b524..8115f86 100644 --- a/source/game/options.hpp +++ b/source/game/options.hpp @@ -19,6 +19,7 @@ namespace Options { SDL_Scancode next_shader{Defaults::KeysGUI::NEXT_SHADER}; SDL_Scancode next_shader_preset{Defaults::KeysGUI::NEXT_SHADER_PRESET}; SDL_Scancode toggle_stretch_filter{Defaults::KeysGUI::TOGGLE_STRETCH_FILTER}; + SDL_Scancode toggle_render_info{Defaults::KeysGUI::TOGGLE_RENDER_INFO}; }; // Tecles de joc (moviment, accions) @@ -30,6 +31,11 @@ namespace Options { SDL_Scancode exit{Defaults::KeysGame::EXIT}; }; + // Posició del render info + enum class RenderInfoPosition { OFF = 0, + TOP = 1, + BOTTOM = 2 }; + // Opcions de vídeo struct Video { bool gpu_acceleration{Defaults::Video::GPU_ACCELERATION}; @@ -40,6 +46,16 @@ namespace Options { bool stretch_filter_linear{Defaults::Video::STRETCH_FILTER_LINEAR}; int downscale_algo{Defaults::Video::DOWNSCALE_ALGO}; bool linear_upscale{Defaults::Video::LINEAR_UPSCALE}; + std::string current_shader{"postfx"}; // "postfx" o "crtpi" + std::string current_postfx_preset{"CRT"}; // Nom del preset PostFX actiu + std::string current_crtpi_preset{"DEFAULT"}; // Nom del preset CrtPi actiu + }; + + // Opcions del render info + struct RenderInfo { + RenderInfoPosition position{RenderInfoPosition::OFF}; + Uint32 text_color{0xFF00D7FF}; // Groc daurat (ABGR) + Uint32 shadow_color{0xFF005A6B}; // Ombra daurada fosca (ABGR) }; // Opcions d'àudio @@ -101,6 +117,7 @@ namespace Options { inline KeysGUI keys_gui{}; inline KeysGame keys_game{}; inline Video video{}; + inline RenderInfo render_info{}; inline Audio audio{}; inline Window window{}; inline Game game{}; diff --git a/source/utils/utils.cpp b/source/utils/utils.cpp new file mode 100644 index 0000000..152da69 --- /dev/null +++ b/source/utils/utils.cpp @@ -0,0 +1,10 @@ +#include "utils/utils.hpp" + +#include +#include + +auto toLower(const std::string& str) -> std::string { + std::string lower = str; + std::ranges::transform(lower, lower.begin(), ::tolower); + return lower; +} diff --git a/source/utils/utils.hpp b/source/utils/utils.hpp new file mode 100644 index 0000000..5f78641 --- /dev/null +++ b/source/utils/utils.hpp @@ -0,0 +1,5 @@ +#pragma once + +#include + +auto toLower(const std::string& str) -> std::string;