#include "dynamic_theme.hpp" #include // for std::min DynamicTheme::DynamicTheme(const char* name_en, const char* name_es, int text_r, int text_g, int text_b, std::vector keyframes, bool loop) : name_en_(name_en), name_es_(name_es), text_r_(text_r), text_g_(text_g), text_b_(text_b), keyframes_(std::move(keyframes)), loop_(loop), current_keyframe_index_(0), target_keyframe_index_(1), transition_progress_(0.0f), paused_(false) { // Validación: mínimo 2 keyframes if (keyframes_.size() < 2) { // Fallback: duplicar primer keyframe si solo hay 1 if (keyframes_.size() == 1) { keyframes_.push_back(keyframes_[0]); } } // Asegurar que target_keyframe_index es válido if (target_keyframe_index_ >= keyframes_.size()) { target_keyframe_index_ = 0; } } void DynamicTheme::update(float delta_time) { if (paused_) return; // No actualizar si está pausado // Obtener duración del keyframe objetivo float duration = keyframes_[target_keyframe_index_].duration; if (duration <= 0.0f) { duration = 1.0f; // Fallback si duración inválida } // Avanzar progreso transition_progress_ += delta_time / duration; // Si completamos la transición, avanzar al siguiente keyframe if (transition_progress_ >= 1.0f) { advanceToNextKeyframe(); } } void DynamicTheme::resetProgress() { current_keyframe_index_ = 0; target_keyframe_index_ = 1; if (target_keyframe_index_ >= keyframes_.size()) { target_keyframe_index_ = 0; } transition_progress_ = 0.0f; } void DynamicTheme::advanceToNextKeyframe() { // Mover al siguiente keyframe current_keyframe_index_ = target_keyframe_index_; target_keyframe_index_++; // Loop: volver al inicio si llegamos al final if (target_keyframe_index_ >= keyframes_.size()) { if (loop_) { target_keyframe_index_ = 0; } else { // Si no hay loop, quedarse en el último keyframe target_keyframe_index_ = keyframes_.size() - 1; } } // Reiniciar progreso transition_progress_ = 0.0f; } Color DynamicTheme::getBallColor(size_t ball_index, float progress) const { // Obtener keyframes actual y objetivo const auto& current_kf = keyframes_[current_keyframe_index_]; const auto& target_kf = keyframes_[target_keyframe_index_]; // Si paletas vacías, retornar blanco if (current_kf.ball_colors.empty() || target_kf.ball_colors.empty()) { return {255, 255, 255}; } // Obtener colores de ambos keyframes (con wrap) size_t current_palette_size = current_kf.ball_colors.size(); size_t target_palette_size = target_kf.ball_colors.size(); Color c1 = current_kf.ball_colors[ball_index % current_palette_size]; Color c2 = target_kf.ball_colors[ball_index % target_palette_size]; // Interpolar entre ambos colores usando progreso interno // (progress parámetro será usado en PHASE 3 para LERP externo) float t = transition_progress_; return { static_cast(lerp(c1.r, c2.r, t)), static_cast(lerp(c1.g, c2.g, t)), static_cast(lerp(c1.b, c2.b, t)) }; } void DynamicTheme::getBackgroundColors(float progress, float& tr, float& tg, float& tb, float& br, float& bg, float& bb) const { // Obtener keyframes actual y objetivo const auto& current_kf = keyframes_[current_keyframe_index_]; const auto& target_kf = keyframes_[target_keyframe_index_]; // Interpolar colores de fondo usando progreso interno // (progress parámetro será usado en PHASE 3 para LERP externo) float t = transition_progress_; tr = lerp(current_kf.bg_top_r, target_kf.bg_top_r, t); tg = lerp(current_kf.bg_top_g, target_kf.bg_top_g, t); tb = lerp(current_kf.bg_top_b, target_kf.bg_top_b, t); br = lerp(current_kf.bg_bottom_r, target_kf.bg_bottom_r, t); bg = lerp(current_kf.bg_bottom_g, target_kf.bg_bottom_g, t); bb = lerp(current_kf.bg_bottom_b, target_kf.bg_bottom_b, t); } void DynamicTheme::getNotificationBackgroundColor(int& r, int& g, int& b) const { // Obtener keyframes actual y objetivo const auto& current_kf = keyframes_[current_keyframe_index_]; const auto& target_kf = keyframes_[target_keyframe_index_]; // Interpolar color de fondo de notificación usando progreso interno float t = transition_progress_; r = static_cast(lerp(static_cast(current_kf.notif_bg_r), static_cast(target_kf.notif_bg_r), t)); g = static_cast(lerp(static_cast(current_kf.notif_bg_g), static_cast(target_kf.notif_bg_g), t)); b = static_cast(lerp(static_cast(current_kf.notif_bg_b), static_cast(target_kf.notif_bg_b), t)); }