#define _USE_MATH_DEFINES #include "color.h" #include // Para min, clamp #include // Para fmaxf, fminf, M_PI, fmodf, roundf, sin, abs #include // Para invalid_argument #include // Para basic_string, string // Método estático para crear Color desde string hexadecimal auto Color::fromHex(const std::string &hex_str) -> Color { std::string hex = hex_str; // Quitar '#' si existe if (!hex.empty() && hex[0] == '#') { hex = hex.substr(1); } // Verificar longitud válida (6 para RGB o 8 para RGBA) if (hex.length() != HEX_RGB_LENGTH && hex.length() != HEX_RGBA_LENGTH) { throw std::invalid_argument("String hexadecimal debe tener 6 o 8 caracteres"); } // Verificar que todos los caracteres sean hexadecimales válidos for (char c : hex) { if (std::isxdigit(c) == 0) { throw std::invalid_argument("String contiene caracteres no hexadecimales"); } } // Convertir cada par de caracteres a valores RGB(A) Uint8 r = static_cast(std::stoi(hex.substr(0, HEX_COMPONENT_LENGTH), nullptr, HEX_BASE)); Uint8 g = static_cast(std::stoi(hex.substr(HEX_COMPONENT_LENGTH, HEX_COMPONENT_LENGTH), nullptr, HEX_BASE)); Uint8 b = static_cast(std::stoi(hex.substr(HEX_COMPONENT_LENGTH * 2, HEX_COMPONENT_LENGTH), nullptr, HEX_BASE)); Uint8 a = DEFAULT_ALPHA; // Alpha por defecto // Si tiene 8 caracteres, extraer el alpha if (hex.length() == HEX_RGBA_LENGTH) { a = static_cast(std::stoi(hex.substr(HEX_COMPONENT_LENGTH * 3, HEX_COMPONENT_LENGTH), nullptr, HEX_BASE)); } return Color(r, g, b, a); } // Obtiene un color del vector de colores imitando al Coche Fantástico auto getColorLikeKnightRider(const std::vector &colors, int counter) -> Color { int cycle_length = colors.size() * 2 - 2; size_t n = counter % cycle_length; size_t index; if (n < colors.size()) { index = n; // Avanza: 0,1,2,3 } else { index = 2 * (colors.size() - 1) - n; // Retrocede: 2,1 } return colors[index]; } constexpr auto rgbToHsv(Color color) -> HSV { float r = color.r / 255.0F; float g = color.g / 255.0F; float b = color.b / 255.0F; float max = fmaxf(fmaxf(r, g), b); float min = fminf(fminf(r, g), b); float delta = max - min; float h = 0.0F; if (delta > 0.00001F) { if (max == r) { h = fmodf((g - b) / delta, 6.0F); } else if (max == g) { h = ((b - r) / delta) + 2.0F; } else { h = ((r - g) / delta) + 4.0F; } h *= 60.0F; if (h < 0.0F) { h += 360.0F; } } float s = (max <= 0.0F) ? 0.0F : delta / max; float v = max; return {h, s, v}; } constexpr auto hsvToRgb(HSV hsv) -> Color { float c = hsv.v * hsv.s; float x = c * (1 - std::abs(std::fmod(hsv.h / 60.0F, 2) - 1)); float m = hsv.v - c; float r = 0; float g = 0; float b = 0; if (hsv.h < 60) { r = c; g = x; b = 0; } else if (hsv.h < 120) { r = x; g = c; b = 0; } else if (hsv.h < 180) { r = 0; g = c; b = x; } else if (hsv.h < 240) { r = 0; g = x; b = c; } else if (hsv.h < 300) { r = x; g = 0; b = c; } else { r = c; g = 0; b = x; } return Color( static_cast(roundf((r + m) * 255)), static_cast(roundf((g + m) * 255)), static_cast(roundf((b + m) * 255))); } auto generateMirroredCycle(Color base, ColorCycleStyle style) -> ColorCycle { ColorCycle result{}; HSV base_hsv = rgbToHsv(base); for (size_t i = 0; i < COLOR_CYCLE_SIZE; ++i) { float t = static_cast(i) / (COLOR_CYCLE_SIZE - 1); // 0 → 1 float hue_shift = 0.0F; float sat_shift = 0.0F; float val_shift = 0.0F; switch (style) { case ColorCycleStyle::SUBTLE_PULSE: // Solo brillo suave val_shift = 0.07F * sinf(t * M_PI); break; case ColorCycleStyle::HUE_WAVE: // Oscilación leve de tono hue_shift = 15.0F * (t - 0.5F) * 2.0F; val_shift = 0.05F * sinf(t * M_PI); break; case ColorCycleStyle::VIBRANT: // Cambios fuertes en tono y brillo hue_shift = 35.0F * sinf(t * M_PI); val_shift = 0.2F * sinf(t * M_PI); sat_shift = -0.2F * sinf(t * M_PI); break; case ColorCycleStyle::DARKEN_GLOW: // Se oscurece al centro val_shift = -0.15F * sinf(t * M_PI); break; case ColorCycleStyle::LIGHT_FLASH: // Se ilumina al centro val_shift = 0.25F * sinf(t * M_PI); break; } HSV adjusted = { fmodf(base_hsv.h + hue_shift + 360.0F, 360.0F), fminf(1.0F, fmaxf(0.0F, base_hsv.s + sat_shift)), fminf(1.0F, fmaxf(0.0F, base_hsv.v + val_shift))}; Color c = hsvToRgb(adjusted); result[i] = c; result[2 * COLOR_CYCLE_SIZE - 1 - i] = c; // espejo } return result; }