-
Notifications
You must be signed in to change notification settings - Fork 515
Expand file tree
/
Copy pathColorCode.cpp
More file actions
205 lines (155 loc) · 5.05 KB
/
Copy pathColorCode.cpp
File metadata and controls
205 lines (155 loc) · 5.05 KB
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
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
#include <Geode/utils/ColorCode.hpp>
using namespace geode::prelude;
Result<Color> Color::parse(std::string_view hex) {
if (hex.starts_with("#")) {
hex.remove_prefix(1);
}
const size_t size = hex.size();
// If the string is an exact size of 1, 2, 3, 4, 6 or 8
if (!size || (size > 4 && size != 6 && size != 8)) {
return Err("Unsupported size");
}
GEODE_UNWRAP_INTO(const uint32_t colorNum, utils::numFromString<uint32_t>(hex, 16));
ccColor4B color;
if (size <= 2) {
color.r = color.g = color.b = Color::getByte(colorNum, 0, size == 1);
color.a = 0xFF;
} else if (size % 3 == 0) {
const bool isShort = size == 3;
color.r = Color::getByte(colorNum, 2, isShort);
color.g = Color::getByte(colorNum, 1, isShort);
color.b = Color::getByte(colorNum, 0, isShort);
color.a = 0xFF;
} else {
const bool isShort = size == 4;
color.r = Color::getByte(colorNum, 3, isShort);
color.g = Color::getByte(colorNum, 2, isShort);
color.b = Color::getByte(colorNum, 1, isShort);
color.a = Color::getByte(colorNum, 0, isShort);
}
return Ok(Color(color));
}
GLubyte Color::getByte(uint32_t colorNum, size_t index, bool isShort) {
const uint32_t shiftSize = (isShort ? 4 : 8) * index;
const GLubyte byte = (colorNum >> shiftSize) & 0xFF;
// If it's short, mirror the nibble
return isShort ? (byte << 4) | byte : byte;
}
Color::operator ccColor3B() const {
return { r, g, b };
}
Color::operator ccColor4B() const {
return { r, g, b, a };
}
Color::operator ccColor4F() const {
return { r / 255.0f, g / 255.0f, b / 255.0f, a / 255.0f };
}
Color::operator HSV() const {
const double red = r / 255.0;
const double green = g / 255.0;
const double blue = b / 255.0;
const double max = std::max({ red, green, blue });
const double delta = max - std::min({ red, green, blue });
HSV hsv;
if (delta == 0) {
hsv.h = 0;
} else if (max == red) {
hsv.h = 60 * std::fmod((green - blue) / delta, 6);
} else if (max == green) {
hsv.h = 60 * ((blue - red) / delta + 2);
} else {
hsv.h = 60 * ((red - green) / delta + 4);
}
if (hsv.h < 0) {
hsv.h += 360;
}
hsv.s = max == 0 ? 0 : delta / max;
hsv.v = max;
return hsv;
}
Color::Color(GLubyte alpha): r(0x00), g(0x00), b(0x00), a(alpha) { }
Color::Color(GLubyte red, GLubyte green, GLubyte blue, GLubyte alpha): r(red), g(green), b(blue), a(alpha) { }
Color::Color(const ccColor3B& color, GLubyte alpha): r(color.r), g(color.g), b(color.b), a(alpha) { }
Color::Color(const ccColor4B& color): r(color.r), g(color.g), b(color.b), a(color.a) { }
Color::Color(const ccColor4F& color): r(std::round(color.r * 255)), g(std::round(color.g * 255)), b(std::round(color.b * 255)), a(std::round(color.a * 255)) { }
Color::Color(const HSV& hsv, GLubyte alpha): a(alpha) {
double correctedHue = std::fmod(hsv.h, 360);
if (correctedHue < 0) {
correctedHue += 360;
}
const double c = hsv.v * hsv.s;
const double x = c * (1 - std::abs(std::fmod(correctedHue / 60, 2) - 1));
const double m = hsv.v - c;
double rp, gp, bp;
if (correctedHue < 60) {
rp = c; gp = x; bp = 0;
} else if (correctedHue < 120) {
rp = x; gp = c; bp = 0;
} else if (correctedHue < 180) {
rp = 0; gp = c; bp = x;
} else if (correctedHue < 240) {
rp = 0; gp = x; bp = c;
} else if (correctedHue < 300) {
rp = x; gp = 0; bp = c;
} else {
rp = c; gp = 0; bp = x;
}
r = std::round((rp + m) * 255);
g = std::round((gp + m) * 255);
b = std::round((bp + m) * 255);
}
void Color::applyH(double hue) {
this->applyHSV({ hue, 1, 1 });
}
void Color::applyHue(double hue) {
this->applyHSV({ hue, 1, 1 });
}
void Color::applyS(double saturation) {
this->applyHSV({ 0, saturation, 1 });
}
void Color::applySaturation(double saturation) {
this->applyHSV({ 0, saturation, 1 });
}
void Color::applyV(double value) {
this->applyHSV({ 0, 1, value });
}
void Color::applyValue(double value) {
this->applyHSV({ 0, 1, value });
}
void Color::applyB(double brightness) {
this->applyHSV({ 0, 1, brightness });
}
void Color::applyBrightness(double brightness) {
this->applyHSV({ 0, 1, brightness });
}
void Color::applyHSV(const HSV& hsv) {
HSV currentHSV = *this;
currentHSV.h = std::fmod(currentHSV.h + hsv.h, 360);
if (currentHSV.h < 0) {
currentHSV.h += 360;
}
currentHSV.s = std::clamp<double>(currentHSV.s * hsv.s, 0, 1);
currentHSV.v = std::clamp<double>(currentHSV.v * hsv.v, 0, 1);
*this = currentHSV;
}
ccColor3B Color::to3B() const {
return *this;
}
ccColor4B Color::to4B() const {
return *this;
}
ccColor4F Color::to4F() const {
return *this;
}
HSV Color::toHSV() const {
return *this;
}
bool Color::isInvisible() const {
return a == 0x00;
}
bool Color::isTranslucent() const {
return a > 0x00 && a < 0xFF;
}
bool Color::isOpaque() const {
return a == 0xFF;
}