reestructuració
This commit is contained in:
@@ -0,0 +1,186 @@
|
||||
#define _USE_MATH_DEFINES
|
||||
#include "color.hpp"
|
||||
|
||||
#include <cctype> // Para isxdigit
|
||||
#include <cmath> // Para sinf, fmaxf, fminf, M_PI, fmodf, roundf, fmod
|
||||
#include <cstdint> // Para uint8_t
|
||||
#include <stdexcept> // Para invalid_argument
|
||||
#include <string> // Para basic_string, stoi, 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<Uint8>(std::stoi(hex.substr(0, HEX_COMPONENT_LENGTH), nullptr, HEX_BASE));
|
||||
Uint8 g = static_cast<Uint8>(std::stoi(hex.substr(HEX_COMPONENT_LENGTH, HEX_COMPONENT_LENGTH), nullptr, HEX_BASE));
|
||||
Uint8 b = static_cast<Uint8>(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<Uint8>(std::stoi(hex.substr(HEX_COMPONENT_LENGTH * 3, HEX_COMPONENT_LENGTH), nullptr, HEX_BASE));
|
||||
}
|
||||
|
||||
return Color(r, g, b, a);
|
||||
}
|
||||
|
||||
// Implementaciones de métodos estáticos de Color
|
||||
constexpr auto Color::RGB_TO_HSV(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 = h, .s = s, .v = v};
|
||||
}
|
||||
|
||||
constexpr auto Color::HSV_TO_RGB(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<uint8_t>(roundf((r + m) * 255)),
|
||||
static_cast<uint8_t>(roundf((g + m) * 255)),
|
||||
static_cast<uint8_t>(roundf((b + m) * 255)));
|
||||
}
|
||||
|
||||
// Implementaciones del namespace Colors
|
||||
namespace Colors {
|
||||
// Obtiene un color del vector de colores imitando al Coche Fantástico
|
||||
auto getColorLikeKnightRider(const std::vector<Color>& 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];
|
||||
}
|
||||
|
||||
auto generateMirroredCycle(Color base, ColorCycleStyle style) -> Cycle {
|
||||
Cycle result{};
|
||||
HSV base_hsv = Color::RGB_TO_HSV(base);
|
||||
|
||||
for (size_t i = 0; i < CYCLE_SIZE; ++i) {
|
||||
float t = static_cast<float>(i) / (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 = {
|
||||
.h = fmodf(base_hsv.h + hue_shift + 360.0F, 360.0F),
|
||||
.s = fminf(1.0F, fmaxf(0.0F, base_hsv.s + sat_shift)),
|
||||
.v = fminf(1.0F, fmaxf(0.0F, base_hsv.v + val_shift))};
|
||||
|
||||
Color c = Color::HSV_TO_RGB(adjusted);
|
||||
result[i] = c;
|
||||
result[(2 * CYCLE_SIZE) - 1 - i] = c; // espejo
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
} // namespace Colors
|
||||
Reference in New Issue
Block a user