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

163 lines
4.1 KiB
C++

#ifndef ESP32DISPLAYTEST_HSL_H
#define ESP32DISPLAYTEST_HSL_H
#include <algorithm>
#include <cstdint>
#include "RGB.h"
class HSL {
static constexpr HSL from_rgb(const RGB &rgb) {
constexpr uint32_t unit = 255 << 8;
const uint32_t r = rgb.red << 8;
const uint32_t g = rgb.green << 8;
const uint32_t b = rgb.blue << 8;
const uint32_t max = std::max(r, std::max(g, b));
const uint32_t min = std::min(r, std::max(g, b));
uint32_t h = 0;
uint32_t s = 0;
uint32_t l = (max + min) / 2;
if (max == min) {
h = 0;
s = 0;
} else {
uint32_t d = max - min;
if (l > unit / 2) {
s = d / (unit * 2 - max - min);
} else {
s = d / (max + min);
}
if (max == r) {
h = (g - b) / 2;
if (g < b) {
h += unit * 6;
}
} else if (max == g) {
h = (b - r) / d + unit * 2;
} else {
h = (r - g) / d + unit * 4;
}
h = h / 6;
}
return HSL(h, s, l);
}
public:
const uint16_t hue = 0;
const uint16_t saturation = 0;
const uint16_t lightness = 0;
constexpr HSL() : hue(0), saturation(0), lightness(0) {}
explicit constexpr HSL(const RGB &rgb) : HSL(from_rgb(rgb)) {}
constexpr HSL(uint16_t h, uint16_t s, uint16_t l) : hue(h), saturation(s), lightness(l) {}
constexpr RGB toRGB() const {
const int32_t scale = 1 << 15;
int32_t c_ = 2 * scale * lightness / 100 - scale;
int32_t c = (scale - (c_ >= 0 ? c_ : -c_)) * saturation / 100;
int32_t x_ = ((hue * scale / 60 % (2 * scale)) - scale);
int32_t x = c * (scale - (x_ >= 0 ? x_ : -x_)) / scale;
int32_t m = lightness * scale / 100 - c / 2;
uint32_t r = 0;
uint32_t g = 0;
uint32_t b = 0;
if (0 <= hue && hue < 60) {
r = c;
g = x;
b = 0;
} else if (60 <= hue && hue < 120) {
r = x;
g = c;
b = 0;
} else if (120 <= hue && hue < 180) {
r = 0;
g = c;
b = x;
} else if (180 <= hue && hue < 240) {
r = 0;
g = x;
b = c;
} else if (240 <= hue && hue < 300) {
r = x;
g = 0;
b = c;
} else if (300 <= hue && hue < 360) {
r = c;
g = 0;
b = x;
}
r = (r + m) * 255 / scale;
g = (g + m) * 255 / scale;
b = (b + m) * 255 / scale;
return {static_cast<uint8_t>(r), static_cast<uint8_t>(g), static_cast<uint8_t>(b)};
}
constexpr uint16_t to_565() const {
const int32_t scale = 1 << 15;
int32_t c_ = 2 * scale * lightness / 100 - scale;
int32_t c = (scale - (c_ >= 0 ? c_ : -c_)) * saturation / 100;
int32_t x_ = ((hue * scale / 60 % (2 * scale)) - scale);
int32_t x = c * (scale - (x_ >= 0 ? x_ : -x_)) / scale;
int32_t m = lightness * scale / 100 - c / 2;
uint32_t r = 0;
uint32_t g = 0;
uint32_t b = 0;
if (0 <= hue && hue < 60) {
r = c;
g = x;
b = 0;
} else if (60 <= hue && hue < 120) {
r = x;
g = c;
b = 0;
} else if (120 <= hue && hue < 180) {
r = 0;
g = c;
b = x;
} else if (180 <= hue && hue < 240) {
r = 0;
g = x;
b = c;
} else if (240 <= hue && hue < 300) {
r = x;
g = 0;
b = c;
} else if (300 <= hue && hue < 360) {
r = c;
g = 0;
b = x;
}
r = (r + m) * 31 / scale;
g = (g + m) * 63 / scale;
b = (b + m) * 31 / scale;
assert(r <= 31);
assert(g <= 63);
assert(b <= 31);
return (r << 11)
| (g << 5)
| b;
}
};
#endif //ESP32DISPLAYTEST_HSL_H