Treballant en text independent de la resolucio

This commit is contained in:
2025-10-09 20:43:34 +02:00
parent f00b08b6be
commit 68381dc92d
4 changed files with 128 additions and 32 deletions

View File

@@ -203,21 +203,8 @@ bool Engine::initialize(int width, int height, int zoom, bool fullscreen) {
srand(static_cast<unsigned>(time(nullptr))); srand(static_cast<unsigned>(time(nullptr)));
// Calcular tamaño de fuente escalado según resolución // Calcular tamaño físico de ventana y tamaño de fuente absoluto
// Usa las constantes configurables de la clase updatePhysicalWindowSize();
int font_size = (base_screen_height_ * TEXT_BASE_SIZE) / 240;
// Inicializar TextRenderer para display (texto centrado)
if (!text_renderer_.init(renderer_, TEXT_FONT_PATH, font_size, TEXT_ANTIALIASING)) {
SDL_Log("Error al inicializar TextRenderer (display)");
return false;
}
// Inicializar TextRenderer para debug (HUD)
if (!text_renderer_debug_.init(renderer_, TEXT_FONT_PATH, font_size, TEXT_ANTIALIASING)) {
SDL_Log("Error al inicializar TextRenderer (debug)");
return false;
}
// Inicializar ThemeManager // Inicializar ThemeManager
theme_manager_ = std::make_unique<ThemeManager>(); theme_manager_ = std::make_unique<ThemeManager>();
@@ -883,6 +870,10 @@ void Engine::render() {
SDL_RenderGeometry(renderer_, texture_->getSDLTexture(), batch_vertices_.data(), static_cast<int>(batch_vertices_.size()), batch_indices_.data(), static_cast<int>(batch_indices_.size())); SDL_RenderGeometry(renderer_, texture_->getSDLTexture(), batch_vertices_.data(), static_cast<int>(batch_vertices_.size()), batch_indices_.data(), static_cast<int>(batch_indices_.size()));
} }
// Calcular factores de escala lógica → física para texto absoluto
float text_scale_x = static_cast<float>(physical_window_width_) / static_cast<float>(current_screen_width_);
float text_scale_y = static_cast<float>(physical_window_height_) / static_cast<float>(current_screen_height_);
if (show_text_) { if (show_text_) {
// Obtener datos del tema actual (delegado a ThemeManager) // Obtener datos del tema actual (delegado a ThemeManager)
int text_color_r, text_color_g, text_color_b; int text_color_r, text_color_g, text_color_b;
@@ -894,7 +885,7 @@ void Engine::render() {
int margin = 8; int margin = 8;
// Texto del número de pelotas con color del tema // Texto del número de pelotas con color del tema
text_renderer_.print(text_pos_, margin, text_.c_str(), text_color_r, text_color_g, text_color_b); text_renderer_.printPhysical(text_pos_, margin, text_.c_str(), text_color_r, text_color_g, text_color_b, text_scale_x, text_scale_y);
// Mostrar nombre del tema en castellano debajo del número de pelotas // Mostrar nombre del tema en castellano debajo del número de pelotas
// (solo si text_ NO es ya el nombre del tema, para evitar duplicación) // (solo si text_ NO es ya el nombre del tema, para evitar duplicación)
@@ -904,7 +895,7 @@ void Engine::render() {
int theme_y = margin + line_height; // Espaciado dinámico int theme_y = margin + line_height; // Espaciado dinámico
// Texto del nombre del tema con el mismo color // Texto del nombre del tema con el mismo color
text_renderer_.print(theme_x, theme_y, theme_name_es, text_color_r, text_color_g, text_color_b); text_renderer_.printPhysical(theme_x, theme_y, theme_name_es, text_color_r, text_color_g, text_color_b, text_scale_x, text_scale_y);
} }
} }
@@ -918,10 +909,10 @@ void Engine::render() {
// Mostrar contador de FPS en esquina superior derecha // Mostrar contador de FPS en esquina superior derecha
int fps_text_width = text_renderer_debug_.getTextWidth(fps_text_.c_str()); int fps_text_width = text_renderer_debug_.getTextWidth(fps_text_.c_str());
int fps_x = current_screen_width_ - fps_text_width - margin; int fps_x = current_screen_width_ - fps_text_width - margin;
text_renderer_debug_.print(fps_x, current_y, fps_text_.c_str(), 255, 255, 0); // Amarillo text_renderer_debug_.printPhysical(fps_x, current_y, fps_text_.c_str(), 255, 255, 0, text_scale_x, text_scale_y); // Amarillo
// Mostrar estado V-Sync en esquina superior izquierda // Mostrar estado V-Sync en esquina superior izquierda
text_renderer_debug_.print(margin, current_y, vsync_text_.c_str(), 0, 255, 255); // Cian text_renderer_debug_.printPhysical(margin, current_y, vsync_text_.c_str(), 0, 255, 255, text_scale_x, text_scale_y); // Cian
current_y += line_height; current_y += line_height;
// Debug: Mostrar valores de la primera pelota (si existe) // Debug: Mostrar valores de la primera pelota (si existe)
@@ -929,35 +920,35 @@ void Engine::render() {
// Línea 1: Gravedad // Línea 1: Gravedad
int grav_int = static_cast<int>(balls_[0]->getGravityForce()); int grav_int = static_cast<int>(balls_[0]->getGravityForce());
std::string grav_text = "Gravedad: " + std::to_string(grav_int); std::string grav_text = "Gravedad: " + std::to_string(grav_int);
text_renderer_debug_.print(margin, current_y, grav_text.c_str(), 255, 0, 255); // Magenta text_renderer_debug_.printPhysical(margin, current_y, grav_text.c_str(), 255, 0, 255, text_scale_x, text_scale_y); // Magenta
current_y += line_height; current_y += line_height;
// Línea 2: Velocidad Y // Línea 2: Velocidad Y
int vy_int = static_cast<int>(balls_[0]->getVelocityY()); int vy_int = static_cast<int>(balls_[0]->getVelocityY());
std::string vy_text = "Velocidad Y: " + std::to_string(vy_int); std::string vy_text = "Velocidad Y: " + std::to_string(vy_int);
text_renderer_debug_.print(margin, current_y, vy_text.c_str(), 255, 0, 255); // Magenta text_renderer_debug_.printPhysical(margin, current_y, vy_text.c_str(), 255, 0, 255, text_scale_x, text_scale_y); // Magenta
current_y += line_height; current_y += line_height;
// Línea 3: Estado superficie // Línea 3: Estado superficie
std::string surface_text = balls_[0]->isOnSurface() ? "Superficie: Sí" : "Superficie: No"; std::string surface_text = balls_[0]->isOnSurface() ? "Superficie: Sí" : "Superficie: No";
text_renderer_debug_.print(margin, current_y, surface_text.c_str(), 255, 0, 255); // Magenta text_renderer_debug_.printPhysical(margin, current_y, surface_text.c_str(), 255, 0, 255, text_scale_x, text_scale_y); // Magenta
current_y += line_height; current_y += line_height;
// Línea 4: Coeficiente de rebote (loss) // Línea 4: Coeficiente de rebote (loss)
float loss_val = balls_[0]->getLossCoefficient(); float loss_val = balls_[0]->getLossCoefficient();
std::string loss_text = "Rebote: " + std::to_string(loss_val).substr(0, 4); std::string loss_text = "Rebote: " + std::to_string(loss_val).substr(0, 4);
text_renderer_debug_.print(margin, current_y, loss_text.c_str(), 255, 0, 255); // Magenta text_renderer_debug_.printPhysical(margin, current_y, loss_text.c_str(), 255, 0, 255, text_scale_x, text_scale_y); // Magenta
current_y += line_height; current_y += line_height;
// Línea 5: Dirección de gravedad // Línea 5: Dirección de gravedad
std::string gravity_dir_text = "Dirección: " + gravityDirectionToString(current_gravity_); std::string gravity_dir_text = "Dirección: " + gravityDirectionToString(current_gravity_);
text_renderer_debug_.print(margin, current_y, gravity_dir_text.c_str(), 255, 255, 0); // Amarillo text_renderer_debug_.printPhysical(margin, current_y, gravity_dir_text.c_str(), 255, 255, 0, text_scale_x, text_scale_y); // Amarillo
current_y += line_height; current_y += line_height;
} }
// Debug: Mostrar tema actual (delegado a ThemeManager) // Debug: Mostrar tema actual (delegado a ThemeManager)
std::string theme_text = std::string("Tema: ") + theme_manager_->getCurrentThemeNameEN(); std::string theme_text = std::string("Tema: ") + theme_manager_->getCurrentThemeNameEN();
text_renderer_debug_.print(margin, current_y, theme_text.c_str(), 255, 255, 128); // Amarillo claro text_renderer_debug_.printPhysical(margin, current_y, theme_text.c_str(), 255, 255, 128, text_scale_x, text_scale_y); // Amarillo claro
current_y += line_height; current_y += line_height;
// Debug: Mostrar modo de simulación actual // Debug: Mostrar modo de simulación actual
@@ -969,14 +960,14 @@ void Engine::render() {
} else { } else {
mode_text = "Modo: Forma"; mode_text = "Modo: Forma";
} }
text_renderer_debug_.print(margin, current_y, mode_text.c_str(), 0, 255, 128); // Verde claro text_renderer_debug_.printPhysical(margin, current_y, mode_text.c_str(), 0, 255, 128, text_scale_x, text_scale_y); // Verde claro
current_y += line_height; current_y += line_height;
// Debug: Mostrar convergencia en modo LOGO (solo cuando está activo) // Debug: Mostrar convergencia en modo LOGO (solo cuando está activo)
if (current_app_mode_ == AppMode::LOGO && current_mode_ == SimulationMode::SHAPE) { if (current_app_mode_ == AppMode::LOGO && current_mode_ == SimulationMode::SHAPE) {
int convergence_percent = static_cast<int>(shape_convergence_ * 100.0f); int convergence_percent = static_cast<int>(shape_convergence_ * 100.0f);
std::string convergence_text = "Convergencia: " + std::to_string(convergence_percent) + "%"; std::string convergence_text = "Convergencia: " + std::to_string(convergence_percent) + "%";
text_renderer_debug_.print(margin, current_y, convergence_text.c_str(), 255, 128, 0); // Naranja text_renderer_debug_.printPhysical(margin, current_y, convergence_text.c_str(), 255, 128, 0, text_scale_x, text_scale_y); // Naranja
current_y += line_height; current_y += line_height;
} }
@@ -987,17 +978,17 @@ void Engine::render() {
const char* logo_text = "Modo Logo"; const char* logo_text = "Modo Logo";
int logo_text_width = text_renderer_debug_.getTextWidth(logo_text); int logo_text_width = text_renderer_debug_.getTextWidth(logo_text);
int logo_x = (current_screen_width_ - logo_text_width) / 2; int logo_x = (current_screen_width_ - logo_text_width) / 2;
text_renderer_debug_.print(logo_x, fixed_y, logo_text, 255, 128, 0); // Naranja text_renderer_debug_.printPhysical(logo_x, fixed_y, logo_text, 255, 128, 0, text_scale_x, text_scale_y); // Naranja
} else if (current_app_mode_ == AppMode::DEMO) { } else if (current_app_mode_ == AppMode::DEMO) {
const char* demo_text = "Modo Demo"; const char* demo_text = "Modo Demo";
int demo_text_width = text_renderer_debug_.getTextWidth(demo_text); int demo_text_width = text_renderer_debug_.getTextWidth(demo_text);
int demo_x = (current_screen_width_ - demo_text_width) / 2; int demo_x = (current_screen_width_ - demo_text_width) / 2;
text_renderer_debug_.print(demo_x, fixed_y, demo_text, 255, 165, 0); // Naranja text_renderer_debug_.printPhysical(demo_x, fixed_y, demo_text, 255, 165, 0, text_scale_x, text_scale_y); // Naranja
} else if (current_app_mode_ == AppMode::DEMO_LITE) { } else if (current_app_mode_ == AppMode::DEMO_LITE) {
const char* lite_text = "Modo Demo Lite"; const char* lite_text = "Modo Demo Lite";
int lite_text_width = text_renderer_debug_.getTextWidth(lite_text); int lite_text_width = text_renderer_debug_.getTextWidth(lite_text);
int lite_x = (current_screen_width_ - lite_text_width) / 2; int lite_x = (current_screen_width_ - lite_text_width) / 2;
text_renderer_debug_.print(lite_x, fixed_y, lite_text, 255, 200, 0); // Amarillo-naranja text_renderer_debug_.printPhysical(lite_x, fixed_y, lite_text, 255, 200, 0, text_scale_x, text_scale_y); // Amarillo-naranja
} }
} }
@@ -1174,6 +1165,9 @@ void Engine::toggleRealFullscreen() {
// Actualizar presentación lógica del renderizador // Actualizar presentación lógica del renderizador
SDL_SetRenderLogicalPresentation(renderer_, current_screen_width_, current_screen_height_, SDL_LOGICAL_PRESENTATION_INTEGER_SCALE); SDL_SetRenderLogicalPresentation(renderer_, current_screen_width_, current_screen_height_, SDL_LOGICAL_PRESENTATION_INTEGER_SCALE);
// Actualizar tamaño físico de ventana y fuentes
updatePhysicalWindowSize();
// Reinicar la escena con nueva resolución // Reinicar la escena con nueva resolución
initBalls(scenario_); initBalls(scenario_);
} }
@@ -1191,6 +1185,9 @@ void Engine::toggleRealFullscreen() {
// Restaurar presentación lógica base // Restaurar presentación lógica base
SDL_SetRenderLogicalPresentation(renderer_, base_screen_width_, base_screen_height_, SDL_LOGICAL_PRESENTATION_INTEGER_SCALE); SDL_SetRenderLogicalPresentation(renderer_, base_screen_width_, base_screen_height_, SDL_LOGICAL_PRESENTATION_INTEGER_SCALE);
// Actualizar tamaño físico de ventana y fuentes
updatePhysicalWindowSize();
// Reinicar la escena con resolución original // Reinicar la escena con resolución original
initBalls(scenario_); initBalls(scenario_);
} }
@@ -1376,6 +1373,9 @@ void Engine::setWindowZoom(int new_zoom) {
SDL_SetWindowSize(window_, new_width, new_height); SDL_SetWindowSize(window_, new_width, new_height);
SDL_SetWindowPosition(window_, new_x, new_y); SDL_SetWindowPosition(window_, new_x, new_y);
current_window_zoom_ = new_zoom; current_window_zoom_ = new_zoom;
// Actualizar tamaño físico de ventana y fuentes
updatePhysicalWindowSize();
} }
void Engine::zoomIn() { void Engine::zoomIn() {
@@ -1386,6 +1386,31 @@ void Engine::zoomOut() {
setWindowZoom(current_window_zoom_ - 1); setWindowZoom(current_window_zoom_ - 1);
} }
void Engine::updatePhysicalWindowSize() {
if (real_fullscreen_enabled_) {
// En fullscreen real, usar resolución del display
physical_window_width_ = current_screen_width_;
physical_window_height_ = current_screen_height_;
} else {
// En modo ventana, obtener tamaño real de la ventana (lógica * zoom)
int window_w = 0, window_h = 0;
SDL_GetWindowSize(window_, &window_w, &window_h);
physical_window_width_ = window_w;
physical_window_height_ = window_h;
}
// Recalcular tamaño de fuente basado en altura física
// Referencia: 8px a 1440p (monitor del usuario)
int font_size = (physical_window_height_ * TEXT_BASE_SIZE) / 1440;
if (font_size < 6) font_size = 6; // Tamaño mínimo legible
// Reinicializar TextRenderers con nuevo tamaño de fuente
text_renderer_.cleanup();
text_renderer_debug_.cleanup();
text_renderer_.init(renderer_, TEXT_FONT_PATH, font_size, TEXT_ANTIALIASING);
text_renderer_debug_.init(renderer_, TEXT_FONT_PATH, font_size, TEXT_ANTIALIASING);
}
// ============================================================================ // ============================================================================
// Sistema de gestión de estados (MANUAL/DEMO/DEMO_LITE/LOGO) // Sistema de gestión de estados (MANUAL/DEMO/DEMO_LITE/LOGO)
// ============================================================================ // ============================================================================

View File

@@ -83,6 +83,10 @@ class Engine {
int current_screen_width_ = DEFAULT_SCREEN_WIDTH; int current_screen_width_ = DEFAULT_SCREEN_WIDTH;
int current_screen_height_ = DEFAULT_SCREEN_HEIGHT; int current_screen_height_ = DEFAULT_SCREEN_HEIGHT;
// Resolución física real de ventana/pantalla (para texto absoluto)
int physical_window_width_ = DEFAULT_SCREEN_WIDTH;
int physical_window_height_ = DEFAULT_SCREEN_HEIGHT;
// Sistema de temas (delegado a ThemeManager) // Sistema de temas (delegado a ThemeManager)
std::unique_ptr<ThemeManager> theme_manager_; std::unique_ptr<ThemeManager> theme_manager_;
int theme_page_ = 0; // Página actual de temas (0 o 1) para acceso por Numpad int theme_page_ = 0; // Página actual de temas (0 o 1) para acceso por Numpad
@@ -124,7 +128,7 @@ class Engine {
// Configuración del sistema de texto (constantes configurables) // Configuración del sistema de texto (constantes configurables)
static constexpr const char* TEXT_FONT_PATH = "data/fonts/determination.ttf"; static constexpr const char* TEXT_FONT_PATH = "data/fonts/determination.ttf";
static constexpr int TEXT_BASE_SIZE = 8; // Tamaño base para 240p static constexpr int TEXT_BASE_SIZE = 24; // Tamaño base para 240p
static constexpr bool TEXT_ANTIALIASING = true; // true = suavizado, false = píxeles nítidos static constexpr bool TEXT_ANTIALIASING = true; // true = suavizado, false = píxeles nítidos
// Métodos principales del loop // Métodos principales del loop
@@ -171,6 +175,7 @@ class Engine {
void setWindowZoom(int new_zoom); void setWindowZoom(int new_zoom);
void zoomIn(); void zoomIn();
void zoomOut(); void zoomOut();
void updatePhysicalWindowSize(); // Actualizar tamaño físico real de ventana
// Rendering // Rendering
void addSpriteToBatch(float x, float y, float w, float h, int r, int g, int b, float scale = 1.0f); void addSpriteToBatch(float x, float y, float w, float h, int r, int g, int b, float scale = 1.0f);

View File

@@ -90,6 +90,68 @@ void TextRenderer::print(int x, int y, const std::string& text, uint8_t r, uint8
print(x, y, text.c_str(), r, g, b); print(x, y, text.c_str(), r, g, b);
} }
void TextRenderer::printPhysical(int logical_x, int logical_y, const char* text, uint8_t r, uint8_t g, uint8_t b, float scale_x, float scale_y) {
if (!isInitialized() || text == nullptr || text[0] == '\0') {
return;
}
// Convertir coordenadas lógicas a físicas
int physical_x = static_cast<int>(logical_x * scale_x);
int physical_y = static_cast<int>(logical_y * scale_y);
// Crear superficie con el texto renderizado
SDL_Color color = {r, g, b, 255};
SDL_Surface* text_surface = nullptr;
if (use_antialiasing_) {
text_surface = TTF_RenderText_Blended(font_, text, strlen(text), color);
} else {
text_surface = TTF_RenderText_Solid(font_, text, strlen(text), color);
}
if (text_surface == nullptr) {
SDL_Log("Error al renderizar texto: %s", SDL_GetError());
return;
}
// Crear textura desde la superficie
SDL_Texture* text_texture = SDL_CreateTextureFromSurface(renderer_, text_surface);
if (text_texture == nullptr) {
SDL_Log("Error al crear textura: %s", SDL_GetError());
SDL_DestroySurface(text_surface);
return;
}
// Renderizar en coordenadas físicas (bypass presentación lógica)
// Usar SDL_RenderTexture con coordenadas absolutas de ventana
SDL_FRect dest_rect;
dest_rect.x = static_cast<float>(physical_x);
dest_rect.y = static_cast<float>(physical_y);
dest_rect.w = static_cast<float>(text_surface->w);
dest_rect.h = static_cast<float>(text_surface->h);
// Deshabilitar temporalmente presentación lógica para renderizar en píxeles físicos
int logical_w = 0, logical_h = 0;
SDL_RendererLogicalPresentation presentation_mode;
SDL_GetRenderLogicalPresentation(renderer_, &logical_w, &logical_h, &presentation_mode);
// Renderizar sin presentación lógica (coordenadas absolutas)
SDL_SetRenderLogicalPresentation(renderer_, 0, 0, SDL_LOGICAL_PRESENTATION_DISABLED);
SDL_RenderTexture(renderer_, text_texture, nullptr, &dest_rect);
// Restaurar presentación lógica
SDL_SetRenderLogicalPresentation(renderer_, logical_w, logical_h, presentation_mode);
// Limpiar recursos
SDL_DestroyTexture(text_texture);
SDL_DestroySurface(text_surface);
}
void TextRenderer::printPhysical(int logical_x, int logical_y, const std::string& text, uint8_t r, uint8_t g, uint8_t b, float scale_x, float scale_y) {
printPhysical(logical_x, logical_y, text.c_str(), r, g, b, scale_x, scale_y);
}
int TextRenderer::getTextWidth(const char* text) { int TextRenderer::getTextWidth(const char* text) {
if (!isInitialized() || text == nullptr) { if (!isInitialized() || text == nullptr) {
return 0; return 0;

View File

@@ -19,7 +19,11 @@ public:
void print(int x, int y, const char* text, uint8_t r, uint8_t g, uint8_t b); void print(int x, int y, const char* text, uint8_t r, uint8_t g, uint8_t b);
void print(int x, int y, const std::string& text, uint8_t r, uint8_t g, uint8_t b); void print(int x, int y, const std::string& text, uint8_t r, uint8_t g, uint8_t b);
// Obtiene el ancho de un texto renderizado // Renderiza texto en coordenadas lógicas, pero convierte a físicas para tamaño absoluto
void printPhysical(int logical_x, int logical_y, const char* text, uint8_t r, uint8_t g, uint8_t b, float scale_x, float scale_y);
void printPhysical(int logical_x, int logical_y, const std::string& text, uint8_t r, uint8_t g, uint8_t b, float scale_x, float scale_y);
// Obtiene el ancho de un texto renderizado (en píxeles lógicos para compatibilidad)
int getTextWidth(const char* text); int getTextWidth(const char* text);
// Obtiene la altura de la fuente // Obtiene la altura de la fuente