Deluge Firmware 1.3.0
Build date: 2025.04.16
Loading...
Searching...
No Matches
rgb.h
1#pragma once
2#include "util/const_functions.h"
3#include "util/fixedpoint.h"
4#include <algorithm>
5#include <cstdint>
6#include <functional>
7#include <limits>
8#include <type_traits>
9
14class RGB {
15public:
17 using channel_type = uint8_t;
18
21 static constexpr auto channel_min = std::numeric_limits<channel_type>::min();
22
25 static constexpr auto channel_max = std::numeric_limits<channel_type>::max();
26
29
32
35
37 constexpr RGB& operator=(const RGB& other) = default;
38
45 static constexpr RGB monochrome(uint8_t brightness) {
46 return RGB{.r = brightness, .g = brightness, .b = brightness};
47 }
48
55 static RGB fromHue(int32_t hue);
56
63 static RGB fromHuePastel(int32_t hue);
64
73 template <typename UnaryOp> // std::function<channel_type(channel_type)>
74 requires std::convertible_to<UnaryOp, std::function<channel_type(channel_type)>>
75 [[nodiscard]] constexpr RGB transform(UnaryOp transformFn) const {
76 return RGB(transformFn(r), transformFn(g), transformFn(b));
77 }
78
84 [[nodiscard]] constexpr RGB forTail() const {
85 uint32_t averageBrightness = ((uint32_t)r + g + b);
86 return transform([averageBrightness](channel_type channel) { //<
87 return (((int32_t)channel * 21 + averageBrightness) * 120) >> 14;
88 });
89 }
90
96 [[nodiscard]] constexpr RGB forBlur() const {
97 uint32_t averageBrightness = (uint32_t)r * 5 + g * 9 + b * 9;
98 return transform([averageBrightness](channel_type channel) { //<
99 return ((uint32_t)channel * 5 + averageBrightness) >> 5;
100 });
101 }
102
110 static constexpr RGB average(RGB colourA, RGB colourB) {
111 return RGB::transform2(colourA, colourB, [](channel_type channelA, channel_type channelB) {
112 auto average = (static_cast<uint32_t>(channelA) + static_cast<uint32_t>(channelB)) / 2;
113 return std::clamp<uint32_t>(average, 0, channel_max);
114 });
115 }
116
123 [[nodiscard]] constexpr RGB dim(uint8_t level = 1) const {
124 return transform([level](channel_type channel) { return channel >> level; });
125 }
126
136 [[nodiscard]] constexpr RGB dull() const {
137 return transform([](channel_type channel) { //<
138 return std::clamp<channel_type>(channel, 5, 50);
139 });
140 }
141
148 [[nodiscard]] constexpr RGB greyOut(int32_t proportion) {
149 uint32_t totalRGB = (uint32_t)r + g + b; // max 765
150
151 return transform([proportion, totalRGB](channel_type channel) {
152 auto val = rshift_round(
153 (uint32_t)channel * (uint32_t)(0x808080 - proportion) + ((int32_t)totalRGB * (proportion >> 5)), 23);
154 return std::clamp<uint32_t>(val, 0, channel_max);
155 });
156 }
157
166 [[nodiscard]] static constexpr RGB blend(RGB sourceA, RGB sourceB, uint16_t index) {
167 return transform2(sourceA, sourceB, [index](channel_type channelA, channel_type channelB) { //<
168 return blendChannel(channelA, channelB, index);
169 });
170 }
171
181 [[nodiscard]] static constexpr RGB blend2(RGB sourceA, RGB sourceB, uint16_t indexA, uint16_t indexB) {
182 return transform2(sourceA, sourceB, [indexA, indexB](channel_type channelA, channel_type channelB) {
183 return blendChannel2(channelA, channelB, indexA, indexB);
184 });
185 }
186
192 bool operator==(RGB const&) const = default;
193
200 constexpr channel_type& operator[](size_t idx) {
201 switch (idx) {
202 case 0:
203 return r;
204 case 1:
205 return g;
206 case 2:
207 return b;
208 default:
209 __builtin_unreachable(); // TODO: should be std::unreachable() with C++23
210 }
211 }
212
218 static constexpr size_t size() { return 3; }
219
227 constexpr channel_type* begin() { return &this->r; }
228
236 constexpr channel_type* end() { return (&this->b + 1); }
237
248 template <typename BinaryOp>
249 requires std::convertible_to<BinaryOp, std::function<channel_type(channel_type, channel_type)>>
250 static constexpr RGB transform2(RGB colourA, RGB colourB, BinaryOp transformFn) {
251 return RGB(transformFn(colourA.r, colourB.r), transformFn(colourA.g, colourB.g),
252 transformFn(colourA.b, colourB.b));
253 }
254
259 [[nodiscard]] constexpr RGB adjust(uint8_t intensity, uint8_t brightnessDivider) const {
260 return transform([intensity, brightnessDivider](channel_type channel) { //<
261 return ((channel * intensity / 255) / brightnessDivider);
262 });
263 }
264
269 [[nodiscard]] constexpr RGB adjustFractional(uint16_t numerator, uint16_t divisor) const {
270 return transform([numerator, divisor](channel_type channel) { //<
271 return ((channel * numerator) / divisor);
272 });
273 }
274
279 constexpr RGB rotate() { return xform(RMat); }
280
281private:
282 static constexpr uint32_t IMat[4][4] = {
283 {ONE_Q16, 0, 0, 0},
284 {0, ONE_Q16, 0, 0},
285 {0, 0, ONE_Q16, 0},
286 {0, 0, 0, ONE_Q16},
287 };
288 static constexpr float c = 0.5403f;
289 static constexpr float s = 0.8414f;
290 static constexpr uint32_t RMat[4][4] = {
291 {(uint32_t)(c * ONE_Q16), 0, (uint32_t)(s* ONE_Q16), 0},
292 {(uint32_t)(s * ONE_Q16), (uint32_t)(c* ONE_Q16), 0, 0},
293 {0, (uint32_t)(s* ONE_Q16), (uint32_t)(c* ONE_Q16), 0},
294 {0, 0, 0, ONE_Q16},
295 };
296
297 constexpr RGB xform(const uint32_t mat[4][4]) {
298 return {
299 .r = static_cast<channel_type>((r * mat[0][0] + g * mat[1][0] + b * mat[2][0] + mat[3][0]) >> 16),
300 .g = static_cast<channel_type>((r * mat[0][1] + g * mat[1][1] + b * mat[2][1] + mat[3][1]) >> 16),
301 .b = static_cast<channel_type>((r * mat[0][2] + g * mat[1][2] + b * mat[2][2] + mat[3][2]) >> 16),
302 };
303 }
304
309 static constexpr channel_type blendChannel(uint32_t channelA, uint32_t channelB, uint16_t index) {
310 return blendChannel2(channelA, channelB, index, (std::numeric_limits<uint16_t>::max() - index + 1));
311 }
312
317 static constexpr channel_type blendChannel2(uint32_t channelA, uint32_t channelB, uint16_t indexA,
318 uint16_t indexB) {
319 uint32_t newRGB = rshift_round(channelA * indexA, 16) + rshift_round(channelB * indexB, 16);
320 return std::clamp<uint32_t>(newRGB, 0, channel_max);
321 }
322};
323static_assert(std::is_trivially_copyable_v<RGB>, "RGB must be trivially copyable");
This class represents the colour format most used by the Deluge globally.
Definition rgb.h:14
static RGB fromHue(int32_t hue)
Construct a colour from a hue.
Definition rgb.cpp:4
channel_type b
Blue channel.
Definition rgb.h:34
uint8_t channel_type
The size of each colour channel.
Definition rgb.h:17
constexpr channel_type & operator[](size_t idx)
Legacy access to the colour internals for ease of use.
Definition rgb.h:200
constexpr RGB adjust(uint8_t intensity, uint8_t brightnessDivider) const
Adjust a colour by altering its intensity and brightness.
Definition rgb.h:259
constexpr RGB dim(uint8_t level=1) const
Dim a colour.
Definition rgb.h:123
static constexpr size_t size()
Used in combination with operator[] and begin end.
Definition rgb.h:218
channel_type r
Red channel.
Definition rgb.h:28
static constexpr auto channel_max
Definition rgb.h:25
constexpr channel_type * end()
Iterator constructor for the end sentinel of this structure.
Definition rgb.h:236
static constexpr RGB monochrome(uint8_t brightness)
Construct a monochrome (white) shade.
Definition rgb.h:45
constexpr RGB dull() const
Dull a colour, clamping it to [5, 50].
Definition rgb.h:136
constexpr channel_type * begin()
Iterator constructor pointing to the beginning of this structure.
Definition rgb.h:227
static RGB fromHuePastel(int32_t hue)
Construct a colour from a hue.
Definition rgb.cpp:36
static constexpr auto channel_min
Definition rgb.h:21
static constexpr RGB average(RGB colourA, RGB colourB)
Average two colours together.
Definition rgb.h:110
constexpr RGB transform(UnaryOp transformFn) const
Create a new colour by transforming each channel of a colour.
Definition rgb.h:75
bool operator==(RGB const &) const =default
Compare two colours to determine if they're the same.
static constexpr channel_type blendChannel(uint32_t channelA, uint32_t channelB, uint16_t index)
Blend a channel in equal proportions.
Definition rgb.h:309
static constexpr RGB blend(RGB sourceA, RGB sourceB, uint16_t index)
Generate a new colour made from blending two source colours.
Definition rgb.h:166
constexpr RGB adjustFractional(uint16_t numerator, uint16_t divisor) const
Adjust a colour by altering its intensity and brightness. Intensity/brightnessDivider must be less th...
Definition rgb.h:269
constexpr RGB & operator=(const RGB &other)=default
Copies RGB values from a colour.
constexpr RGB rotate()
Definition rgb.h:279
channel_type g
Green channel.
Definition rgb.h:31
constexpr RGB greyOut(int32_t proportion)
Grey out a colour.
Definition rgb.h:148
constexpr RGB forTail() const
Create a derived colour for tails (used by views)
Definition rgb.h:84
static constexpr RGB blend2(RGB sourceA, RGB sourceB, uint16_t indexA, uint16_t indexB)
Generate a new colour made from blending two source colours with individual proportions.
Definition rgb.h:181
static constexpr RGB transform2(RGB colourA, RGB colourB, BinaryOp transformFn)
Create a new colour by transforming the channels of two colours.
Definition rgb.h:250
static constexpr channel_type blendChannel2(uint32_t channelA, uint32_t channelB, uint16_t indexA, uint16_t indexB)
Blend two channels in differing proportions.
Definition rgb.h:317
constexpr RGB forBlur() const
Create a derived colour for blurs (used by views)
Definition rgb.h:96