#include "app_logo.hpp" #include // for SDL_DestroyTexture, SDL_RenderGeometry, SDL_SetTextureAlphaMod #include // for powf, sinf, cosf #include // for free() #include // for std::cout #include "logo_scaler.hpp" // for LogoScaler #include "defines.hpp" // for APPLOGO_HEIGHT_PERCENT, getResourcesDirectory // ============================================================================ // Destructor - Liberar las 4 texturas SDL // ============================================================================ AppLogo::~AppLogo() { 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; } } // ============================================================================ // Inicialización - Pre-escalar logos a 2 resoluciones (base y nativa) // ============================================================================ bool AppLogo::initialize(SDL_Renderer* renderer, int screen_width, int screen_height) { renderer_ = renderer; base_screen_width_ = screen_width; base_screen_height_ = screen_height; screen_width_ = screen_width; screen_height_ = screen_height; std::string resources_dir = getResourcesDirectory(); // ======================================================================== // 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; // Fallback: usar resolución base como nativa native_screen_width_ = screen_width; native_screen_height_ = screen_height; } // ======================================================================== // 2. Calcular alturas finales para ambas resoluciones // ======================================================================== int logo_base_target_height = static_cast(base_screen_height_ * APPLOGO_HEIGHT_PERCENT); int logo_native_target_height = static_cast(native_screen_height_ * APPLOGO_HEIGHT_PERCENT); std::cout << "Pre-escalando logos:" << std::endl; std::cout << " Base: " << base_screen_width_ << "x" << base_screen_height_ << " (altura logo: " << logo_base_target_height << "px)" << std::endl; std::cout << " Nativa: " << native_screen_width_ << "x" << native_screen_height_ << " (altura logo: " << logo_native_target_height << "px)" << std::endl; // ======================================================================== // 3. Cargar y escalar LOGO1 (data/logo/logo.png) a 2 versiones // ======================================================================== std::string logo1_path = resources_dir + "/data/logo/logo.png"; // 3a. Versión BASE de logo1 unsigned char* logo1_base_data = LogoScaler::loadAndScale( logo1_path, 0, // width calculado automáticamente por aspect ratio logo_base_target_height, logo1_base_width_, logo1_base_height_ ); if (logo1_base_data == nullptr) { std::cout << "Error: No se pudo escalar logo1 (base)" << std::endl; return false; } logo1_base_texture_ = LogoScaler::createTextureFromBuffer( 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; return false; } // Habilitar alpha blending SDL_SetTextureBlendMode(logo1_base_texture_, SDL_BLENDMODE_BLEND); // 3b. Versión NATIVA de logo1 unsigned char* logo1_native_data = LogoScaler::loadAndScale( logo1_path, 0, // width calculado automáticamente logo_native_target_height, logo1_native_width_, logo1_native_height_ ); if (logo1_native_data == nullptr) { std::cout << "Error: No se pudo escalar logo1 (nativa)" << std::endl; return false; } logo1_native_texture_ = LogoScaler::createTextureFromBuffer( 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; return false; } SDL_SetTextureBlendMode(logo1_native_texture_, SDL_BLENDMODE_BLEND); // ======================================================================== // 4. Cargar y escalar LOGO2 (data/logo/logo2.png) a 2 versiones // ======================================================================== std::string logo2_path = resources_dir + "/data/logo/logo2.png"; // 4a. Versión BASE de logo2 unsigned char* logo2_base_data = LogoScaler::loadAndScale( logo2_path, 0, logo_base_target_height, logo2_base_width_, logo2_base_height_ ); if (logo2_base_data == nullptr) { std::cout << "Error: No se pudo escalar logo2 (base)" << std::endl; return false; } logo2_base_texture_ = LogoScaler::createTextureFromBuffer( 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; return false; } SDL_SetTextureBlendMode(logo2_base_texture_, SDL_BLENDMODE_BLEND); // 4b. Versión NATIVA de logo2 unsigned char* logo2_native_data = LogoScaler::loadAndScale( logo2_path, 0, logo_native_target_height, logo2_native_width_, logo2_native_height_ ); if (logo2_native_data == nullptr) { std::cout << "Error: No se pudo escalar logo2 (nativa)" << std::endl; return false; } logo2_native_texture_ = LogoScaler::createTextureFromBuffer( 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; return false; } SDL_SetTextureBlendMode(logo2_native_texture_, SDL_BLENDMODE_BLEND); // ======================================================================== // 5. Inicialmente usar texturas BASE (la resolución de inicio) // ======================================================================== logo1_current_texture_ = logo1_base_texture_; logo1_current_width_ = logo1_base_width_; logo1_current_height_ = logo1_base_height_; logo2_current_texture_ = logo2_base_texture_; logo2_current_width_ = logo2_base_width_; logo2_current_height_ = logo2_base_height_; std::cout << "Logos pre-escalados exitosamente (4 texturas creadas)" << std::endl; 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; logo1_alpha_ = 0; logo2_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; logo1_alpha_ = 0; logo2_alpha_ = 0; // Elegir UNA animación aleatoria (misma para ambos logos, misma entrada y salida) current_animation_ = getRandomAnimation(); } break; case AppLogoState::FADE_IN: // Fade in: alpha de 0 a 255, con Logo 2 retrasado 0.25s { // Calcular progreso de cada logo (Logo 2 con retraso) float fade_progress_logo1 = timer_ / APPLOGO_ANIMATION_DURATION; float fade_progress_logo2 = std::max(0.0f, (timer_ - APPLOGO_LOGO2_DELAY) / APPLOGO_ANIMATION_DURATION); // Verificar si fade in completado (cuando logo2 también termina) if (fade_progress_logo2 >= 1.0f) { // Fade in completado para ambos logos state_ = AppLogoState::VISIBLE; timer_ = 0.0f; logo1_alpha_ = 255; logo2_alpha_ = 255; // Resetear variables de ambos logos logo1_scale_ = 1.0f; logo1_squash_y_ = 1.0f; logo1_stretch_x_ = 1.0f; logo1_rotation_ = 0.0f; logo2_scale_ = 1.0f; logo2_squash_y_ = 1.0f; logo2_stretch_x_ = 1.0f; logo2_rotation_ = 0.0f; } else { // Interpolar alpha con retraso de forma LINEAL (sin easing) logo1_alpha_ = static_cast(std::min(1.0f, fade_progress_logo1) * 255.0f); logo2_alpha_ = static_cast(std::min(1.0f, fade_progress_logo2) * 255.0f); // ================================================================ // Aplicar MISMA animación (current_animation_) a ambos logos // con sus respectivos progresos // ================================================================ switch (current_animation_) { case AppLogoAnimationType::ZOOM_ONLY: logo1_scale_ = 1.2f - (std::min(1.0f, fade_progress_logo1) * 0.2f); logo1_squash_y_ = 1.0f; logo1_stretch_x_ = 1.0f; logo1_rotation_ = 0.0f; logo2_scale_ = 1.2f - (std::min(1.0f, fade_progress_logo2) * 0.2f); logo2_squash_y_ = 1.0f; logo2_stretch_x_ = 1.0f; 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; 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; 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; 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; } } } break; case AppLogoState::VISIBLE: // Logo completamente visible, esperando duración if (timer_ >= APPLOGO_DISPLAY_DURATION) { state_ = AppLogoState::FADE_OUT; timer_ = 0.0f; logo1_alpha_ = 255; logo2_alpha_ = 255; // NO elegir nueva animación - reutilizar current_animation_ (simetría entrada/salida) } break; case AppLogoState::FADE_OUT: // Fade out: alpha de 255 a 0, con Logo 2 retrasado 0.25s (misma animación que entrada) { // Calcular progreso de cada logo (Logo 2 con retraso) float fade_progress_logo1 = timer_ / APPLOGO_ANIMATION_DURATION; float fade_progress_logo2 = std::max(0.0f, (timer_ - APPLOGO_LOGO2_DELAY) / APPLOGO_ANIMATION_DURATION); // Verificar si fade out completado (cuando logo2 también termina) if (fade_progress_logo2 >= 1.0f) { // Fade out completado, volver a HIDDEN state_ = AppLogoState::HIDDEN; timer_ = 0.0f; logo1_alpha_ = 0; logo2_alpha_ = 0; // Resetear variables de ambos logos logo1_scale_ = 1.0f; logo1_squash_y_ = 1.0f; logo1_stretch_x_ = 1.0f; logo1_rotation_ = 0.0f; logo2_scale_ = 1.0f; logo2_squash_y_ = 1.0f; logo2_stretch_x_ = 1.0f; logo2_rotation_ = 0.0f; } else { // Interpolar alpha con retraso de forma LINEAL (255 → 0, sin easing) logo1_alpha_ = static_cast((1.0f - std::min(1.0f, fade_progress_logo1)) * 255.0f); logo2_alpha_ = static_cast((1.0f - std::min(1.0f, fade_progress_logo2)) * 255.0f); // ================================================================ // Aplicar MISMA animación (current_animation_) de forma invertida // ================================================================ switch (current_animation_) { case AppLogoAnimationType::ZOOM_ONLY: logo1_scale_ = 1.0f + (std::min(1.0f, fade_progress_logo1) * 0.2f); logo1_squash_y_ = 1.0f; logo1_stretch_x_ = 1.0f; logo1_rotation_ = 0.0f; logo2_scale_ = 1.0f + (std::min(1.0f, fade_progress_logo2) * 0.2f); logo2_squash_y_ = 1.0f; logo2_stretch_x_ = 1.0f; 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; 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); } 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; } } } break; } } void AppLogo::render() { // Renderizar si NO está en estado HIDDEN (incluye FADE_IN, VISIBLE, FADE_OUT) if (state_ != AppLogoState::HIDDEN) { // Renderizar LOGO1 primero (fondo), luego LOGO2 (encima) renderWithGeometry(1); renderWithGeometry(2); } } void AppLogo::updateScreenSize(int screen_width, int screen_height) { screen_width_ = screen_width; screen_height_ = screen_height; // ======================================================================== // Detectar si coincide con resolución nativa o base, cambiar texturas // ======================================================================== bool is_native = (screen_width == native_screen_width_ && screen_height == native_screen_height_); if (is_native) { // Cambiar a texturas nativas (F4 fullscreen) logo1_current_texture_ = logo1_native_texture_; logo1_current_width_ = logo1_native_width_; logo1_current_height_ = logo1_native_height_; logo2_current_texture_ = logo2_native_texture_; logo2_current_width_ = logo2_native_width_; logo2_current_height_ = logo2_native_height_; std::cout << "AppLogo: Cambiado a texturas NATIVAS" << std::endl; } else { // Cambiar a texturas base (ventana redimensionable) logo1_current_texture_ = logo1_base_texture_; logo1_current_width_ = logo1_base_width_; logo1_current_height_ = logo1_base_height_; logo2_current_texture_ = logo2_base_texture_; logo2_current_width_ = logo2_base_width_; logo2_current_height_ = logo2_base_height_; std::cout << "AppLogo: Cambiado a texturas BASE" << std::endl; } // Nota: No es necesario recalcular escalas porque las texturas están pre-escaladas // al tamaño exacto de pantalla. Solo renderizamos al 100% (o con deformaciones de animación). } // ============================================================================ // Funciones de easing para animaciones // ============================================================================ float AppLogo::easeOutElastic(float t) { // Elastic easing out: bounce elástico al final const float c4 = (2.0f * 3.14159f) / 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; } } float AppLogo::easeInOutQuad(float t) { // 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; } } // ============================================================================ // Función auxiliar para aleatorización // ============================================================================ AppLogoAnimationType AppLogo::getRandomAnimation() { // Generar número aleatorio entre 0 y 3 (4 tipos de animación) int random_value = rand() % 4; switch (random_value) { case 0: return AppLogoAnimationType::ZOOM_ONLY; case 1: return AppLogoAnimationType::ELASTIC_STICK; case 2: return AppLogoAnimationType::ROTATE_SPIRAL; case 3: default: return AppLogoAnimationType::BOUNCE_SQUASH; } } // ============================================================================ // Renderizado con geometría (para todos los logos, con deformaciones) // ============================================================================ void AppLogo::renderWithGeometry(int logo_index) { if (!renderer_) 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; if (logo_index == 1) { if (!logo1_current_texture_) return; texture = logo1_current_texture_; base_width = logo1_current_width_; base_height = logo1_current_height_; scale = logo1_scale_; squash_y = logo1_squash_y_; stretch_x = logo1_stretch_x_; rotation = logo1_rotation_; } else if (logo_index == 2) { if (!logo2_current_texture_) return; texture = logo2_current_texture_; base_width = logo2_current_width_; base_height = logo2_current_height_; scale = logo2_scale_; squash_y = logo2_squash_y_; stretch_x = logo2_stretch_x_; rotation = logo2_rotation_; } else { return; // Índice inválido } // Aplicar alpha específico de cada logo (con retraso para logo2) int alpha = (logo_index == 1) ? logo1_alpha_ : logo2_alpha_; float alpha_normalized = static_cast(alpha) / 255.0f; // Convertir 0-255 → 0.0-1.0 // NO usar SDL_SetTextureAlphaMod - aplicar alpha directamente a vértices // Calcular padding desde bordes derecho e inferior float padding_x = screen_width_ * APPLOGO_PADDING_PERCENT; float padding_y = screen_height_ * APPLOGO_PADDING_PERCENT; // Calcular esquina BASE (sin escala) para obtener centro FIJO // Esto asegura que el centro no se mueva cuando cambia scale/squash/stretch float corner_x_base = screen_width_ - base_width - padding_x; float corner_y_base = screen_height_ - base_height - padding_y; // Centro FIJO del logo (no cambia con scale/squash/stretch) float center_x = corner_x_base + (base_width / 2.0f); float center_y = corner_y_base + (base_height / 2.0f); // Calcular tamaño ESCALADO (para vértices) // (base_width y base_height ya están pre-escalados al tamaño correcto de pantalla) float width = base_width * scale * stretch_x; float height = base_height * scale * squash_y; // Pre-calcular seno y coseno de rotación float cos_rot = cosf(rotation); float sin_rot = sinf(rotation); // Crear 4 vértices del quad (centrado en center_x, center_y) SDL_Vertex vertices[4]; // Offset desde el centro float half_w = width / 2.0f; float half_h = height / 2.0f; // Vértice superior 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[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 } // 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 } // 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 } // 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 } // Índices para 2 triángulos int indices[6] = {0, 1, 2, 2, 3, 0}; // Renderizar con la textura del logo correspondiente SDL_RenderGeometry(renderer_, texture, vertices, 4, indices, 6); }