145 lines
5.2 KiB
C++
145 lines
5.2 KiB
C++
#include "core/rendering/render_info.hpp"
|
|
|
|
#include <SDL3/SDL.h>
|
|
|
|
#include <algorithm> // Para transform
|
|
#include <cmath> // Para round, floor
|
|
#include <iomanip> // Para setprecision
|
|
#include <sstream> // Para ostringstream
|
|
#include <string> // 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
|
|
#include "utils/utils.hpp" // Para prettyName
|
|
|
|
// [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: arranca oculto; quien quiera activarlo debe llamar a toggle()
|
|
RenderInfo::RenderInfo() = default;
|
|
|
|
// Actualiza la animación de entrada/salida del overlay
|
|
void RenderInfo::update(float delta_time) {
|
|
switch (status_) {
|
|
case Status::RISING:
|
|
y_ += SLIDE_SPEED * delta_time;
|
|
if (y_ >= 0.0F) {
|
|
y_ = 0.0F;
|
|
status_ = Status::ACTIVE;
|
|
}
|
|
break;
|
|
case Status::VANISHING:
|
|
y_ -= SLIDE_SPEED * delta_time;
|
|
if (y_ <= static_cast<float>(-HEIGHT)) {
|
|
y_ = static_cast<float>(-HEIGHT);
|
|
status_ = Status::HIDDEN;
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Renderiza el overlay de información por pantalla
|
|
void RenderInfo::render() const {
|
|
if (status_ == Status::HIDDEN) { 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<int>(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::ranges::replace(zoom_str, '.', ',');
|
|
}
|
|
line += " | " + zoom_str + "x";
|
|
|
|
// PostFX: muestra shader + preset y supersampling, o nada si está desactivado
|
|
if (Options::video.shader.enabled) {
|
|
const bool IS_CRTPI = (Options::video.shader.current_shader == Rendering::ShaderType::CRTPI);
|
|
const std::string SHADER_NAME = IS_CRTPI ? "crtpi" : "postfx";
|
|
std::string preset_name = "-";
|
|
if (IS_CRTPI) {
|
|
if (!Options::crtpi_presets.empty()) {
|
|
preset_name = prettyName(Options::crtpi_presets[static_cast<size_t>(Options::video.shader.current_crtpi_preset)].name);
|
|
}
|
|
} else {
|
|
if (!Options::postfx_presets.empty()) {
|
|
preset_name = prettyName(Options::postfx_presets[static_cast<size_t>(Options::video.shader.current_postfx_preset)].name);
|
|
}
|
|
}
|
|
const bool SHOW_SS = Options::video.supersampling.enabled && !IS_CRTPI;
|
|
line += " | " + SHADER_NAME + " " + preset_name + (SHOW_SS ? " (ss)" : "");
|
|
}
|
|
|
|
// Todo en lowercase
|
|
std::ranges::transform(line, line.begin(), [](unsigned char c) { return std::tolower(c); });
|
|
|
|
// Constantes visuales
|
|
static constexpr Uint8 MSG_COLOR = 9; // PaletteColor::BRIGHT_GREEN
|
|
static constexpr int TEXT_SIZE = Console::TEXT_SIZE;
|
|
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 + offset animado propio
|
|
const int CONSOLE_Y = (Console::get() != nullptr) ? Console::get()->getVisibleHeight() : 0;
|
|
const int Y = CONSOLE_Y + static_cast<int>(y_);
|
|
|
|
text_obj->writeDX(Text::CENTER_FLAG | Text::COLOR_FLAG,
|
|
static_cast<int>(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() {
|
|
switch (status_) {
|
|
case Status::HIDDEN:
|
|
status_ = Status::RISING;
|
|
Screen::get()->updateZoomFactor();
|
|
if (Notifier::get() != nullptr) { Notifier::get()->addYOffset(HEIGHT); }
|
|
break;
|
|
case Status::ACTIVE:
|
|
status_ = Status::VANISHING;
|
|
if (Notifier::get() != nullptr) { Notifier::get()->removeYOffset(HEIGHT); }
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|