1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
|
// Copyright 2025 [email protected]
// SPDX-License-Identifier: GPL-2.0-or-later
#include "color.h"
#include <lib/lib8tion/lib8tion.h>
#define K255 255
#define K171 171
#define K170 170
#define K85 85
// Adapted from https://fastled.io/docs/hsv2rgb_8cpp_source.html
// void hsv2rgb_rainbow() function
RGB rgb_matrix_hsv_to_rgb(const HSV hsv) {
// Yellow has a higher inherent brightness than
// any other color; 'pure' yellow is perceived to
// be 93% as bright as white. In order to make
// yellow appear the correct relative brightness,
// it has to be rendered brighter than all other
// colors.
const uint8_t hue = hsv.h;
const uint8_t sat = hsv.s;
uint8_t val = hsv.v;
// offset8 = (hue [0..31]) * 8
uint8_t offset8 = hue & 0x1F;
offset8 <<= 3;
uint8_t third = scale8(offset8, (256 / 3)); // max = 85
uint8_t r, g, b;
if (!(hue & 0x80)) {
// 0XX
if (!(hue & 0x40)) {
// 00X
// section 0-1
if (!(hue & 0x20)) {
// 000
// case 0: // R -> O
r = K255 - third;
g = third;
b = 0;
} else {
// 001
// case 1: // O -> Y
r = K171;
g = K85 + third;
b = 0;
}
} else {
// 01X
// section 2-3
if (!(hue & 0x20)) {
// 010
// case 2: // Y -> G
// uint8_t twothirds = (third << 1);
uint8_t twothirds = scale8(offset8, ((256 * 2) / 3)); // max=170
r = K171 - twothirds;
g = K170 + third;
b = 0;
} else {
// 011
// case 3: // G -> A
r = 0;
g = K255 - third;
b = third;
}
}
} else {
// section 4-7
// 1XX
if (!(hue & 0x40)) {
// 10X
if (!(hue & 0x20)) {
// 100
// case 4: // A -> B
r = 0;
// uint8_t twothirds = (third << 1);
uint8_t twothirds = scale8(offset8, ((256 * 2) / 3)); // max=170
g = K171 - twothirds; // K170?
b = K85 + twothirds;
} else {
// 101
// case 5: // B -> P
r = third;
g = 0;
b = K255 - third;
}
} else {
if (!(hue & 0x20)) {
// 110
// case 6: // P -- K
r = K85 + third;
g = 0;
b = K171 - third;
} else {
// 111
// case 7: // K -> R
r = K170 + third;
g = 0;
b = K85 - third;
}
}
}
// This is one of the good places to scale the green down,
// although the client can scale green down as well.
g >>= 1;
// Scale down colors if we're desaturated at all
// and add the brightness_floor to r, g, and b.
if (sat != 255) {
if (sat == 0) {
r = 255;
b = 255;
g = 255;
} else {
uint8_t desat = 255 - sat;
desat = scale8_video(desat, desat);
uint8_t satscale = 255 - desat;
r = scale8(r, satscale);
g = scale8(g, satscale);
b = scale8(b, satscale);
uint8_t brightness_floor = desat;
r += brightness_floor;
g += brightness_floor;
b += brightness_floor;
}
}
// Now scale everything down if we're at value < 255.
if (val != 255) {
val = scale8_video(val, val);
if (val == 0) {
r = 0;
g = 0;
b = 0;
} else {
r = scale8(r, val);
g = scale8(g, val);
b = scale8(b, val);
}
}
return (RGB){.r = r, .g = g, .b = b};
}
|