bevy_color/
color.rs

1use crate::{
2    color_difference::EuclideanDistance, Alpha, Hsla, Hsva, Hue, Hwba, Laba, Lcha, LinearRgba,
3    Luminance, Mix, Oklaba, Oklcha, Saturation, Srgba, StandardColor, Xyza,
4};
5use bevy_math::{MismatchedUnitsError, TryStableInterpolate};
6#[cfg(feature = "bevy_reflect")]
7use bevy_reflect::prelude::*;
8use derive_more::derive::From;
9
10/// An enumerated type that can represent any of the color types in this crate.
11///
12/// This is useful when you need to store a color in a data structure that can't be generic over
13/// the color type.
14#[doc = include_str!("../docs/conversion.md")]
15/// <div>
16#[doc = include_str!("../docs/diagrams/model_graph.svg")]
17/// </div>
18///
19/// # Operations
20///
21/// [`Color`] supports all the standard color operations, such as [mixing](Mix),
22/// [luminance](Luminance) and [hue](Hue) adjustment,
23/// and [diffing](EuclideanDistance). These operations delegate to the concrete color space contained
24/// by [`Color`], but will convert to [`Oklch`](Oklcha) for operations which aren't supported in the
25/// current space. After performing the operation, if a conversion was required, the result will be
26/// converted back into the original color space.
27///
28/// ```rust
29/// # use bevy_color::{Hue, Color};
30/// let red_hsv = Color::hsv(0., 1., 1.);
31/// let red_srgb = Color::srgb(1., 0., 0.);
32///
33/// // HSV has a definition of hue, so it will be returned.
34/// red_hsv.hue();
35///
36/// // SRGB doesn't have a native definition for hue.
37/// // Converts to Oklch and returns that result.
38/// red_srgb.hue();
39/// ```
40///
41/// [`Oklch`](Oklcha) has been chosen as the intermediary space in cases where conversion is required
42/// due to its perceptual uniformity and broad support for Bevy's color operations.
43/// To avoid the cost of repeated conversion, and ensure consistent results where that is desired,
44/// first convert this [`Color`] into your desired color space.
45#[derive(Debug, Clone, Copy, PartialEq, From)]
46#[cfg_attr(
47    feature = "bevy_reflect",
48    derive(Reflect),
49    reflect(Clone, PartialEq, Default)
50)]
51#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
52#[cfg_attr(
53    all(feature = "serialize", feature = "bevy_reflect"),
54    reflect(Serialize, Deserialize)
55)]
56pub enum Color {
57    /// A color in the sRGB color space with alpha.
58    Srgba(Srgba),
59    /// A color in the linear sRGB color space with alpha.
60    LinearRgba(LinearRgba),
61    /// A color in the HSL color space with alpha.
62    Hsla(Hsla),
63    /// A color in the HSV color space with alpha.
64    Hsva(Hsva),
65    /// A color in the HWB color space with alpha.
66    Hwba(Hwba),
67    /// A color in the LAB color space with alpha.
68    Laba(Laba),
69    /// A color in the LCH color space with alpha.
70    Lcha(Lcha),
71    /// A color in the Oklab color space with alpha.
72    Oklaba(Oklaba),
73    /// A color in the Oklch color space with alpha.
74    Oklcha(Oklcha),
75    /// A color in the XYZ color space with alpha.
76    Xyza(Xyza),
77}
78
79impl StandardColor for Color {}
80
81impl Color {
82    /// Return the color as a linear RGBA color.
83    pub fn to_linear(&self) -> LinearRgba {
84        (*self).into()
85    }
86
87    /// Return the color as an SRGBA color.
88    pub fn to_srgba(&self) -> Srgba {
89        (*self).into()
90    }
91
92    /// Creates a new [`Color`] object storing a [`Srgba`] color.
93    ///
94    /// # Arguments
95    ///
96    /// * `red` - Red channel. [0.0, 1.0]
97    /// * `green` - Green channel. [0.0, 1.0]
98    /// * `blue` - Blue channel. [0.0, 1.0]
99    /// * `alpha` - Alpha channel. [0.0, 1.0]
100    pub const fn srgba(red: f32, green: f32, blue: f32, alpha: f32) -> Self {
101        Self::Srgba(Srgba {
102            red,
103            green,
104            blue,
105            alpha,
106        })
107    }
108
109    /// Creates a new [`Color`] object storing a [`Srgba`] color with an alpha of 1.0.
110    ///
111    /// # Arguments
112    ///
113    /// * `red` - Red channel. [0.0, 1.0]
114    /// * `green` - Green channel. [0.0, 1.0]
115    /// * `blue` - Blue channel. [0.0, 1.0]
116    pub const fn srgb(red: f32, green: f32, blue: f32) -> Self {
117        Self::Srgba(Srgba {
118            red,
119            green,
120            blue,
121            alpha: 1.0,
122        })
123    }
124
125    /// Reads an array of floats to creates a new [`Color`] object storing a [`Srgba`] color with an alpha of 1.0.
126    ///
127    /// # Arguments
128    /// * `array` - Red, Green and Blue channels. Each channel is in the range [0.0, 1.0]
129    pub const fn srgb_from_array(array: [f32; 3]) -> Self {
130        Self::Srgba(Srgba {
131            red: array[0],
132            green: array[1],
133            blue: array[2],
134            alpha: 1.0,
135        })
136    }
137
138    /// Creates a new [`Color`] object storing a [`Srgba`] color from [`u8`] values.
139    ///
140    /// # Arguments
141    ///
142    /// * `red` - Red channel. [0, 255]
143    /// * `green` - Green channel. [0, 255]
144    /// * `blue` - Blue channel. [0, 255]
145    /// * `alpha` - Alpha channel. [0, 255]
146    pub const fn srgba_u8(red: u8, green: u8, blue: u8, alpha: u8) -> Self {
147        Self::Srgba(Srgba {
148            red: red as f32 / 255.0,
149            green: green as f32 / 255.0,
150            blue: blue as f32 / 255.0,
151            alpha: alpha as f32 / 255.0,
152        })
153    }
154
155    /// Creates a new [`Color`] object storing a [`Srgba`] color from [`u8`] values with an alpha of 1.0.
156    ///
157    /// # Arguments
158    ///
159    /// * `red` - Red channel. [0, 255]
160    /// * `green` - Green channel. [0, 255]
161    /// * `blue` - Blue channel. [0, 255]
162    pub const fn srgb_u8(red: u8, green: u8, blue: u8) -> Self {
163        Self::Srgba(Srgba {
164            red: red as f32 / 255.0,
165            green: green as f32 / 255.0,
166            blue: blue as f32 / 255.0,
167            alpha: 1.0,
168        })
169    }
170
171    /// Creates a new [`Color`] object storing a [`LinearRgba`] color.
172    ///
173    /// # Arguments
174    ///
175    /// * `red` - Red channel. [0.0, 1.0]
176    /// * `green` - Green channel. [0.0, 1.0]
177    /// * `blue` - Blue channel. [0.0, 1.0]
178    /// * `alpha` - Alpha channel. [0.0, 1.0]
179    pub const fn linear_rgba(red: f32, green: f32, blue: f32, alpha: f32) -> Self {
180        Self::LinearRgba(LinearRgba {
181            red,
182            green,
183            blue,
184            alpha,
185        })
186    }
187
188    /// Creates a new [`Color`] object storing a [`LinearRgba`] color with an alpha of 1.0.
189    ///
190    /// # Arguments
191    ///
192    /// * `red` - Red channel. [0.0, 1.0]
193    /// * `green` - Green channel. [0.0, 1.0]
194    /// * `blue` - Blue channel. [0.0, 1.0]
195    pub const fn linear_rgb(red: f32, green: f32, blue: f32) -> Self {
196        Self::LinearRgba(LinearRgba {
197            red,
198            green,
199            blue,
200            alpha: 1.0,
201        })
202    }
203
204    /// Creates a new [`Color`] object storing a [`Hsla`] color.
205    ///
206    /// # Arguments
207    ///
208    /// * `hue` - Hue channel. [0.0, 360.0]
209    /// * `saturation` - Saturation channel. [0.0, 1.0]
210    /// * `lightness` - Lightness channel. [0.0, 1.0]
211    /// * `alpha` - Alpha channel. [0.0, 1.0]
212    pub const fn hsla(hue: f32, saturation: f32, lightness: f32, alpha: f32) -> Self {
213        Self::Hsla(Hsla {
214            hue,
215            saturation,
216            lightness,
217            alpha,
218        })
219    }
220
221    /// Creates a new [`Color`] object storing a [`Hsla`] color with an alpha of 1.0.
222    ///
223    /// # Arguments
224    ///
225    /// * `hue` - Hue channel. [0.0, 360.0]
226    /// * `saturation` - Saturation channel. [0.0, 1.0]
227    /// * `lightness` - Lightness channel. [0.0, 1.0]
228    pub const fn hsl(hue: f32, saturation: f32, lightness: f32) -> Self {
229        Self::Hsla(Hsla {
230            hue,
231            saturation,
232            lightness,
233            alpha: 1.0,
234        })
235    }
236
237    /// Creates a new [`Color`] object storing a [`Hsva`] color.
238    ///
239    /// # Arguments
240    ///
241    /// * `hue` - Hue channel. [0.0, 360.0]
242    /// * `saturation` - Saturation channel. [0.0, 1.0]
243    /// * `value` - Value channel. [0.0, 1.0]
244    /// * `alpha` - Alpha channel. [0.0, 1.0]
245    pub const fn hsva(hue: f32, saturation: f32, value: f32, alpha: f32) -> Self {
246        Self::Hsva(Hsva {
247            hue,
248            saturation,
249            value,
250            alpha,
251        })
252    }
253
254    /// Creates a new [`Color`] object storing a [`Hsva`] color with an alpha of 1.0.
255    ///
256    /// # Arguments
257    ///
258    /// * `hue` - Hue channel. [0.0, 360.0]
259    /// * `saturation` - Saturation channel. [0.0, 1.0]
260    /// * `value` - Value channel. [0.0, 1.0]
261    pub const fn hsv(hue: f32, saturation: f32, value: f32) -> Self {
262        Self::Hsva(Hsva {
263            hue,
264            saturation,
265            value,
266            alpha: 1.0,
267        })
268    }
269
270    /// Creates a new [`Color`] object storing a [`Hwba`] color.
271    ///
272    /// # Arguments
273    ///
274    /// * `hue` - Hue channel. [0.0, 360.0]
275    /// * `whiteness` - Whiteness channel. [0.0, 1.0]
276    /// * `blackness` - Blackness channel. [0.0, 1.0]
277    /// * `alpha` - Alpha channel. [0.0, 1.0]
278    pub const fn hwba(hue: f32, whiteness: f32, blackness: f32, alpha: f32) -> Self {
279        Self::Hwba(Hwba {
280            hue,
281            whiteness,
282            blackness,
283            alpha,
284        })
285    }
286
287    /// Creates a new [`Color`] object storing a [`Hwba`] color with an alpha of 1.0.
288    ///
289    /// # Arguments
290    ///
291    /// * `hue` - Hue channel. [0.0, 360.0]
292    /// * `whiteness` - Whiteness channel. [0.0, 1.0]
293    /// * `blackness` - Blackness channel. [0.0, 1.0]
294    pub const fn hwb(hue: f32, whiteness: f32, blackness: f32) -> Self {
295        Self::Hwba(Hwba {
296            hue,
297            whiteness,
298            blackness,
299            alpha: 1.0,
300        })
301    }
302
303    /// Creates a new [`Color`] object storing a [`Laba`] color.
304    ///
305    /// # Arguments
306    ///
307    /// * `lightness` - Lightness channel. [0.0, 1.5]
308    /// * `a` - a axis. [-1.5, 1.5]
309    /// * `b` - b axis. [-1.5, 1.5]
310    /// * `alpha` - Alpha channel. [0.0, 1.0]
311    pub const fn laba(lightness: f32, a: f32, b: f32, alpha: f32) -> Self {
312        Self::Laba(Laba {
313            lightness,
314            a,
315            b,
316            alpha,
317        })
318    }
319
320    /// Creates a new [`Color`] object storing a [`Laba`] color with an alpha of 1.0.
321    ///
322    /// # Arguments
323    ///
324    /// * `lightness` - Lightness channel. [0.0, 1.5]
325    /// * `a` - a axis. [-1.5, 1.5]
326    /// * `b` - b axis. [-1.5, 1.5]
327    pub const fn lab(lightness: f32, a: f32, b: f32) -> Self {
328        Self::Laba(Laba {
329            lightness,
330            a,
331            b,
332            alpha: 1.0,
333        })
334    }
335
336    /// Creates a new [`Color`] object storing a [`Lcha`] color.
337    ///
338    /// # Arguments
339    ///
340    /// * `lightness` - Lightness channel. [0.0, 1.5]
341    /// * `chroma` - Chroma channel. [0.0, 1.5]
342    /// * `hue` - Hue channel. [0.0, 360.0]
343    /// * `alpha` - Alpha channel. [0.0, 1.0]
344    pub const fn lcha(lightness: f32, chroma: f32, hue: f32, alpha: f32) -> Self {
345        Self::Lcha(Lcha {
346            lightness,
347            chroma,
348            hue,
349            alpha,
350        })
351    }
352
353    /// Creates a new [`Color`] object storing a [`Lcha`] color with an alpha of 1.0.
354    ///
355    /// # Arguments
356    ///
357    /// * `lightness` - Lightness channel. [0.0, 1.5]
358    /// * `chroma` - Chroma channel. [0.0, 1.5]
359    /// * `hue` - Hue channel. [0.0, 360.0]
360    pub const fn lch(lightness: f32, chroma: f32, hue: f32) -> Self {
361        Self::Lcha(Lcha {
362            lightness,
363            chroma,
364            hue,
365            alpha: 1.0,
366        })
367    }
368
369    /// Creates a new [`Color`] object storing a [`Oklaba`] color.
370    ///
371    /// # Arguments
372    ///
373    /// * `lightness` - Lightness channel. [0.0, 1.0]
374    /// * `a` - Green-red channel. [-1.0, 1.0]
375    /// * `b` - Blue-yellow channel. [-1.0, 1.0]
376    /// * `alpha` - Alpha channel. [0.0, 1.0]
377    pub const fn oklaba(lightness: f32, a: f32, b: f32, alpha: f32) -> Self {
378        Self::Oklaba(Oklaba {
379            lightness,
380            a,
381            b,
382            alpha,
383        })
384    }
385
386    /// Creates a new [`Color`] object storing a [`Oklaba`] color with an alpha of 1.0.
387    ///
388    /// # Arguments
389    ///
390    /// * `lightness` - Lightness channel. [0.0, 1.0]
391    /// * `a` - Green-red channel. [-1.0, 1.0]
392    /// * `b` - Blue-yellow channel. [-1.0, 1.0]
393    pub const fn oklab(lightness: f32, a: f32, b: f32) -> Self {
394        Self::Oklaba(Oklaba {
395            lightness,
396            a,
397            b,
398            alpha: 1.0,
399        })
400    }
401
402    /// Creates a new [`Color`] object storing a [`Oklcha`] color.
403    ///
404    /// # Arguments
405    ///
406    /// * `lightness` - Lightness channel. [0.0, 1.0]
407    /// * `chroma` - Chroma channel. [0.0, 1.0]
408    /// * `hue` - Hue channel. [0.0, 360.0]
409    /// * `alpha` - Alpha channel. [0.0, 1.0]
410    pub const fn oklcha(lightness: f32, chroma: f32, hue: f32, alpha: f32) -> Self {
411        Self::Oklcha(Oklcha {
412            lightness,
413            chroma,
414            hue,
415            alpha,
416        })
417    }
418
419    /// Creates a new [`Color`] object storing a [`Oklcha`] color with an alpha of 1.0.
420    ///
421    /// # Arguments
422    ///
423    /// * `lightness` - Lightness channel. [0.0, 1.0]
424    /// * `chroma` - Chroma channel. [0.0, 1.0]
425    /// * `hue` - Hue channel. [0.0, 360.0]
426    pub const fn oklch(lightness: f32, chroma: f32, hue: f32) -> Self {
427        Self::Oklcha(Oklcha {
428            lightness,
429            chroma,
430            hue,
431            alpha: 1.0,
432        })
433    }
434
435    /// Creates a new [`Color`] object storing a [`Xyza`] color.
436    ///
437    /// # Arguments
438    ///
439    /// * `x` - x-axis. [0.0, 1.0]
440    /// * `y` - y-axis. [0.0, 1.0]
441    /// * `z` - z-axis. [0.0, 1.0]
442    /// * `alpha` - Alpha channel. [0.0, 1.0]
443    pub const fn xyza(x: f32, y: f32, z: f32, alpha: f32) -> Self {
444        Self::Xyza(Xyza { x, y, z, alpha })
445    }
446
447    /// Creates a new [`Color`] object storing a [`Xyza`] color with an alpha of 1.0.
448    ///
449    /// # Arguments
450    ///
451    /// * `x` - x-axis. [0.0, 1.0]
452    /// * `y` - y-axis. [0.0, 1.0]
453    /// * `z` - z-axis. [0.0, 1.0]
454    pub const fn xyz(x: f32, y: f32, z: f32) -> Self {
455        Self::Xyza(Xyza {
456            x,
457            y,
458            z,
459            alpha: 1.0,
460        })
461    }
462
463    /// A fully white [`Color::LinearRgba`] color with an alpha of 1.0.
464    pub const WHITE: Self = Self::linear_rgb(1.0, 1.0, 1.0);
465
466    /// A fully black [`Color::LinearRgba`] color with an alpha of 1.0.
467    pub const BLACK: Self = Self::linear_rgb(0., 0., 0.);
468
469    /// A fully transparent [`Color::LinearRgba`] color with 0 red, green and blue.
470    pub const NONE: Self = Self::linear_rgba(0., 0., 0., 0.);
471}
472
473impl Default for Color {
474    /// A fully white [`Color::LinearRgba`] color with an alpha of 1.0.
475    fn default() -> Self {
476        Color::WHITE
477    }
478}
479
480impl Alpha for Color {
481    fn with_alpha(&self, alpha: f32) -> Self {
482        let mut new = *self;
483
484        match &mut new {
485            Color::Srgba(x) => *x = x.with_alpha(alpha),
486            Color::LinearRgba(x) => *x = x.with_alpha(alpha),
487            Color::Hsla(x) => *x = x.with_alpha(alpha),
488            Color::Hsva(x) => *x = x.with_alpha(alpha),
489            Color::Hwba(x) => *x = x.with_alpha(alpha),
490            Color::Laba(x) => *x = x.with_alpha(alpha),
491            Color::Lcha(x) => *x = x.with_alpha(alpha),
492            Color::Oklaba(x) => *x = x.with_alpha(alpha),
493            Color::Oklcha(x) => *x = x.with_alpha(alpha),
494            Color::Xyza(x) => *x = x.with_alpha(alpha),
495        }
496
497        new
498    }
499
500    fn alpha(&self) -> f32 {
501        match self {
502            Color::Srgba(x) => x.alpha(),
503            Color::LinearRgba(x) => x.alpha(),
504            Color::Hsla(x) => x.alpha(),
505            Color::Hsva(x) => x.alpha(),
506            Color::Hwba(x) => x.alpha(),
507            Color::Laba(x) => x.alpha(),
508            Color::Lcha(x) => x.alpha(),
509            Color::Oklaba(x) => x.alpha(),
510            Color::Oklcha(x) => x.alpha(),
511            Color::Xyza(x) => x.alpha(),
512        }
513    }
514
515    fn set_alpha(&mut self, alpha: f32) {
516        match self {
517            Color::Srgba(x) => x.set_alpha(alpha),
518            Color::LinearRgba(x) => x.set_alpha(alpha),
519            Color::Hsla(x) => x.set_alpha(alpha),
520            Color::Hsva(x) => x.set_alpha(alpha),
521            Color::Hwba(x) => x.set_alpha(alpha),
522            Color::Laba(x) => x.set_alpha(alpha),
523            Color::Lcha(x) => x.set_alpha(alpha),
524            Color::Oklaba(x) => x.set_alpha(alpha),
525            Color::Oklcha(x) => x.set_alpha(alpha),
526            Color::Xyza(x) => x.set_alpha(alpha),
527        }
528    }
529}
530
531impl From<Color> for Srgba {
532    fn from(value: Color) -> Self {
533        match value {
534            Color::Srgba(srgba) => srgba,
535            Color::LinearRgba(linear) => linear.into(),
536            Color::Hsla(hsla) => hsla.into(),
537            Color::Hsva(hsva) => hsva.into(),
538            Color::Hwba(hwba) => hwba.into(),
539            Color::Laba(laba) => laba.into(),
540            Color::Lcha(lcha) => lcha.into(),
541            Color::Oklaba(oklab) => oklab.into(),
542            Color::Oklcha(oklch) => oklch.into(),
543            Color::Xyza(xyza) => xyza.into(),
544        }
545    }
546}
547
548impl From<Color> for LinearRgba {
549    fn from(value: Color) -> Self {
550        match value {
551            Color::Srgba(srgba) => srgba.into(),
552            Color::LinearRgba(linear) => linear,
553            Color::Hsla(hsla) => hsla.into(),
554            Color::Hsva(hsva) => hsva.into(),
555            Color::Hwba(hwba) => hwba.into(),
556            Color::Laba(laba) => laba.into(),
557            Color::Lcha(lcha) => lcha.into(),
558            Color::Oklaba(oklab) => oklab.into(),
559            Color::Oklcha(oklch) => oklch.into(),
560            Color::Xyza(xyza) => xyza.into(),
561        }
562    }
563}
564
565impl From<Color> for Hsla {
566    fn from(value: Color) -> Self {
567        match value {
568            Color::Srgba(srgba) => srgba.into(),
569            Color::LinearRgba(linear) => linear.into(),
570            Color::Hsla(hsla) => hsla,
571            Color::Hsva(hsva) => hsva.into(),
572            Color::Hwba(hwba) => hwba.into(),
573            Color::Laba(laba) => laba.into(),
574            Color::Lcha(lcha) => lcha.into(),
575            Color::Oklaba(oklab) => oklab.into(),
576            Color::Oklcha(oklch) => oklch.into(),
577            Color::Xyza(xyza) => xyza.into(),
578        }
579    }
580}
581
582impl From<Color> for Hsva {
583    fn from(value: Color) -> Self {
584        match value {
585            Color::Srgba(srgba) => srgba.into(),
586            Color::LinearRgba(linear) => linear.into(),
587            Color::Hsla(hsla) => hsla.into(),
588            Color::Hsva(hsva) => hsva,
589            Color::Hwba(hwba) => hwba.into(),
590            Color::Laba(laba) => laba.into(),
591            Color::Lcha(lcha) => lcha.into(),
592            Color::Oklaba(oklab) => oklab.into(),
593            Color::Oklcha(oklch) => oklch.into(),
594            Color::Xyza(xyza) => xyza.into(),
595        }
596    }
597}
598
599impl From<Color> for Hwba {
600    fn from(value: Color) -> Self {
601        match value {
602            Color::Srgba(srgba) => srgba.into(),
603            Color::LinearRgba(linear) => linear.into(),
604            Color::Hsla(hsla) => hsla.into(),
605            Color::Hsva(hsva) => hsva.into(),
606            Color::Hwba(hwba) => hwba,
607            Color::Laba(laba) => laba.into(),
608            Color::Lcha(lcha) => lcha.into(),
609            Color::Oklaba(oklab) => oklab.into(),
610            Color::Oklcha(oklch) => oklch.into(),
611            Color::Xyza(xyza) => xyza.into(),
612        }
613    }
614}
615
616impl From<Color> for Laba {
617    fn from(value: Color) -> Self {
618        match value {
619            Color::Srgba(srgba) => srgba.into(),
620            Color::LinearRgba(linear) => linear.into(),
621            Color::Hsla(hsla) => hsla.into(),
622            Color::Hsva(hsva) => hsva.into(),
623            Color::Hwba(hwba) => hwba.into(),
624            Color::Laba(laba) => laba,
625            Color::Lcha(lcha) => lcha.into(),
626            Color::Oklaba(oklab) => oklab.into(),
627            Color::Oklcha(oklch) => oklch.into(),
628            Color::Xyza(xyza) => xyza.into(),
629        }
630    }
631}
632
633impl From<Color> for Lcha {
634    fn from(value: Color) -> Self {
635        match value {
636            Color::Srgba(srgba) => srgba.into(),
637            Color::LinearRgba(linear) => linear.into(),
638            Color::Hsla(hsla) => hsla.into(),
639            Color::Hsva(hsva) => hsva.into(),
640            Color::Hwba(hwba) => hwba.into(),
641            Color::Laba(laba) => laba.into(),
642            Color::Lcha(lcha) => lcha,
643            Color::Oklaba(oklab) => oklab.into(),
644            Color::Oklcha(oklch) => oklch.into(),
645            Color::Xyza(xyza) => xyza.into(),
646        }
647    }
648}
649
650impl From<Color> for Oklaba {
651    fn from(value: Color) -> Self {
652        match value {
653            Color::Srgba(srgba) => srgba.into(),
654            Color::LinearRgba(linear) => linear.into(),
655            Color::Hsla(hsla) => hsla.into(),
656            Color::Hsva(hsva) => hsva.into(),
657            Color::Hwba(hwba) => hwba.into(),
658            Color::Laba(laba) => laba.into(),
659            Color::Lcha(lcha) => lcha.into(),
660            Color::Oklaba(oklab) => oklab,
661            Color::Oklcha(oklch) => oklch.into(),
662            Color::Xyza(xyza) => xyza.into(),
663        }
664    }
665}
666
667impl From<Color> for Oklcha {
668    fn from(value: Color) -> Self {
669        match value {
670            Color::Srgba(srgba) => srgba.into(),
671            Color::LinearRgba(linear) => linear.into(),
672            Color::Hsla(hsla) => hsla.into(),
673            Color::Hsva(hsva) => hsva.into(),
674            Color::Hwba(hwba) => hwba.into(),
675            Color::Laba(laba) => laba.into(),
676            Color::Lcha(lcha) => lcha.into(),
677            Color::Oklaba(oklab) => oklab.into(),
678            Color::Oklcha(oklch) => oklch,
679            Color::Xyza(xyza) => xyza.into(),
680        }
681    }
682}
683
684impl From<Color> for Xyza {
685    fn from(value: Color) -> Self {
686        match value {
687            Color::Srgba(x) => x.into(),
688            Color::LinearRgba(x) => x.into(),
689            Color::Hsla(x) => x.into(),
690            Color::Hsva(hsva) => hsva.into(),
691            Color::Hwba(hwba) => hwba.into(),
692            Color::Laba(laba) => laba.into(),
693            Color::Lcha(x) => x.into(),
694            Color::Oklaba(x) => x.into(),
695            Color::Oklcha(oklch) => oklch.into(),
696            Color::Xyza(xyza) => xyza,
697        }
698    }
699}
700
701/// Color space chosen for operations on `Color`.
702type ChosenColorSpace = Oklcha;
703
704impl Luminance for Color {
705    fn luminance(&self) -> f32 {
706        match self {
707            Color::Srgba(x) => x.luminance(),
708            Color::LinearRgba(x) => x.luminance(),
709            Color::Hsla(x) => x.luminance(),
710            Color::Hsva(x) => ChosenColorSpace::from(*x).luminance(),
711            Color::Hwba(x) => ChosenColorSpace::from(*x).luminance(),
712            Color::Laba(x) => x.luminance(),
713            Color::Lcha(x) => x.luminance(),
714            Color::Oklaba(x) => x.luminance(),
715            Color::Oklcha(x) => x.luminance(),
716            Color::Xyza(x) => x.luminance(),
717        }
718    }
719
720    fn with_luminance(&self, value: f32) -> Self {
721        let mut new = *self;
722
723        match &mut new {
724            Color::Srgba(x) => *x = x.with_luminance(value),
725            Color::LinearRgba(x) => *x = x.with_luminance(value),
726            Color::Hsla(x) => *x = x.with_luminance(value),
727            Color::Hsva(x) => *x = ChosenColorSpace::from(*x).with_luminance(value).into(),
728            Color::Hwba(x) => *x = ChosenColorSpace::from(*x).with_luminance(value).into(),
729            Color::Laba(x) => *x = x.with_luminance(value),
730            Color::Lcha(x) => *x = x.with_luminance(value),
731            Color::Oklaba(x) => *x = x.with_luminance(value),
732            Color::Oklcha(x) => *x = x.with_luminance(value),
733            Color::Xyza(x) => *x = x.with_luminance(value),
734        }
735
736        new
737    }
738
739    fn darker(&self, amount: f32) -> Self {
740        let mut new = *self;
741
742        match &mut new {
743            Color::Srgba(x) => *x = x.darker(amount),
744            Color::LinearRgba(x) => *x = x.darker(amount),
745            Color::Hsla(x) => *x = x.darker(amount),
746            Color::Hsva(x) => *x = ChosenColorSpace::from(*x).darker(amount).into(),
747            Color::Hwba(x) => *x = ChosenColorSpace::from(*x).darker(amount).into(),
748            Color::Laba(x) => *x = x.darker(amount),
749            Color::Lcha(x) => *x = x.darker(amount),
750            Color::Oklaba(x) => *x = x.darker(amount),
751            Color::Oklcha(x) => *x = x.darker(amount),
752            Color::Xyza(x) => *x = x.darker(amount),
753        }
754
755        new
756    }
757
758    fn lighter(&self, amount: f32) -> Self {
759        let mut new = *self;
760
761        match &mut new {
762            Color::Srgba(x) => *x = x.lighter(amount),
763            Color::LinearRgba(x) => *x = x.lighter(amount),
764            Color::Hsla(x) => *x = x.lighter(amount),
765            Color::Hsva(x) => *x = ChosenColorSpace::from(*x).lighter(amount).into(),
766            Color::Hwba(x) => *x = ChosenColorSpace::from(*x).lighter(amount).into(),
767            Color::Laba(x) => *x = x.lighter(amount),
768            Color::Lcha(x) => *x = x.lighter(amount),
769            Color::Oklaba(x) => *x = x.lighter(amount),
770            Color::Oklcha(x) => *x = x.lighter(amount),
771            Color::Xyza(x) => *x = x.lighter(amount),
772        }
773
774        new
775    }
776}
777
778impl Hue for Color {
779    fn with_hue(&self, hue: f32) -> Self {
780        let mut new = *self;
781
782        match &mut new {
783            Color::Srgba(x) => *x = ChosenColorSpace::from(*x).with_hue(hue).into(),
784            Color::LinearRgba(x) => *x = ChosenColorSpace::from(*x).with_hue(hue).into(),
785            Color::Hsla(x) => *x = x.with_hue(hue),
786            Color::Hsva(x) => *x = x.with_hue(hue),
787            Color::Hwba(x) => *x = x.with_hue(hue),
788            Color::Laba(x) => *x = ChosenColorSpace::from(*x).with_hue(hue).into(),
789            Color::Lcha(x) => *x = x.with_hue(hue),
790            Color::Oklaba(x) => *x = ChosenColorSpace::from(*x).with_hue(hue).into(),
791            Color::Oklcha(x) => *x = x.with_hue(hue),
792            Color::Xyza(x) => *x = ChosenColorSpace::from(*x).with_hue(hue).into(),
793        }
794
795        new
796    }
797
798    fn hue(&self) -> f32 {
799        match self {
800            Color::Srgba(x) => ChosenColorSpace::from(*x).hue(),
801            Color::LinearRgba(x) => ChosenColorSpace::from(*x).hue(),
802            Color::Hsla(x) => x.hue(),
803            Color::Hsva(x) => x.hue(),
804            Color::Hwba(x) => x.hue(),
805            Color::Laba(x) => ChosenColorSpace::from(*x).hue(),
806            Color::Lcha(x) => x.hue(),
807            Color::Oklaba(x) => ChosenColorSpace::from(*x).hue(),
808            Color::Oklcha(x) => x.hue(),
809            Color::Xyza(x) => ChosenColorSpace::from(*x).hue(),
810        }
811    }
812
813    fn set_hue(&mut self, hue: f32) {
814        *self = self.with_hue(hue);
815    }
816}
817
818impl Saturation for Color {
819    fn with_saturation(&self, saturation: f32) -> Self {
820        let mut new = *self;
821
822        match &mut new {
823            Color::Srgba(x) => Hsla::from(*x).with_saturation(saturation).into(),
824            Color::LinearRgba(x) => Hsla::from(*x).with_saturation(saturation).into(),
825            Color::Hsla(x) => x.with_saturation(saturation).into(),
826            Color::Hsva(x) => x.with_saturation(saturation).into(),
827            Color::Hwba(x) => Hsla::from(*x).with_saturation(saturation).into(),
828            Color::Laba(x) => Hsla::from(*x).with_saturation(saturation).into(),
829            Color::Lcha(x) => Hsla::from(*x).with_saturation(saturation).into(),
830            Color::Oklaba(x) => Hsla::from(*x).with_saturation(saturation).into(),
831            Color::Oklcha(x) => Hsla::from(*x).with_saturation(saturation).into(),
832            Color::Xyza(x) => Hsla::from(*x).with_saturation(saturation).into(),
833        }
834    }
835
836    fn saturation(&self) -> f32 {
837        match self {
838            Color::Srgba(x) => Hsla::from(*x).saturation(),
839            Color::LinearRgba(x) => Hsla::from(*x).saturation(),
840            Color::Hsla(x) => x.saturation(),
841            Color::Hsva(x) => x.saturation(),
842            Color::Hwba(x) => Hsla::from(*x).saturation(),
843            Color::Laba(x) => Hsla::from(*x).saturation(),
844            Color::Lcha(x) => Hsla::from(*x).saturation(),
845            Color::Oklaba(x) => Hsla::from(*x).saturation(),
846            Color::Oklcha(x) => Hsla::from(*x).saturation(),
847            Color::Xyza(x) => Hsla::from(*x).saturation(),
848        }
849    }
850
851    fn set_saturation(&mut self, saturation: f32) {
852        *self = self.with_saturation(saturation);
853    }
854}
855
856impl Mix for Color {
857    fn mix(&self, other: &Self, factor: f32) -> Self {
858        let mut new = *self;
859
860        match &mut new {
861            Color::Srgba(x) => *x = x.mix(&(*other).into(), factor),
862            Color::LinearRgba(x) => *x = x.mix(&(*other).into(), factor),
863            Color::Hsla(x) => *x = x.mix(&(*other).into(), factor),
864            Color::Hsva(x) => *x = x.mix(&(*other).into(), factor),
865            Color::Hwba(x) => *x = x.mix(&(*other).into(), factor),
866            Color::Laba(x) => *x = x.mix(&(*other).into(), factor),
867            Color::Lcha(x) => *x = x.mix(&(*other).into(), factor),
868            Color::Oklaba(x) => *x = x.mix(&(*other).into(), factor),
869            Color::Oklcha(x) => *x = x.mix(&(*other).into(), factor),
870            Color::Xyza(x) => *x = x.mix(&(*other).into(), factor),
871        }
872
873        new
874    }
875}
876
877impl EuclideanDistance for Color {
878    fn distance_squared(&self, other: &Self) -> f32 {
879        match self {
880            Color::Srgba(x) => x.distance_squared(&(*other).into()),
881            Color::LinearRgba(x) => x.distance_squared(&(*other).into()),
882            Color::Hsla(x) => ChosenColorSpace::from(*x).distance_squared(&(*other).into()),
883            Color::Hsva(x) => ChosenColorSpace::from(*x).distance_squared(&(*other).into()),
884            Color::Hwba(x) => ChosenColorSpace::from(*x).distance_squared(&(*other).into()),
885            Color::Laba(x) => ChosenColorSpace::from(*x).distance_squared(&(*other).into()),
886            Color::Lcha(x) => ChosenColorSpace::from(*x).distance_squared(&(*other).into()),
887            Color::Oklaba(x) => x.distance_squared(&(*other).into()),
888            Color::Oklcha(x) => x.distance_squared(&(*other).into()),
889            Color::Xyza(x) => ChosenColorSpace::from(*x).distance_squared(&(*other).into()),
890        }
891    }
892}
893
894impl TryStableInterpolate for Color {
895    type Error = MismatchedUnitsError;
896
897    fn try_interpolate_stable(&self, other: &Self, t: f32) -> Result<Self, Self::Error> {
898        match (self, other) {
899            (Color::Srgba(a), Color::Srgba(b)) => Ok(Color::Srgba(a.mix(b, t))),
900            (Color::LinearRgba(a), Color::LinearRgba(b)) => Ok(Color::LinearRgba(a.mix(b, t))),
901            (Color::Hsla(a), Color::Hsla(b)) => Ok(Color::Hsla(a.mix(b, t))),
902            (Color::Hsva(a), Color::Hsva(b)) => Ok(Color::Hsva(a.mix(b, t))),
903            (Color::Hwba(a), Color::Hwba(b)) => Ok(Color::Hwba(a.mix(b, t))),
904            (Color::Laba(a), Color::Laba(b)) => Ok(Color::Laba(a.mix(b, t))),
905            (Color::Lcha(a), Color::Lcha(b)) => Ok(Color::Lcha(a.mix(b, t))),
906            (Color::Oklaba(a), Color::Oklaba(b)) => Ok(Color::Oklaba(a.mix(b, t))),
907            (Color::Oklcha(a), Color::Oklcha(b)) => Ok(Color::Oklcha(a.mix(b, t))),
908            (Color::Xyza(a), Color::Xyza(b)) => Ok(Color::Xyza(a.mix(b, t))),
909            _ => Err(MismatchedUnitsError),
910        }
911    }
912}