gpui_kit_material_color/dynamic/
utils.rs1const SRGB_TO_XYZ: [[f64; 3]; 3] = [
9 [0.41233895, 0.35762064, 0.18051042],
10 [0.2126, 0.7152, 0.0722],
11 [0.01932141, 0.11916382, 0.95034478],
12];
13
14const XYZ_TO_SRGB: [[f64; 3]; 3] = [
15 [
16 3.2413774792388685,
17 -1.5376652402851851,
18 -0.49885366846268053,
19 ],
20 [-0.9691452513005321, 1.8758853451067872, 0.04156585616912061],
21 [
22 0.05562093689691305,
23 -0.20395524564742123,
24 1.0571799111220335,
25 ],
26];
27
28pub const WHITE_POINT_D65: [f64; 3] = [95.047, 100.0, 108.883];
30
31pub fn signum(num: f64) -> f64 {
33 if num < 0. {
34 -1.
35 } else if num == 0. {
36 0.
37 } else {
38 1.
39 }
40}
41
42pub fn lerp(start: f64, stop: f64, amount: f64) -> f64 {
44 (1. - amount) * start + amount * stop
45}
46
47pub fn clamp_double(min: f64, max: f64, input: f64) -> f64 {
51 if input < min {
52 min
53 } else if input > max {
54 max
55 } else {
56 input
57 }
58}
59
60pub fn sanitize_degrees_int(degrees: i32) -> i32 {
62 degrees.rem_euclid(360)
63}
64
65pub fn sanitize_degrees_double(degrees: f64) -> f64 {
67 let degrees = degrees % 360.;
68 if degrees < 0. {
69 degrees + 360.
70 } else {
71 degrees
72 }
73}
74
75pub fn rotation_direction(from: f64, to: f64) -> f64 {
78 if sanitize_degrees_double(to - from) <= 180. {
79 1.
80 } else {
81 -1.
82 }
83}
84
85pub fn difference_degrees(a: f64, b: f64) -> f64 {
87 180. - ((a - b).abs() - 180.).abs()
88}
89
90pub(crate) fn matrix_multiply(row: [f64; 3], matrix: &[[f64; 3]; 3]) -> [f64; 3] {
92 [
93 row[0] * matrix[0][0] + row[1] * matrix[0][1] + row[2] * matrix[0][2],
94 row[0] * matrix[1][0] + row[1] * matrix[1][1] + row[2] * matrix[1][2],
95 row[0] * matrix[2][0] + row[1] * matrix[2][1] + row[2] * matrix[2][2],
96 ]
97}
98
99pub const fn argb_from_rgb(red: u8, green: u8, blue: u8) -> u32 {
101 0xff00_0000 | (red as u32) << 16 | (green as u32) << 8 | blue as u32
102}
103
104pub fn argb_from_linrgb(linrgb: [f64; 3]) -> u32 {
106 argb_from_rgb(
107 delinearized(linrgb[0]),
108 delinearized(linrgb[1]),
109 delinearized(linrgb[2]),
110 )
111}
112
113pub const fn red_from_argb(argb: u32) -> u8 {
115 (argb >> 16) as u8
116}
117
118pub const fn green_from_argb(argb: u32) -> u8 {
120 (argb >> 8) as u8
121}
122
123pub const fn blue_from_argb(argb: u32) -> u8 {
125 argb as u8
126}
127
128pub fn argb_from_xyz(x: f64, y: f64, z: f64) -> u32 {
130 argb_from_linrgb(matrix_multiply([x, y, z], &XYZ_TO_SRGB))
131}
132
133pub fn xyz_from_argb(argb: u32) -> [f64; 3] {
135 matrix_multiply(
136 [
137 linearized(red_from_argb(argb)),
138 linearized(green_from_argb(argb)),
139 linearized(blue_from_argb(argb)),
140 ],
141 &SRGB_TO_XYZ,
142 )
143}
144
145pub fn lab_from_argb(argb: u32) -> [f64; 3] {
147 let [x, y, z] = xyz_from_argb(argb);
148 let fx = lab_f(x / WHITE_POINT_D65[0]);
149 let fy = lab_f(y / WHITE_POINT_D65[1]);
150 let fz = lab_f(z / WHITE_POINT_D65[2]);
151 [116. * fy - 16., 500. * (fx - fy), 200. * (fy - fz)]
152}
153
154pub fn argb_from_lstar(lstar: f64) -> u32 {
156 let component = delinearized(y_from_lstar(lstar));
157 argb_from_rgb(component, component, component)
158}
159
160pub fn lstar_from_argb(argb: u32) -> f64 {
162 116. * lab_f(xyz_from_argb(argb)[1] / 100.) - 16.
163}
164
165pub fn y_from_lstar(lstar: f64) -> f64 {
167 100. * lab_invf((lstar + 16.) / 116.)
168}
169
170pub fn lstar_from_y(y: f64) -> f64 {
172 lab_f(y / 100.) * 116. - 16.
173}
174
175pub fn linearized(component: u8) -> f64 {
177 let normalized = f64::from(component) / 255.;
178 if normalized <= 0.040449936 {
179 normalized / 12.92 * 100.
180 } else {
181 ((normalized + 0.055) / 1.055).powf(2.4) * 100.
182 }
183}
184
185pub fn delinearized(component: f64) -> u8 {
187 let normalized = component / 100.;
188 let delinearized = if normalized <= 0.0031308 {
189 normalized * 12.92
190 } else {
191 1.055 * normalized.powf(1. / 2.4) - 0.055
192 };
193 (delinearized * 255.).round() as u8
195}
196
197fn lab_f(t: f64) -> f64 {
198 const E: f64 = 216. / 24389.;
199 const KAPPA: f64 = 24389. / 27.;
200 if t > E {
201 t.powf(1. / 3.)
202 } else {
203 (KAPPA * t + 16.) / 116.
204 }
205}
206
207fn lab_invf(ft: f64) -> f64 {
208 const E: f64 = 216. / 24389.;
209 const KAPPA: f64 = 24389. / 27.;
210 let ft3 = ft * ft * ft;
211 if ft3 > E {
212 ft3
213 } else {
214 (116. * ft - 16.) / KAPPA
215 }
216}