163 lines
4.1 KiB
C++
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
|