13class Color :
public ll::math::floatN4<Color> {
15 [[nodiscard]]
constexpr Color()
noexcept =
default;
17 template <std::
integral T0, std::
integral T1, std::
integral T2, std::
integral T3 = u
int>
18 [[nodiscard]]
constexpr Color(T0
const& ir, T1
const& ig, T2
const& ib, T3
const& ia = 255) noexcept
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
25 template <std::
floating_po
int T0, std::
floating_po
int T1, std::
floating_po
int T2, std::
floating_po
int 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) {}
29 template <ll::math::IsFloatN V, std::
floating_po
int 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) {}
34 [[nodiscard]]
constexpr Color(uint hex) noexcept :
Color((hex >> 16) & 0xFF, (hex >> 8) & 0xFF, hex & 0xFF) {}
36 [[nodiscard]]
constexpr Color(std::string_view hex) noexcept : floatN4(0, 0, 0, 1) {
41 using ll::string_utils::digitFromChar;
43 switch (hex.length()) {
45 a =
static_cast<float>(digitFromChar(hex[3]) * 17) / 255.0f;
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;
52 a =
static_cast<float>(16 * digitFromChar(hex[6]) + digitFromChar(hex[7])) / 255.0f;
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;
63 [[nodiscard]]
constexpr class Vec3 toVec3() const noexcept {
return {r, g, b}; }
65 [[nodiscard]]
constexpr class mce::Color sRGBToLinear() const noexcept {
67 return {select(color.gt(0.04045f), pow(color / 1.055f + 0.055f, {2.4f}), color / 12.92f), a};
70 [[nodiscard]]
constexpr class mce::Color linearTosRGB() const noexcept {
72 return {select(color.gt(0.0031308f), pow(color, {1.0f / 2.4f}) * 1.055f - 0.055f, color * 12.92f), a};
75 [[nodiscard]]
constexpr class mce::Color linearToXYZ() const noexcept {
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}),
85 [[nodiscard]]
constexpr class mce::Color XYZToLinear() const noexcept {
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}),
95 [[nodiscard]]
constexpr class mce::Color linearToLMS() const noexcept {
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}),
105 [[nodiscard]]
constexpr class mce::Color LMSToLinear() const noexcept {
106 auto color{toVec3()};
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}),
115 [[nodiscard]]
constexpr class mce::Color LMSToOklab() const noexcept {
116 auto color{pow(toVec3(), {1.0f / 3.0f})};
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}),
125 [[nodiscard]]
constexpr class mce::Color OklabToLMS() const noexcept {
126 auto color{toVec3()};
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})},
136 [[nodiscard]]
constexpr class mce::Color XYZToLab() const noexcept {
137 auto color = toVec3() /
Vec3{0.950489f, 1.0f, 1.08884f};
139 constexpr float delta = 6.0f / 29.0f;
140 constexpr float delta2 = delta * delta;
141 constexpr float delta3 = delta2 * delta;
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};
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};
151 constexpr float delta = 6.0f / 29.0f;
152 constexpr float delta2 = delta * delta;
154 color = select(color.gt(delta), pow(color, {3.0f}), (color - 4.0f / 29.0f) * (3.0f * delta2));
156 color *
Vec3{0.950489f, 1.0f, 1.08884f},
161 [[nodiscard]]
constexpr double deltaE76(
Color const& dst)
const noexcept {
162 return this->sRGBToLinear().linearToXYZ().XYZToLab().toVec3().distanceTo(
163 dst.sRGBToLinear().linearToXYZ().XYZToLab().toVec3()
167 [[nodiscard]]
inline double deltaE94(
Color const& dst)
const noexcept {
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();
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();
179 [[nodiscard]]
inline double deltaE00(
Color const& dst)
const noexcept {
180 auto ma = this->sRGBToLinear().linearToXYZ().XYZToLab().toVec3();
181 auto mb = dst.sRGBToLinear().linearToXYZ().XYZToLab().toVec3();
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;
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;
217 double h_p = (h1p + h2p) * 0.5;
220 if (C1p == 0 || C2p == 0) {
223 if (180 < abs(h1p - h2p)) {
225 dhp = h2p - h1p + 360;
227 dhp = h2p - h1p - 360;
229 if (h2p + h1p < 360) {
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);
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);
255 return sqrt(dL * dL + dCp * dCp + dHp * dHp + RT * dCp * dHp);
258 [[nodiscard]]
inline double distanceTo(
Color const& dst)
const noexcept {
return deltaE00(dst); }
263 MCAPI
int toARGB()
const;
265 MCAPI ::std::string toHexString()
const;
271 MCAPI static ::mce::Color fromARGB(
int col);
273 MCAPI static ::mce::Color fromHexString(::std::string
const& hexStr);
275 MCAPI static ::mce::Color fromRGBHexString(::std::string
const& hexStr);
281 MCAPI static ::mce::Color
const& BLACK();
283 MCAPI static ::mce::Color
const& BLUE();
285 MCAPI static ::mce::Color
const& CYAN();
287 MCAPI static ::mce::Color
const& GREEN();
289 MCAPI static ::mce::Color
const& GREY();
291 MCAPI static ::mce::Color
const& MINECOIN_GOLD();
293 MCAPI static ::mce::Color
const& NIL();
295 MCAPI static ::mce::Color
const& ORANGE();
297 MCAPI static ::mce::Color
const& PINK();
299 MCAPI static ::mce::Color
const& PURPLE();
301 MCAPI static ::mce::Color
const& REBECCA_PURPLE();
303 MCAPI static ::mce::Color
const& RED();
305 MCAPI static ::mce::Color
const& SHADE_DOWN();
307 MCAPI static ::mce::Color
const& SHADE_NORTH_SOUTH();
309 MCAPI static ::mce::Color
const& SHADE_UP();
311 MCAPI static ::mce::Color
const& SHADE_WEST_EAST();
313 MCAPI static ::mce::Color
const& WHITE();
315 MCAPI static ::mce::Color
const& YELLOW();
321 MCFOLD
void* $ctor();