#include "core/rendering/render_info.hpp" #include #include // Para transform #include // Para round, floor #include // Para setprecision #include // Para ostringstream #include // Para string #include "core/rendering/screen.hpp" // Para Screen #include "core/rendering/surface.hpp" // Para Surface #include "core/rendering/text.hpp" // Para Text #include "game/options.hpp" // Para Options #include "game/ui/console.hpp" // Para Console #include "game/ui/notifier.hpp" // Para Notifier // [SINGLETON] RenderInfo* RenderInfo::render_info = nullptr; // [SINGLETON] Crearemos el objeto con esta función estática void RenderInfo::init() { RenderInfo::render_info = new RenderInfo(); } // [SINGLETON] Destruiremos el objeto con esta función estática void RenderInfo::destroy() { delete RenderInfo::render_info; RenderInfo::render_info = nullptr; } // [SINGLETON] Con este método obtenemos el objeto y podemos trabajar con él auto RenderInfo::get() -> RenderInfo* { return RenderInfo::render_info; } // Constructor: en DEBUG se activa inmediatamente (notifica a Notifier del offset) RenderInfo::RenderInfo() { #ifdef _DEBUG toggle(); #endif } // Renderiza el overlay de información por pantalla void RenderInfo::render() const { if (!active_) { return; } // FPS std::string line = std::to_string(Screen::get()->getLastFPS()) + " fps"; // Driver GPU const auto& driver = Screen::get()->getGPUDriver(); line += " | " + (driver.empty() ? std::string("sdl") : driver); // Zoom calculado (alto físico / alto lógico), con coma decimal y sin ceros innecesarios const float ROUNDED = std::round(Screen::get()->getZoomFactor() * 100.0F) / 100.0F; std::string zoom_str; if (ROUNDED == std::floor(ROUNDED)) { zoom_str = std::to_string(static_cast(ROUNDED)); } else { std::ostringstream oss; oss << std::fixed << std::setprecision(2) << ROUNDED; zoom_str = oss.str(); if (zoom_str.back() == '0') { zoom_str.pop_back(); } std::replace(zoom_str.begin(), zoom_str.end(), '.', ','); } line += " | " + zoom_str + "x"; // PostFX: muestra preset y supersampling, o nada si está desactivado if (Options::video.postfx) { std::string preset_name = "-"; if (!Options::postfx_presets.empty()) { preset_name = Options::postfx_presets[static_cast(Options::current_postfx_preset)].name; } line += " | " + preset_name + (Options::video.supersampling ? " (ss)" : ""); } // Todo en lowercase std::transform(line.begin(), line.end(), line.begin(), [](unsigned char c) { return std::tolower(c); }); // Constantes visuales (igual que Console) static constexpr Uint8 BG_COLOR = 0; // PaletteColor::BLACK static constexpr Uint8 MSG_COLOR = 9; // PaletteColor::BRIGHT_GREEN static constexpr int TEXT_SIZE = 6; static constexpr int PADDING_V = TEXT_SIZE / 2 - 1; // Fuente: preferir la de la consola si está disponible auto text_obj = (Console::get() != nullptr) ? Console::get()->getText() : Screen::get()->getText(); // Posición Y (debajo de la consola si está visible) const int Y = (Console::get() != nullptr) ? Console::get()->getVisibleHeight() : 0; // Rectángulo de fondo: ancho completo, alto ajustado al texto const SDL_FRect RECT = { .x = 0.0F, .y = static_cast(Y), .w = Options::game.width, .h = static_cast(TEXT_SIZE + (PADDING_V * 2))}; auto game_surface = Screen::get()->getGameSurface(); game_surface->fillRect(&RECT, BG_COLOR); // game_surface->drawRectBorder(&RECT, BORDER_COLOR); text_obj->writeDX(Text::CENTER_FLAG | Text::COLOR_FLAG, static_cast(Options::game.width / 2), Y + PADDING_V, line, 1, MSG_COLOR); } // Activa o desactiva el overlay y notifica a Notifier del cambio de offset void RenderInfo::toggle() { active_ = !active_; if (active_) { Screen::get()->updateZoomFactor(); if (Notifier::get() != nullptr) { Notifier::get()->addYOffset(HEIGHT); } } else { if (Notifier::get() != nullptr) { Notifier::get()->removeYOffset(HEIGHT); } } }