Files
cpputils/src/color_utils.h
2021-08-06 21:54:25 +02:00

144 lines
4.0 KiB
C++

#pragma once
// system includes
#include <string>
#include <string_view>
#include <array>
// 3rdparty lib includes
#include <tl/expected.hpp>
namespace cpputils {
struct ColorHelper
{
constexpr ColorHelper() = default;
constexpr ColorHelper(uint8_t _r, uint8_t _g, uint8_t _b) : r{_r}, g{_g}, b{_b} {}
constexpr ColorHelper(const ColorHelper &other) = default;
constexpr ColorHelper &operator=(const ColorHelper &other) = default;
constexpr bool operator==(const ColorHelper &other) const { return r == other.r && g == other.g && b == other.b; }
constexpr bool operator!=(const ColorHelper &other) const { return r != other.r || g != other.g || b != other.b; }
uint8_t r{};
uint8_t g{};
uint8_t b{};
};
namespace {
constexpr ColorHelper black{};
constexpr ColorHelper red{255, 0, 0};
constexpr ColorHelper blue{0, 0, 255};
constexpr ColorHelper yellow{255, 255, 0};
constexpr ColorHelper cyan{0, 255, 255};
constexpr ColorHelper green{0, 255, 0};
constexpr ColorHelper white{255, 255, 255};
constexpr ColorHelper pink{255, 0, 255};
} // namespace
struct HsvColor
{
constexpr HsvColor() = default;
constexpr HsvColor(uint8_t _h, uint8_t _s, uint8_t _v) : h{_h}, s{_s}, v{_v} {}
constexpr HsvColor(const HsvColor &other) = default;
constexpr HsvColor &operator=(const HsvColor &other) = default;
constexpr bool operator==(const HsvColor &other) const { return h == other.h && s == other.s && v == other.v; }
constexpr bool operator!=(const HsvColor &other) const { return h != other.h || s != other.s || v != other.v; }
uint8_t h{};
uint8_t s{};
uint8_t v{};
};
std::string toString(ColorHelper color);
tl::expected<ColorHelper, std::string> parseColor(std::string_view str);
inline uint32_t colorToNumber(ColorHelper color)
{
union {
uint32_t temp;
struct {
// reverse order to be reverse compatible with existing configs
uint8_t b;
uint8_t g;
uint8_t r;
uint8_t x;
};
} helper;
helper.b = color.b;
helper.g = color.g;
helper.r = color.r;
helper.x = 0;
return helper.temp;
}
inline ColorHelper numberToColor(uint32_t number)
{
union {
uint32_t temp;
struct {
// reverse order to be reverse compatible with existing configs
uint8_t b;
uint8_t g;
uint8_t r;
uint8_t x;
};
} helper;
helper.temp = number;
return ColorHelper{helper.r, helper.g, helper.b};
}
constexpr inline ColorHelper interpolateColor(ColorHelper left, ColorHelper right, uint8_t pos)
{
int16_t leftAmount = pos;
int16_t rightAmount = 255 - pos;
return ColorHelper (
(left.r * leftAmount / 255) + (right.r * rightAmount / 255),
(left.g * leftAmount / 255) + (right.g * rightAmount / 255),
(left.b * leftAmount / 255) + (right.b * rightAmount / 255)
);
}
constexpr inline ColorHelper HsvToRgb(HsvColor hsv)
{
if (hsv.s == 0)
return ColorHelper{hsv.v, hsv.v, hsv.v};
const uint8_t region = hsv.h / 43;
const uint8_t remainder = (hsv.h - (region * 43)) * 6;
const uint8_t p = (hsv.v * (255 - hsv.s)) >> 8;
const uint8_t q = (hsv.v * (255 - ((hsv.s * remainder) >> 8))) >> 8;
const uint8_t t = (hsv.v * (255 - ((hsv.s * (255 - remainder)) >> 8))) >> 8;
switch (region)
{
case 0: return ColorHelper{hsv.v, t, p };
case 1: return ColorHelper{q, hsv.v, p };
case 2: return ColorHelper{p, hsv.v, t };
case 3: return ColorHelper{p, q, hsv.v};
case 4: return ColorHelper{t, p, hsv.v};
default: return ColorHelper{hsv.v, p, q };
}
}
template<size_t COUNT>
constexpr inline std::array<ColorHelper, COUNT> generateRainbowColors()
{
std::array<ColorHelper, COUNT> colors;
for (int i = 0; i < COUNT; i++)
{
HsvColor hsvColor{uint8_t(i * 256.f / COUNT), 240, 255};
ColorHelper rgbColor = HsvToRgb(hsvColor);
colors[i] = rgbColor;
}
return colors;
}
} // namespace cpputils