color: CM structs, constants & math (#14)

This commit is contained in:
UjinT34 2025-04-06 18:27:46 +03:00 committed by GitHub
parent 175c6b29b6
commit 760d67a2a8
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 165 additions and 1 deletions

View file

@ -1,5 +1,6 @@
#pragma once
#include <array>
namespace Hyprgraphics {
class CColor {
public:
@ -18,6 +19,25 @@ namespace Hyprgraphics {
double l = 0, a = 0, b = 0;
};
// xy 0.0 - 1.0
struct xy {
double x = 0, y = 0;
bool operator==(const xy& p2) const {
return x == p2.x && y == p2.y;
}
};
// XYZ 0.0 - 1.0
struct XYZ {
double x = 0, y = 0, z = 0;
// per-component division
XYZ operator/(const XYZ& other) const {
return {x / other.x, y / other.y, z / other.z};
}
};
CColor(); // black
CColor(const SSRGB& rgb);
CColor(const SHSL& hsl);
@ -27,7 +47,7 @@ namespace Hyprgraphics {
SHSL asHSL() const;
SOkLab asOkLab() const;
bool operator==(const CColor& other) const {
bool operator==(const CColor& other) const {
return other.r == r && other.g == g && other.b == b;
}
@ -35,4 +55,40 @@ namespace Hyprgraphics {
// SRGB space for internal color storage
double r = 0, g = 0, b = 0;
};
// 3x3 matrix for CM transformations
class CMatrix3 {
public:
CMatrix3() = default;
CMatrix3(const std::array<std::array<double, 3>, 3>& values);
CMatrix3 invert() const;
CColor::XYZ operator*(const CColor::XYZ& xyz) const;
CMatrix3 operator*(const CMatrix3& other) const;
const std::array<std::array<double, 3>, 3>& mat();
static const CMatrix3& identity();
private:
std::array<std::array<double, 3>, 3> m = {
0, 0, 0, //
0, 0, 0, //
0, 0, 0, //
};
};
CColor::XYZ xy2xyz(const CColor::xy& xy);
CMatrix3 adaptWhite(const CColor::xy& src, const CColor::xy& dst);
struct SPCPRimaries {
CColor::xy red, green, blue, white;
bool operator==(const SPCPRimaries& p2) const {
return red == p2.red && green == p2.green && blue == p2.blue && white == p2.white;
}
CMatrix3 toXYZ() const; // toXYZ() * rgb -> xyz
CMatrix3 convertMatrix(const SPCPRimaries& dst) const; // convertMatrix(dst) * rgb with "this" primaries -> rgb with dst primaries
};
};

View file

@ -26,6 +26,114 @@ static double hueToRgb(double p, double q, double t) {
return p;
}
Hyprgraphics::CMatrix3::CMatrix3(const std::array<std::array<double, 3>, 3>& values) : m(values) {}
CMatrix3 Hyprgraphics::CMatrix3::invert() const {
double invDet = 1 /
(0 //
+ m[0][0] * (m[1][1] * m[2][2] - m[2][1] * m[1][2]) //
- m[0][1] * (m[1][0] * m[2][2] - m[1][2] * m[2][0]) //
+ m[0][2] * (m[1][0] * m[2][1] - m[1][1] * m[2][0]) //
);
return CMatrix3(std::array<std::array<double, 3>, 3>{
(m[1][1] * m[2][2] - m[2][1] * m[1][2]) * invDet, (m[0][2] * m[2][1] - m[0][1] * m[2][2]) * invDet, (m[0][1] * m[1][2] - m[0][2] * m[1][1]) * invDet, //
(m[1][2] * m[2][0] - m[1][0] * m[2][2]) * invDet, (m[0][0] * m[2][2] - m[0][2] * m[2][0]) * invDet, (m[1][0] * m[0][2] - m[0][0] * m[1][2]) * invDet, //
(m[1][0] * m[2][1] - m[2][0] * m[1][1]) * invDet, (m[2][0] * m[0][1] - m[0][0] * m[2][1]) * invDet, (m[0][0] * m[1][1] - m[1][0] * m[0][1]) * invDet, //
});
}
CColor::XYZ Hyprgraphics::CMatrix3::operator*(const CColor::XYZ& value) const {
return CColor::XYZ{
m[0][0] * value.x + m[0][1] * value.y + m[0][2] * value.z, //
m[1][0] * value.x + m[1][1] * value.y + m[1][2] * value.z, //
m[2][0] * value.x + m[2][1] * value.y + m[2][2] * value.z, //
};
}
CMatrix3 Hyprgraphics::CMatrix3::operator*(const CMatrix3& other) const {
std::array<std::array<double, 3>, 3> res = {0, 0, 0, 0, 0, 0, 0, 0, 0};
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
for (int k = 0; k < 3; k++) {
res[i][j] += m[i][k] * other.m[k][j];
}
}
}
return CMatrix3(res);
}
const std::array<std::array<double, 3>, 3>& Hyprgraphics::CMatrix3::mat() {
return m;
};
const CMatrix3& CMatrix3::identity() {
static const CMatrix3 Identity3 = CMatrix3(std::array<std::array<double, 3>, 3>{
1, 0, 0, //
0, 1, 0, //
0, 0, 1, //
});
return Identity3;
}
CColor::XYZ Hyprgraphics::xy2xyz(const CColor::xy& xy) {
if (xy.y == 0.0)
return {0.0, 0.0, 0.0};
return {xy.x / xy.y, 1.0, (1.0 - xy.x - xy.y) / xy.y};
}
CMatrix3 Bradford = CMatrix3(std::array<std::array<double, 3>, 3>{
0.8951, 0.2664, -0.1614, //
-0.7502, 1.7135, 0.0367, //
0.0389, -0.0685, 1.0296, //
});
CMatrix3 BradfordInv = Bradford.invert();
CMatrix3 Hyprgraphics::adaptWhite(const CColor::xy& src, const CColor::xy& dst) {
if (src == dst)
return CMatrix3::identity();
const auto srcXYZ = xy2xyz(src);
const auto dstXYZ = xy2xyz(dst);
const auto factors = (Bradford * dstXYZ) / (Bradford * srcXYZ);
return BradfordInv *
CMatrix3(std::array<std::array<double, 3>, 3>{
factors.x, 0.0, 0.0, //
0.0, factors.y, 0.0, //
0.0, 0.0, factors.z, //
}) *
Bradford;
}
CMatrix3 Hyprgraphics::SPCPRimaries::toXYZ() const {
const auto r = xy2xyz(red);
const auto g = xy2xyz(green);
const auto b = xy2xyz(blue);
const auto w = xy2xyz(white);
const auto invMat = CMatrix3(std::array<std::array<double, 3>, 3>{
r.x, g.x, b.x, //
r.y, g.y, b.y, //
r.z, g.z, b.z, //
})
.invert();
const auto s = invMat * w;
return std::array<std::array<double, 3>, 3>{
s.x * r.x, s.y * g.x, s.z * b.x, //
s.x * r.y, s.y * g.y, s.z * b.y, //
s.x * r.z, s.y * g.z, s.z * b.z, //
};
}
CMatrix3 Hyprgraphics::SPCPRimaries::convertMatrix(const SPCPRimaries& dst) const {
return dst.toXYZ().invert() * adaptWhite(white, dst.white) * toXYZ();
}
Hyprgraphics::CColor::CColor() {
;
}