#include "logo.h" #include // Manejo de eventos de SDL (teclado, ratón, etc.) #include // Inicialización y limpieza de SDL #include // Manejo de logs en SDL #include // Funciones de temporización de SDL #include "global_inputs.h" // Funciones para manejar entradas globales #include "mouse.h" // Manejo de eventos del ratón #include "options.h" // Configuración global de opciones #include "s_sprite.h" // Clase para manejar sprites #include "screen.h" // Clase para manejar la pantalla #include "surface.h" // Clase para manejar superficies // Constructor de la clase Logo: inicializa los recursos necesarios Logo::Logo() { init(); } // Destructor de la clase Logo: libera los recursos utilizados Logo::~Logo() { close(); } // Método privado para inicializar los recursos del logotipo void Logo::init() { // Configura las prioridades de los logs SDL_SetLogPriority(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_INFO); SDL_SetLogPriority(SDL_LOG_CATEGORY_TEST, SDL_LOG_PRIORITY_ERROR); // Inicializa la pantalla Screen::get()->init(); // Carga la superficie del logotipo desde un archivo y la escala logo_surface = std::make_shared("jailgames.gif"); logo_surface->setTransparentColor(0); blackOutPalette(); // Crea el sprite del logotipo y lo posiciona en el centro de la pantalla logo_sprite = std::make_unique(logo_surface); logo_sprite->setPosition( (options.logo.width - logo_sprite->getWidth()) / 2, (options.logo.height - logo_sprite->getHeight()) / 2); // Inicia el contador de tiempo init_time = SDL_GetTicks(); // Log de inicio del logotipo SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "Logo start"); } // Método privado para liberar los recursos del logotipo void Logo::close() { // Destruye la pantalla Screen::get()->destroy(); // Log de finalización del logotipo SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "\nBye!"); // Finaliza SDL SDL_Quit(); } // Método privado para manejar los eventos de entrada void Logo::checkEvents() { SDL_Event event; while (SDL_PollEvent(&event)) // Procesa todos los eventos en la cola { switch (event.type) { case SDL_EVENT_QUIT: // Evento de salida (cerrar la ventana) options.logo.running = false; // Detiene el bucle principal return; } // Maneja entradas globales y eventos del ratón globalInputs::check(event); Mouse::handleEvent(event); } } // Método privado para actualizar el estado del logotipo void Logo::update() { // Comprueba si ha pasado suficiente tiempo para actualizar if (SDL_GetTicks() - ticks > options.logo.speed) { ticks = SDL_GetTicks(); // Actualiza el contador de ticks // Actualiza la pantalla Screen::get()->update(); // Gestiona los diferentes estados del logo updateState(); } } // Método privado para renderizar el logotipo en pantalla void Logo::render() { Screen::get()->start(); // Inicia el proceso de renderizado Screen::get()->clearSurface(0); // Limpia la superficie logo_sprite->render(); // Renderiza el sprite del logotipo Screen::get()->render(); // Finaliza el renderizado } // Método principal que ejecuta el ciclo de vida del logotipo int Logo::run() { while (options.logo.running) // Bucle principal mientras el logotipo esté activo { update(); // Actualiza el estado del logotipo checkEvents(); // Maneja los eventos de entrada render(); // Renderiza el logotipo } return 0; // Devuelve 0 al finalizar } // Transforma todos los colores de la paleta a negro void Logo::blackOutPalette() { for (int i = 1; i < 256; ++i) { Screen::get()->getRendererSurface()->setColor(i, 0xFF000000); } } // Gestiona los diferentes estados del logo void Logo::updateState() { switch (state) { case LogoState::BLACK: elapsed_time = SDL_GetTicks() - init_time; if (elapsed_time > 2000) { state = LogoState::LINES; init_time = SDL_GetTicks(); initSteps(); } break; case LogoState::LINES: elapsed_time = SDL_GetTicks() - init_time; if (elapsed_time > 20) { init_time = SDL_GetTicks(); if (advancePaletteStep(70, steps, max_step)) { state = LogoState::FLASH; } } break; case LogoState::FLASH: elapsed_time = SDL_GetTicks() - init_time; if (elapsed_time > 5) { init_time = SDL_GetTicks(); if (flashPalette(flash_step, max_flash_step)) { state = LogoState::COMPLETE; } else { ++flash_step; } } break; case LogoState::COMPLETE: elapsed_time = SDL_GetTicks() - init_time; if (elapsed_time > 5000) { state = LogoState::BLACK; init_time = SDL_GetTicks(); blackOutPalette(); } break; case LogoState::END: options.logo.running = false; break; default: break; } } bool Logo::advancePaletteStep(int size, int steps[], int max_step) { bool all_done = true; for (int i = 1; i < size; ++i) { if (steps[i] > 0 && steps[i] < max_step) { // Avanza un paso steps[i]++; // Calcula la intensidad del color int intensity = (steps[i] * 256) / max_step; if (intensity > 255) intensity = 255; // Actualiza el color al nuevo valor en formato ARGB Screen::get()->getRendererSurface()->setColor(i, 0xFF000000 | (intensity << 16) | (intensity << 8) | intensity); } if (i < size - 1 && steps[i + 1] >= 1 && steps[i] == 0) { // Inicia el paso de este color si el siguiente ha avanzado al menos dos pasos steps[i] = 1; Screen::get()->getRendererSurface()->setColor(i, 0xFF000000 | (64 << 16) | (64 << 8) | 64); // Paso inicial } if (steps[i] < max_step) { all_done = false; } } return all_done; } void Logo::initSteps() { std::fill(std::begin(steps), std::end(steps), 0); steps[69] = 1; flash_step = 0; } // Modifica los colores de la paleta para simular un flash bool Logo::flashPalette(int step, int maxSteps) { // Constantes para ajustar los porcentajes (en función de maxSteps) const float PERCENT_UP = 0.05f; const float PERCENT_HOLD = 0.3f; bool all_done = true; // Calcula los límites de cada fase basados en los porcentajes int stepUp = static_cast(PERCENT_UP * maxSteps); int stepHold = static_cast(PERCENT_HOLD * maxSteps) + stepUp; int stepDown = maxSteps; // La bajada ocupa el resto de los pasos // Calcula la intensidad según el paso actual int intensity = 0; if (step <= stepUp) { // Subida: incrementa la intensidad linealmente intensity = (step * 255) / stepUp; } else if (step <= stepHold) { // Mantenimiento: intensidad máxima intensity = 255; } else if (step <= stepDown) { // Bajada: decrementa la intensidad más lentamente int adjustedStep = step - stepHold; // Ajustamos el paso relativo a la bajada intensity = 255 - (adjustedStep * 255) / (stepDown - stepHold); } // Clampea la intensidad para garantizar que esté entre 0 y 255 intensity = std::clamp(intensity, 0, 255); // Calcula los colores para el efecto de flash Uint32 color0 = 0xFF000000 | (intensity << 16) | (intensity << 8) | intensity; Uint32 inverseColor = 0xFF000000 | ((255 - intensity) << 16) | ((255 - intensity) << 8) | (255 - intensity); // Aplica los colores calculados Screen::get()->getRendererSurface()->setColor(0, color0); for (int i = 1; i < 70; ++i) { Screen::get()->getRendererSurface()->setColor(i, inverseColor); } // Comprueba si hemos completado todos los pasos if (step >= maxSteps) { all_done = true; // Animación completada } else { all_done = false; // Aún quedan pasos pendientes } return all_done; }