feat: Sistema de logo periódico con fade in/out
- Nuevo sistema AppLogo que muestra el logo cada 20 segundos por 5 segundos - Fade in/out suave de 0.5 segundos con alpha blending - Máquina de estados: HIDDEN → FADE_IN → VISIBLE → FADE_OUT - Logo posicionado en cuadrante inferior derecho (1/4 de pantalla) - Añadido método setAlpha() a Texture para control de transparencia - Habilitado SDL_BLENDMODE_BLEND en todas las texturas - Filtrado LINEAR para suavizado del logo escalado - Desactivado automáticamente en modo SANDBOX 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
185
source/app_logo.cpp
Normal file
185
source/app_logo.cpp
Normal file
@@ -0,0 +1,185 @@
|
||||
#include "app_logo.h"
|
||||
|
||||
#include <SDL3/SDL_render.h> // for SDL_SCALEMODE_LINEAR
|
||||
|
||||
#include "external/sprite.h" // for Sprite
|
||||
#include "external/texture.h" // for Texture
|
||||
|
||||
bool AppLogo::initialize(SDL_Renderer* renderer, int screen_width, int screen_height) {
|
||||
screen_width_ = screen_width;
|
||||
screen_height_ = screen_height;
|
||||
|
||||
// Cargar textura del logo desde data/logo/logo.png
|
||||
std::string resources_dir = getResourcesDirectory();
|
||||
std::string logo_path = resources_dir + "/data/logo/logo.png";
|
||||
|
||||
logo_texture_ = std::make_shared<Texture>(renderer, logo_path);
|
||||
if (logo_texture_->getWidth() == 0 || logo_texture_->getHeight() == 0) {
|
||||
// Error al cargar textura
|
||||
return false;
|
||||
}
|
||||
|
||||
// Configurar filtrado LINEAR para suavizado (mejor para logos escalados)
|
||||
logo_texture_->setScaleMode(SDL_SCALEMODE_LINEAR);
|
||||
|
||||
// Crear sprite con la textura
|
||||
logo_sprite_ = std::make_unique<Sprite>(logo_texture_);
|
||||
|
||||
// IMPORTANTE: Configurar el clip para que use toda la textura
|
||||
float logo_width = static_cast<float>(logo_texture_->getWidth());
|
||||
float logo_height = static_cast<float>(logo_texture_->getHeight());
|
||||
logo_sprite_->setClip({0.0f, 0.0f, logo_width, logo_height});
|
||||
|
||||
// Calcular factor de escala para que el logo ocupe 1/4 de la pantalla (un cuadrante)
|
||||
// El logo debe caber en width/2 x height/2
|
||||
float quadrant_width = screen_width_ / 2.0f;
|
||||
float quadrant_height = screen_height_ / 2.0f;
|
||||
|
||||
float scale_x = quadrant_width / logo_width;
|
||||
float scale_y = quadrant_height / logo_height;
|
||||
float scale = (scale_x < scale_y) ? scale_x : scale_y;
|
||||
|
||||
// Aplicar escala
|
||||
float scaled_width = logo_width * scale;
|
||||
float scaled_height = logo_height * scale;
|
||||
logo_sprite_->setSize(scaled_width, scaled_height);
|
||||
|
||||
// Posicionar logo en el centro del cuadrante inferior derecho
|
||||
updateLogoPosition();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void AppLogo::update(float delta_time, AppMode current_mode) {
|
||||
// Si estamos en SANDBOX, resetear y no hacer nada (logo desactivado)
|
||||
if (current_mode == AppMode::SANDBOX) {
|
||||
state_ = AppLogoState::HIDDEN;
|
||||
timer_ = 0.0f;
|
||||
current_alpha_ = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
// Máquina de estados con fade in/out
|
||||
timer_ += delta_time;
|
||||
|
||||
switch (state_) {
|
||||
case AppLogoState::HIDDEN:
|
||||
// Esperando el intervalo de espera
|
||||
if (timer_ >= APPLOGO_DISPLAY_INTERVAL) {
|
||||
state_ = AppLogoState::FADE_IN;
|
||||
timer_ = 0.0f;
|
||||
current_alpha_ = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case AppLogoState::FADE_IN:
|
||||
// Fade in: alpha de 0 a 255
|
||||
{
|
||||
float fade_progress = timer_ / APPLOGO_FADE_DURATION;
|
||||
if (fade_progress >= 1.0f) {
|
||||
// Fade in completado
|
||||
state_ = AppLogoState::VISIBLE;
|
||||
timer_ = 0.0f;
|
||||
current_alpha_ = 255;
|
||||
} else {
|
||||
// Interpolar alpha linealmente
|
||||
current_alpha_ = static_cast<int>(fade_progress * 255.0f);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case AppLogoState::VISIBLE:
|
||||
// Logo completamente visible, esperando duración
|
||||
if (timer_ >= APPLOGO_DISPLAY_DURATION) {
|
||||
state_ = AppLogoState::FADE_OUT;
|
||||
timer_ = 0.0f;
|
||||
current_alpha_ = 255;
|
||||
}
|
||||
break;
|
||||
|
||||
case AppLogoState::FADE_OUT:
|
||||
// Fade out: alpha de 255 a 0
|
||||
{
|
||||
float fade_progress = timer_ / APPLOGO_FADE_DURATION;
|
||||
if (fade_progress >= 1.0f) {
|
||||
// Fade out completado, volver a HIDDEN
|
||||
state_ = AppLogoState::HIDDEN;
|
||||
timer_ = 0.0f;
|
||||
current_alpha_ = 0;
|
||||
} else {
|
||||
// Interpolar alpha linealmente (inverso)
|
||||
current_alpha_ = static_cast<int>((1.0f - fade_progress) * 255.0f);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// Aplicar alpha a la textura
|
||||
if (logo_texture_) {
|
||||
logo_texture_->setAlpha(current_alpha_);
|
||||
}
|
||||
}
|
||||
|
||||
void AppLogo::render() {
|
||||
// Renderizar si NO está en estado HIDDEN (incluye FADE_IN, VISIBLE, FADE_OUT)
|
||||
if (state_ != AppLogoState::HIDDEN && logo_sprite_) {
|
||||
logo_sprite_->render();
|
||||
}
|
||||
}
|
||||
|
||||
void AppLogo::updateScreenSize(int screen_width, int screen_height) {
|
||||
screen_width_ = screen_width;
|
||||
screen_height_ = screen_height;
|
||||
|
||||
// Recalcular escala y posición del logo
|
||||
if (logo_sprite_ && logo_texture_) {
|
||||
float logo_width = static_cast<float>(logo_texture_->getWidth());
|
||||
float logo_height = static_cast<float>(logo_texture_->getHeight());
|
||||
|
||||
// Calcular factor de escala para que el logo ocupe 1/4 de la pantalla
|
||||
float quadrant_width = screen_width_ / 2.0f;
|
||||
float quadrant_height = screen_height_ / 2.0f;
|
||||
|
||||
float scale_x = quadrant_width / logo_width;
|
||||
float scale_y = quadrant_height / logo_height;
|
||||
float scale = (scale_x < scale_y) ? scale_x : scale_y;
|
||||
|
||||
// Aplicar escala
|
||||
float scaled_width = logo_width * scale;
|
||||
float scaled_height = logo_height * scale;
|
||||
logo_sprite_->setSize(scaled_width, scaled_height);
|
||||
|
||||
// Posicionar logo
|
||||
updateLogoPosition();
|
||||
}
|
||||
}
|
||||
|
||||
void AppLogo::updateLogoPosition() {
|
||||
if (!logo_sprite_ || !logo_texture_) return;
|
||||
|
||||
// Calcular tamaño escalado del logo (ya configurado en setSize)
|
||||
float logo_width = static_cast<float>(logo_texture_->getWidth());
|
||||
float logo_height = static_cast<float>(logo_texture_->getHeight());
|
||||
|
||||
float quadrant_width = screen_width_ / 2.0f;
|
||||
float quadrant_height = screen_height_ / 2.0f;
|
||||
|
||||
float scale_x = quadrant_width / logo_width;
|
||||
float scale_y = quadrant_height / logo_height;
|
||||
float scale = (scale_x < scale_y) ? scale_x : scale_y;
|
||||
|
||||
float scaled_width = logo_width * scale;
|
||||
float scaled_height = logo_height * scale;
|
||||
|
||||
// Centro del cuadrante inferior derecho
|
||||
// Cuadrante inferior derecho va de (width/2, height/2) a (width, height)
|
||||
// Su centro está en (3/4 * width, 3/4 * height)
|
||||
float quadrant_center_x = screen_width_ * 0.75f;
|
||||
float quadrant_center_y = screen_height_ * 0.75f;
|
||||
|
||||
// Centrar el logo en ese punto (sprite se posiciona por esquina superior izquierda)
|
||||
float pos_x = quadrant_center_x - (scaled_width / 2.0f);
|
||||
float pos_y = quadrant_center_y - (scaled_height / 2.0f);
|
||||
|
||||
logo_sprite_->setPos({pos_x, pos_y});
|
||||
}
|
||||
Reference in New Issue
Block a user