style: aplicar fixes de clang-tidy (todo excepto uppercase-literal-suffix)
Corregidos ~2570 issues automáticamente con clang-tidy --fix-errors más ajustes manuales posteriores: - modernize: designated-initializers, trailing-return-type, use-auto, avoid-c-arrays (→ std::array<>), use-ranges, use-emplace, deprecated-headers, use-equals-default, pass-by-value, return-braced-init-list, use-default-member-init - readability: math-missing-parentheses, implicit-bool-conversion, braces-around-statements, isolate-declaration, use-std-min-max, identifier-naming, else-after-return, redundant-casting, convert-member-functions-to-static, make-member-function-const, static-accessed-through-instance - performance: avoid-endl, unnecessary-value-param, type-promotion, inefficient-vector-operation - dead code: XOR_KEY (orphan tras eliminar encryptData/decryptData), dead stores en engine.cpp y png_shape.cpp - NOLINT justificado en 10 funciones con alta complejidad cognitiva (initialize, render, main, processEvents, update×3, performDemoAction, randomizeOnDemoStart, renderDebugHUD, AppLogo::update) Compilación: gcc -Wall sin warnings. clang-tidy: 0 issues. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,31 +1,34 @@
|
||||
#include "app_logo.hpp"
|
||||
|
||||
#include <SDL3/SDL_render.h> // for SDL_DestroyTexture, SDL_RenderGeometry, SDL_SetTextureAlphaMod
|
||||
#include <cmath> // for powf, sinf, cosf
|
||||
#include <cstdlib> // for free()
|
||||
#include <iostream> // for std::cout
|
||||
|
||||
#include "logo_scaler.hpp" // for LogoScaler
|
||||
#include "defines.hpp" // for APPLOGO_HEIGHT_PERCENT, getResourcesDirectory
|
||||
#include <array> // for std::array
|
||||
#include <cmath> // for powf, sinf, cosf
|
||||
#include <cstdlib> // for free()
|
||||
#include <iostream> // for std::cout
|
||||
#include <numbers>
|
||||
|
||||
#include "defines.hpp" // for APPLOGO_HEIGHT_PERCENT, getResourcesDirectory
|
||||
#include "logo_scaler.hpp" // for LogoScaler
|
||||
|
||||
// ============================================================================
|
||||
// Destructor - Liberar las 4 texturas SDL
|
||||
// ============================================================================
|
||||
|
||||
AppLogo::~AppLogo() {
|
||||
if (logo1_base_texture_) {
|
||||
if (logo1_base_texture_ != nullptr) {
|
||||
SDL_DestroyTexture(logo1_base_texture_);
|
||||
logo1_base_texture_ = nullptr;
|
||||
}
|
||||
if (logo1_native_texture_) {
|
||||
if (logo1_native_texture_ != nullptr) {
|
||||
SDL_DestroyTexture(logo1_native_texture_);
|
||||
logo1_native_texture_ = nullptr;
|
||||
}
|
||||
if (logo2_base_texture_) {
|
||||
if (logo2_base_texture_ != nullptr) {
|
||||
SDL_DestroyTexture(logo2_base_texture_);
|
||||
logo2_base_texture_ = nullptr;
|
||||
}
|
||||
if (logo2_native_texture_) {
|
||||
if (logo2_native_texture_ != nullptr) {
|
||||
SDL_DestroyTexture(logo2_native_texture_);
|
||||
logo2_native_texture_ = nullptr;
|
||||
}
|
||||
@@ -35,11 +38,23 @@ AppLogo::~AppLogo() {
|
||||
// Inicialización - Pre-escalar logos a 2 resoluciones (base y nativa)
|
||||
// ============================================================================
|
||||
|
||||
bool AppLogo::initialize(SDL_Renderer* renderer, int screen_width, int screen_height) {
|
||||
if (logo1_base_texture_) { SDL_DestroyTexture(logo1_base_texture_); logo1_base_texture_ = nullptr; }
|
||||
if (logo1_native_texture_) { SDL_DestroyTexture(logo1_native_texture_); logo1_native_texture_ = nullptr; }
|
||||
if (logo2_base_texture_) { SDL_DestroyTexture(logo2_base_texture_); logo2_base_texture_ = nullptr; }
|
||||
if (logo2_native_texture_) { SDL_DestroyTexture(logo2_native_texture_); logo2_native_texture_ = nullptr; }
|
||||
auto AppLogo::initialize(SDL_Renderer* renderer, int screen_width, int screen_height) -> bool {
|
||||
if (logo1_base_texture_ != nullptr) {
|
||||
SDL_DestroyTexture(logo1_base_texture_);
|
||||
logo1_base_texture_ = nullptr;
|
||||
}
|
||||
if (logo1_native_texture_ != nullptr) {
|
||||
SDL_DestroyTexture(logo1_native_texture_);
|
||||
logo1_native_texture_ = nullptr;
|
||||
}
|
||||
if (logo2_base_texture_ != nullptr) {
|
||||
SDL_DestroyTexture(logo2_base_texture_);
|
||||
logo2_base_texture_ = nullptr;
|
||||
}
|
||||
if (logo2_native_texture_ != nullptr) {
|
||||
SDL_DestroyTexture(logo2_native_texture_);
|
||||
logo2_native_texture_ = nullptr;
|
||||
}
|
||||
|
||||
renderer_ = renderer;
|
||||
base_screen_width_ = screen_width;
|
||||
@@ -53,7 +68,7 @@ bool AppLogo::initialize(SDL_Renderer* renderer, int screen_width, int screen_he
|
||||
// 1. Detectar resolución nativa del monitor
|
||||
// ========================================================================
|
||||
if (!LogoScaler::detectNativeResolution(native_screen_width_, native_screen_height_)) {
|
||||
std::cout << "No se pudo detectar resolución nativa, usando solo base" << std::endl;
|
||||
std::cout << "No se pudo detectar resolución nativa, usando solo base" << '\n';
|
||||
// Fallback: usar resolución base como nativa
|
||||
native_screen_width_ = screen_width;
|
||||
native_screen_height_ = screen_height;
|
||||
@@ -76,20 +91,21 @@ bool AppLogo::initialize(SDL_Renderer* renderer, int screen_width, int screen_he
|
||||
0, // width calculado automáticamente por aspect ratio
|
||||
logo_base_target_height,
|
||||
logo1_base_width_,
|
||||
logo1_base_height_
|
||||
);
|
||||
logo1_base_height_);
|
||||
if (logo1_base_data == nullptr) {
|
||||
std::cout << "Error: No se pudo escalar logo1 (base)" << std::endl;
|
||||
std::cout << "Error: No se pudo escalar logo1 (base)" << '\n';
|
||||
return false;
|
||||
}
|
||||
|
||||
logo1_base_texture_ = LogoScaler::createTextureFromBuffer(
|
||||
renderer, logo1_base_data, logo1_base_width_, logo1_base_height_
|
||||
);
|
||||
renderer,
|
||||
logo1_base_data,
|
||||
logo1_base_width_,
|
||||
logo1_base_height_);
|
||||
free(logo1_base_data); // Liberar buffer temporal
|
||||
|
||||
if (logo1_base_texture_ == nullptr) {
|
||||
std::cout << "Error: No se pudo crear textura logo1 (base)" << std::endl;
|
||||
std::cout << "Error: No se pudo crear textura logo1 (base)" << '\n';
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -102,20 +118,21 @@ bool AppLogo::initialize(SDL_Renderer* renderer, int screen_width, int screen_he
|
||||
0, // width calculado automáticamente
|
||||
logo_native_target_height,
|
||||
logo1_native_width_,
|
||||
logo1_native_height_
|
||||
);
|
||||
logo1_native_height_);
|
||||
if (logo1_native_data == nullptr) {
|
||||
std::cout << "Error: No se pudo escalar logo1 (nativa)" << std::endl;
|
||||
std::cout << "Error: No se pudo escalar logo1 (nativa)" << '\n';
|
||||
return false;
|
||||
}
|
||||
|
||||
logo1_native_texture_ = LogoScaler::createTextureFromBuffer(
|
||||
renderer, logo1_native_data, logo1_native_width_, logo1_native_height_
|
||||
);
|
||||
renderer,
|
||||
logo1_native_data,
|
||||
logo1_native_width_,
|
||||
logo1_native_height_);
|
||||
free(logo1_native_data);
|
||||
|
||||
if (logo1_native_texture_ == nullptr) {
|
||||
std::cout << "Error: No se pudo crear textura logo1 (nativa)" << std::endl;
|
||||
std::cout << "Error: No se pudo crear textura logo1 (nativa)" << '\n';
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -132,20 +149,21 @@ bool AppLogo::initialize(SDL_Renderer* renderer, int screen_width, int screen_he
|
||||
0,
|
||||
logo_base_target_height,
|
||||
logo2_base_width_,
|
||||
logo2_base_height_
|
||||
);
|
||||
logo2_base_height_);
|
||||
if (logo2_base_data == nullptr) {
|
||||
std::cout << "Error: No se pudo escalar logo2 (base)" << std::endl;
|
||||
std::cout << "Error: No se pudo escalar logo2 (base)" << '\n';
|
||||
return false;
|
||||
}
|
||||
|
||||
logo2_base_texture_ = LogoScaler::createTextureFromBuffer(
|
||||
renderer, logo2_base_data, logo2_base_width_, logo2_base_height_
|
||||
);
|
||||
renderer,
|
||||
logo2_base_data,
|
||||
logo2_base_width_,
|
||||
logo2_base_height_);
|
||||
free(logo2_base_data);
|
||||
|
||||
if (logo2_base_texture_ == nullptr) {
|
||||
std::cout << "Error: No se pudo crear textura logo2 (base)" << std::endl;
|
||||
std::cout << "Error: No se pudo crear textura logo2 (base)" << '\n';
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -157,20 +175,21 @@ bool AppLogo::initialize(SDL_Renderer* renderer, int screen_width, int screen_he
|
||||
0,
|
||||
logo_native_target_height,
|
||||
logo2_native_width_,
|
||||
logo2_native_height_
|
||||
);
|
||||
logo2_native_height_);
|
||||
if (logo2_native_data == nullptr) {
|
||||
std::cout << "Error: No se pudo escalar logo2 (nativa)" << std::endl;
|
||||
std::cout << "Error: No se pudo escalar logo2 (nativa)" << '\n';
|
||||
return false;
|
||||
}
|
||||
|
||||
logo2_native_texture_ = LogoScaler::createTextureFromBuffer(
|
||||
renderer, logo2_native_data, logo2_native_width_, logo2_native_height_
|
||||
);
|
||||
renderer,
|
||||
logo2_native_data,
|
||||
logo2_native_width_,
|
||||
logo2_native_height_);
|
||||
free(logo2_native_data);
|
||||
|
||||
if (logo2_native_texture_ == nullptr) {
|
||||
std::cout << "Error: No se pudo crear textura logo2 (nativa)" << std::endl;
|
||||
std::cout << "Error: No se pudo crear textura logo2 (nativa)" << '\n';
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -191,7 +210,7 @@ bool AppLogo::initialize(SDL_Renderer* renderer, int screen_width, int screen_he
|
||||
return true;
|
||||
}
|
||||
|
||||
void AppLogo::update(float delta_time, AppMode current_mode) {
|
||||
void AppLogo::update(float delta_time, AppMode current_mode) { // NOLINT(readability-function-cognitive-complexity)
|
||||
// Si estamos en SANDBOX, resetear y no hacer nada (logo desactivado)
|
||||
if (current_mode == AppMode::SANDBOX) {
|
||||
state_ = AppLogoState::HIDDEN;
|
||||
@@ -262,63 +281,57 @@ void AppLogo::update(float delta_time, AppMode current_mode) {
|
||||
logo2_rotation_ = 0.0f;
|
||||
break;
|
||||
|
||||
case AppLogoAnimationType::ELASTIC_STICK:
|
||||
{
|
||||
float prog1 = std::min(1.0f, fade_progress_logo1);
|
||||
float elastic_t1 = easeOutElastic(prog1);
|
||||
logo1_scale_ = 1.2f - (elastic_t1 * 0.2f);
|
||||
float squash_t1 = easeOutBack(prog1);
|
||||
logo1_squash_y_ = 0.6f + (squash_t1 * 0.4f);
|
||||
logo1_stretch_x_ = 1.0f + (1.0f - logo1_squash_y_) * 0.5f;
|
||||
logo1_rotation_ = 0.0f;
|
||||
case AppLogoAnimationType::ELASTIC_STICK: {
|
||||
float prog1 = std::min(1.0f, fade_progress_logo1);
|
||||
float elastic_t1 = easeOutElastic(prog1);
|
||||
logo1_scale_ = 1.2f - (elastic_t1 * 0.2f);
|
||||
float squash_t1 = easeOutBack(prog1);
|
||||
logo1_squash_y_ = 0.6f + (squash_t1 * 0.4f);
|
||||
logo1_stretch_x_ = 1.0f + (1.0f - logo1_squash_y_) * 0.5f;
|
||||
logo1_rotation_ = 0.0f;
|
||||
|
||||
float prog2 = std::min(1.0f, fade_progress_logo2);
|
||||
float elastic_t2 = easeOutElastic(prog2);
|
||||
logo2_scale_ = 1.2f - (elastic_t2 * 0.2f);
|
||||
float squash_t2 = easeOutBack(prog2);
|
||||
logo2_squash_y_ = 0.6f + (squash_t2 * 0.4f);
|
||||
logo2_stretch_x_ = 1.0f + (1.0f - logo2_squash_y_) * 0.5f;
|
||||
logo2_rotation_ = 0.0f;
|
||||
}
|
||||
break;
|
||||
float prog2 = std::min(1.0f, fade_progress_logo2);
|
||||
float elastic_t2 = easeOutElastic(prog2);
|
||||
logo2_scale_ = 1.2f - (elastic_t2 * 0.2f);
|
||||
float squash_t2 = easeOutBack(prog2);
|
||||
logo2_squash_y_ = 0.6f + (squash_t2 * 0.4f);
|
||||
logo2_stretch_x_ = 1.0f + (1.0f - logo2_squash_y_) * 0.5f;
|
||||
logo2_rotation_ = 0.0f;
|
||||
} break;
|
||||
|
||||
case AppLogoAnimationType::ROTATE_SPIRAL:
|
||||
{
|
||||
float prog1 = std::min(1.0f, fade_progress_logo1);
|
||||
float ease_t1 = easeInOutQuad(prog1);
|
||||
logo1_scale_ = 0.3f + (ease_t1 * 0.7f);
|
||||
logo1_rotation_ = (1.0f - prog1) * 6.28f;
|
||||
logo1_squash_y_ = 1.0f;
|
||||
logo1_stretch_x_ = 1.0f;
|
||||
case AppLogoAnimationType::ROTATE_SPIRAL: {
|
||||
float prog1 = std::min(1.0f, fade_progress_logo1);
|
||||
float ease_t1 = easeInOutQuad(prog1);
|
||||
logo1_scale_ = 0.3f + (ease_t1 * 0.7f);
|
||||
logo1_rotation_ = (1.0f - prog1) * 6.28f;
|
||||
logo1_squash_y_ = 1.0f;
|
||||
logo1_stretch_x_ = 1.0f;
|
||||
|
||||
float prog2 = std::min(1.0f, fade_progress_logo2);
|
||||
float ease_t2 = easeInOutQuad(prog2);
|
||||
logo2_scale_ = 0.3f + (ease_t2 * 0.7f);
|
||||
logo2_rotation_ = (1.0f - prog2) * 6.28f;
|
||||
logo2_squash_y_ = 1.0f;
|
||||
logo2_stretch_x_ = 1.0f;
|
||||
}
|
||||
break;
|
||||
float prog2 = std::min(1.0f, fade_progress_logo2);
|
||||
float ease_t2 = easeInOutQuad(prog2);
|
||||
logo2_scale_ = 0.3f + (ease_t2 * 0.7f);
|
||||
logo2_rotation_ = (1.0f - prog2) * 6.28f;
|
||||
logo2_squash_y_ = 1.0f;
|
||||
logo2_stretch_x_ = 1.0f;
|
||||
} break;
|
||||
|
||||
case AppLogoAnimationType::BOUNCE_SQUASH:
|
||||
{
|
||||
float prog1 = std::min(1.0f, fade_progress_logo1);
|
||||
float bounce_t1 = easeOutBounce(prog1);
|
||||
logo1_scale_ = 1.0f;
|
||||
float squash_amount1 = (1.0f - bounce_t1) * 0.3f;
|
||||
logo1_squash_y_ = 1.0f - squash_amount1;
|
||||
logo1_stretch_x_ = 1.0f + squash_amount1 * 0.5f;
|
||||
logo1_rotation_ = 0.0f;
|
||||
case AppLogoAnimationType::BOUNCE_SQUASH: {
|
||||
float prog1 = std::min(1.0f, fade_progress_logo1);
|
||||
float bounce_t1 = easeOutBounce(prog1);
|
||||
logo1_scale_ = 1.0f;
|
||||
float squash_amount1 = (1.0f - bounce_t1) * 0.3f;
|
||||
logo1_squash_y_ = 1.0f - squash_amount1;
|
||||
logo1_stretch_x_ = 1.0f + squash_amount1 * 0.5f;
|
||||
logo1_rotation_ = 0.0f;
|
||||
|
||||
float prog2 = std::min(1.0f, fade_progress_logo2);
|
||||
float bounce_t2 = easeOutBounce(prog2);
|
||||
logo2_scale_ = 1.0f;
|
||||
float squash_amount2 = (1.0f - bounce_t2) * 0.3f;
|
||||
logo2_squash_y_ = 1.0f - squash_amount2;
|
||||
logo2_stretch_x_ = 1.0f + squash_amount2 * 0.5f;
|
||||
logo2_rotation_ = 0.0f;
|
||||
}
|
||||
break;
|
||||
float prog2 = std::min(1.0f, fade_progress_logo2);
|
||||
float bounce_t2 = easeOutBounce(prog2);
|
||||
logo2_scale_ = 1.0f;
|
||||
float squash_amount2 = (1.0f - bounce_t2) * 0.3f;
|
||||
logo2_squash_y_ = 1.0f - squash_amount2;
|
||||
logo2_stretch_x_ = 1.0f + squash_amount2 * 0.5f;
|
||||
logo2_rotation_ = 0.0f;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -379,69 +392,63 @@ void AppLogo::update(float delta_time, AppMode current_mode) {
|
||||
logo2_rotation_ = 0.0f;
|
||||
break;
|
||||
|
||||
case AppLogoAnimationType::ELASTIC_STICK:
|
||||
{
|
||||
float prog1 = std::min(1.0f, fade_progress_logo1);
|
||||
logo1_scale_ = 1.0f + (prog1 * prog1 * 0.2f);
|
||||
logo1_squash_y_ = 1.0f + (prog1 * 0.3f);
|
||||
logo1_stretch_x_ = 1.0f - (prog1 * 0.2f);
|
||||
logo1_rotation_ = prog1 * 0.1f;
|
||||
case AppLogoAnimationType::ELASTIC_STICK: {
|
||||
float prog1 = std::min(1.0f, fade_progress_logo1);
|
||||
logo1_scale_ = 1.0f + (prog1 * prog1 * 0.2f);
|
||||
logo1_squash_y_ = 1.0f + (prog1 * 0.3f);
|
||||
logo1_stretch_x_ = 1.0f - (prog1 * 0.2f);
|
||||
logo1_rotation_ = prog1 * 0.1f;
|
||||
|
||||
float prog2 = std::min(1.0f, fade_progress_logo2);
|
||||
logo2_scale_ = 1.0f + (prog2 * prog2 * 0.2f);
|
||||
logo2_squash_y_ = 1.0f + (prog2 * 0.3f);
|
||||
logo2_stretch_x_ = 1.0f - (prog2 * 0.2f);
|
||||
logo2_rotation_ = prog2 * 0.1f;
|
||||
float prog2 = std::min(1.0f, fade_progress_logo2);
|
||||
logo2_scale_ = 1.0f + (prog2 * prog2 * 0.2f);
|
||||
logo2_squash_y_ = 1.0f + (prog2 * 0.3f);
|
||||
logo2_stretch_x_ = 1.0f - (prog2 * 0.2f);
|
||||
logo2_rotation_ = prog2 * 0.1f;
|
||||
} break;
|
||||
|
||||
case AppLogoAnimationType::ROTATE_SPIRAL: {
|
||||
float prog1 = std::min(1.0f, fade_progress_logo1);
|
||||
float ease_t1 = easeInOutQuad(prog1);
|
||||
logo1_scale_ = 1.0f - (ease_t1 * 0.7f);
|
||||
logo1_rotation_ = prog1 * 6.28f;
|
||||
logo1_squash_y_ = 1.0f;
|
||||
logo1_stretch_x_ = 1.0f;
|
||||
|
||||
float prog2 = std::min(1.0f, fade_progress_logo2);
|
||||
float ease_t2 = easeInOutQuad(prog2);
|
||||
logo2_scale_ = 1.0f - (ease_t2 * 0.7f);
|
||||
logo2_rotation_ = prog2 * 6.28f;
|
||||
logo2_squash_y_ = 1.0f;
|
||||
logo2_stretch_x_ = 1.0f;
|
||||
} break;
|
||||
|
||||
case AppLogoAnimationType::BOUNCE_SQUASH: {
|
||||
float prog1 = std::min(1.0f, fade_progress_logo1);
|
||||
if (prog1 < 0.2f) {
|
||||
float squash_t = prog1 / 0.2f;
|
||||
logo1_squash_y_ = 1.0f - (squash_t * 0.3f);
|
||||
logo1_stretch_x_ = 1.0f + (squash_t * 0.2f);
|
||||
} else {
|
||||
float jump_t = (prog1 - 0.2f) / 0.8f;
|
||||
logo1_squash_y_ = 0.7f + (jump_t * 0.5f);
|
||||
logo1_stretch_x_ = 1.2f - (jump_t * 0.2f);
|
||||
}
|
||||
break;
|
||||
logo1_scale_ = 1.0f + (prog1 * 0.3f);
|
||||
logo1_rotation_ = 0.0f;
|
||||
|
||||
case AppLogoAnimationType::ROTATE_SPIRAL:
|
||||
{
|
||||
float prog1 = std::min(1.0f, fade_progress_logo1);
|
||||
float ease_t1 = easeInOutQuad(prog1);
|
||||
logo1_scale_ = 1.0f - (ease_t1 * 0.7f);
|
||||
logo1_rotation_ = prog1 * 6.28f;
|
||||
logo1_squash_y_ = 1.0f;
|
||||
logo1_stretch_x_ = 1.0f;
|
||||
|
||||
float prog2 = std::min(1.0f, fade_progress_logo2);
|
||||
float ease_t2 = easeInOutQuad(prog2);
|
||||
logo2_scale_ = 1.0f - (ease_t2 * 0.7f);
|
||||
logo2_rotation_ = prog2 * 6.28f;
|
||||
logo2_squash_y_ = 1.0f;
|
||||
logo2_stretch_x_ = 1.0f;
|
||||
float prog2 = std::min(1.0f, fade_progress_logo2);
|
||||
if (prog2 < 0.2f) {
|
||||
float squash_t = prog2 / 0.2f;
|
||||
logo2_squash_y_ = 1.0f - (squash_t * 0.3f);
|
||||
logo2_stretch_x_ = 1.0f + (squash_t * 0.2f);
|
||||
} else {
|
||||
float jump_t = (prog2 - 0.2f) / 0.8f;
|
||||
logo2_squash_y_ = 0.7f + (jump_t * 0.5f);
|
||||
logo2_stretch_x_ = 1.2f - (jump_t * 0.2f);
|
||||
}
|
||||
break;
|
||||
|
||||
case AppLogoAnimationType::BOUNCE_SQUASH:
|
||||
{
|
||||
float prog1 = std::min(1.0f, fade_progress_logo1);
|
||||
if (prog1 < 0.2f) {
|
||||
float squash_t = prog1 / 0.2f;
|
||||
logo1_squash_y_ = 1.0f - (squash_t * 0.3f);
|
||||
logo1_stretch_x_ = 1.0f + (squash_t * 0.2f);
|
||||
} else {
|
||||
float jump_t = (prog1 - 0.2f) / 0.8f;
|
||||
logo1_squash_y_ = 0.7f + (jump_t * 0.5f);
|
||||
logo1_stretch_x_ = 1.2f - (jump_t * 0.2f);
|
||||
}
|
||||
logo1_scale_ = 1.0f + (prog1 * 0.3f);
|
||||
logo1_rotation_ = 0.0f;
|
||||
|
||||
float prog2 = std::min(1.0f, fade_progress_logo2);
|
||||
if (prog2 < 0.2f) {
|
||||
float squash_t = prog2 / 0.2f;
|
||||
logo2_squash_y_ = 1.0f - (squash_t * 0.3f);
|
||||
logo2_stretch_x_ = 1.0f + (squash_t * 0.2f);
|
||||
} else {
|
||||
float jump_t = (prog2 - 0.2f) / 0.8f;
|
||||
logo2_squash_y_ = 0.7f + (jump_t * 0.5f);
|
||||
logo2_stretch_x_ = 1.2f - (jump_t * 0.2f);
|
||||
}
|
||||
logo2_scale_ = 1.0f + (prog2 * 0.3f);
|
||||
logo2_rotation_ = 0.0f;
|
||||
}
|
||||
break;
|
||||
logo2_scale_ = 1.0f + (prog2 * 0.3f);
|
||||
logo2_rotation_ = 0.0f;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -477,7 +484,7 @@ void AppLogo::updateScreenSize(int screen_width, int screen_height) {
|
||||
logo2_current_width_ = logo2_native_width_;
|
||||
logo2_current_height_ = logo2_native_height_;
|
||||
|
||||
std::cout << "AppLogo: Cambiado a texturas NATIVAS" << std::endl;
|
||||
std::cout << "AppLogo: Cambiado a texturas NATIVAS" << '\n';
|
||||
} else {
|
||||
// Cambiar a texturas base (ventana redimensionable)
|
||||
logo1_current_texture_ = logo1_base_texture_;
|
||||
@@ -488,7 +495,7 @@ void AppLogo::updateScreenSize(int screen_width, int screen_height) {
|
||||
logo2_current_width_ = logo2_base_width_;
|
||||
logo2_current_height_ = logo2_base_height_;
|
||||
|
||||
std::cout << "AppLogo: Cambiado a texturas BASE" << std::endl;
|
||||
std::cout << "AppLogo: Cambiado a texturas BASE" << '\n';
|
||||
}
|
||||
|
||||
// Nota: No es necesario recalcular escalas porque las texturas están pre-escaladas
|
||||
@@ -499,57 +506,61 @@ void AppLogo::updateScreenSize(int screen_width, int screen_height) {
|
||||
// Funciones de easing para animaciones
|
||||
// ============================================================================
|
||||
|
||||
float AppLogo::easeOutElastic(float t) {
|
||||
auto AppLogo::easeOutElastic(float t) -> float {
|
||||
// Elastic easing out: bounce elástico al final
|
||||
const float c4 = (2.0f * 3.14159f) / 3.0f;
|
||||
const float C4 = (2.0f * std::numbers::pi_v<float>) / 3.0f;
|
||||
|
||||
if (t == 0.0f) return 0.0f;
|
||||
if (t == 1.0f) return 1.0f;
|
||||
|
||||
return powf(2.0f, -10.0f * t) * sinf((t * 10.0f - 0.75f) * c4) + 1.0f;
|
||||
}
|
||||
|
||||
float AppLogo::easeOutBack(float t) {
|
||||
// Back easing out: overshoot suave al final
|
||||
const float c1 = 1.70158f;
|
||||
const float c3 = c1 + 1.0f;
|
||||
|
||||
return 1.0f + c3 * powf(t - 1.0f, 3.0f) + c1 * powf(t - 1.0f, 2.0f);
|
||||
}
|
||||
|
||||
float AppLogo::easeOutBounce(float t) {
|
||||
// Bounce easing out: rebotes decrecientes (para BOUNCE_SQUASH)
|
||||
const float n1 = 7.5625f;
|
||||
const float d1 = 2.75f;
|
||||
|
||||
if (t < 1.0f / d1) {
|
||||
return n1 * t * t;
|
||||
} else if (t < 2.0f / d1) {
|
||||
t -= 1.5f / d1;
|
||||
return n1 * t * t + 0.75f;
|
||||
} else if (t < 2.5f / d1) {
|
||||
t -= 2.25f / d1;
|
||||
return n1 * t * t + 0.9375f;
|
||||
} else {
|
||||
t -= 2.625f / d1;
|
||||
return n1 * t * t + 0.984375f;
|
||||
if (t == 0.0f) {
|
||||
return 0.0f;
|
||||
}
|
||||
if (t == 1.0f) {
|
||||
return 1.0f;
|
||||
}
|
||||
|
||||
return (powf(2.0f, -10.0f * t) * sinf((t * 10.0f - 0.75f) * C4)) + 1.0f;
|
||||
}
|
||||
|
||||
float AppLogo::easeInOutQuad(float t) {
|
||||
auto AppLogo::easeOutBack(float t) -> float {
|
||||
// Back easing out: overshoot suave al final
|
||||
const float C1 = 1.70158f;
|
||||
const float C3 = C1 + 1.0f;
|
||||
|
||||
return 1.0f + (C3 * powf(t - 1.0f, 3.0f)) + (C1 * powf(t - 1.0f, 2.0f));
|
||||
}
|
||||
|
||||
auto AppLogo::easeOutBounce(float t) -> float {
|
||||
// Bounce easing out: rebotes decrecientes (para BOUNCE_SQUASH)
|
||||
const float N1 = 7.5625f;
|
||||
const float D1 = 2.75f;
|
||||
|
||||
if (t < 1.0f / D1) {
|
||||
return N1 * t * t;
|
||||
}
|
||||
if (t < 2.0f / D1) {
|
||||
t -= 1.5f / D1;
|
||||
return (N1 * t * t) + 0.75f;
|
||||
}
|
||||
if (t < 2.5f / D1) {
|
||||
t -= 2.25f / D1;
|
||||
return (N1 * t * t) + 0.9375f;
|
||||
}
|
||||
t -= 2.625f / D1;
|
||||
return (N1 * t * t) + 0.984375f;
|
||||
}
|
||||
|
||||
auto AppLogo::easeInOutQuad(float t) -> float {
|
||||
// Quadratic easing in/out: aceleración suave (para ROTATE_SPIRAL)
|
||||
if (t < 0.5f) {
|
||||
return 2.0f * t * t;
|
||||
} else {
|
||||
return 1.0f - powf(-2.0f * t + 2.0f, 2.0f) / 2.0f;
|
||||
}
|
||||
return 1.0f - (powf((-2.0f * t) + 2.0f, 2.0f) / 2.0f);
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Función auxiliar para aleatorización
|
||||
// ============================================================================
|
||||
|
||||
AppLogoAnimationType AppLogo::getRandomAnimation() {
|
||||
auto AppLogo::getRandomAnimation() -> AppLogoAnimationType {
|
||||
// Generar número aleatorio entre 0 y 3 (4 tipos de animación)
|
||||
int random_value = rand() % 4;
|
||||
|
||||
@@ -571,15 +582,23 @@ AppLogoAnimationType AppLogo::getRandomAnimation() {
|
||||
// ============================================================================
|
||||
|
||||
void AppLogo::renderWithGeometry(int logo_index) {
|
||||
if (!renderer_) return;
|
||||
if (renderer_ == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Seleccionar variables según el logo_index (1 = logo1, 2 = logo2)
|
||||
SDL_Texture* texture;
|
||||
int base_width, base_height;
|
||||
float scale, squash_y, stretch_x, rotation;
|
||||
int base_width;
|
||||
int base_height;
|
||||
float scale;
|
||||
float squash_y;
|
||||
float stretch_x;
|
||||
float rotation;
|
||||
|
||||
if (logo_index == 1) {
|
||||
if (!logo1_current_texture_) return;
|
||||
if (logo1_current_texture_ == nullptr) {
|
||||
return;
|
||||
}
|
||||
texture = logo1_current_texture_;
|
||||
base_width = logo1_current_width_;
|
||||
base_height = logo1_current_height_;
|
||||
@@ -588,7 +607,9 @@ void AppLogo::renderWithGeometry(int logo_index) {
|
||||
stretch_x = logo1_stretch_x_;
|
||||
rotation = logo1_rotation_;
|
||||
} else if (logo_index == 2) {
|
||||
if (!logo2_current_texture_) return;
|
||||
if (logo2_current_texture_ == nullptr) {
|
||||
return;
|
||||
}
|
||||
texture = logo2_current_texture_;
|
||||
base_width = logo2_current_width_;
|
||||
base_height = logo2_current_height_;
|
||||
@@ -628,7 +649,7 @@ void AppLogo::renderWithGeometry(int logo_index) {
|
||||
float sin_rot = sinf(rotation);
|
||||
|
||||
// Crear 4 vértices del quad (centrado en center_x, center_y)
|
||||
SDL_Vertex vertices[4];
|
||||
std::array<SDL_Vertex, 4> vertices{};
|
||||
|
||||
// Offset desde el centro
|
||||
float half_w = width / 2.0f;
|
||||
@@ -638,49 +659,49 @@ void AppLogo::renderWithGeometry(int logo_index) {
|
||||
{
|
||||
float local_x = -half_w;
|
||||
float local_y = -half_h;
|
||||
float rotated_x = local_x * cos_rot - local_y * sin_rot;
|
||||
float rotated_y = local_x * sin_rot + local_y * cos_rot;
|
||||
vertices[0].position = {center_x + rotated_x, center_y + rotated_y};
|
||||
vertices[0].tex_coord = {0.0f, 0.0f};
|
||||
vertices[0].color = {1.0f, 1.0f, 1.0f, alpha_normalized}; // Alpha aplicado al vértice
|
||||
float rotated_x = (local_x * cos_rot) - (local_y * sin_rot);
|
||||
float rotated_y = (local_x * sin_rot) + (local_y * cos_rot);
|
||||
vertices[0].position = {.x = center_x + rotated_x, .y = center_y + rotated_y};
|
||||
vertices[0].tex_coord = {.x = 0.0f, .y = 0.0f};
|
||||
vertices[0].color = {.r = 1.0f, .g = 1.0f, .b = 1.0f, .a = alpha_normalized}; // Alpha aplicado al vértice
|
||||
}
|
||||
|
||||
// Vértice superior derecho (rotado)
|
||||
{
|
||||
float local_x = half_w;
|
||||
float local_y = -half_h;
|
||||
float rotated_x = local_x * cos_rot - local_y * sin_rot;
|
||||
float rotated_y = local_x * sin_rot + local_y * cos_rot;
|
||||
vertices[1].position = {center_x + rotated_x, center_y + rotated_y};
|
||||
vertices[1].tex_coord = {1.0f, 0.0f};
|
||||
vertices[1].color = {1.0f, 1.0f, 1.0f, alpha_normalized}; // Alpha aplicado al vértice
|
||||
float rotated_x = (local_x * cos_rot) - (local_y * sin_rot);
|
||||
float rotated_y = (local_x * sin_rot) + (local_y * cos_rot);
|
||||
vertices[1].position = {.x = center_x + rotated_x, .y = center_y + rotated_y};
|
||||
vertices[1].tex_coord = {.x = 1.0f, .y = 0.0f};
|
||||
vertices[1].color = {.r = 1.0f, .g = 1.0f, .b = 1.0f, .a = alpha_normalized}; // Alpha aplicado al vértice
|
||||
}
|
||||
|
||||
// Vértice inferior derecho (rotado)
|
||||
{
|
||||
float local_x = half_w;
|
||||
float local_y = half_h;
|
||||
float rotated_x = local_x * cos_rot - local_y * sin_rot;
|
||||
float rotated_y = local_x * sin_rot + local_y * cos_rot;
|
||||
vertices[2].position = {center_x + rotated_x, center_y + rotated_y};
|
||||
vertices[2].tex_coord = {1.0f, 1.0f};
|
||||
vertices[2].color = {1.0f, 1.0f, 1.0f, alpha_normalized}; // Alpha aplicado al vértice
|
||||
float rotated_x = (local_x * cos_rot) - (local_y * sin_rot);
|
||||
float rotated_y = (local_x * sin_rot) + (local_y * cos_rot);
|
||||
vertices[2].position = {.x = center_x + rotated_x, .y = center_y + rotated_y};
|
||||
vertices[2].tex_coord = {.x = 1.0f, .y = 1.0f};
|
||||
vertices[2].color = {.r = 1.0f, .g = 1.0f, .b = 1.0f, .a = alpha_normalized}; // Alpha aplicado al vértice
|
||||
}
|
||||
|
||||
// Vértice inferior izquierdo (rotado)
|
||||
{
|
||||
float local_x = -half_w;
|
||||
float local_y = half_h;
|
||||
float rotated_x = local_x * cos_rot - local_y * sin_rot;
|
||||
float rotated_y = local_x * sin_rot + local_y * cos_rot;
|
||||
vertices[3].position = {center_x + rotated_x, center_y + rotated_y};
|
||||
vertices[3].tex_coord = {0.0f, 1.0f};
|
||||
vertices[3].color = {1.0f, 1.0f, 1.0f, alpha_normalized}; // Alpha aplicado al vértice
|
||||
float rotated_x = (local_x * cos_rot) - (local_y * sin_rot);
|
||||
float rotated_y = (local_x * sin_rot) + (local_y * cos_rot);
|
||||
vertices[3].position = {.x = center_x + rotated_x, .y = center_y + rotated_y};
|
||||
vertices[3].tex_coord = {.x = 0.0f, .y = 1.0f};
|
||||
vertices[3].color = {.r = 1.0f, .g = 1.0f, .b = 1.0f, .a = alpha_normalized}; // Alpha aplicado al vértice
|
||||
}
|
||||
|
||||
// Índices para 2 triángulos
|
||||
int indices[6] = {0, 1, 2, 2, 3, 0};
|
||||
std::array<int, 6> indices = {0, 1, 2, 2, 3, 0};
|
||||
|
||||
// Renderizar con la textura del logo correspondiente
|
||||
SDL_RenderGeometry(renderer_, texture, vertices, 4, indices, 6);
|
||||
SDL_RenderGeometry(renderer_, texture, vertices.data(), 4, indices.data(), 6);
|
||||
}
|
||||
|
||||
@@ -11,18 +11,18 @@ class Sprite;
|
||||
|
||||
// Estados de la máquina de estados del logo
|
||||
enum class AppLogoState {
|
||||
HIDDEN, // Logo oculto, esperando APPLOGO_DISPLAY_INTERVAL
|
||||
FADE_IN, // Apareciendo (alpha 0 → 255)
|
||||
VISIBLE, // Completamente visible, esperando APPLOGO_DISPLAY_DURATION
|
||||
FADE_OUT // Desapareciendo (alpha 255 → 0)
|
||||
HIDDEN, // Logo oculto, esperando APPLOGO_DISPLAY_INTERVAL
|
||||
FADE_IN, // Apareciendo (alpha 0 → 255)
|
||||
VISIBLE, // Completamente visible, esperando APPLOGO_DISPLAY_DURATION
|
||||
FADE_OUT // Desapareciendo (alpha 255 → 0)
|
||||
};
|
||||
|
||||
// Tipo de animación de entrada/salida
|
||||
enum class AppLogoAnimationType {
|
||||
ZOOM_ONLY, // A: Solo zoom simple (120% → 100% → 120%)
|
||||
ELASTIC_STICK, // B: Zoom + deformación elástica tipo "pegatina"
|
||||
ROTATE_SPIRAL, // C: Rotación en espiral (entra girando, sale girando)
|
||||
BOUNCE_SQUASH // D: Rebote con aplastamiento (cae rebotando, salta)
|
||||
ZOOM_ONLY, // A: Solo zoom simple (120% → 100% → 120%)
|
||||
ELASTIC_STICK, // B: Zoom + deformación elástica tipo "pegatina"
|
||||
ROTATE_SPIRAL, // C: Rotación en espiral (entra girando, sale girando)
|
||||
BOUNCE_SQUASH // D: Rebote con aplastamiento (cae rebotando, salta)
|
||||
};
|
||||
|
||||
class AppLogo {
|
||||
@@ -46,10 +46,10 @@ class AppLogo {
|
||||
// ====================================================================
|
||||
// Texturas pre-escaladas (4 texturas: 2 logos × 2 resoluciones)
|
||||
// ====================================================================
|
||||
SDL_Texture* logo1_base_texture_ = nullptr; // Logo1 para resolución base
|
||||
SDL_Texture* logo1_native_texture_ = nullptr; // Logo1 para resolución nativa (F4)
|
||||
SDL_Texture* logo2_base_texture_ = nullptr; // Logo2 para resolución base
|
||||
SDL_Texture* logo2_native_texture_ = nullptr; // Logo2 para resolución nativa (F4)
|
||||
SDL_Texture* logo1_base_texture_ = nullptr; // Logo1 para resolución base
|
||||
SDL_Texture* logo1_native_texture_ = nullptr; // Logo1 para resolución nativa (F4)
|
||||
SDL_Texture* logo2_base_texture_ = nullptr; // Logo2 para resolución base
|
||||
SDL_Texture* logo2_native_texture_ = nullptr; // Logo2 para resolución nativa (F4)
|
||||
|
||||
// Dimensiones pre-calculadas para cada textura
|
||||
int logo1_base_width_ = 0, logo1_base_height_ = 0;
|
||||
@@ -64,8 +64,8 @@ class AppLogo {
|
||||
int logo2_current_width_ = 0, logo2_current_height_ = 0;
|
||||
|
||||
// Resoluciones conocidas
|
||||
int base_screen_width_ = 0, base_screen_height_ = 0; // Resolución inicial
|
||||
int native_screen_width_ = 0, native_screen_height_ = 0; // Resolución nativa (F4)
|
||||
int base_screen_width_ = 0, base_screen_height_ = 0; // Resolución inicial
|
||||
int native_screen_width_ = 0, native_screen_height_ = 0; // Resolución nativa (F4)
|
||||
|
||||
// ====================================================================
|
||||
// Variables COMPARTIDAS (sincronización de ambos logos)
|
||||
@@ -74,8 +74,8 @@ class AppLogo {
|
||||
float timer_ = 0.0f; // Contador de tiempo para estado actual
|
||||
|
||||
// Alpha INDEPENDIENTE para cada logo (Logo 2 con retraso)
|
||||
int logo1_alpha_ = 0; // Alpha de Logo 1 (0-255)
|
||||
int logo2_alpha_ = 0; // Alpha de Logo 2 (0-255, con retraso)
|
||||
int logo1_alpha_ = 0; // Alpha de Logo 1 (0-255)
|
||||
int logo2_alpha_ = 0; // Alpha de Logo 2 (0-255, con retraso)
|
||||
|
||||
// Animación COMPARTIDA (misma para ambos logos, misma entrada y salida)
|
||||
AppLogoAnimationType current_animation_ = AppLogoAnimationType::ZOOM_ONLY;
|
||||
@@ -103,15 +103,15 @@ class AppLogo {
|
||||
SDL_Renderer* renderer_ = nullptr;
|
||||
|
||||
// Métodos privados auxiliares
|
||||
void updateLogoPosition(); // Centrar ambos logos en pantalla (superpuestos)
|
||||
void updateLogoPosition(); // Centrar ambos logos en pantalla (superpuestos)
|
||||
void renderWithGeometry(int logo_index); // Renderizar logo con vértices deformados (1 o 2)
|
||||
|
||||
// Funciones de easing
|
||||
float easeOutElastic(float t); // Elastic bounce out
|
||||
float easeOutBack(float t); // Overshoot out
|
||||
float easeOutBounce(float t); // Bounce easing (para BOUNCE_SQUASH)
|
||||
float easeInOutQuad(float t); // Quadratic easing (para ROTATE_SPIRAL)
|
||||
static float easeOutElastic(float t); // Elastic bounce out
|
||||
static float easeOutBack(float t); // Overshoot out
|
||||
static float easeOutBounce(float t); // Bounce easing (para BOUNCE_SQUASH)
|
||||
static float easeInOutQuad(float t); // Quadratic easing (para ROTATE_SPIRAL)
|
||||
|
||||
// Función auxiliar para elegir animación aleatoria
|
||||
AppLogoAnimationType getRandomAnimation();
|
||||
static AppLogoAnimationType getRandomAnimation();
|
||||
};
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include "help_overlay.hpp"
|
||||
|
||||
#include <algorithm> // for std::min
|
||||
#include <array> // for std::array
|
||||
|
||||
#include "defines.hpp"
|
||||
#include "text/textrenderer.hpp"
|
||||
@@ -21,69 +22,69 @@ HelpOverlay::HelpOverlay()
|
||||
column2_width_(0),
|
||||
column3_width_(0),
|
||||
cached_texture_(nullptr),
|
||||
last_category_color_({0, 0, 0, 255}),
|
||||
last_content_color_({0, 0, 0, 255}),
|
||||
last_bg_color_({0, 0, 0, 255}),
|
||||
last_category_color_({.r = 0, .g = 0, .b = 0, .a = 255}),
|
||||
last_content_color_({.r = 0, .g = 0, .b = 0, .a = 255}),
|
||||
last_bg_color_({.r = 0, .g = 0, .b = 0, .a = 255}),
|
||||
texture_needs_rebuild_(true) {
|
||||
// Llenar lista de controles (organizados por categoría, equilibrado en 3 columnas)
|
||||
key_bindings_ = {
|
||||
// COLUMNA 1: SIMULACIÓN
|
||||
{"SIMULACIÓN", ""},
|
||||
{"1-8", "Escenarios (10 a 50.000 pelotas)"},
|
||||
{"F", "Cambia entre figura y física"},
|
||||
{"B", "Cambia entre boids y física"},
|
||||
{"ESPACIO", "Impulso contra la gravedad"},
|
||||
{"G", "Activar / Desactivar gravedad"},
|
||||
{"CURSORES", "Dirección de la gravedad"},
|
||||
{"", ""}, // Separador
|
||||
{.key = "SIMULACIÓN", .description = ""},
|
||||
{.key = "1-8", .description = "Escenarios (10 a 50.000 pelotas)"},
|
||||
{.key = "F", .description = "Cambia entre figura y física"},
|
||||
{.key = "B", .description = "Cambia entre boids y física"},
|
||||
{.key = "ESPACIO", .description = "Impulso contra la gravedad"},
|
||||
{.key = "G", .description = "Activar / Desactivar gravedad"},
|
||||
{.key = "CURSORES", .description = "Dirección de la gravedad"},
|
||||
{.key = "", .description = ""}, // Separador
|
||||
|
||||
// COLUMNA 1: FIGURAS 3D
|
||||
{"FIGURAS 3D", ""},
|
||||
{"Q/W/E/R", "Esfera / Lissajous / Hélice / Toroide"},
|
||||
{"T/Y/U/I", "Cubo / Cilindro / Icosaedro / Átomo"},
|
||||
{"Num+/-", "Escalar figura"},
|
||||
{"Num*", "Reset escala"},
|
||||
{"Num/", "Activar / Desactivar profundidad"},
|
||||
{"[new_col]", ""}, // CAMBIO DE COLUMNA -> COLUMNA 2
|
||||
{.key = "FIGURAS 3D", .description = ""},
|
||||
{.key = "Q/W/E/R", .description = "Esfera / Lissajous / Hélice / Toroide"},
|
||||
{.key = "T/Y/U/I", .description = "Cubo / Cilindro / Icosaedro / Átomo"},
|
||||
{.key = "Num+/-", .description = "Escalar figura"},
|
||||
{.key = "Num*", .description = "Reset escala"},
|
||||
{.key = "Num/", .description = "Activar / Desactivar profundidad"},
|
||||
{.key = "[new_col]", .description = ""}, // CAMBIO DE COLUMNA -> COLUMNA 2
|
||||
|
||||
// COLUMNA 2: MODOS
|
||||
{"MODOS", ""},
|
||||
{"D", "Activar / Desactivar modo demo"},
|
||||
{"L", "Activar / Desactivar modo demo lite"},
|
||||
{"K", "Activar / Desactivar modo logo"},
|
||||
{"", ""}, // Separador
|
||||
{.key = "MODOS", .description = ""},
|
||||
{.key = "D", .description = "Activar / Desactivar modo demo"},
|
||||
{.key = "L", .description = "Activar / Desactivar modo demo lite"},
|
||||
{.key = "K", .description = "Activar / Desactivar modo logo"},
|
||||
{.key = "", .description = ""}, // Separador
|
||||
|
||||
// COLUMNA 2: VISUAL
|
||||
{"VISUAL", ""},
|
||||
{"C", "Tema siguiente"},
|
||||
{"Shift+C", "Tema anterior"},
|
||||
{"NumEnter", "Página de temas"},
|
||||
{"Shift+D", "Pausar tema dinámico"},
|
||||
{"N", "Cambiar tamaño de pelota"},
|
||||
{"X", "Ciclar presets PostFX"},
|
||||
{"[new_col]", ""}, // CAMBIO DE COLUMNA -> COLUMNA 3
|
||||
|
||||
{.key = "VISUAL", .description = ""},
|
||||
{.key = "C", .description = "Tema siguiente"},
|
||||
{.key = "Shift+C", .description = "Tema anterior"},
|
||||
{.key = "NumEnter", .description = "Página de temas"},
|
||||
{.key = "Shift+D", .description = "Pausar tema dinámico"},
|
||||
{.key = "N", .description = "Cambiar tamaño de pelota"},
|
||||
{.key = "X", .description = "Ciclar presets PostFX"},
|
||||
{.key = "[new_col]", .description = ""}, // CAMBIO DE COLUMNA -> COLUMNA 3
|
||||
|
||||
// COLUMNA 3: PANTALLA
|
||||
{"PANTALLA", ""},
|
||||
{"F1", "Disminuye ventana"},
|
||||
{"F2", "Aumenta ventana"},
|
||||
{"F3", "Pantalla completa"},
|
||||
{"F4", "Pantalla completa real"},
|
||||
{"F5", "Activar / Desactivar PostFX"},
|
||||
{"F6", "Cambia el escalado de pantalla"},
|
||||
{"V", "Activar / Desactivar V-Sync"},
|
||||
{"", ""}, // Separador
|
||||
{.key = "PANTALLA", .description = ""},
|
||||
{.key = "F1", .description = "Disminuye ventana"},
|
||||
{.key = "F2", .description = "Aumenta ventana"},
|
||||
{.key = "F3", .description = "Pantalla completa"},
|
||||
{.key = "F4", .description = "Pantalla completa real"},
|
||||
{.key = "F5", .description = "Activar / Desactivar PostFX"},
|
||||
{.key = "F6", .description = "Cambia el escalado de pantalla"},
|
||||
{.key = "V", .description = "Activar / Desactivar V-Sync"},
|
||||
{.key = "", .description = ""}, // Separador
|
||||
|
||||
// COLUMNA 3: DEBUG/AYUDA
|
||||
{"DEBUG / AYUDA", ""},
|
||||
{"F12", "Activar / Desactivar info debug"},
|
||||
{"H", "Esta ayuda"},
|
||||
{"ESC", "Salir"}};
|
||||
{.key = "DEBUG / AYUDA", .description = ""},
|
||||
{.key = "F12", .description = "Activar / Desactivar info debug"},
|
||||
{.key = "H", .description = "Esta ayuda"},
|
||||
{.key = "ESC", .description = "Salir"}};
|
||||
}
|
||||
|
||||
HelpOverlay::~HelpOverlay() {
|
||||
// Destruir textura cacheada si existe
|
||||
if (cached_texture_) {
|
||||
if (cached_texture_ != nullptr) {
|
||||
SDL_DestroyTexture(cached_texture_);
|
||||
cached_texture_ = nullptr;
|
||||
}
|
||||
@@ -117,7 +118,9 @@ void HelpOverlay::updatePhysicalWindowSize(int physical_width, int physical_heig
|
||||
}
|
||||
|
||||
void HelpOverlay::reinitializeFontSize(int new_font_size) {
|
||||
if (!text_renderer_) return;
|
||||
if (text_renderer_ == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Reinicializar text renderer con nuevo tamaño
|
||||
text_renderer_->reinitialize(new_font_size);
|
||||
@@ -136,7 +139,7 @@ void HelpOverlay::updateAll(int font_size, int physical_width, int physical_heig
|
||||
physical_height_ = physical_height;
|
||||
|
||||
// Reinicializar text renderer con nuevo tamaño (si cambió)
|
||||
if (text_renderer_) {
|
||||
if (text_renderer_ != nullptr) {
|
||||
text_renderer_->reinitialize(font_size);
|
||||
}
|
||||
|
||||
@@ -148,7 +151,7 @@ void HelpOverlay::updateAll(int font_size, int physical_width, int physical_heig
|
||||
}
|
||||
|
||||
void HelpOverlay::calculateTextDimensions(int& max_width, int& total_height) {
|
||||
if (!text_renderer_) {
|
||||
if (text_renderer_ == nullptr) {
|
||||
max_width = 0;
|
||||
total_height = 0;
|
||||
return;
|
||||
@@ -210,7 +213,7 @@ void HelpOverlay::calculateTextDimensions(int& max_width, int& total_height) {
|
||||
max_width = max_col1_width + max_col2_width + max_col3_width + padding * 2 + col_gap * 2;
|
||||
|
||||
// Calcular altura real simulando exactamente lo que hace el render
|
||||
int col_heights[3] = {0, 0, 0};
|
||||
std::array<int, 3> col_heights = {0, 0, 0};
|
||||
current_column = 0;
|
||||
|
||||
for (const auto& binding : key_bindings_) {
|
||||
@@ -220,11 +223,11 @@ void HelpOverlay::calculateTextDimensions(int& max_width, int& total_height) {
|
||||
}
|
||||
|
||||
if (binding.key[0] == '\0') {
|
||||
col_heights[current_column] += line_height; // separador vacío
|
||||
col_heights[current_column] += line_height; // separador vacío
|
||||
} else if (binding.description[0] == '\0') {
|
||||
col_heights[current_column] += line_height; // encabezado
|
||||
col_heights[current_column] += line_height; // encabezado
|
||||
} else {
|
||||
col_heights[current_column] += line_height; // línea normal
|
||||
col_heights[current_column] += line_height; // línea normal
|
||||
}
|
||||
}
|
||||
|
||||
@@ -240,7 +243,8 @@ void HelpOverlay::calculateTextDimensions(int& max_width, int& total_height) {
|
||||
|
||||
void HelpOverlay::calculateBoxDimensions() {
|
||||
// Calcular dimensiones necesarias según el texto
|
||||
int text_width, text_height;
|
||||
int text_width;
|
||||
int text_height;
|
||||
calculateTextDimensions(text_width, text_height);
|
||||
|
||||
// Aplicar límites máximos: 95% ancho, 90% altura
|
||||
@@ -253,26 +257,27 @@ void HelpOverlay::calculateBoxDimensions() {
|
||||
// Centrar en pantalla
|
||||
box_x_ = (physical_width_ - box_width_) / 2;
|
||||
box_y_ = (physical_height_ - box_height_) / 2;
|
||||
|
||||
}
|
||||
|
||||
void HelpOverlay::rebuildCachedTexture() {
|
||||
if (!renderer_ || !theme_mgr_ || !text_renderer_) return;
|
||||
if ((renderer_ == nullptr) || (theme_mgr_ == nullptr) || (text_renderer_ == nullptr)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Destruir textura anterior si existe
|
||||
if (cached_texture_) {
|
||||
if (cached_texture_ != nullptr) {
|
||||
SDL_DestroyTexture(cached_texture_);
|
||||
cached_texture_ = nullptr;
|
||||
}
|
||||
|
||||
// Crear nueva textura del tamaño del overlay
|
||||
cached_texture_ = SDL_CreateTexture(renderer_,
|
||||
SDL_PIXELFORMAT_RGBA8888,
|
||||
SDL_TEXTUREACCESS_TARGET,
|
||||
box_width_,
|
||||
box_height_);
|
||||
SDL_PIXELFORMAT_RGBA8888,
|
||||
SDL_TEXTUREACCESS_TARGET,
|
||||
box_width_,
|
||||
box_height_);
|
||||
|
||||
if (!cached_texture_) {
|
||||
if (cached_texture_ == nullptr) {
|
||||
SDL_Log("Error al crear textura cacheada: %s", SDL_GetError());
|
||||
return;
|
||||
}
|
||||
@@ -294,42 +299,46 @@ void HelpOverlay::rebuildCachedTexture() {
|
||||
SDL_SetRenderDrawBlendMode(renderer_, SDL_BLENDMODE_BLEND);
|
||||
|
||||
// Obtener colores actuales del tema
|
||||
int notif_bg_r, notif_bg_g, notif_bg_b;
|
||||
int notif_bg_r;
|
||||
int notif_bg_g;
|
||||
int notif_bg_b;
|
||||
theme_mgr_->getCurrentNotificationBackgroundColor(notif_bg_r, notif_bg_g, notif_bg_b);
|
||||
|
||||
// Renderizar fondo del overlay a la textura
|
||||
float alpha = 0.85f;
|
||||
SDL_Vertex bg_vertices[4];
|
||||
std::array<SDL_Vertex, 4> bg_vertices{};
|
||||
|
||||
float r = notif_bg_r / 255.0f;
|
||||
float g = notif_bg_g / 255.0f;
|
||||
float b = notif_bg_b / 255.0f;
|
||||
|
||||
// Vértices del fondo (posición relativa 0,0 porque estamos renderizando a textura)
|
||||
bg_vertices[0].position = {0, 0};
|
||||
bg_vertices[0].tex_coord = {0.0f, 0.0f};
|
||||
bg_vertices[0].color = {r, g, b, alpha};
|
||||
bg_vertices[0].position = {.x = 0, .y = 0};
|
||||
bg_vertices[0].tex_coord = {.x = 0.0f, .y = 0.0f};
|
||||
bg_vertices[0].color = {.r = r, .g = g, .b = b, .a = alpha};
|
||||
|
||||
bg_vertices[1].position = {static_cast<float>(box_width_), 0};
|
||||
bg_vertices[1].tex_coord = {1.0f, 0.0f};
|
||||
bg_vertices[1].color = {r, g, b, alpha};
|
||||
bg_vertices[1].position = {.x = static_cast<float>(box_width_), .y = 0};
|
||||
bg_vertices[1].tex_coord = {.x = 1.0f, .y = 0.0f};
|
||||
bg_vertices[1].color = {.r = r, .g = g, .b = b, .a = alpha};
|
||||
|
||||
bg_vertices[2].position = {static_cast<float>(box_width_), static_cast<float>(box_height_)};
|
||||
bg_vertices[2].tex_coord = {1.0f, 1.0f};
|
||||
bg_vertices[2].color = {r, g, b, alpha};
|
||||
bg_vertices[2].position = {.x = static_cast<float>(box_width_), .y = static_cast<float>(box_height_)};
|
||||
bg_vertices[2].tex_coord = {.x = 1.0f, .y = 1.0f};
|
||||
bg_vertices[2].color = {.r = r, .g = g, .b = b, .a = alpha};
|
||||
|
||||
bg_vertices[3].position = {0, static_cast<float>(box_height_)};
|
||||
bg_vertices[3].tex_coord = {0.0f, 1.0f};
|
||||
bg_vertices[3].color = {r, g, b, alpha};
|
||||
bg_vertices[3].position = {.x = 0, .y = static_cast<float>(box_height_)};
|
||||
bg_vertices[3].tex_coord = {.x = 0.0f, .y = 1.0f};
|
||||
bg_vertices[3].color = {.r = r, .g = g, .b = b, .a = alpha};
|
||||
|
||||
int bg_indices[6] = {0, 1, 2, 2, 3, 0};
|
||||
SDL_RenderGeometry(renderer_, nullptr, bg_vertices, 4, bg_indices, 6);
|
||||
std::array<int, 6> bg_indices = {0, 1, 2, 2, 3, 0};
|
||||
SDL_RenderGeometry(renderer_, nullptr, bg_vertices.data(), 4, bg_indices.data(), 6);
|
||||
|
||||
// Renderizar texto del overlay (ajustando coordenadas para que sean relativas a 0,0)
|
||||
// Necesito renderizar el texto igual que en renderHelpText() pero con coordenadas ajustadas
|
||||
|
||||
// Obtener colores para el texto
|
||||
int text_r, text_g, text_b;
|
||||
int text_r;
|
||||
int text_g;
|
||||
int text_b;
|
||||
theme_mgr_->getCurrentThemeTextColor(text_r, text_g, text_b);
|
||||
SDL_Color category_color = {static_cast<Uint8>(text_r), static_cast<Uint8>(text_g), static_cast<Uint8>(text_b), 255};
|
||||
|
||||
@@ -339,7 +348,7 @@ void HelpOverlay::rebuildCachedTexture() {
|
||||
// Guardar colores actuales para comparación futura
|
||||
last_category_color_ = category_color;
|
||||
last_content_color_ = content_color;
|
||||
last_bg_color_ = {static_cast<Uint8>(notif_bg_r), static_cast<Uint8>(notif_bg_g), static_cast<Uint8>(notif_bg_b), 255};
|
||||
last_bg_color_ = {.r = static_cast<Uint8>(notif_bg_r), .g = static_cast<Uint8>(notif_bg_g), .b = static_cast<Uint8>(notif_bg_b), .a = 255};
|
||||
|
||||
// Configuración de espaciado
|
||||
int line_height = text_renderer_->getTextHeight();
|
||||
@@ -347,13 +356,13 @@ void HelpOverlay::rebuildCachedTexture() {
|
||||
int col_gap = padding * 2;
|
||||
|
||||
// Posición X de inicio de cada columna
|
||||
int col_start[3];
|
||||
std::array<int, 3> col_start{};
|
||||
col_start[0] = padding;
|
||||
col_start[1] = padding + column1_width_ + col_gap;
|
||||
col_start[2] = padding + column1_width_ + col_gap + column2_width_ + col_gap;
|
||||
|
||||
// Ancho de cada columna (para centrado interno)
|
||||
int col_width[3] = {column1_width_, column2_width_, column3_width_};
|
||||
std::array<int, 3> col_width = {column1_width_, column2_width_, column3_width_};
|
||||
|
||||
int glyph_height = text_renderer_->getGlyphHeight();
|
||||
int current_y = padding;
|
||||
@@ -387,7 +396,7 @@ void HelpOverlay::rebuildCachedTexture() {
|
||||
} else {
|
||||
// Encabezado de sección — centrado en la columna
|
||||
int w = text_renderer_->getTextWidthPhysical(binding.key);
|
||||
text_renderer_->printAbsolute(cx + (cw - w) / 2, current_y, binding.key, category_color);
|
||||
text_renderer_->printAbsolute(cx + ((cw - w) / 2), current_y, binding.key, category_color);
|
||||
current_y += line_height;
|
||||
}
|
||||
continue;
|
||||
@@ -397,7 +406,7 @@ void HelpOverlay::rebuildCachedTexture() {
|
||||
int key_width = text_renderer_->getTextWidthPhysical(binding.key);
|
||||
int desc_width = text_renderer_->getTextWidthPhysical(binding.description);
|
||||
int total_width = key_width + 10 + desc_width;
|
||||
int line_x = cx + (cw - total_width) / 2;
|
||||
int line_x = cx + ((cw - total_width) / 2);
|
||||
|
||||
text_renderer_->printAbsolute(line_x, current_y, binding.key, category_color);
|
||||
text_renderer_->printAbsolute(line_x + key_width + 10, current_y, binding.description, content_color);
|
||||
@@ -413,13 +422,19 @@ void HelpOverlay::rebuildCachedTexture() {
|
||||
}
|
||||
|
||||
void HelpOverlay::render(SDL_Renderer* renderer) {
|
||||
if (!visible_) return;
|
||||
if (!visible_) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Obtener colores actuales del tema
|
||||
int notif_bg_r, notif_bg_g, notif_bg_b;
|
||||
int notif_bg_r;
|
||||
int notif_bg_g;
|
||||
int notif_bg_b;
|
||||
theme_mgr_->getCurrentNotificationBackgroundColor(notif_bg_r, notif_bg_g, notif_bg_b);
|
||||
|
||||
int text_r, text_g, text_b;
|
||||
int text_r;
|
||||
int text_g;
|
||||
int text_b;
|
||||
theme_mgr_->getCurrentThemeTextColor(text_r, text_g, text_b);
|
||||
|
||||
Color ball_color = theme_mgr_->getInterpolatedColor(0);
|
||||
@@ -433,22 +448,24 @@ void HelpOverlay::render(SDL_Renderer* renderer) {
|
||||
constexpr int COLOR_CHANGE_THRESHOLD = 5;
|
||||
bool colors_changed =
|
||||
(abs(current_bg.r - last_bg_color_.r) > COLOR_CHANGE_THRESHOLD ||
|
||||
abs(current_bg.g - last_bg_color_.g) > COLOR_CHANGE_THRESHOLD ||
|
||||
abs(current_bg.b - last_bg_color_.b) > COLOR_CHANGE_THRESHOLD ||
|
||||
abs(current_category.r - last_category_color_.r) > COLOR_CHANGE_THRESHOLD ||
|
||||
abs(current_category.g - last_category_color_.g) > COLOR_CHANGE_THRESHOLD ||
|
||||
abs(current_category.b - last_category_color_.b) > COLOR_CHANGE_THRESHOLD ||
|
||||
abs(current_content.r - last_content_color_.r) > COLOR_CHANGE_THRESHOLD ||
|
||||
abs(current_content.g - last_content_color_.g) > COLOR_CHANGE_THRESHOLD ||
|
||||
abs(current_content.b - last_content_color_.b) > COLOR_CHANGE_THRESHOLD);
|
||||
abs(current_bg.g - last_bg_color_.g) > COLOR_CHANGE_THRESHOLD ||
|
||||
abs(current_bg.b - last_bg_color_.b) > COLOR_CHANGE_THRESHOLD ||
|
||||
abs(current_category.r - last_category_color_.r) > COLOR_CHANGE_THRESHOLD ||
|
||||
abs(current_category.g - last_category_color_.g) > COLOR_CHANGE_THRESHOLD ||
|
||||
abs(current_category.b - last_category_color_.b) > COLOR_CHANGE_THRESHOLD ||
|
||||
abs(current_content.r - last_content_color_.r) > COLOR_CHANGE_THRESHOLD ||
|
||||
abs(current_content.g - last_content_color_.g) > COLOR_CHANGE_THRESHOLD ||
|
||||
abs(current_content.b - last_content_color_.b) > COLOR_CHANGE_THRESHOLD);
|
||||
|
||||
// Regenerar textura si es necesario (colores cambiaron O flag de rebuild activo)
|
||||
if (texture_needs_rebuild_ || colors_changed || !cached_texture_) {
|
||||
if (texture_needs_rebuild_ || colors_changed || (cached_texture_ == nullptr)) {
|
||||
rebuildCachedTexture();
|
||||
}
|
||||
|
||||
// Si no hay textura cacheada (error), salir
|
||||
if (!cached_texture_) return;
|
||||
if (cached_texture_ == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
// CRÍTICO: Habilitar alpha blending para que la transparencia funcione
|
||||
SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_BLEND);
|
||||
@@ -460,8 +477,8 @@ void HelpOverlay::render(SDL_Renderer* renderer) {
|
||||
// Calcular posición centrada dentro del VIEWPORT, no de la pantalla física
|
||||
// viewport.w y viewport.h son las dimensiones del área visible
|
||||
// viewport.x y viewport.y son el offset de las barras negras
|
||||
int centered_x = viewport.x + (viewport.w - box_width_) / 2;
|
||||
int centered_y = viewport.y + (viewport.h - box_height_) / 2;
|
||||
int centered_x = viewport.x + ((viewport.w - box_width_) / 2);
|
||||
int centered_y = viewport.y + ((viewport.h - box_height_) / 2);
|
||||
|
||||
// Renderizar la textura cacheada centrada en el viewport
|
||||
SDL_FRect dest_rect;
|
||||
|
||||
@@ -17,89 +17,89 @@ class TextRenderer;
|
||||
* Toggle on/off con tecla H. La simulación continúa en el fondo.
|
||||
*/
|
||||
class HelpOverlay {
|
||||
public:
|
||||
HelpOverlay();
|
||||
~HelpOverlay();
|
||||
public:
|
||||
HelpOverlay();
|
||||
~HelpOverlay();
|
||||
|
||||
/**
|
||||
* @brief Inicializa el overlay con renderer y theme manager
|
||||
*/
|
||||
void initialize(SDL_Renderer* renderer, ThemeManager* theme_mgr, int physical_width, int physical_height, int font_size);
|
||||
/**
|
||||
* @brief Inicializa el overlay con renderer y theme manager
|
||||
*/
|
||||
void initialize(SDL_Renderer* renderer, ThemeManager* theme_mgr, int physical_width, int physical_height, int font_size);
|
||||
|
||||
/**
|
||||
* @brief Renderiza el overlay si está visible
|
||||
*/
|
||||
void render(SDL_Renderer* renderer);
|
||||
/**
|
||||
* @brief Renderiza el overlay si está visible
|
||||
*/
|
||||
void render(SDL_Renderer* renderer);
|
||||
|
||||
/**
|
||||
* @brief Actualiza dimensiones físicas de ventana (zoom, fullscreen, etc.)
|
||||
*/
|
||||
void updatePhysicalWindowSize(int physical_width, int physical_height);
|
||||
/**
|
||||
* @brief Actualiza dimensiones físicas de ventana (zoom, fullscreen, etc.)
|
||||
*/
|
||||
void updatePhysicalWindowSize(int physical_width, int physical_height);
|
||||
|
||||
/**
|
||||
* @brief Reinitializa el tamaño de fuente (cuando cambia el tamaño de ventana)
|
||||
*/
|
||||
void reinitializeFontSize(int new_font_size);
|
||||
/**
|
||||
* @brief Reinitializa el tamaño de fuente (cuando cambia el tamaño de ventana)
|
||||
*/
|
||||
void reinitializeFontSize(int new_font_size);
|
||||
|
||||
/**
|
||||
* @brief Actualiza font size Y dimensiones físicas de forma atómica
|
||||
* @param font_size Tamaño de fuente actual
|
||||
* @param physical_width Nueva anchura física
|
||||
* @param physical_height Nueva altura física
|
||||
*/
|
||||
void updateAll(int font_size, int physical_width, int physical_height);
|
||||
/**
|
||||
* @brief Actualiza font size Y dimensiones físicas de forma atómica
|
||||
* @param font_size Tamaño de fuente actual
|
||||
* @param physical_width Nueva anchura física
|
||||
* @param physical_height Nueva altura física
|
||||
*/
|
||||
void updateAll(int font_size, int physical_width, int physical_height);
|
||||
|
||||
/**
|
||||
* @brief Toggle visibilidad del overlay
|
||||
*/
|
||||
void toggle();
|
||||
/**
|
||||
* @brief Toggle visibilidad del overlay
|
||||
*/
|
||||
void toggle();
|
||||
|
||||
/**
|
||||
* @brief Consulta si el overlay está visible
|
||||
*/
|
||||
bool isVisible() const { return visible_; }
|
||||
/**
|
||||
* @brief Consulta si el overlay está visible
|
||||
*/
|
||||
bool isVisible() const { return visible_; }
|
||||
|
||||
private:
|
||||
SDL_Renderer* renderer_;
|
||||
ThemeManager* theme_mgr_;
|
||||
TextRenderer* text_renderer_; // Renderer de texto para la ayuda
|
||||
int physical_width_;
|
||||
int physical_height_;
|
||||
bool visible_;
|
||||
private:
|
||||
SDL_Renderer* renderer_;
|
||||
ThemeManager* theme_mgr_;
|
||||
TextRenderer* text_renderer_; // Renderer de texto para la ayuda
|
||||
int physical_width_;
|
||||
int physical_height_;
|
||||
bool visible_;
|
||||
|
||||
// Dimensiones calculadas del recuadro (anchura dinámica según texto, centrado)
|
||||
int box_width_;
|
||||
int box_height_;
|
||||
int box_x_;
|
||||
int box_y_;
|
||||
// Dimensiones calculadas del recuadro (anchura dinámica según texto, centrado)
|
||||
int box_width_;
|
||||
int box_height_;
|
||||
int box_x_;
|
||||
int box_y_;
|
||||
|
||||
// Anchos individuales de cada columna (para evitar solapamiento)
|
||||
int column1_width_;
|
||||
int column2_width_;
|
||||
int column3_width_;
|
||||
// Anchos individuales de cada columna (para evitar solapamiento)
|
||||
int column1_width_;
|
||||
int column2_width_;
|
||||
int column3_width_;
|
||||
|
||||
// Sistema de caché para optimización de rendimiento
|
||||
SDL_Texture* cached_texture_; // Textura cacheada del overlay completo
|
||||
SDL_Color last_category_color_; // Último color de categorías renderizado
|
||||
SDL_Color last_content_color_; // Último color de contenido renderizado
|
||||
SDL_Color last_bg_color_; // Último color de fondo renderizado
|
||||
bool texture_needs_rebuild_; // Flag para forzar regeneración de textura
|
||||
// Sistema de caché para optimización de rendimiento
|
||||
SDL_Texture* cached_texture_; // Textura cacheada del overlay completo
|
||||
SDL_Color last_category_color_; // Último color de categorías renderizado
|
||||
SDL_Color last_content_color_; // Último color de contenido renderizado
|
||||
SDL_Color last_bg_color_; // Último color de fondo renderizado
|
||||
bool texture_needs_rebuild_; // Flag para forzar regeneración de textura
|
||||
|
||||
// Calcular dimensiones del texto más largo
|
||||
void calculateTextDimensions(int& max_width, int& total_height);
|
||||
// Calcular dimensiones del texto más largo
|
||||
void calculateTextDimensions(int& max_width, int& total_height);
|
||||
|
||||
// Calcular dimensiones del recuadro según tamaño de ventana y texto
|
||||
void calculateBoxDimensions();
|
||||
// Calcular dimensiones del recuadro según tamaño de ventana y texto
|
||||
void calculateBoxDimensions();
|
||||
|
||||
// Regenerar textura cacheada del overlay
|
||||
void rebuildCachedTexture();
|
||||
// Regenerar textura cacheada del overlay
|
||||
void rebuildCachedTexture();
|
||||
|
||||
// Estructura para par tecla-descripción
|
||||
struct KeyBinding {
|
||||
const char* key;
|
||||
const char* description;
|
||||
};
|
||||
// Estructura para par tecla-descripción
|
||||
struct KeyBinding {
|
||||
const char* key;
|
||||
const char* description;
|
||||
};
|
||||
|
||||
// Lista de todos los controles (se llena en constructor)
|
||||
std::vector<KeyBinding> key_bindings_;
|
||||
// Lista de todos los controles (se llena en constructor)
|
||||
std::vector<KeyBinding> key_bindings_;
|
||||
};
|
||||
|
||||
@@ -1,25 +1,25 @@
|
||||
#define STB_IMAGE_RESIZE_IMPLEMENTATION
|
||||
#include "logo_scaler.hpp"
|
||||
|
||||
#include <SDL3/SDL_error.h> // Para SDL_GetError
|
||||
#include <SDL3/SDL_log.h> // Para SDL_Log
|
||||
#include <SDL3/SDL_pixels.h> // Para SDL_PixelFormat
|
||||
#include <SDL3/SDL_render.h> // Para SDL_CreateTexture
|
||||
#include <SDL3/SDL_surface.h> // Para SDL_CreateSurfaceFrom
|
||||
#include <SDL3/SDL_video.h> // Para SDL_GetDisplays
|
||||
#include <SDL3/SDL_error.h> // Para SDL_GetError
|
||||
#include <SDL3/SDL_log.h> // Para SDL_Log
|
||||
#include <SDL3/SDL_pixels.h> // Para SDL_PixelFormat
|
||||
#include <SDL3/SDL_render.h> // Para SDL_CreateTexture
|
||||
#include <SDL3/SDL_surface.h> // Para SDL_CreateSurfaceFrom
|
||||
#include <SDL3/SDL_video.h> // Para SDL_GetDisplays
|
||||
|
||||
#include <cstdlib> // Para free()
|
||||
#include <iostream> // Para std::cout
|
||||
|
||||
#include "external/stb_image.h" // Para stbi_load, stbi_image_free
|
||||
#include "external/stb_image_resize2.h" // Para stbir_resize_uint8_srgb
|
||||
#include "resource_manager.hpp" // Para cargar desde pack
|
||||
#include "resource_manager.hpp" // Para cargar desde pack
|
||||
|
||||
// ============================================================================
|
||||
// Detectar resolución nativa del monitor principal
|
||||
// ============================================================================
|
||||
|
||||
bool LogoScaler::detectNativeResolution(int& native_width, int& native_height) {
|
||||
auto LogoScaler::detectNativeResolution(int& native_width, int& native_height) -> bool {
|
||||
int num_displays = 0;
|
||||
SDL_DisplayID* displays = SDL_GetDisplays(&num_displays);
|
||||
|
||||
@@ -48,22 +48,25 @@ bool LogoScaler::detectNativeResolution(int& native_width, int& native_height) {
|
||||
// Cargar PNG y escalar al tamaño especificado
|
||||
// ============================================================================
|
||||
|
||||
unsigned char* LogoScaler::loadAndScale(const std::string& path,
|
||||
int target_width, int target_height,
|
||||
int& out_width, int& out_height) {
|
||||
auto LogoScaler::loadAndScale(const std::string& path,
|
||||
int target_width,
|
||||
int target_height,
|
||||
int& out_width,
|
||||
int& out_height) -> unsigned char* {
|
||||
// 1. Intentar cargar imagen desde ResourceManager (pack o disco)
|
||||
int orig_width, orig_height, orig_channels;
|
||||
int orig_width;
|
||||
int orig_height;
|
||||
int orig_channels;
|
||||
unsigned char* orig_data = nullptr;
|
||||
|
||||
// 1a. Cargar desde ResourceManager
|
||||
unsigned char* resourceData = nullptr;
|
||||
size_t resourceSize = 0;
|
||||
unsigned char* resource_data = nullptr;
|
||||
size_t resource_size = 0;
|
||||
|
||||
if (ResourceManager::loadResource(path, resourceData, resourceSize)) {
|
||||
if (ResourceManager::loadResource(path, resource_data, resource_size)) {
|
||||
// Descodificar imagen desde memoria usando stb_image
|
||||
orig_data = stbi_load_from_memory(resourceData, static_cast<int>(resourceSize),
|
||||
&orig_width, &orig_height, &orig_channels, STBI_rgb_alpha);
|
||||
delete[] resourceData; // Liberar buffer temporal
|
||||
orig_data = stbi_load_from_memory(resource_data, static_cast<int>(resource_size), &orig_width, &orig_height, &orig_channels, STBI_rgb_alpha);
|
||||
delete[] resource_data; // Liberar buffer temporal
|
||||
}
|
||||
|
||||
// 1b. Si falla todo, error
|
||||
@@ -80,7 +83,7 @@ unsigned char* LogoScaler::loadAndScale(const std::string& path,
|
||||
out_height = target_height;
|
||||
|
||||
// 3. Alocar buffer para imagen escalada (RGBA = 4 bytes por píxel)
|
||||
unsigned char* scaled_data = static_cast<unsigned char*>(malloc(out_width * out_height * 4));
|
||||
auto* scaled_data = static_cast<unsigned char*>(malloc(out_width * out_height * 4));
|
||||
if (scaled_data == nullptr) {
|
||||
SDL_Log("Error al alocar memoria para imagen escalada");
|
||||
stbi_image_free(orig_data);
|
||||
@@ -90,9 +93,15 @@ unsigned char* LogoScaler::loadAndScale(const std::string& path,
|
||||
// 4. Escalar con stb_image_resize2 (algoritmo Mitchell, espacio sRGB)
|
||||
// La función devuelve el puntero de salida, o nullptr si falla
|
||||
unsigned char* result = stbir_resize_uint8_srgb(
|
||||
orig_data, orig_width, orig_height, 0, // Input
|
||||
scaled_data, out_width, out_height, 0, // Output
|
||||
STBIR_RGBA // Formato píxel
|
||||
orig_data,
|
||||
orig_width,
|
||||
orig_height,
|
||||
0, // Input
|
||||
scaled_data,
|
||||
out_width,
|
||||
out_height,
|
||||
0, // Output
|
||||
STBIR_RGBA // Formato píxel
|
||||
);
|
||||
|
||||
// Liberar imagen original (ya no la necesitamos)
|
||||
@@ -111,9 +120,10 @@ unsigned char* LogoScaler::loadAndScale(const std::string& path,
|
||||
// Crear textura SDL desde buffer RGBA
|
||||
// ============================================================================
|
||||
|
||||
SDL_Texture* LogoScaler::createTextureFromBuffer(SDL_Renderer* renderer,
|
||||
unsigned char* data,
|
||||
int width, int height) {
|
||||
auto LogoScaler::createTextureFromBuffer(SDL_Renderer* renderer,
|
||||
unsigned char* data,
|
||||
int width,
|
||||
int height) -> SDL_Texture* {
|
||||
if (renderer == nullptr || data == nullptr || width <= 0 || height <= 0) {
|
||||
SDL_Log("Parámetros inválidos para createTextureFromBuffer");
|
||||
return nullptr;
|
||||
@@ -124,11 +134,11 @@ SDL_Texture* LogoScaler::createTextureFromBuffer(SDL_Renderer* renderer,
|
||||
SDL_PixelFormat pixel_format = SDL_PIXELFORMAT_RGBA32;
|
||||
|
||||
SDL_Surface* surface = SDL_CreateSurfaceFrom(
|
||||
width, height,
|
||||
width,
|
||||
height,
|
||||
pixel_format,
|
||||
data,
|
||||
pitch
|
||||
);
|
||||
pitch);
|
||||
|
||||
if (surface == nullptr) {
|
||||
SDL_Log("Error al crear surface: %s", SDL_GetError());
|
||||
|
||||
@@ -17,45 +17,48 @@
|
||||
* de pantalla, eliminando el escalado dinámico de SDL y mejorando calidad visual.
|
||||
*/
|
||||
class LogoScaler {
|
||||
public:
|
||||
/**
|
||||
* @brief Detecta la resolución nativa del monitor principal
|
||||
*
|
||||
* @param native_width [out] Ancho nativo del display en píxeles
|
||||
* @param native_height [out] Alto nativo del display en píxeles
|
||||
* @return true si se pudo detectar, false si hubo error
|
||||
*/
|
||||
static bool detectNativeResolution(int& native_width, int& native_height);
|
||||
public:
|
||||
/**
|
||||
* @brief Detecta la resolución nativa del monitor principal
|
||||
*
|
||||
* @param native_width [out] Ancho nativo del display en píxeles
|
||||
* @param native_height [out] Alto nativo del display en píxeles
|
||||
* @return true si se pudo detectar, false si hubo error
|
||||
*/
|
||||
static bool detectNativeResolution(int& native_width, int& native_height);
|
||||
|
||||
/**
|
||||
* @brief Carga un PNG y lo escala al tamaño especificado
|
||||
*
|
||||
* Usa stb_image para cargar y stb_image_resize2 para escalar con
|
||||
* algoritmo Mitchell (balance calidad/velocidad) en espacio sRGB.
|
||||
*
|
||||
* @param path Ruta al archivo PNG (ej: "data/logo/logo.png")
|
||||
* @param target_width Ancho destino en píxeles
|
||||
* @param target_height Alto destino en píxeles
|
||||
* @param out_width [out] Ancho real de la imagen escalada
|
||||
* @param out_height [out] Alto real de la imagen escalada
|
||||
* @return Buffer RGBA (4 bytes por píxel) o nullptr si falla
|
||||
* IMPORTANTE: El caller debe liberar con free() cuando termine
|
||||
*/
|
||||
static unsigned char* loadAndScale(const std::string& path,
|
||||
int target_width, int target_height,
|
||||
int& out_width, int& out_height);
|
||||
/**
|
||||
* @brief Carga un PNG y lo escala al tamaño especificado
|
||||
*
|
||||
* Usa stb_image para cargar y stb_image_resize2 para escalar con
|
||||
* algoritmo Mitchell (balance calidad/velocidad) en espacio sRGB.
|
||||
*
|
||||
* @param path Ruta al archivo PNG (ej: "data/logo/logo.png")
|
||||
* @param target_width Ancho destino en píxeles
|
||||
* @param target_height Alto destino en píxeles
|
||||
* @param out_width [out] Ancho real de la imagen escalada
|
||||
* @param out_height [out] Alto real de la imagen escalada
|
||||
* @return Buffer RGBA (4 bytes por píxel) o nullptr si falla
|
||||
* IMPORTANTE: El caller debe liberar con free() cuando termine
|
||||
*/
|
||||
static unsigned char* loadAndScale(const std::string& path,
|
||||
int target_width,
|
||||
int target_height,
|
||||
int& out_width,
|
||||
int& out_height);
|
||||
|
||||
/**
|
||||
* @brief Crea una textura SDL desde un buffer RGBA
|
||||
*
|
||||
* @param renderer Renderizador SDL activo
|
||||
* @param data Buffer RGBA (4 bytes por píxel)
|
||||
* @param width Ancho del buffer en píxeles
|
||||
* @param height Alto del buffer en píxeles
|
||||
* @return Textura SDL creada o nullptr si falla
|
||||
* IMPORTANTE: El caller debe destruir con SDL_DestroyTexture()
|
||||
*/
|
||||
static SDL_Texture* createTextureFromBuffer(SDL_Renderer* renderer,
|
||||
unsigned char* data,
|
||||
int width, int height);
|
||||
/**
|
||||
* @brief Crea una textura SDL desde un buffer RGBA
|
||||
*
|
||||
* @param renderer Renderizador SDL activo
|
||||
* @param data Buffer RGBA (4 bytes por píxel)
|
||||
* @param width Ancho del buffer en píxeles
|
||||
* @param height Alto del buffer en píxeles
|
||||
* @return Textura SDL creada o nullptr si falla
|
||||
* IMPORTANTE: El caller debe destruir con SDL_DestroyTexture()
|
||||
*/
|
||||
static SDL_Texture* createTextureFromBuffer(SDL_Renderer* renderer,
|
||||
unsigned char* data,
|
||||
int width,
|
||||
int height);
|
||||
};
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
#include "notifier.hpp"
|
||||
|
||||
#include <SDL3/SDL.h>
|
||||
|
||||
#include "defines.hpp"
|
||||
#include "text/textrenderer.hpp"
|
||||
#include "theme_manager.hpp"
|
||||
#include "defines.hpp"
|
||||
#include "utils/easing_functions.hpp"
|
||||
#include <SDL3/SDL.h>
|
||||
|
||||
// ============================================================================
|
||||
// HELPER: Obtener viewport en coordenadas físicas (no lógicas)
|
||||
@@ -11,9 +13,10 @@
|
||||
// SDL_GetRenderViewport() devuelve coordenadas LÓGICAS cuando hay presentación
|
||||
// lógica activa. Para obtener coordenadas FÍSICAS, necesitamos deshabilitar
|
||||
// temporalmente la presentación lógica.
|
||||
static SDL_Rect getPhysicalViewport(SDL_Renderer* renderer) {
|
||||
static auto getPhysicalViewport(SDL_Renderer* renderer) -> SDL_Rect {
|
||||
// Guardar estado actual de presentación lógica
|
||||
int logical_w = 0, logical_h = 0;
|
||||
int logical_w = 0;
|
||||
int logical_h = 0;
|
||||
SDL_RendererLogicalPresentation presentation_mode;
|
||||
SDL_GetRenderLogicalPresentation(renderer, &logical_w, &logical_h, &presentation_mode);
|
||||
|
||||
@@ -31,19 +34,19 @@ static SDL_Rect getPhysicalViewport(SDL_Renderer* renderer) {
|
||||
}
|
||||
|
||||
Notifier::Notifier()
|
||||
: renderer_(nullptr)
|
||||
, text_renderer_(nullptr)
|
||||
, theme_manager_(nullptr)
|
||||
, window_width_(0)
|
||||
, window_height_(0)
|
||||
, current_notification_(nullptr) {
|
||||
: renderer_(nullptr),
|
||||
text_renderer_(nullptr),
|
||||
theme_manager_(nullptr),
|
||||
window_width_(0),
|
||||
window_height_(0),
|
||||
current_notification_(nullptr) {
|
||||
}
|
||||
|
||||
Notifier::~Notifier() {
|
||||
clear();
|
||||
}
|
||||
|
||||
bool Notifier::init(SDL_Renderer* renderer, TextRenderer* text_renderer, ThemeManager* theme_manager, int window_width, int window_height) {
|
||||
auto Notifier::init(SDL_Renderer* renderer, TextRenderer* text_renderer, ThemeManager* theme_manager, int window_width, int window_height) -> bool {
|
||||
renderer_ = renderer;
|
||||
text_renderer_ = text_renderer;
|
||||
theme_manager_ = theme_manager;
|
||||
@@ -105,7 +108,7 @@ void Notifier::update(Uint64 current_time) {
|
||||
// Animación de entrada (NOTIFICATION_SLIDE_TIME ms)
|
||||
if (elapsed < NOTIFICATION_SLIDE_TIME) {
|
||||
float progress = static_cast<float>(elapsed) / static_cast<float>(NOTIFICATION_SLIDE_TIME);
|
||||
float eased = Easing::easeOutBack(progress); // Efecto con ligero overshoot
|
||||
float eased = Easing::easeOutBack(progress); // Efecto con ligero overshoot
|
||||
current_notification_->y_offset = -50.0f + (50.0f * eased); // De -50 a 0
|
||||
} else {
|
||||
// Transición a VISIBLE
|
||||
@@ -151,28 +154,30 @@ void Notifier::update(Uint64 current_time) {
|
||||
}
|
||||
|
||||
void Notifier::render() {
|
||||
if (!current_notification_ || !text_renderer_ || !renderer_ || !theme_manager_) {
|
||||
if (!current_notification_ || (text_renderer_ == nullptr) || (renderer_ == nullptr) || (theme_manager_ == nullptr)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Obtener colores DINÁMICOS desde ThemeManager (incluye LERP automático)
|
||||
int text_r, text_g, text_b;
|
||||
int text_r;
|
||||
int text_g;
|
||||
int text_b;
|
||||
theme_manager_->getCurrentThemeTextColor(text_r, text_g, text_b);
|
||||
SDL_Color text_color = {
|
||||
static_cast<Uint8>(text_r),
|
||||
static_cast<Uint8>(text_g),
|
||||
static_cast<Uint8>(text_b),
|
||||
static_cast<Uint8>(current_notification_->alpha * 255.0f)
|
||||
};
|
||||
static_cast<Uint8>(current_notification_->alpha * 255.0f)};
|
||||
|
||||
int bg_r, bg_g, bg_b;
|
||||
int bg_r;
|
||||
int bg_g;
|
||||
int bg_b;
|
||||
theme_manager_->getCurrentNotificationBackgroundColor(bg_r, bg_g, bg_b);
|
||||
SDL_Color bg_color = {
|
||||
static_cast<Uint8>(bg_r),
|
||||
static_cast<Uint8>(bg_g),
|
||||
static_cast<Uint8>(bg_b),
|
||||
255
|
||||
};
|
||||
255};
|
||||
|
||||
// Calcular dimensiones del texto en píxeles FÍSICOS
|
||||
// IMPORTANTE: Usar getTextWidthPhysical() en lugar de getTextWidth()
|
||||
@@ -207,7 +212,7 @@ void Notifier::render() {
|
||||
}
|
||||
|
||||
void Notifier::renderBackground(int x, int y, int width, int height, float alpha, SDL_Color bg_color) {
|
||||
if (!renderer_) {
|
||||
if (renderer_ == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -225,7 +230,7 @@ void Notifier::renderBackground(int x, int y, int width, int height, float alpha
|
||||
bg_rect.h = static_cast<float>(height);
|
||||
|
||||
// Color del tema con alpha
|
||||
Uint8 bg_alpha = static_cast<Uint8>(alpha * 255.0f);
|
||||
auto bg_alpha = static_cast<Uint8>(alpha * 255.0f);
|
||||
SDL_SetRenderDrawColor(renderer_, bg_color.r, bg_color.g, bg_color.b, bg_alpha);
|
||||
|
||||
// Habilitar blending para transparencia
|
||||
@@ -233,7 +238,8 @@ void Notifier::renderBackground(int x, int y, int width, int height, float alpha
|
||||
|
||||
// CRÍTICO: Deshabilitar presentación lógica para renderizar en píxeles físicos absolutos
|
||||
// (igual que printAbsolute() en TextRenderer)
|
||||
int logical_w = 0, logical_h = 0;
|
||||
int logical_w = 0;
|
||||
int logical_h = 0;
|
||||
SDL_RendererLogicalPresentation presentation_mode;
|
||||
SDL_GetRenderLogicalPresentation(renderer_, &logical_w, &logical_h, &presentation_mode);
|
||||
|
||||
@@ -248,7 +254,7 @@ void Notifier::renderBackground(int x, int y, int width, int height, float alpha
|
||||
SDL_SetRenderDrawBlendMode(renderer_, SDL_BLENDMODE_NONE);
|
||||
}
|
||||
|
||||
bool Notifier::isActive() const {
|
||||
auto Notifier::isActive() const -> bool {
|
||||
return (current_notification_ != nullptr);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
#include <SDL3/SDL.h>
|
||||
#include <string>
|
||||
#include <queue>
|
||||
|
||||
#include <memory>
|
||||
#include <queue>
|
||||
#include <string>
|
||||
|
||||
// Forward declarations
|
||||
class TextRenderer;
|
||||
@@ -20,92 +21,92 @@ class ThemeManager;
|
||||
* - Texto de tamaño fijo independiente de resolución
|
||||
*/
|
||||
class Notifier {
|
||||
public:
|
||||
enum class NotificationState {
|
||||
SLIDING_IN, // Animación de entrada desde arriba
|
||||
VISIBLE, // Visible estático
|
||||
FADING_OUT, // Animación de salida (fade)
|
||||
DONE // Completado, listo para eliminar
|
||||
};
|
||||
public:
|
||||
enum class NotificationState {
|
||||
SLIDING_IN, // Animación de entrada desde arriba
|
||||
VISIBLE, // Visible estático
|
||||
FADING_OUT, // Animación de salida (fade)
|
||||
DONE // Completado, listo para eliminar
|
||||
};
|
||||
|
||||
struct Notification {
|
||||
std::string text;
|
||||
Uint64 created_time;
|
||||
Uint64 duration;
|
||||
NotificationState state;
|
||||
float alpha; // Opacidad 0.0-1.0
|
||||
float y_offset; // Offset Y para animación slide (píxeles)
|
||||
// NOTA: Los colores se obtienen dinámicamente desde ThemeManager en render()
|
||||
};
|
||||
struct Notification {
|
||||
std::string text;
|
||||
Uint64 created_time;
|
||||
Uint64 duration;
|
||||
NotificationState state;
|
||||
float alpha; // Opacidad 0.0-1.0
|
||||
float y_offset; // Offset Y para animación slide (píxeles)
|
||||
// NOTA: Los colores se obtienen dinámicamente desde ThemeManager en render()
|
||||
};
|
||||
|
||||
Notifier();
|
||||
~Notifier();
|
||||
Notifier();
|
||||
~Notifier();
|
||||
|
||||
/**
|
||||
* @brief Inicializa el notifier con un TextRenderer y ThemeManager
|
||||
* @param renderer SDL renderer para dibujar
|
||||
* @param text_renderer TextRenderer configurado con tamaño absoluto
|
||||
* @param theme_manager ThemeManager para obtener colores dinámicos con LERP
|
||||
* @param window_width Ancho de ventana física
|
||||
* @param window_height Alto de ventana física
|
||||
* @return true si inicialización exitosa
|
||||
*/
|
||||
bool init(SDL_Renderer* renderer, TextRenderer* text_renderer, ThemeManager* theme_manager, int window_width, int window_height);
|
||||
/**
|
||||
* @brief Inicializa el notifier con un TextRenderer y ThemeManager
|
||||
* @param renderer SDL renderer para dibujar
|
||||
* @param text_renderer TextRenderer configurado con tamaño absoluto
|
||||
* @param theme_manager ThemeManager para obtener colores dinámicos con LERP
|
||||
* @param window_width Ancho de ventana física
|
||||
* @param window_height Alto de ventana física
|
||||
* @return true si inicialización exitosa
|
||||
*/
|
||||
bool init(SDL_Renderer* renderer, TextRenderer* text_renderer, ThemeManager* theme_manager, int window_width, int window_height);
|
||||
|
||||
/**
|
||||
* @brief Actualiza las dimensiones de la ventana (llamar en resize)
|
||||
* @param window_width Nuevo ancho de ventana física
|
||||
* @param window_height Nuevo alto de ventana física
|
||||
*/
|
||||
void updateWindowSize(int window_width, int window_height);
|
||||
/**
|
||||
* @brief Actualiza las dimensiones de la ventana (llamar en resize)
|
||||
* @param window_width Nuevo ancho de ventana física
|
||||
* @param window_height Nuevo alto de ventana física
|
||||
*/
|
||||
void updateWindowSize(int window_width, int window_height);
|
||||
|
||||
/**
|
||||
* @brief Muestra una nueva notificación
|
||||
* @param text Texto a mostrar
|
||||
* @param duration Duración en milisegundos (0 = usar default)
|
||||
* @note Los colores se obtienen dinámicamente desde ThemeManager cada frame
|
||||
*/
|
||||
void show(const std::string& text, Uint64 duration = 0);
|
||||
/**
|
||||
* @brief Muestra una nueva notificación
|
||||
* @param text Texto a mostrar
|
||||
* @param duration Duración en milisegundos (0 = usar default)
|
||||
* @note Los colores se obtienen dinámicamente desde ThemeManager cada frame
|
||||
*/
|
||||
void show(const std::string& text, Uint64 duration = 0);
|
||||
|
||||
/**
|
||||
* @brief Actualiza las animaciones de notificaciones
|
||||
* @param current_time Tiempo actual en ms (SDL_GetTicks())
|
||||
*/
|
||||
void update(Uint64 current_time);
|
||||
/**
|
||||
* @brief Actualiza las animaciones de notificaciones
|
||||
* @param current_time Tiempo actual en ms (SDL_GetTicks())
|
||||
*/
|
||||
void update(Uint64 current_time);
|
||||
|
||||
/**
|
||||
* @brief Renderiza la notificación activa
|
||||
*/
|
||||
void render();
|
||||
/**
|
||||
* @brief Renderiza la notificación activa
|
||||
*/
|
||||
void render();
|
||||
|
||||
/**
|
||||
* @brief Verifica si hay una notificación activa (visible)
|
||||
* @return true si hay notificación mostrándose
|
||||
*/
|
||||
bool isActive() const;
|
||||
/**
|
||||
* @brief Verifica si hay una notificación activa (visible)
|
||||
* @return true si hay notificación mostrándose
|
||||
*/
|
||||
bool isActive() const;
|
||||
|
||||
/**
|
||||
* @brief Limpia todas las notificaciones pendientes
|
||||
*/
|
||||
void clear();
|
||||
/**
|
||||
* @brief Limpia todas las notificaciones pendientes
|
||||
*/
|
||||
void clear();
|
||||
|
||||
private:
|
||||
SDL_Renderer* renderer_;
|
||||
TextRenderer* text_renderer_;
|
||||
ThemeManager* theme_manager_; // Gestor de temas para obtener colores dinámicos con LERP
|
||||
int window_width_;
|
||||
int window_height_;
|
||||
private:
|
||||
SDL_Renderer* renderer_;
|
||||
TextRenderer* text_renderer_;
|
||||
ThemeManager* theme_manager_; // Gestor de temas para obtener colores dinámicos con LERP
|
||||
int window_width_;
|
||||
int window_height_;
|
||||
|
||||
std::queue<Notification> notification_queue_;
|
||||
std::unique_ptr<Notification> current_notification_;
|
||||
std::queue<Notification> notification_queue_;
|
||||
std::unique_ptr<Notification> current_notification_;
|
||||
|
||||
/**
|
||||
* @brief Procesa la cola y activa la siguiente notificación si es posible
|
||||
*/
|
||||
void processQueue();
|
||||
/**
|
||||
* @brief Procesa la cola y activa la siguiente notificación si es posible
|
||||
*/
|
||||
void processQueue();
|
||||
|
||||
/**
|
||||
* @brief Dibuja el fondo semitransparente de la notificación
|
||||
*/
|
||||
void renderBackground(int x, int y, int width, int height, float alpha, SDL_Color bg_color);
|
||||
/**
|
||||
* @brief Dibuja el fondo semitransparente de la notificación
|
||||
*/
|
||||
void renderBackground(int x, int y, int width, int height, float alpha, SDL_Color bg_color);
|
||||
};
|
||||
|
||||
@@ -1,18 +1,20 @@
|
||||
#include "ui_manager.hpp"
|
||||
|
||||
#include <SDL3/SDL.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <string>
|
||||
|
||||
#include "ball.hpp" // for Ball
|
||||
#include "defines.hpp" // for TEXT_DURATION, NOTIFICATION_DURATION, AppMode, SimulationMode
|
||||
#include "engine.hpp" // for Engine (info de sistema)
|
||||
#include "scene/scene_manager.hpp" // for SceneManager
|
||||
#include "shapes/shape.hpp" // for Shape
|
||||
#include "text/textrenderer.hpp" // for TextRenderer
|
||||
#include "theme_manager.hpp" // for ThemeManager
|
||||
#include "notifier.hpp" // for Notifier
|
||||
#include "help_overlay.hpp" // for HelpOverlay
|
||||
#include "ball.hpp" // for Ball
|
||||
#include "defines.hpp" // for TEXT_DURATION, NOTIFICATION_DURATION, AppMode, SimulationMode
|
||||
#include "engine.hpp" // for Engine (info de sistema)
|
||||
#include "help_overlay.hpp" // for HelpOverlay
|
||||
#include "notifier.hpp" // for Notifier
|
||||
#include "scene/scene_manager.hpp" // for SceneManager
|
||||
#include "shapes/shape.hpp" // for Shape
|
||||
#include "text/textrenderer.hpp" // for TextRenderer
|
||||
#include "theme_manager.hpp" // for ThemeManager
|
||||
|
||||
// ============================================================================
|
||||
// HELPER: Obtener viewport en coordenadas físicas (no lógicas)
|
||||
@@ -20,9 +22,10 @@
|
||||
// SDL_GetRenderViewport() devuelve coordenadas LÓGICAS cuando hay presentación
|
||||
// lógica activa. Para obtener coordenadas FÍSICAS, necesitamos deshabilitar
|
||||
// temporalmente la presentación lógica.
|
||||
static SDL_Rect getPhysicalViewport(SDL_Renderer* renderer) {
|
||||
static auto getPhysicalViewport(SDL_Renderer* renderer) -> SDL_Rect {
|
||||
// Guardar estado actual de presentación lógica
|
||||
int logical_w = 0, logical_h = 0;
|
||||
int logical_w = 0;
|
||||
int logical_h = 0;
|
||||
SDL_RendererLogicalPresentation presentation_mode;
|
||||
SDL_GetRenderLogicalPresentation(renderer, &logical_w, &logical_h, &presentation_mode);
|
||||
|
||||
@@ -40,23 +43,23 @@ static SDL_Rect getPhysicalViewport(SDL_Renderer* renderer) {
|
||||
}
|
||||
|
||||
UIManager::UIManager()
|
||||
: text_renderer_debug_(nullptr)
|
||||
, text_renderer_notifier_(nullptr)
|
||||
, notifier_(nullptr)
|
||||
, help_overlay_(nullptr)
|
||||
, show_debug_(false)
|
||||
, 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)
|
||||
, logical_window_width_(0)
|
||||
, logical_window_height_(0)
|
||||
, current_font_size_(18) { // Tamaño por defecto (medium)
|
||||
: text_renderer_debug_(nullptr),
|
||||
text_renderer_notifier_(nullptr),
|
||||
notifier_(nullptr),
|
||||
help_overlay_(nullptr),
|
||||
show_debug_(false),
|
||||
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),
|
||||
logical_window_width_(0),
|
||||
logical_window_height_(0),
|
||||
current_font_size_(18) { // Tamaño por defecto (medium)
|
||||
}
|
||||
|
||||
UIManager::~UIManager() {
|
||||
@@ -67,13 +70,15 @@ UIManager::~UIManager() {
|
||||
delete help_overlay_;
|
||||
}
|
||||
|
||||
void UIManager::initialize(SDL_Renderer* renderer, ThemeManager* theme_manager,
|
||||
int physical_width, int physical_height,
|
||||
int logical_width, int logical_height) {
|
||||
delete text_renderer_debug_; text_renderer_debug_ = nullptr;
|
||||
delete text_renderer_notifier_; text_renderer_notifier_ = nullptr;
|
||||
delete notifier_; notifier_ = nullptr;
|
||||
delete help_overlay_; help_overlay_ = nullptr;
|
||||
void UIManager::initialize(SDL_Renderer* renderer, ThemeManager* theme_manager, int physical_width, int physical_height, int logical_width, int logical_height) {
|
||||
delete text_renderer_debug_;
|
||||
text_renderer_debug_ = nullptr;
|
||||
delete text_renderer_notifier_;
|
||||
text_renderer_notifier_ = nullptr;
|
||||
delete notifier_;
|
||||
notifier_ = nullptr;
|
||||
delete help_overlay_;
|
||||
help_overlay_ = nullptr;
|
||||
|
||||
renderer_ = renderer;
|
||||
theme_manager_ = theme_manager;
|
||||
@@ -95,8 +100,7 @@ void UIManager::initialize(SDL_Renderer* renderer, ThemeManager* theme_manager,
|
||||
|
||||
// Crear y configurar sistema de notificaciones
|
||||
notifier_ = new Notifier();
|
||||
notifier_->init(renderer, text_renderer_notifier_, theme_manager_,
|
||||
physical_width, physical_height);
|
||||
notifier_->init(renderer, text_renderer_notifier_, theme_manager_, physical_width, physical_height);
|
||||
|
||||
// Crear y configurar sistema de ayuda (overlay)
|
||||
help_overlay_ = new HelpOverlay();
|
||||
@@ -123,30 +127,29 @@ void UIManager::update(Uint64 current_time, float delta_time) {
|
||||
}
|
||||
|
||||
void UIManager::render(SDL_Renderer* renderer,
|
||||
const Engine* engine,
|
||||
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) {
|
||||
const Engine* engine,
|
||||
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 debug HUD si está activo
|
||||
if (show_debug_) {
|
||||
renderDebugHUD(engine, scene_manager, current_mode, current_app_mode,
|
||||
active_shape, shape_convergence);
|
||||
renderDebugHUD(engine, 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_) {
|
||||
if (help_overlay_ != nullptr) {
|
||||
help_overlay_->render(renderer);
|
||||
}
|
||||
}
|
||||
@@ -156,7 +159,7 @@ void UIManager::toggleDebug() {
|
||||
}
|
||||
|
||||
void UIManager::toggleHelp() {
|
||||
if (help_overlay_) {
|
||||
if (help_overlay_ != nullptr) {
|
||||
help_overlay_->toggle();
|
||||
}
|
||||
}
|
||||
@@ -190,16 +193,16 @@ void UIManager::updatePhysicalWindowSize(int width, int height, int logical_heig
|
||||
current_font_size_ = new_font_size;
|
||||
|
||||
// Reinicializar text renderers con nuevo tamaño
|
||||
if (text_renderer_debug_) {
|
||||
if (text_renderer_debug_ != nullptr) {
|
||||
text_renderer_debug_->reinitialize(std::max(9, current_font_size_ - 2));
|
||||
}
|
||||
if (text_renderer_notifier_) {
|
||||
if (text_renderer_notifier_ != nullptr) {
|
||||
text_renderer_notifier_->reinitialize(current_font_size_);
|
||||
}
|
||||
}
|
||||
|
||||
// Actualizar help overlay con font size actual Y nuevas dimensiones (atómicamente)
|
||||
if (help_overlay_) {
|
||||
if (help_overlay_ != nullptr) {
|
||||
help_overlay_->updateAll(std::max(9, current_font_size_ - 1), width, height);
|
||||
}
|
||||
|
||||
@@ -209,12 +212,12 @@ void UIManager::updatePhysicalWindowSize(int width, int height, int logical_heig
|
||||
|
||||
// === Métodos privados ===
|
||||
|
||||
void UIManager::renderDebugHUD(const Engine* engine,
|
||||
const SceneManager* scene_manager,
|
||||
SimulationMode current_mode,
|
||||
AppMode current_app_mode,
|
||||
const Shape* active_shape,
|
||||
float shape_convergence) {
|
||||
void UIManager::renderDebugHUD(const Engine* engine, // NOLINT(readability-function-cognitive-complexity)
|
||||
const SceneManager* scene_manager,
|
||||
SimulationMode current_mode,
|
||||
AppMode current_app_mode,
|
||||
const Shape* active_shape,
|
||||
float shape_convergence) {
|
||||
int line_height = text_renderer_debug_->getTextHeight();
|
||||
int margin = 8;
|
||||
SDL_Rect physical_viewport = getPhysicalViewport(renderer_);
|
||||
@@ -236,7 +239,7 @@ void UIManager::renderDebugHUD(const Engine* engine,
|
||||
if (current_mode == SimulationMode::PHYSICS) {
|
||||
simmode_text = "SimMode: PHYSICS";
|
||||
} else if (current_mode == SimulationMode::SHAPE) {
|
||||
if (active_shape) {
|
||||
if (active_shape != nullptr) {
|
||||
simmode_text = std::string("SimMode: SHAPE (") + active_shape->getName() + ")";
|
||||
} else {
|
||||
simmode_text = "SimMode: SHAPE";
|
||||
@@ -246,7 +249,7 @@ void UIManager::renderDebugHUD(const Engine* engine,
|
||||
}
|
||||
|
||||
std::string sprite_name = engine->getCurrentTextureName();
|
||||
std::transform(sprite_name.begin(), sprite_name.end(), sprite_name.begin(), ::toupper);
|
||||
std::ranges::transform(sprite_name, sprite_name.begin(), ::toupper);
|
||||
std::string sprite_text = "Sprite: " + sprite_name;
|
||||
|
||||
size_t ball_count = scene_manager->getBallCount();
|
||||
@@ -256,7 +259,9 @@ void UIManager::renderDebugHUD(const Engine* engine,
|
||||
std::string formatted;
|
||||
int digits = static_cast<int>(count_str.length());
|
||||
for (int i = 0; i < digits; i++) {
|
||||
if (i > 0 && (digits - i) % 3 == 0) formatted += ',';
|
||||
if (i > 0 && (digits - i) % 3 == 0) {
|
||||
formatted += ',';
|
||||
}
|
||||
formatted += count_str[i];
|
||||
}
|
||||
balls_text = "Balls: " + formatted;
|
||||
@@ -275,7 +280,9 @@ void UIManager::renderDebugHUD(const Engine* engine,
|
||||
std::string formatted;
|
||||
int digits = static_cast<int>(count_str.length());
|
||||
for (int i = 0; i < digits; i++) {
|
||||
if (i > 0 && (digits - i) % 3 == 0) formatted += ',';
|
||||
if (i > 0 && (digits - i) % 3 == 0) {
|
||||
formatted += ',';
|
||||
}
|
||||
formatted += count_str[i];
|
||||
}
|
||||
max_auto_text = "Auto max: " + formatted;
|
||||
@@ -303,9 +310,9 @@ void UIManager::renderDebugHUD(const Engine* engine,
|
||||
std::string refresh_text;
|
||||
int num_displays = 0;
|
||||
SDL_DisplayID* displays = SDL_GetDisplays(&num_displays);
|
||||
if (displays && num_displays > 0) {
|
||||
if ((displays != nullptr) && num_displays > 0) {
|
||||
const auto* dm = SDL_GetCurrentDisplayMode(displays[0]);
|
||||
if (dm) {
|
||||
if (dm != nullptr) {
|
||||
refresh_text = "Refresh: " + std::to_string(static_cast<int>(dm->refresh_rate)) + " Hz";
|
||||
} else {
|
||||
refresh_text = "Refresh: N/A";
|
||||
@@ -322,9 +329,9 @@ void UIManager::renderDebugHUD(const Engine* engine,
|
||||
int hh = static_cast<int>(total_secs / 3600);
|
||||
int mm = static_cast<int>((total_secs % 3600) / 60);
|
||||
int ss = static_cast<int>(total_secs % 60);
|
||||
char elapsed_buf[32];
|
||||
SDL_snprintf(elapsed_buf, sizeof(elapsed_buf), "Elapsed: %02d:%02d:%02d", hh, mm, ss);
|
||||
std::string elapsed_text(elapsed_buf);
|
||||
std::array<char, 32> elapsed_buf{};
|
||||
SDL_snprintf(elapsed_buf.data(), elapsed_buf.size(), "Elapsed: %02d:%02d:%02d", hh, mm, ss);
|
||||
std::string elapsed_text(elapsed_buf.data());
|
||||
|
||||
// --- Construir vector de líneas en orden ---
|
||||
std::vector<std::string> lines;
|
||||
@@ -344,17 +351,15 @@ void UIManager::renderDebugHUD(const Engine* engine,
|
||||
if (!engine->isPostFXEnabled()) {
|
||||
postfx_text = "PostFX: OFF";
|
||||
} else {
|
||||
static constexpr const char* preset_names[4] = {
|
||||
"Vinyeta", "Scanlines", "Cromatica", "Complet"
|
||||
};
|
||||
static constexpr std::array<const char*, 4> PRESET_NAMES = {
|
||||
"Vinyeta",
|
||||
"Scanlines",
|
||||
"Cromatica",
|
||||
"Complet"};
|
||||
int mode = engine->getPostFXMode();
|
||||
char buf[64];
|
||||
SDL_snprintf(buf, sizeof(buf), "PostFX: %s [V:%.2f C:%.2f S:%.2f]",
|
||||
preset_names[mode],
|
||||
engine->getPostFXVignette(),
|
||||
engine->getPostFXChroma(),
|
||||
engine->getPostFXScanline());
|
||||
postfx_text = buf;
|
||||
std::array<char, 64> buf{};
|
||||
SDL_snprintf(buf.data(), buf.size(), "PostFX: %s [V:%.2f C:%.2f S:%.2f]", PRESET_NAMES[mode], engine->getPostFXVignette(), engine->getPostFXChroma(), engine->getPostFXScanline());
|
||||
postfx_text = buf.data();
|
||||
}
|
||||
lines.push_back(postfx_text);
|
||||
lines.push_back(elapsed_text);
|
||||
@@ -366,7 +371,7 @@ void UIManager::renderDebugHUD(const Engine* engine,
|
||||
SDL_FRect pos = first_ball->getPosition();
|
||||
lines.push_back("Pos: (" + std::to_string(static_cast<int>(pos.x)) + ", " + std::to_string(static_cast<int>(pos.y)) + ")");
|
||||
lines.push_back("Gravity: " + std::to_string(static_cast<int>(first_ball->getGravityForce())));
|
||||
lines.push_back(first_ball->isOnSurface() ? "Surface: YES" : "Surface: NO");
|
||||
lines.emplace_back(first_ball->isOnSurface() ? "Surface: YES" : "Surface: NO");
|
||||
lines.push_back("Loss: " + std::to_string(first_ball->getLossCoefficient()).substr(0, 4));
|
||||
lines.push_back("Dir: " + gravityDirectionToString(static_cast<int>(scene_manager->getCurrentGravity())));
|
||||
}
|
||||
@@ -378,29 +383,34 @@ void UIManager::renderDebugHUD(const Engine* engine,
|
||||
|
||||
// --- Render con desbordamiento a segunda columna ---
|
||||
int max_lines = (physical_viewport.h - 2 * margin) / line_height;
|
||||
if (max_lines < 1) max_lines = 1;
|
||||
max_lines = std::max(max_lines, 1);
|
||||
int col_width = physical_viewport.w / 2;
|
||||
|
||||
for (int i = 0; i < static_cast<int>(lines.size()); i++) {
|
||||
int col = i / max_lines;
|
||||
int row = i % max_lines;
|
||||
int x = margin + col * col_width;
|
||||
int y = margin + row * line_height;
|
||||
int x = margin + (col * col_width);
|
||||
int y = margin + (row * line_height);
|
||||
text_renderer_debug_->printAbsoluteShadowed(x, y, lines[i].c_str());
|
||||
}
|
||||
}
|
||||
|
||||
std::string UIManager::gravityDirectionToString(int direction) const {
|
||||
auto UIManager::gravityDirectionToString(int direction) -> std::string {
|
||||
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";
|
||||
case 0:
|
||||
return "Abajo"; // DOWN
|
||||
case 1:
|
||||
return "Arriba"; // UP
|
||||
case 2:
|
||||
return "Izquierda"; // LEFT
|
||||
case 3:
|
||||
return "Derecha"; // RIGHT
|
||||
default:
|
||||
return "Desconocida";
|
||||
}
|
||||
}
|
||||
|
||||
int UIManager::calculateFontSize(int logical_height) const {
|
||||
auto UIManager::calculateFontSize(int logical_height) -> int {
|
||||
// Escalado híbrido basado en ALTURA LÓGICA (resolución interna, sin zoom)
|
||||
// Esto asegura que el tamaño de fuente sea consistente independientemente del zoom de ventana
|
||||
// - Proporcional en extremos (muy bajo/alto)
|
||||
@@ -435,8 +445,8 @@ int UIManager::calculateFontSize(int logical_height) const {
|
||||
}
|
||||
|
||||
// Aplicar límites: mínimo 9px, máximo 72px
|
||||
if (font_size < 9) font_size = 9;
|
||||
if (font_size > 72) font_size = 72;
|
||||
font_size = std::max(font_size, 9);
|
||||
font_size = std::min(font_size, 72);
|
||||
|
||||
return font_size;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
#include <SDL3/SDL_stdinc.h> // for Uint64
|
||||
#include <string> // for std::string
|
||||
|
||||
#include <string> // for std::string
|
||||
|
||||
// Forward declarations
|
||||
struct SDL_Renderer;
|
||||
@@ -49,9 +50,7 @@ class UIManager {
|
||||
* @param logical_width Ancho lógico (resolución interna)
|
||||
* @param logical_height Alto lógico (resolución interna)
|
||||
*/
|
||||
void initialize(SDL_Renderer* renderer, ThemeManager* theme_manager,
|
||||
int physical_width, int physical_height,
|
||||
int logical_width, int logical_height);
|
||||
void initialize(SDL_Renderer* renderer, ThemeManager* theme_manager, int physical_width, int physical_height, int logical_width, int logical_height);
|
||||
|
||||
/**
|
||||
* @brief Actualiza UI (FPS counter, notificaciones, texto obsoleto)
|
||||
@@ -74,15 +73,15 @@ class UIManager {
|
||||
* @param current_screen_width Ancho lógico de pantalla (para texto centrado)
|
||||
*/
|
||||
void render(SDL_Renderer* renderer,
|
||||
const Engine* engine,
|
||||
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);
|
||||
const Engine* engine,
|
||||
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);
|
||||
|
||||
/**
|
||||
* @brief Toggle del debug HUD (tecla F12)
|
||||
@@ -138,31 +137,31 @@ class UIManager {
|
||||
* @param shape_convergence % de convergencia en LOGO mode
|
||||
*/
|
||||
void renderDebugHUD(const Engine* engine,
|
||||
const SceneManager* scene_manager,
|
||||
SimulationMode current_mode,
|
||||
AppMode current_app_mode,
|
||||
const Shape* active_shape,
|
||||
float shape_convergence);
|
||||
const SceneManager* scene_manager,
|
||||
SimulationMode current_mode,
|
||||
AppMode current_app_mode,
|
||||
const Shape* active_shape,
|
||||
float shape_convergence);
|
||||
|
||||
/**
|
||||
* @brief Convierte dirección de gravedad a string
|
||||
* @param direction Dirección como int (cast de GravityDirection)
|
||||
* @return String en español ("Abajo", "Arriba", etc.)
|
||||
*/
|
||||
std::string gravityDirectionToString(int direction) const;
|
||||
static std::string gravityDirectionToString(int direction);
|
||||
|
||||
/**
|
||||
* @brief Calcula tamaño de fuente apropiado según dimensiones lógicas
|
||||
* @param logical_height Alto lógico (resolución interna, sin zoom)
|
||||
* @return Tamaño de fuente (9-72px)
|
||||
*/
|
||||
int calculateFontSize(int logical_height) const;
|
||||
static int calculateFontSize(int logical_height);
|
||||
|
||||
// === Recursos de renderizado ===
|
||||
TextRenderer* text_renderer_debug_; // HUD de debug
|
||||
TextRenderer* text_renderer_notifier_; // Notificaciones
|
||||
Notifier* notifier_; // Sistema de notificaciones
|
||||
HelpOverlay* help_overlay_; // Overlay de ayuda (tecla H)
|
||||
TextRenderer* text_renderer_debug_; // HUD de debug
|
||||
TextRenderer* text_renderer_notifier_; // Notificaciones
|
||||
Notifier* notifier_; // Sistema de notificaciones
|
||||
HelpOverlay* help_overlay_; // Overlay de ayuda (tecla H)
|
||||
|
||||
// === Estado de UI ===
|
||||
bool show_debug_; // HUD de debug activo (tecla F12)
|
||||
@@ -175,13 +174,13 @@ class UIManager {
|
||||
std::string vsync_text_; // Texto "V-Sync: On/Off"
|
||||
|
||||
// === Referencias externas ===
|
||||
SDL_Renderer* renderer_; // Renderizador SDL3 (referencia)
|
||||
ThemeManager* theme_manager_; // Gestor de temas (para colores)
|
||||
int physical_window_width_; // Ancho físico de ventana (píxeles reales)
|
||||
int physical_window_height_; // Alto físico de ventana (píxeles reales)
|
||||
int logical_window_width_; // Ancho lógico (resolución interna)
|
||||
int logical_window_height_; // Alto lógico (resolución interna)
|
||||
SDL_Renderer* renderer_; // Renderizador SDL3 (referencia)
|
||||
ThemeManager* theme_manager_; // Gestor de temas (para colores)
|
||||
int physical_window_width_; // Ancho físico de ventana (píxeles reales)
|
||||
int physical_window_height_; // Alto físico de ventana (píxeles reales)
|
||||
int logical_window_width_; // Ancho lógico (resolución interna)
|
||||
int logical_window_height_; // Alto lógico (resolución interna)
|
||||
|
||||
// === Sistema de escalado dinámico de texto ===
|
||||
int current_font_size_; // Tamaño de fuente actual (9-72px)
|
||||
int current_font_size_; // Tamaño de fuente actual (9-72px)
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user