esp32displaytest/lib/Util/RGB.h
2022-03-12 12:33:52 +01:00

154 lines
3.7 KiB
C++

#ifndef ESP32DISPLAYTEST_RGB_H
#define ESP32DISPLAYTEST_RGB_H
//#include "HSL.h"
#include <cstdint>
#include <cstddef>
#include <cassert>
#include <vector>
#include <Print.h>
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<uint8_t>((num >> 16) & 0xFF)),
green(static_cast<uint8_t>((num >> 8) & 0xFF)),
blue(static_cast<uint8_t>((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<uint8_t>(r / 255), static_cast<uint8_t>(g / 255), static_cast<uint8_t>(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<RGB> &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<uint8_t>(r), static_cast<uint8_t>(g), static_cast<uint8_t>(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