297 lines
12 KiB
C++
297 lines
12 KiB
C++
#include "ui_manager.h"
|
|
|
|
#include <SDL3/SDL.h>
|
|
#include <string>
|
|
|
|
#include "../ball.h" // for Ball
|
|
#include "../defines.h" // for TEXT_DURATION, NOTIFICATION_DURATION, AppMode, SimulationMode
|
|
#include "../scene/scene_manager.h" // for SceneManager
|
|
#include "../shapes/shape.h" // for Shape
|
|
#include "../text/textrenderer.h" // for TextRenderer
|
|
#include "../theme_manager.h" // for ThemeManager
|
|
#include "notifier.h" // for Notifier
|
|
#include "help_overlay.h" // for HelpOverlay
|
|
|
|
UIManager::UIManager()
|
|
: text_renderer_(nullptr)
|
|
, text_renderer_debug_(nullptr)
|
|
, text_renderer_notifier_(nullptr)
|
|
, notifier_(nullptr)
|
|
, help_overlay_(nullptr)
|
|
, show_debug_(false)
|
|
, show_text_(true)
|
|
, text_()
|
|
, text_pos_(0)
|
|
, text_init_time_(0)
|
|
, fps_last_time_(0)
|
|
, fps_frame_count_(0)
|
|
, fps_current_(0)
|
|
, fps_text_("FPS: 0")
|
|
, vsync_text_("VSYNC ON")
|
|
, renderer_(nullptr)
|
|
, theme_manager_(nullptr)
|
|
, physical_window_width_(0)
|
|
, physical_window_height_(0) {
|
|
}
|
|
|
|
UIManager::~UIManager() {
|
|
// Limpieza: Los objetos creados con new deben ser eliminados
|
|
delete text_renderer_;
|
|
delete text_renderer_debug_;
|
|
delete text_renderer_notifier_;
|
|
delete notifier_;
|
|
delete help_overlay_;
|
|
}
|
|
|
|
void UIManager::initialize(SDL_Renderer* renderer, ThemeManager* theme_manager,
|
|
int physical_width, int physical_height) {
|
|
renderer_ = renderer;
|
|
theme_manager_ = theme_manager;
|
|
physical_window_width_ = physical_width;
|
|
physical_window_height_ = physical_height;
|
|
|
|
// Crear renderers de texto
|
|
text_renderer_ = new TextRenderer();
|
|
text_renderer_debug_ = new TextRenderer();
|
|
text_renderer_notifier_ = new TextRenderer();
|
|
|
|
// Inicializar renderers
|
|
// (el tamaño se configura dinámicamente en Engine según resolución)
|
|
text_renderer_->init(renderer, "data/fonts/determination.ttf", 24, true);
|
|
text_renderer_debug_->init(renderer, "data/fonts/determination.ttf", 24, true);
|
|
text_renderer_notifier_->init(renderer, "data/fonts/determination.ttf", 24, true);
|
|
|
|
// Crear y configurar sistema de notificaciones
|
|
notifier_ = new Notifier();
|
|
notifier_->init(renderer, text_renderer_notifier_, theme_manager_,
|
|
physical_width, physical_height);
|
|
|
|
// Crear y configurar sistema de ayuda (overlay)
|
|
help_overlay_ = new HelpOverlay();
|
|
help_overlay_->initialize(renderer, theme_manager_, physical_width, physical_height);
|
|
|
|
// Inicializar FPS counter
|
|
fps_last_time_ = SDL_GetTicks();
|
|
fps_frame_count_ = 0;
|
|
fps_current_ = 0;
|
|
}
|
|
|
|
void UIManager::update(Uint64 current_time, float delta_time) {
|
|
// Calcular FPS
|
|
fps_frame_count_++;
|
|
if (current_time - fps_last_time_ >= 1000) { // Actualizar cada segundo
|
|
fps_current_ = fps_frame_count_;
|
|
fps_frame_count_ = 0;
|
|
fps_last_time_ = current_time;
|
|
fps_text_ = "fps: " + std::to_string(fps_current_);
|
|
}
|
|
|
|
// Actualizar texto obsoleto (DEPRECATED)
|
|
if (show_text_) {
|
|
show_text_ = !(SDL_GetTicks() - text_init_time_ > TEXT_DURATION);
|
|
}
|
|
|
|
// Actualizar sistema de notificaciones
|
|
notifier_->update(current_time);
|
|
}
|
|
|
|
void UIManager::render(SDL_Renderer* renderer,
|
|
const SceneManager* scene_manager,
|
|
SimulationMode current_mode,
|
|
AppMode current_app_mode,
|
|
const Shape* active_shape,
|
|
float shape_convergence,
|
|
int physical_width,
|
|
int physical_height,
|
|
int current_screen_width) {
|
|
// Actualizar dimensiones físicas (puede cambiar en fullscreen)
|
|
physical_window_width_ = physical_width;
|
|
physical_window_height_ = physical_height;
|
|
|
|
// Renderizar texto obsoleto centrado (DEPRECATED - mantener temporalmente)
|
|
if (show_text_) {
|
|
renderObsoleteText(current_screen_width);
|
|
}
|
|
|
|
// Renderizar debug HUD si está activo
|
|
if (show_debug_) {
|
|
renderDebugHUD(scene_manager, current_mode, current_app_mode,
|
|
active_shape, shape_convergence);
|
|
}
|
|
|
|
// Renderizar notificaciones (siempre al final, sobre todo lo demás)
|
|
notifier_->render();
|
|
|
|
// Renderizar ayuda (siempre última, sobre todo incluso notificaciones)
|
|
if (help_overlay_) {
|
|
help_overlay_->render(renderer);
|
|
}
|
|
}
|
|
|
|
void UIManager::toggleDebug() {
|
|
show_debug_ = !show_debug_;
|
|
}
|
|
|
|
void UIManager::toggleHelp() {
|
|
if (help_overlay_) {
|
|
help_overlay_->toggle();
|
|
}
|
|
}
|
|
|
|
void UIManager::showNotification(const std::string& text, Uint64 duration) {
|
|
if (duration == 0) {
|
|
duration = NOTIFICATION_DURATION;
|
|
}
|
|
notifier_->show(text, duration);
|
|
}
|
|
|
|
void UIManager::updateVSyncText(bool enabled) {
|
|
vsync_text_ = enabled ? "V-Sync: On" : "V-Sync: Off";
|
|
}
|
|
|
|
void UIManager::updatePhysicalWindowSize(int width, int height) {
|
|
physical_window_width_ = width;
|
|
physical_window_height_ = height;
|
|
notifier_->updateWindowSize(width, height);
|
|
if (help_overlay_) {
|
|
help_overlay_->updatePhysicalWindowSize(width, height);
|
|
}
|
|
}
|
|
|
|
void UIManager::setTextObsolete(const std::string& text, int pos, int current_screen_width) {
|
|
text_ = text;
|
|
text_pos_ = pos;
|
|
text_init_time_ = SDL_GetTicks();
|
|
show_text_ = true;
|
|
}
|
|
|
|
// === Métodos privados ===
|
|
|
|
void UIManager::renderDebugHUD(const SceneManager* scene_manager,
|
|
SimulationMode current_mode,
|
|
AppMode current_app_mode,
|
|
const Shape* active_shape,
|
|
float shape_convergence) {
|
|
// Obtener altura de línea para espaciado dinámico
|
|
int line_height = text_renderer_debug_->getTextHeight();
|
|
int margin = 8; // Margen constante en píxeles físicos
|
|
int current_y = margin; // Y inicial en píxeles físicos
|
|
|
|
// Mostrar contador de FPS en esquina superior derecha
|
|
int fps_text_width = text_renderer_debug_->getTextWidthPhysical(fps_text_.c_str());
|
|
int fps_x = physical_window_width_ - fps_text_width - margin;
|
|
text_renderer_debug_->printAbsolute(fps_x, current_y, fps_text_.c_str(), {255, 255, 0, 255}); // Amarillo
|
|
|
|
// Mostrar estado V-Sync en esquina superior izquierda
|
|
text_renderer_debug_->printAbsolute(margin, current_y, vsync_text_.c_str(), {0, 255, 255, 255}); // Cian
|
|
current_y += line_height;
|
|
|
|
// Debug: Mostrar valores de la primera pelota (si existe)
|
|
const Ball* first_ball = scene_manager->getFirstBall();
|
|
if (first_ball != nullptr) {
|
|
// Línea 1: Gravedad
|
|
int grav_int = static_cast<int>(first_ball->getGravityForce());
|
|
std::string grav_text = "Gravedad: " + std::to_string(grav_int);
|
|
text_renderer_debug_->printAbsolute(margin, current_y, grav_text.c_str(), {255, 0, 255, 255}); // Magenta
|
|
current_y += line_height;
|
|
|
|
// Línea 2: Velocidad Y
|
|
int vy_int = static_cast<int>(first_ball->getVelocityY());
|
|
std::string vy_text = "Velocidad Y: " + std::to_string(vy_int);
|
|
text_renderer_debug_->printAbsolute(margin, current_y, vy_text.c_str(), {255, 0, 255, 255}); // Magenta
|
|
current_y += line_height;
|
|
|
|
// Línea 3: Estado superficie
|
|
std::string surface_text = first_ball->isOnSurface() ? "Superficie: Sí" : "Superficie: No";
|
|
text_renderer_debug_->printAbsolute(margin, current_y, surface_text.c_str(), {255, 0, 255, 255}); // Magenta
|
|
current_y += line_height;
|
|
|
|
// Línea 4: Coeficiente de rebote (loss)
|
|
float loss_val = first_ball->getLossCoefficient();
|
|
std::string loss_text = "Rebote: " + std::to_string(loss_val).substr(0, 4);
|
|
text_renderer_debug_->printAbsolute(margin, current_y, loss_text.c_str(), {255, 0, 255, 255}); // Magenta
|
|
current_y += line_height;
|
|
|
|
// Línea 5: Dirección de gravedad
|
|
std::string gravity_dir_text = "Dirección: " + gravityDirectionToString(static_cast<int>(scene_manager->getCurrentGravity()));
|
|
text_renderer_debug_->printAbsolute(margin, current_y, gravity_dir_text.c_str(), {255, 255, 0, 255}); // Amarillo
|
|
current_y += line_height;
|
|
}
|
|
|
|
// Debug: Mostrar tema actual (delegado a ThemeManager)
|
|
std::string theme_text = std::string("Tema: ") + theme_manager_->getCurrentThemeNameEN();
|
|
text_renderer_debug_->printAbsolute(margin, current_y, theme_text.c_str(), {255, 255, 128, 255}); // Amarillo claro
|
|
current_y += line_height;
|
|
|
|
// Debug: Mostrar modo de simulación actual
|
|
std::string mode_text;
|
|
if (current_mode == SimulationMode::PHYSICS) {
|
|
mode_text = "Modo: Física";
|
|
} else if (active_shape) {
|
|
mode_text = std::string("Modo: ") + active_shape->getName();
|
|
} else {
|
|
mode_text = "Modo: Forma";
|
|
}
|
|
text_renderer_debug_->printAbsolute(margin, current_y, mode_text.c_str(), {0, 255, 128, 255}); // Verde claro
|
|
current_y += line_height;
|
|
|
|
// Debug: Mostrar convergencia en modo LOGO (solo cuando está activo)
|
|
if (current_app_mode == AppMode::LOGO && current_mode == SimulationMode::SHAPE) {
|
|
int convergence_percent = static_cast<int>(shape_convergence * 100.0f);
|
|
std::string convergence_text = "Convergencia: " + std::to_string(convergence_percent) + "%";
|
|
text_renderer_debug_->printAbsolute(margin, current_y, convergence_text.c_str(), {255, 128, 0, 255}); // Naranja
|
|
current_y += line_height;
|
|
}
|
|
|
|
// Debug: Mostrar modo DEMO/LOGO activo (siempre visible cuando debug está ON)
|
|
// FIJO en tercera fila (no se mueve con otros elementos del HUD)
|
|
int fixed_y = margin + (line_height * 2); // Tercera fila fija
|
|
if (current_app_mode == AppMode::LOGO) {
|
|
const char* logo_text = "Modo Logo";
|
|
int logo_text_width = text_renderer_debug_->getTextWidthPhysical(logo_text);
|
|
int logo_x = (physical_window_width_ - logo_text_width) / 2;
|
|
text_renderer_debug_->printAbsolute(logo_x, fixed_y, logo_text, {255, 128, 0, 255}); // Naranja
|
|
} else if (current_app_mode == AppMode::DEMO) {
|
|
const char* demo_text = "Modo Demo";
|
|
int demo_text_width = text_renderer_debug_->getTextWidthPhysical(demo_text);
|
|
int demo_x = (physical_window_width_ - demo_text_width) / 2;
|
|
text_renderer_debug_->printAbsolute(demo_x, fixed_y, demo_text, {255, 165, 0, 255}); // Naranja
|
|
} else if (current_app_mode == AppMode::DEMO_LITE) {
|
|
const char* lite_text = "Modo Demo Lite";
|
|
int lite_text_width = text_renderer_debug_->getTextWidthPhysical(lite_text);
|
|
int lite_x = (physical_window_width_ - lite_text_width) / 2;
|
|
text_renderer_debug_->printAbsolute(lite_x, fixed_y, lite_text, {255, 200, 0, 255}); // Amarillo-naranja
|
|
}
|
|
}
|
|
|
|
void UIManager::renderObsoleteText(int current_screen_width) {
|
|
// DEPRECATED: Sistema antiguo de texto centrado
|
|
// Mantener por compatibilidad temporal hasta migrar todo a Notifier
|
|
|
|
// Calcular escala dinámica basada en resolución física
|
|
float text_scale_x = static_cast<float>(physical_window_width_) / 426.0f;
|
|
float text_scale_y = static_cast<float>(physical_window_height_) / 240.0f;
|
|
|
|
// Obtener color del tema actual (LERP interpolado)
|
|
int margin = 8;
|
|
Color text_color = theme_manager_->getInterpolatedColor(0);
|
|
int text_color_r = text_color.r;
|
|
int text_color_g = text_color.g;
|
|
int text_color_b = text_color.b;
|
|
|
|
// Renderizar texto centrado usando coordenadas físicas
|
|
text_renderer_->printPhysical(text_pos_, margin, text_.c_str(),
|
|
text_color_r, text_color_g, text_color_b,
|
|
text_scale_x, text_scale_y);
|
|
}
|
|
|
|
std::string UIManager::gravityDirectionToString(int direction) const {
|
|
switch (direction) {
|
|
case 0: return "Abajo"; // DOWN
|
|
case 1: return "Arriba"; // UP
|
|
case 2: return "Izquierda"; // LEFT
|
|
case 3: return "Derecha"; // RIGHT
|
|
default: return "Desconocida";
|
|
}
|
|
}
|