1use crate::mlaf::mlaf;
30use crate::{Matrix3f, Vector3f, Xyz};
31use pxfm::{f_atan2f, f_hypotf, f_sincosf};
32
33#[repr(C)]
37#[derive(Default, Debug, PartialOrd, PartialEq, Copy, Clone)]
38pub struct Yrg {
39 pub y: f32,
40 pub r: f32,
41 pub g: f32,
42}
43
44#[repr(C)]
46#[derive(Default, Debug, PartialOrd, PartialEq, Copy, Clone)]
47pub struct Ych {
48 pub y: f32,
49 pub c: f32,
50 pub h: f32,
51}
52
53const LMS_TO_XYZ: Matrix3f = Matrix3f {
54 v: [
55 [1.8079466, -1.2997167, 0.34785876],
56 [0.61783963, 0.39595452, -0.041046873],
57 [-0.12546961, 0.20478038, 1.7427418],
58 ],
59};
60const XYZ_TO_LMS: Matrix3f = Matrix3f {
61 v: [
62 [0.257085, 0.859943, -0.031061],
63 [-0.394427, 1.175800, 0.106423],
64 [0.064856, -0.076250, 0.559067],
65 ],
66};
67
68impl Yrg {
69 #[inline]
70 pub const fn new(y: f32, r: f32, g: f32) -> Yrg {
71 Yrg { y, r, g }
72 }
73
74 #[inline]
79 pub fn from_xyz(xyz: Xyz) -> Self {
80 let lms = XYZ_TO_LMS.f_mul_vector(Vector3f {
81 v: [xyz.x, xyz.y, xyz.z],
82 });
83 let y = mlaf(0.68990272 * lms.v[0], 0.34832189, lms.v[1]);
84
85 let a = lms.v[0] + lms.v[1] + lms.v[2];
86 let l = if a == 0. { 0. } else { lms.v[0] / a };
87 let m = if a == 0. { 0. } else { lms.v[1] / a };
88 let r = mlaf(mlaf(0.02062, -0.6873, m), 1.0671, l);
89 let g = mlaf(mlaf(-0.05155, -0.0362, l), 1.7182, m);
90 Yrg { y, r, g }
91 }
92
93 #[inline]
94 pub fn to_xyz(&self) -> Xyz {
95 let l = mlaf(0.95 * self.r, 0.38, self.g);
96 let m = mlaf(mlaf(0.03, 0.59, self.g), 0.02, self.r);
97 let den = mlaf(0.68990272 * l, 0.34832189, m);
98 let a = if den == 0. { 0. } else { self.y / den };
99 let l0 = l * a;
100 let m0 = m * a;
101 let s0 = (1f32 - l - m) * a;
102 let v = Vector3f { v: [l0, m0, s0] };
103 let x = LMS_TO_XYZ.f_mul_vector(v);
104 Xyz {
105 x: x.v[0],
106 y: x.v[1],
107 z: x.v[2],
108 }
109 }
110}
111
112impl Ych {
113 #[inline]
114 pub const fn new(y: f32, c: f32, h: f32) -> Self {
115 Ych { y, c, h }
116 }
117
118 #[inline]
119 pub fn from_yrg(yrg: Yrg) -> Self {
120 let y = yrg.y;
121 let r = yrg.r - 0.21902143;
126 let g = yrg.g - 0.54371398;
127 let c = f_hypotf(g, r);
128 let h = f_atan2f(g, r);
129 Self { y, c, h }
130 }
131
132 #[inline]
133 pub fn to_yrg(&self) -> Yrg {
134 let y = self.y;
135 let c = self.c;
136 let h = self.h;
137 let sincos = f_sincosf(h);
138 let r = mlaf(0.21902143, c, sincos.1);
139 let g = mlaf(0.54371398, c, sincos.0);
140 Yrg { y, r, g }
141 }
142}
143
144pub const fn cie_y_1931_to_cie_y_2006(x: f32) -> f32 {
151 1.05785528 * (x)
152}
153
154#[cfg(test)]
155mod tests {
156 use super::*;
157
158 #[test]
159 fn test_yrg() {
160 let xyz = Xyz::new(0.95, 1.0, 1.08);
161 let yrg = Yrg::from_xyz(xyz);
162 let yrg_to_xyz = yrg.to_xyz();
163 assert!((xyz.x - yrg_to_xyz.x) < 1e-5);
164 assert!((xyz.y - yrg_to_xyz.y) < 1e-5);
165 assert!((xyz.z - yrg_to_xyz.z) < 1e-5);
166 }
167
168 #[test]
169 fn test_ych() {
170 let xyz = Yrg::new(0.5, 0.4, 0.3);
171 let yrg = Ych::from_yrg(xyz);
172 let yrg_to_xyz = yrg.to_yrg();
173 assert!((xyz.y - yrg_to_xyz.y) < 1e-5);
174 assert!((xyz.r - yrg_to_xyz.r) < 1e-5);
175 assert!((xyz.g - yrg_to_xyz.g) < 1e-5);
176 }
177}