LeviLamina
Loading...
Searching...
No Matches
Color.h
1#pragma once
2
3#include "mc/_HeaderOutputPredefine.h"
4#include "mc/deps/core/math/Vec2.h"
5#include "mc/deps/core/math/Vec3.h"
6
7#include "ll/api/utils/StringUtils.h"
8
9namespace mce {
10
11class Color;
12
13class Color : public ll::math::floatN4<Color> {
14public:
15 [[nodiscard]] constexpr Color() noexcept = default;
16
17 template <std::integral T0, std::integral T1, std::integral T2, std::integral T3 = uint>
18 [[nodiscard]] constexpr Color(T0 const& ir, T1 const& ig, T2 const& ib, T3 const& ia = 255) noexcept
19 : floatN4(
20 static_cast<float>(ir) / 255.0f,
21 static_cast<float>(ig) / 255.0f,
22 static_cast<float>(ib) / 255.0f,
23 static_cast<float>(ia) / 255.0f
24 ) {}
25 template <std::floating_point T0, std::floating_point T1, std::floating_point T2, std::floating_point T3 = double>
26 [[nodiscard]] constexpr Color(T0 const& r, T1 const& g, T2 const& b, T3 const& a = 1) noexcept
27 : floatN4(r, g, b, a) {}
28
29 template <ll::math::IsFloatN V, std::floating_point A = double>
30 [[nodiscard]] constexpr Color(V const& v, A const& a = 1) noexcept
31 requires(V::size() == 3)
32 : floatN4(v.r, v.g, v.b, a) {}
33
34 [[nodiscard]] constexpr Color(uint hex) noexcept : Color((hex >> 16) & 0xFF, (hex >> 8) & 0xFF, hex & 0xFF) {}
35
36 [[nodiscard]] constexpr Color(std::string_view hex) noexcept : floatN4(0, 0, 0, 1) {
37 if (hex[0] == '#') {
38 hex = hex.substr(1);
39 }
40
41 using ll::string_utils::digitFromChar;
42
43 switch (hex.length()) {
44 case 4:
45 a = static_cast<float>(digitFromChar(hex[3]) * 17) / 255.0f;
46 case 3:
47 r = static_cast<float>(digitFromChar(hex[0]) * 17) / 255.0f;
48 g = static_cast<float>(digitFromChar(hex[1]) * 17) / 255.0f;
49 b = static_cast<float>(digitFromChar(hex[2]) * 17) / 255.0f;
50 break;
51 case 8:
52 a = static_cast<float>(16 * digitFromChar(hex[6]) + digitFromChar(hex[7])) / 255.0f;
53 case 6:
54 r = static_cast<float>(16 * digitFromChar(hex[0]) + digitFromChar(hex[1])) / 255.0f;
55 g = static_cast<float>(16 * digitFromChar(hex[2]) + digitFromChar(hex[3])) / 255.0f;
56 b = static_cast<float>(16 * digitFromChar(hex[4]) + digitFromChar(hex[5])) / 255.0f;
57 break;
58 default:
59 return;
60 }
61 }
62
63 [[nodiscard]] constexpr class Vec3 toVec3() const noexcept { return {r, g, b}; }
64
65 [[nodiscard]] constexpr class mce::Color sRGBToLinear() const noexcept {
66 auto color{toVec3()};
67 return {select(color.gt(0.04045f), pow(color / 1.055f + 0.055f, {2.4f}), color / 12.92f), a};
68 }
69
70 [[nodiscard]] constexpr class mce::Color linearTosRGB() const noexcept {
71 auto color{toVec3()};
72 return {select(color.gt(0.0031308f), pow(color, {1.0f / 2.4f}) * 1.055f - 0.055f, color * 12.92f), a};
73 }
74
75 [[nodiscard]] constexpr class mce::Color linearToXYZ() const noexcept {
76 auto color{toVec3()};
77 return {
78 color.dot({0.4124f, 0.3576f, 0.1805f}),
79 color.dot({0.2126f, 0.7152f, 0.0722f}),
80 color.dot({0.0193f, 0.1192f, 0.9505f}),
81 a
82 };
83 }
84
85 [[nodiscard]] constexpr class mce::Color XYZToLinear() const noexcept {
86 auto color{toVec3()};
87 return {
88 color.dot({3.2410f, -1.5374f, -0.4986f}),
89 color.dot({-0.9692f, 1.8760f, 0.0416f}),
90 color.dot({0.0556f, -0.2040f, 1.0570f}),
91 a
92 };
93 }
94
95 [[nodiscard]] constexpr class mce::Color linearToLMS() const noexcept {
96 auto color{toVec3()};
97 return {
98 color.dot({0.4122214708f, 0.5363325363f, 0.0514459929f}),
99 color.dot({0.2119034982f, 0.6806995451f, 0.1073969566f}),
100 color.dot({0.0883024619f, 0.2817188376f, 0.6299787005f}),
101 a
102 };
103 }
104
105 [[nodiscard]] constexpr class mce::Color LMSToLinear() const noexcept {
106 auto color{toVec3()};
107 return {
108 color.dot({+4.0767416621f, -3.3077115913f, +0.2309699292f}),
109 color.dot({-1.2684380046f, +2.6097574011f, -0.3413193965f}),
110 color.dot({-0.0041960863f, -0.7034186147f, +1.7076147010f}),
111 a
112 };
113 }
114
115 [[nodiscard]] constexpr class mce::Color LMSToOklab() const noexcept {
116 auto color{pow(toVec3(), {1.0f / 3.0f})};
117 return {
118 color.dot({0.2104542553f, +0.7936177850f, -0.0040720468f}),
119 color.dot({1.9779984951f, -2.4285922050f, +0.4505937099f}),
120 color.dot({0.0259040371f, +0.7827717662f, -0.8086757660f}),
121 a
122 };
123 }
124
125 [[nodiscard]] constexpr class mce::Color OklabToLMS() const noexcept {
126 auto color{toVec3()};
127 return {
128 pow({color.dot({1.0f, +0.3963377774f, +0.2158037573f}),
129 color.dot({1.0f, -0.1055613458f, -0.0638541728f}),
130 color.dot({1.0f, -0.0894841775f, -1.2914855480f})},
131 Vec3{3}),
132 a
133 };
134 }
135
136 [[nodiscard]] constexpr class mce::Color XYZToLab() const noexcept {
137 auto color = toVec3() / Vec3{0.950489f, 1.0f, 1.08884f};
138
139 constexpr float delta = 6.0f / 29.0f;
140 constexpr float delta2 = delta * delta;
141 constexpr float delta3 = delta2 * delta;
142
143 color = select(color.gt(delta3), pow(color, {1.0f / 3.0f}), color / (3.0f * delta2) + 4.0f / 29.0f);
144 return {116.0f * color.y - 16.0f, 500.0f * (color.x - color.y), 200.0f * (color.y - color.z), a};
145 }
146
147 [[nodiscard]] constexpr class mce::Color LabToXYZ() const noexcept {
148 float tmpy = (r + 16.0f) / 116.0f;
149 Vec3 color{tmpy + g / 500.0f, tmpy, tmpy - b / 200.0f};
150
151 constexpr float delta = 6.0f / 29.0f;
152 constexpr float delta2 = delta * delta;
153
154 color = select(color.gt(delta), pow(color, {3.0f}), (color - 4.0f / 29.0f) * (3.0f * delta2));
155 return {
156 color * Vec3{0.950489f, 1.0f, 1.08884f},
157 a
158 };
159 }
160
161 [[nodiscard]] constexpr double deltaE76(Color const& dst) const noexcept { // 2.3 for JND
162 return this->sRGBToLinear().linearToXYZ().XYZToLab().toVec3().distanceTo(
163 dst.sRGBToLinear().linearToXYZ().XYZToLab().toVec3()
164 );
165 }
166
167 [[nodiscard]] inline double deltaE94(Color const& dst) const noexcept { // 1.0 for JND
168 auto m1 = this->sRGBToLinear().linearToXYZ().XYZToLab().toVec3();
169 Vec2 ab1{m1.y, m1.z};
170 auto m2 = dst.sRGBToLinear().linearToXYZ().XYZToLab().toVec3();
171 Vec2 ab2{m2.y, m2.z};
172 auto C1 = ab1.length();
173 auto C2 = ab2.length();
174 auto dC = C1 - C2;
175 Vec3 D{m1.x - m2.x, dC, sqrt(ab1.distanceToSqr(ab2) - dC)};
176 return (D / Vec3{1.0, 1.0 + 0.045 * C1, 1.0 + 0.015 * C2}).length();
177 }
178
179 [[nodiscard]] inline double deltaE00(Color const& dst) const noexcept { // 1.0 for JND
180 auto ma = this->sRGBToLinear().linearToXYZ().XYZToLab().toVec3();
181 auto mb = dst.sRGBToLinear().linearToXYZ().XYZToLab().toVec3();
182
183 // https://doi.org/10.1002/col.20070
184 // The CIEDE2000 color-difference formula: Implementation notes,
185 // supplementary test data, and mathematical observations
186
187 constexpr auto rtod = std::numbers::pi / 180.0;
188 constexpr auto dtor = 180.0 / std::numbers::pi;
189 constexpr auto tpi = std::numbers::pi * 2;
190 constexpr auto cons = 6103515625; /*25^7*/
191
192 double L1 = ma.r;
193 double L2 = mb.r;
194 double a1 = ma.g;
195 double a2 = mb.g;
196 double b1 = ma.b;
197 double b2 = mb.b;
198 double dL = L1 - L2;
199 double C1 = sqrt(a1 * a1 + b1 * b1);
200 double C2 = sqrt(a2 * a2 + b2 * b2);
201 double L_ = (L1 + L2) * 0.5;
202 double C_ = (C1 + C2) * 0.5;
203 double C_7 = std::pow(C_, 7);
204 double G = (1 - sqrt(C_7 / (C_7 + cons))) * 0.5;
205 double a1p = a1 * (1 + G);
206 double a2p = a2 * (1 + G);
207 double C1p = sqrt(a1p * a1p + b1 * b1);
208 double C2p = sqrt(a2p * a2p + b2 * b2);
209 double C_p = (C1p + C2p) * 0.5;
210 double dCp = C1p - C2p;
211 double h1p = atan2(b1, a1p);
212 double h2p = atan2(b2, a2p);
213 if (h1p < 0) h1p += tpi;
214 if (h2p < 0) h2p += tpi;
215 h1p *= dtor;
216 h2p *= dtor;
217 double h_p = (h1p + h2p) * 0.5;
218 double dhp = 0;
219 double H_p = 0;
220 if (C1p == 0 || C2p == 0) {
221 H_p = h_p * 2;
222 } else {
223 if (180 < abs(h1p - h2p)) {
224 if (h2p <= h1p) {
225 dhp = h2p - h1p + 360;
226 } else {
227 dhp = h2p - h1p - 360;
228 }
229 if (h2p + h1p < 360) {
230 H_p = h_p + 180;
231 } else {
232 H_p = h_p - 180;
233 }
234 } else {
235 dhp = h2p - h1p;
236 H_p = h_p;
237 }
238 }
239 double T = 1 - 0.17 * cos((H_p - 30) * rtod) + 0.24 * cos((2 * H_p) * rtod) + 0.32 * cos((3 * H_p + 6) * rtod)
240 - 0.20 * cos((4 * H_p - 63.0) * rtod);
241 double dHp = 2 * sqrt(C1p * C2p) * sin(dhp * 0.5 * rtod);
242 L_ -= 50;
243 L_ *= L_;
244 double SL = 1.0 + 0.015 * L_ / sqrt(L_ + 20);
245 double SC = 1.0 + 0.045 * C_p;
246 double SH = 1.0 + 0.015 * C_p * T;
247 double C_p7 = std::pow(C_p, 7);
248 double kH = (H_p - 275) / 25;
249 double RT = -2 * sqrt(C_p7 / (C_p7 + cons)) * sin(60 * exp(-kH * kH) * rtod);
250
251 dL = dL / SL;
252 dCp = dCp / SC;
253 dHp = dHp / SH;
254
255 return sqrt(dL * dL + dCp * dCp + dHp * dHp + RT * dCp * dHp);
256 }
257
258 [[nodiscard]] inline double distanceTo(Color const& dst) const noexcept { return deltaE00(dst); }
259
260public:
261 // member functions
262 // NOLINTBEGIN
263 MCAPI int toARGB() const;
264
265 MCAPI ::std::string toHexString() const;
266 // NOLINTEND
267
268public:
269 // static functions
270 // NOLINTBEGIN
271 MCAPI static ::mce::Color fromARGB(int col);
272
273 MCAPI static ::mce::Color fromHexString(::std::string const& hexStr);
274
275 MCAPI static ::mce::Color fromRGBHexString(::std::string const& hexStr);
276 // NOLINTEND
277
278public:
279 // static variables
280 // NOLINTBEGIN
281 MCAPI static ::mce::Color const& BLACK();
282
283 MCAPI static ::mce::Color const& BLUE();
284
285 MCAPI static ::mce::Color const& CYAN();
286
287 MCAPI static ::mce::Color const& GREEN();
288
289 MCAPI static ::mce::Color const& GREY();
290
291 MCAPI static ::mce::Color const& MINECOIN_GOLD();
292
293 MCAPI static ::mce::Color const& NIL();
294
295 MCAPI static ::mce::Color const& ORANGE();
296
297 MCAPI static ::mce::Color const& PINK();
298
299 MCAPI static ::mce::Color const& PURPLE();
300
301 MCAPI static ::mce::Color const& REBECCA_PURPLE();
302
303 MCAPI static ::mce::Color const& RED();
304
305 MCAPI static ::mce::Color const& SHADE_DOWN();
306
307 MCAPI static ::mce::Color const& SHADE_NORTH_SOUTH();
308
309 MCAPI static ::mce::Color const& SHADE_UP();
310
311 MCAPI static ::mce::Color const& SHADE_WEST_EAST();
312
313 MCAPI static ::mce::Color const& WHITE();
314
315 MCAPI static ::mce::Color const& YELLOW();
316 // NOLINTEND
317
318public:
319 // constructor thunks
320 // NOLINTBEGIN
321 MCFOLD void* $ctor();
322 // NOLINTEND
323};
324
325} // namespace mce
Definition Vec2.h:5
Definition Vec3.h:10
Definition Color.h:13