#ifndef ESP32DISPLAYTEST_RGB_H #define ESP32DISPLAYTEST_RGB_H //#include "HSL.h" #include #include #include #include #include class RGB { static constexpr uint8_t hex_char_to_num(char ch) { assert( (ch >= '0' && ch <= '9') || (ch >= 'a' && ch <= 'f') || (ch >= 'A' && ch <= 'F') ); if (ch >= '0' && ch <= '9') return ch - '0'; if (ch >= 'a' && ch <= 'f') return ch - 'a' + 10; if (ch >= 'A' && ch <= 'F') return ch - 'A' + 10; return -1; } static constexpr size_t const_strlen(const char *str) { size_t len = 0; while (*(str + len) != '\0') len++; return len; } static constexpr uint32_t alpha_blend(uint8_t top, uint8_t bottom, uint8_t alpha) { return ((uint32_t)top) * ((uint32_t)alpha) + ((uint32_t)bottom) * (255 - (uint32_t)alpha); } static constexpr uint32_t hex_str_to_num(const char *hex) { size_t len = const_strlen(hex); assert(len >= 6); if (hex[0] == '0' && (hex[1] == 'x' || hex[1] == 'X')) { assert(len == 8); hex += 2; } else { assert(len == 6); } uint32_t res = 0; for (size_t i = 0; i < 6; ++i) { res = (res << 4) | hex_char_to_num(hex[i]); } return res; } static constexpr uint32_t hex_str_to_num(const char *hex, size_t len) { assert(len >= 6); if (hex[0] == '0' && (hex[1] == 'x' || hex[1] == 'X')) { assert(len == 8); hex += 2; } else { assert(len == 6); } uint32_t res = 0; for (size_t i = 0; i < 6; ++i) { res = (res << 4) | hex_char_to_num(hex[i]); } return res; } explicit constexpr RGB(uint32_t num) : red(static_cast((num >> 16) & 0xFF)), green(static_cast((num >> 8) & 0xFF)), blue(static_cast((num) & 0xFF)) { } public: /*const*/ uint8_t red = 0; /*const*/ uint8_t green = 0; /*const*/ uint8_t blue = 0; constexpr RGB() : red(0), green(0), blue(0) {} constexpr RGB(const RGB &other) = default; constexpr RGB(uint8_t r, uint8_t g, uint8_t b) : red(r), green(g), blue(b) { } explicit constexpr RGB(const char *hex) : RGB(hex_str_to_num(hex)) { } explicit constexpr RGB(const char *hex, size_t len) : RGB(hex_str_to_num(hex, len)) { } constexpr uint16_t to_565() const { uint8_t r = this->red >> 3; uint8_t g = this->green >> 2; uint8_t b = this->blue >> 3; return (r << 11) | (g << 5) | b; } constexpr RGB alpha_blend_over(const RGB &other, uint8_t alpha) const { uint32_t r = alpha_blend(this->red, other.red, alpha); uint32_t g = alpha_blend(this->green, other.green, alpha); uint32_t b = alpha_blend(this->blue, other.blue, alpha); return {static_cast(r / 255), static_cast(g / 255), static_cast(b / 255)}; } constexpr uint16_t alpha_blend_over_to565(const RGB &other, uint8_t alpha) const { uint8_t r = alpha_blend(this->red, other.red, alpha) * 31 / 255 / 255; uint8_t g = alpha_blend(this->green, other.green, alpha) * 31 / 255 / 255; uint8_t b = alpha_blend(this->blue, other.blue, alpha) * 31 / 255 / 255; assert(r <= 31); assert(g <= 63); assert(b <= 31); return (r << 11) | (g << 5) | b; } static RGB blend(const std::vector &colors) { if (colors.empty()) { return {0, 0, 0}; } uint64_t r = 0; uint64_t g = 0; uint64_t b = 0; for (const auto &c : colors) { r += c.red; g += c.green; b += c.blue; } r /= colors.size(); g /= colors.size(); b /= colors.size(); return {static_cast(r), static_cast(g), static_cast(b)}; } size_t printTo(Print &p) const { return p.printf("RGB(%d,%d,%d)", red, green, blue); } }; constexpr RGB operator "" _rgb(const char *lit) { return RGB(lit); } constexpr RGB operator "" _rgb(const char *lit, size_t len) { return RGB(lit, len); } #endif //ESP32DISPLAYTEST_RGB_H