Add HSV <-> RGB conversions

This commit is contained in:
Nikita Lisitsa 2025-02-23 13:56:33 +03:00
parent 4f4e86ce4f
commit 12eed4dda5

View file

@ -317,35 +317,67 @@ namespace psemek::gfx
return generic_color{dark(c.c, darkness)};
}
template <typename T, std::size_t N> requires (std::is_floating_point_v<T> && (N == 3 || N == 4))
T hue(math::vector<T, N> const & c)
template <typename T>
math::vector<T, 3> rgb_to_hsv(math::vector<T, 3> const & rgb)
{
T max = std::max({c[0], c[1], c[2]});
T min = std::min({c[0], c[1], c[2]});
T max = std::max({rgb[0], rgb[1], rgb[2]});
T min = std::min({rgb[0], rgb[1], rgb[2]});
T delta = max - min;
if (delta == T{0})
return T{0};
T hue = T{0};
T result;
if (delta > T{0})
{
if (rgb[0] > rgb[1] && rgb[0] > rgb[2])
{
hue = (rgb[1] - rgb[2]) / delta;
}
else if (rgb[1] > rgb[2])
{
hue = 2.f + (rgb[2] - rgb[0]) / delta;
}
else
{
hue = 4.f + (rgb[0] - rgb[1]) / delta;
}
}
if (c[0] > c[1] && c[0] > c[2])
{
result = (c[1] - c[2]) / delta;
}
else if (c[1] > c[2])
{
result = 2.f + (c[2] - c[0]) / delta;
}
hue *= math::rad<T>(60);
if (hue < 0)
hue += math::rad<T>(360);
math::vector<T, 3> result;
result[0] = hue;
result[1] = (max > T{0}) ? (delta / max) : T{0};
result[2] = max;
return result;
}
template <typename T>
math::vector<T, 3> hsv_to_rgb(math::vector<T, 3> const & hsv)
{
auto c = hsv[1] * hsv[2];
auto x = c * (T{1} - std::abs(std::fmod(hsv[0] / math::rad<T>(60), 2.f) - 1.f));
auto m = hsv[2] - c;
math::vector<T, 3> result;
if (hsv[0] < math::rad<T>(60))
result = {c, x, T{0}};
else if (hsv[0] < math::rad<T>(120))
result = {x, c, T{0}};
else if (hsv[0] < math::rad<T>(180))
result = {T{0}, c, x};
else if (hsv[0] < math::rad<T>(240))
result = {T{0}, x, c};
else if (hsv[0] < math::rad<T>(300))
result = {x, T{0}, c};
else
{
result = 4.f + (c[0] - c[1]) / delta;
}
result = {c, T{0}, x};
result *= math::rad<T>(60);
if (result < 0)
result += math::rad<T>(360);
result += math::vector{m, m, m};
return result;
}