Skip to main content

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 [`Srgba`] color from a [`u32`] value with an alpha of 1.0.
172    ///
173    /// For example, a value of `0x000000` results in black, and a value of `0xff0000` results in red.
174    ///
175    /// # Examples
176    ///
177    /// ```
178    /// # use bevy_color::Color;
179    /// let black = Color::srgb_u32(0x000000);
180    /// let red = Color::srgb_u32(0xff0000);
181    /// ```
182    pub fn srgb_u32(color: u32) -> Self {
183        Self::Srgba(Srgba::rgb(
184            ((color >> 16) & 0xff) as f32 / 255.,
185            ((color >> 8) & 0xff) as f32 / 255.,
186            (color & 0xff) as f32 / 255.,
187        ))
188    }
189
190    /// Creates a new [`Color`] object storing a [`Srgba`] color from a [`u32`] value with the alpha value extracted from the input.
191    ///
192    /// For example, a value of `0x000000ff` results in black with full opacity, and a value of `0xff000080` results in red with half opacity.
193    ///
194    /// # Examples
195    ///
196    /// ```
197    /// # use bevy_color::Color;
198    /// let black = Color::srgba_u32(0x000000ff);
199    /// let semi_transparent_red = Color::srgba_u32(0xff000080);
200    /// ```
201    pub fn srgba_u32(color: u32) -> Self {
202        Self::Srgba(Srgba::new(
203            ((color >> 24) & 0xff) as f32 / 255.,
204            ((color >> 16) & 0xff) as f32 / 255.,
205            ((color >> 8) & 0xff) as f32 / 255.,
206            (color & 0xff) as f32 / 255.,
207        ))
208    }
209
210    /// Creates a new [`Color`] object storing a [`LinearRgba`] color.
211    ///
212    /// # Arguments
213    ///
214    /// * `red` - Red channel. [0.0, 1.0]
215    /// * `green` - Green channel. [0.0, 1.0]
216    /// * `blue` - Blue channel. [0.0, 1.0]
217    /// * `alpha` - Alpha channel. [0.0, 1.0]
218    pub const fn linear_rgba(red: f32, green: f32, blue: f32, alpha: f32) -> Self {
219        Self::LinearRgba(LinearRgba {
220            red,
221            green,
222            blue,
223            alpha,
224        })
225    }
226
227    /// Creates a new [`Color`] object storing a [`LinearRgba`] color with an alpha of 1.0.
228    ///
229    /// # Arguments
230    ///
231    /// * `red` - Red channel. [0.0, 1.0]
232    /// * `green` - Green channel. [0.0, 1.0]
233    /// * `blue` - Blue channel. [0.0, 1.0]
234    pub const fn linear_rgb(red: f32, green: f32, blue: f32) -> Self {
235        Self::LinearRgba(LinearRgba {
236            red,
237            green,
238            blue,
239            alpha: 1.0,
240        })
241    }
242
243    /// Creates a new [`Color`] object storing a [`Hsla`] color.
244    ///
245    /// # Arguments
246    ///
247    /// * `hue` - Hue channel. [0.0, 360.0]
248    /// * `saturation` - Saturation channel. [0.0, 1.0]
249    /// * `lightness` - Lightness channel. [0.0, 1.0]
250    /// * `alpha` - Alpha channel. [0.0, 1.0]
251    pub const fn hsla(hue: f32, saturation: f32, lightness: f32, alpha: f32) -> Self {
252        Self::Hsla(Hsla {
253            hue,
254            saturation,
255            lightness,
256            alpha,
257        })
258    }
259
260    /// Creates a new [`Color`] object storing a [`Hsla`] color with an alpha of 1.0.
261    ///
262    /// # Arguments
263    ///
264    /// * `hue` - Hue channel. [0.0, 360.0]
265    /// * `saturation` - Saturation channel. [0.0, 1.0]
266    /// * `lightness` - Lightness channel. [0.0, 1.0]
267    pub const fn hsl(hue: f32, saturation: f32, lightness: f32) -> Self {
268        Self::Hsla(Hsla {
269            hue,
270            saturation,
271            lightness,
272            alpha: 1.0,
273        })
274    }
275
276    /// Creates a new [`Color`] object storing a [`Hsva`] color.
277    ///
278    /// # Arguments
279    ///
280    /// * `hue` - Hue channel. [0.0, 360.0]
281    /// * `saturation` - Saturation channel. [0.0, 1.0]
282    /// * `value` - Value channel. [0.0, 1.0]
283    /// * `alpha` - Alpha channel. [0.0, 1.0]
284    pub const fn hsva(hue: f32, saturation: f32, value: f32, alpha: f32) -> Self {
285        Self::Hsva(Hsva {
286            hue,
287            saturation,
288            value,
289            alpha,
290        })
291    }
292
293    /// Creates a new [`Color`] object storing a [`Hsva`] color with an alpha of 1.0.
294    ///
295    /// # Arguments
296    ///
297    /// * `hue` - Hue channel. [0.0, 360.0]
298    /// * `saturation` - Saturation channel. [0.0, 1.0]
299    /// * `value` - Value channel. [0.0, 1.0]
300    pub const fn hsv(hue: f32, saturation: f32, value: f32) -> Self {
301        Self::Hsva(Hsva {
302            hue,
303            saturation,
304            value,
305            alpha: 1.0,
306        })
307    }
308
309    /// Creates a new [`Color`] object storing a [`Hwba`] color.
310    ///
311    /// # Arguments
312    ///
313    /// * `hue` - Hue channel. [0.0, 360.0]
314    /// * `whiteness` - Whiteness channel. [0.0, 1.0]
315    /// * `blackness` - Blackness channel. [0.0, 1.0]
316    /// * `alpha` - Alpha channel. [0.0, 1.0]
317    pub const fn hwba(hue: f32, whiteness: f32, blackness: f32, alpha: f32) -> Self {
318        Self::Hwba(Hwba {
319            hue,
320            whiteness,
321            blackness,
322            alpha,
323        })
324    }
325
326    /// Creates a new [`Color`] object storing a [`Hwba`] color with an alpha of 1.0.
327    ///
328    /// # Arguments
329    ///
330    /// * `hue` - Hue channel. [0.0, 360.0]
331    /// * `whiteness` - Whiteness channel. [0.0, 1.0]
332    /// * `blackness` - Blackness channel. [0.0, 1.0]
333    pub const fn hwb(hue: f32, whiteness: f32, blackness: f32) -> Self {
334        Self::Hwba(Hwba {
335            hue,
336            whiteness,
337            blackness,
338            alpha: 1.0,
339        })
340    }
341
342    /// Creates a new [`Color`] object storing a [`Laba`] color.
343    ///
344    /// # Arguments
345    ///
346    /// * `lightness` - Lightness channel. [0.0, 1.5]
347    /// * `a` - a axis. [-1.5, 1.5]
348    /// * `b` - b axis. [-1.5, 1.5]
349    /// * `alpha` - Alpha channel. [0.0, 1.0]
350    pub const fn laba(lightness: f32, a: f32, b: f32, alpha: f32) -> Self {
351        Self::Laba(Laba {
352            lightness,
353            a,
354            b,
355            alpha,
356        })
357    }
358
359    /// Creates a new [`Color`] object storing a [`Laba`] color with an alpha of 1.0.
360    ///
361    /// # Arguments
362    ///
363    /// * `lightness` - Lightness channel. [0.0, 1.5]
364    /// * `a` - a axis. [-1.5, 1.5]
365    /// * `b` - b axis. [-1.5, 1.5]
366    pub const fn lab(lightness: f32, a: f32, b: f32) -> Self {
367        Self::Laba(Laba {
368            lightness,
369            a,
370            b,
371            alpha: 1.0,
372        })
373    }
374
375    /// Creates a new [`Color`] object storing a [`Lcha`] color.
376    ///
377    /// # Arguments
378    ///
379    /// * `lightness` - Lightness channel. [0.0, 1.5]
380    /// * `chroma` - Chroma channel. [0.0, 1.5]
381    /// * `hue` - Hue channel. [0.0, 360.0]
382    /// * `alpha` - Alpha channel. [0.0, 1.0]
383    pub const fn lcha(lightness: f32, chroma: f32, hue: f32, alpha: f32) -> Self {
384        Self::Lcha(Lcha {
385            lightness,
386            chroma,
387            hue,
388            alpha,
389        })
390    }
391
392    /// Creates a new [`Color`] object storing a [`Lcha`] color with an alpha of 1.0.
393    ///
394    /// # Arguments
395    ///
396    /// * `lightness` - Lightness channel. [0.0, 1.5]
397    /// * `chroma` - Chroma channel. [0.0, 1.5]
398    /// * `hue` - Hue channel. [0.0, 360.0]
399    pub const fn lch(lightness: f32, chroma: f32, hue: f32) -> Self {
400        Self::Lcha(Lcha {
401            lightness,
402            chroma,
403            hue,
404            alpha: 1.0,
405        })
406    }
407
408    /// Creates a new [`Color`] object storing a [`Oklaba`] color.
409    ///
410    /// # Arguments
411    ///
412    /// * `lightness` - Lightness channel. [0.0, 1.0]
413    /// * `a` - Green-red channel. [-1.0, 1.0]
414    /// * `b` - Blue-yellow channel. [-1.0, 1.0]
415    /// * `alpha` - Alpha channel. [0.0, 1.0]
416    pub const fn oklaba(lightness: f32, a: f32, b: f32, alpha: f32) -> Self {
417        Self::Oklaba(Oklaba {
418            lightness,
419            a,
420            b,
421            alpha,
422        })
423    }
424
425    /// Creates a new [`Color`] object storing a [`Oklaba`] color with an alpha of 1.0.
426    ///
427    /// # Arguments
428    ///
429    /// * `lightness` - Lightness channel. [0.0, 1.0]
430    /// * `a` - Green-red channel. [-1.0, 1.0]
431    /// * `b` - Blue-yellow channel. [-1.0, 1.0]
432    pub const fn oklab(lightness: f32, a: f32, b: f32) -> Self {
433        Self::Oklaba(Oklaba {
434            lightness,
435            a,
436            b,
437            alpha: 1.0,
438        })
439    }
440
441    /// Creates a new [`Color`] object storing a [`Oklcha`] color.
442    ///
443    /// # Arguments
444    ///
445    /// * `lightness` - Lightness channel. [0.0, 1.0]
446    /// * `chroma` - Chroma channel. [0.0, 1.0]
447    /// * `hue` - Hue channel. [0.0, 360.0]
448    /// * `alpha` - Alpha channel. [0.0, 1.0]
449    pub const fn oklcha(lightness: f32, chroma: f32, hue: f32, alpha: f32) -> Self {
450        Self::Oklcha(Oklcha {
451            lightness,
452            chroma,
453            hue,
454            alpha,
455        })
456    }
457
458    /// Creates a new [`Color`] object storing a [`Oklcha`] color with an alpha of 1.0.
459    ///
460    /// # Arguments
461    ///
462    /// * `lightness` - Lightness channel. [0.0, 1.0]
463    /// * `chroma` - Chroma channel. [0.0, 1.0]
464    /// * `hue` - Hue channel. [0.0, 360.0]
465    pub const fn oklch(lightness: f32, chroma: f32, hue: f32) -> Self {
466        Self::Oklcha(Oklcha {
467            lightness,
468            chroma,
469            hue,
470            alpha: 1.0,
471        })
472    }
473
474    /// Creates a new [`Color`] object storing a [`Xyza`] color.
475    ///
476    /// # Arguments
477    ///
478    /// * `x` - x-axis. [0.0, 1.0]
479    /// * `y` - y-axis. [0.0, 1.0]
480    /// * `z` - z-axis. [0.0, 1.0]
481    /// * `alpha` - Alpha channel. [0.0, 1.0]
482    pub const fn xyza(x: f32, y: f32, z: f32, alpha: f32) -> Self {
483        Self::Xyza(Xyza { x, y, z, alpha })
484    }
485
486    /// Creates a new [`Color`] object storing a [`Xyza`] color with an alpha of 1.0.
487    ///
488    /// # Arguments
489    ///
490    /// * `x` - x-axis. [0.0, 1.0]
491    /// * `y` - y-axis. [0.0, 1.0]
492    /// * `z` - z-axis. [0.0, 1.0]
493    pub const fn xyz(x: f32, y: f32, z: f32) -> Self {
494        Self::Xyza(Xyza {
495            x,
496            y,
497            z,
498            alpha: 1.0,
499        })
500    }
501
502    /// A fully white [`Color::LinearRgba`] color with an alpha of 1.0.
503    pub const WHITE: Self = Self::linear_rgb(1.0, 1.0, 1.0);
504
505    /// A fully black [`Color::LinearRgba`] color with an alpha of 1.0.
506    pub const BLACK: Self = Self::linear_rgb(0., 0., 0.);
507
508    /// A fully transparent [`Color::LinearRgba`] color with 0 red, green and blue.
509    pub const NONE: Self = Self::linear_rgba(0., 0., 0., 0.);
510}
511
512impl Default for Color {
513    /// A fully white [`Color::LinearRgba`] color with an alpha of 1.0.
514    fn default() -> Self {
515        Color::WHITE
516    }
517}
518
519impl Alpha for Color {
520    fn with_alpha(&self, alpha: f32) -> Self {
521        let mut new = *self;
522
523        match &mut new {
524            Color::Srgba(x) => *x = x.with_alpha(alpha),
525            Color::LinearRgba(x) => *x = x.with_alpha(alpha),
526            Color::Hsla(x) => *x = x.with_alpha(alpha),
527            Color::Hsva(x) => *x = x.with_alpha(alpha),
528            Color::Hwba(x) => *x = x.with_alpha(alpha),
529            Color::Laba(x) => *x = x.with_alpha(alpha),
530            Color::Lcha(x) => *x = x.with_alpha(alpha),
531            Color::Oklaba(x) => *x = x.with_alpha(alpha),
532            Color::Oklcha(x) => *x = x.with_alpha(alpha),
533            Color::Xyza(x) => *x = x.with_alpha(alpha),
534        }
535
536        new
537    }
538
539    fn alpha(&self) -> f32 {
540        match self {
541            Color::Srgba(x) => x.alpha(),
542            Color::LinearRgba(x) => x.alpha(),
543            Color::Hsla(x) => x.alpha(),
544            Color::Hsva(x) => x.alpha(),
545            Color::Hwba(x) => x.alpha(),
546            Color::Laba(x) => x.alpha(),
547            Color::Lcha(x) => x.alpha(),
548            Color::Oklaba(x) => x.alpha(),
549            Color::Oklcha(x) => x.alpha(),
550            Color::Xyza(x) => x.alpha(),
551        }
552    }
553
554    fn set_alpha(&mut self, alpha: f32) {
555        match self {
556            Color::Srgba(x) => x.set_alpha(alpha),
557            Color::LinearRgba(x) => x.set_alpha(alpha),
558            Color::Hsla(x) => x.set_alpha(alpha),
559            Color::Hsva(x) => x.set_alpha(alpha),
560            Color::Hwba(x) => x.set_alpha(alpha),
561            Color::Laba(x) => x.set_alpha(alpha),
562            Color::Lcha(x) => x.set_alpha(alpha),
563            Color::Oklaba(x) => x.set_alpha(alpha),
564            Color::Oklcha(x) => x.set_alpha(alpha),
565            Color::Xyza(x) => x.set_alpha(alpha),
566        }
567    }
568}
569
570impl From<Color> for Srgba {
571    fn from(value: Color) -> Self {
572        match value {
573            Color::Srgba(srgba) => srgba,
574            Color::LinearRgba(linear) => linear.into(),
575            Color::Hsla(hsla) => hsla.into(),
576            Color::Hsva(hsva) => hsva.into(),
577            Color::Hwba(hwba) => hwba.into(),
578            Color::Laba(laba) => laba.into(),
579            Color::Lcha(lcha) => lcha.into(),
580            Color::Oklaba(oklab) => oklab.into(),
581            Color::Oklcha(oklch) => oklch.into(),
582            Color::Xyza(xyza) => xyza.into(),
583        }
584    }
585}
586
587impl From<Color> for LinearRgba {
588    fn from(value: Color) -> Self {
589        match value {
590            Color::Srgba(srgba) => srgba.into(),
591            Color::LinearRgba(linear) => linear,
592            Color::Hsla(hsla) => hsla.into(),
593            Color::Hsva(hsva) => hsva.into(),
594            Color::Hwba(hwba) => hwba.into(),
595            Color::Laba(laba) => laba.into(),
596            Color::Lcha(lcha) => lcha.into(),
597            Color::Oklaba(oklab) => oklab.into(),
598            Color::Oklcha(oklch) => oklch.into(),
599            Color::Xyza(xyza) => xyza.into(),
600        }
601    }
602}
603
604impl From<Color> for Hsla {
605    fn from(value: Color) -> Self {
606        match value {
607            Color::Srgba(srgba) => srgba.into(),
608            Color::LinearRgba(linear) => linear.into(),
609            Color::Hsla(hsla) => hsla,
610            Color::Hsva(hsva) => hsva.into(),
611            Color::Hwba(hwba) => hwba.into(),
612            Color::Laba(laba) => laba.into(),
613            Color::Lcha(lcha) => lcha.into(),
614            Color::Oklaba(oklab) => oklab.into(),
615            Color::Oklcha(oklch) => oklch.into(),
616            Color::Xyza(xyza) => xyza.into(),
617        }
618    }
619}
620
621impl From<Color> for Hsva {
622    fn from(value: Color) -> Self {
623        match value {
624            Color::Srgba(srgba) => srgba.into(),
625            Color::LinearRgba(linear) => linear.into(),
626            Color::Hsla(hsla) => hsla.into(),
627            Color::Hsva(hsva) => hsva,
628            Color::Hwba(hwba) => hwba.into(),
629            Color::Laba(laba) => laba.into(),
630            Color::Lcha(lcha) => lcha.into(),
631            Color::Oklaba(oklab) => oklab.into(),
632            Color::Oklcha(oklch) => oklch.into(),
633            Color::Xyza(xyza) => xyza.into(),
634        }
635    }
636}
637
638impl From<Color> for Hwba {
639    fn from(value: Color) -> Self {
640        match value {
641            Color::Srgba(srgba) => srgba.into(),
642            Color::LinearRgba(linear) => linear.into(),
643            Color::Hsla(hsla) => hsla.into(),
644            Color::Hsva(hsva) => hsva.into(),
645            Color::Hwba(hwba) => hwba,
646            Color::Laba(laba) => laba.into(),
647            Color::Lcha(lcha) => lcha.into(),
648            Color::Oklaba(oklab) => oklab.into(),
649            Color::Oklcha(oklch) => oklch.into(),
650            Color::Xyza(xyza) => xyza.into(),
651        }
652    }
653}
654
655impl From<Color> for Laba {
656    fn from(value: Color) -> Self {
657        match value {
658            Color::Srgba(srgba) => srgba.into(),
659            Color::LinearRgba(linear) => linear.into(),
660            Color::Hsla(hsla) => hsla.into(),
661            Color::Hsva(hsva) => hsva.into(),
662            Color::Hwba(hwba) => hwba.into(),
663            Color::Laba(laba) => laba,
664            Color::Lcha(lcha) => lcha.into(),
665            Color::Oklaba(oklab) => oklab.into(),
666            Color::Oklcha(oklch) => oklch.into(),
667            Color::Xyza(xyza) => xyza.into(),
668        }
669    }
670}
671
672impl From<Color> for Lcha {
673    fn from(value: Color) -> Self {
674        match value {
675            Color::Srgba(srgba) => srgba.into(),
676            Color::LinearRgba(linear) => linear.into(),
677            Color::Hsla(hsla) => hsla.into(),
678            Color::Hsva(hsva) => hsva.into(),
679            Color::Hwba(hwba) => hwba.into(),
680            Color::Laba(laba) => laba.into(),
681            Color::Lcha(lcha) => lcha,
682            Color::Oklaba(oklab) => oklab.into(),
683            Color::Oklcha(oklch) => oklch.into(),
684            Color::Xyza(xyza) => xyza.into(),
685        }
686    }
687}
688
689impl From<Color> for Oklaba {
690    fn from(value: Color) -> Self {
691        match value {
692            Color::Srgba(srgba) => srgba.into(),
693            Color::LinearRgba(linear) => linear.into(),
694            Color::Hsla(hsla) => hsla.into(),
695            Color::Hsva(hsva) => hsva.into(),
696            Color::Hwba(hwba) => hwba.into(),
697            Color::Laba(laba) => laba.into(),
698            Color::Lcha(lcha) => lcha.into(),
699            Color::Oklaba(oklab) => oklab,
700            Color::Oklcha(oklch) => oklch.into(),
701            Color::Xyza(xyza) => xyza.into(),
702        }
703    }
704}
705
706impl From<Color> for Oklcha {
707    fn from(value: Color) -> Self {
708        match value {
709            Color::Srgba(srgba) => srgba.into(),
710            Color::LinearRgba(linear) => linear.into(),
711            Color::Hsla(hsla) => hsla.into(),
712            Color::Hsva(hsva) => hsva.into(),
713            Color::Hwba(hwba) => hwba.into(),
714            Color::Laba(laba) => laba.into(),
715            Color::Lcha(lcha) => lcha.into(),
716            Color::Oklaba(oklab) => oklab.into(),
717            Color::Oklcha(oklch) => oklch,
718            Color::Xyza(xyza) => xyza.into(),
719        }
720    }
721}
722
723impl From<Color> for Xyza {
724    fn from(value: Color) -> Self {
725        match value {
726            Color::Srgba(x) => x.into(),
727            Color::LinearRgba(x) => x.into(),
728            Color::Hsla(x) => x.into(),
729            Color::Hsva(hsva) => hsva.into(),
730            Color::Hwba(hwba) => hwba.into(),
731            Color::Laba(laba) => laba.into(),
732            Color::Lcha(x) => x.into(),
733            Color::Oklaba(x) => x.into(),
734            Color::Oklcha(oklch) => oklch.into(),
735            Color::Xyza(xyza) => xyza,
736        }
737    }
738}
739
740/// Color space chosen for operations on `Color`.
741type ChosenColorSpace = Oklcha;
742
743impl Luminance for Color {
744    fn luminance(&self) -> f32 {
745        match self {
746            Color::Srgba(x) => x.luminance(),
747            Color::LinearRgba(x) => x.luminance(),
748            Color::Hsla(x) => x.luminance(),
749            Color::Hsva(x) => ChosenColorSpace::from(*x).luminance(),
750            Color::Hwba(x) => ChosenColorSpace::from(*x).luminance(),
751            Color::Laba(x) => x.luminance(),
752            Color::Lcha(x) => x.luminance(),
753            Color::Oklaba(x) => x.luminance(),
754            Color::Oklcha(x) => x.luminance(),
755            Color::Xyza(x) => x.luminance(),
756        }
757    }
758
759    fn with_luminance(&self, value: f32) -> Self {
760        let mut new = *self;
761
762        match &mut new {
763            Color::Srgba(x) => *x = x.with_luminance(value),
764            Color::LinearRgba(x) => *x = x.with_luminance(value),
765            Color::Hsla(x) => *x = x.with_luminance(value),
766            Color::Hsva(x) => *x = ChosenColorSpace::from(*x).with_luminance(value).into(),
767            Color::Hwba(x) => *x = ChosenColorSpace::from(*x).with_luminance(value).into(),
768            Color::Laba(x) => *x = x.with_luminance(value),
769            Color::Lcha(x) => *x = x.with_luminance(value),
770            Color::Oklaba(x) => *x = x.with_luminance(value),
771            Color::Oklcha(x) => *x = x.with_luminance(value),
772            Color::Xyza(x) => *x = x.with_luminance(value),
773        }
774
775        new
776    }
777
778    fn darker(&self, amount: f32) -> Self {
779        let mut new = *self;
780
781        match &mut new {
782            Color::Srgba(x) => *x = x.darker(amount),
783            Color::LinearRgba(x) => *x = x.darker(amount),
784            Color::Hsla(x) => *x = x.darker(amount),
785            Color::Hsva(x) => *x = ChosenColorSpace::from(*x).darker(amount).into(),
786            Color::Hwba(x) => *x = ChosenColorSpace::from(*x).darker(amount).into(),
787            Color::Laba(x) => *x = x.darker(amount),
788            Color::Lcha(x) => *x = x.darker(amount),
789            Color::Oklaba(x) => *x = x.darker(amount),
790            Color::Oklcha(x) => *x = x.darker(amount),
791            Color::Xyza(x) => *x = x.darker(amount),
792        }
793
794        new
795    }
796
797    fn lighter(&self, amount: f32) -> Self {
798        let mut new = *self;
799
800        match &mut new {
801            Color::Srgba(x) => *x = x.lighter(amount),
802            Color::LinearRgba(x) => *x = x.lighter(amount),
803            Color::Hsla(x) => *x = x.lighter(amount),
804            Color::Hsva(x) => *x = ChosenColorSpace::from(*x).lighter(amount).into(),
805            Color::Hwba(x) => *x = ChosenColorSpace::from(*x).lighter(amount).into(),
806            Color::Laba(x) => *x = x.lighter(amount),
807            Color::Lcha(x) => *x = x.lighter(amount),
808            Color::Oklaba(x) => *x = x.lighter(amount),
809            Color::Oklcha(x) => *x = x.lighter(amount),
810            Color::Xyza(x) => *x = x.lighter(amount),
811        }
812
813        new
814    }
815}
816
817impl Hue for Color {
818    fn with_hue(&self, hue: f32) -> Self {
819        let mut new = *self;
820
821        match &mut new {
822            Color::Srgba(x) => *x = ChosenColorSpace::from(*x).with_hue(hue).into(),
823            Color::LinearRgba(x) => *x = ChosenColorSpace::from(*x).with_hue(hue).into(),
824            Color::Hsla(x) => *x = x.with_hue(hue),
825            Color::Hsva(x) => *x = x.with_hue(hue),
826            Color::Hwba(x) => *x = x.with_hue(hue),
827            Color::Laba(x) => *x = ChosenColorSpace::from(*x).with_hue(hue).into(),
828            Color::Lcha(x) => *x = x.with_hue(hue),
829            Color::Oklaba(x) => *x = ChosenColorSpace::from(*x).with_hue(hue).into(),
830            Color::Oklcha(x) => *x = x.with_hue(hue),
831            Color::Xyza(x) => *x = ChosenColorSpace::from(*x).with_hue(hue).into(),
832        }
833
834        new
835    }
836
837    fn hue(&self) -> f32 {
838        match self {
839            Color::Srgba(x) => ChosenColorSpace::from(*x).hue(),
840            Color::LinearRgba(x) => ChosenColorSpace::from(*x).hue(),
841            Color::Hsla(x) => x.hue(),
842            Color::Hsva(x) => x.hue(),
843            Color::Hwba(x) => x.hue(),
844            Color::Laba(x) => ChosenColorSpace::from(*x).hue(),
845            Color::Lcha(x) => x.hue(),
846            Color::Oklaba(x) => ChosenColorSpace::from(*x).hue(),
847            Color::Oklcha(x) => x.hue(),
848            Color::Xyza(x) => ChosenColorSpace::from(*x).hue(),
849        }
850    }
851
852    fn set_hue(&mut self, hue: f32) {
853        *self = self.with_hue(hue);
854    }
855}
856
857impl Saturation for Color {
858    fn with_saturation(&self, saturation: f32) -> Self {
859        let mut new = *self;
860
861        match &mut new {
862            Color::Srgba(x) => Hsla::from(*x).with_saturation(saturation).into(),
863            Color::LinearRgba(x) => Hsla::from(*x).with_saturation(saturation).into(),
864            Color::Hsla(x) => x.with_saturation(saturation).into(),
865            Color::Hsva(x) => x.with_saturation(saturation).into(),
866            Color::Hwba(x) => Hsla::from(*x).with_saturation(saturation).into(),
867            Color::Laba(x) => Hsla::from(*x).with_saturation(saturation).into(),
868            Color::Lcha(x) => Hsla::from(*x).with_saturation(saturation).into(),
869            Color::Oklaba(x) => Hsla::from(*x).with_saturation(saturation).into(),
870            Color::Oklcha(x) => Hsla::from(*x).with_saturation(saturation).into(),
871            Color::Xyza(x) => Hsla::from(*x).with_saturation(saturation).into(),
872        }
873    }
874
875    fn saturation(&self) -> f32 {
876        match self {
877            Color::Srgba(x) => Hsla::from(*x).saturation(),
878            Color::LinearRgba(x) => Hsla::from(*x).saturation(),
879            Color::Hsla(x) => x.saturation(),
880            Color::Hsva(x) => x.saturation(),
881            Color::Hwba(x) => Hsla::from(*x).saturation(),
882            Color::Laba(x) => Hsla::from(*x).saturation(),
883            Color::Lcha(x) => Hsla::from(*x).saturation(),
884            Color::Oklaba(x) => Hsla::from(*x).saturation(),
885            Color::Oklcha(x) => Hsla::from(*x).saturation(),
886            Color::Xyza(x) => Hsla::from(*x).saturation(),
887        }
888    }
889
890    fn set_saturation(&mut self, saturation: f32) {
891        *self = self.with_saturation(saturation);
892    }
893}
894
895impl Mix for Color {
896    fn mix(&self, other: &Self, factor: f32) -> Self {
897        let mut new = *self;
898
899        match &mut new {
900            Color::Srgba(x) => *x = x.mix(&(*other).into(), factor),
901            Color::LinearRgba(x) => *x = x.mix(&(*other).into(), factor),
902            Color::Hsla(x) => *x = x.mix(&(*other).into(), factor),
903            Color::Hsva(x) => *x = x.mix(&(*other).into(), factor),
904            Color::Hwba(x) => *x = x.mix(&(*other).into(), factor),
905            Color::Laba(x) => *x = x.mix(&(*other).into(), factor),
906            Color::Lcha(x) => *x = x.mix(&(*other).into(), factor),
907            Color::Oklaba(x) => *x = x.mix(&(*other).into(), factor),
908            Color::Oklcha(x) => *x = x.mix(&(*other).into(), factor),
909            Color::Xyza(x) => *x = x.mix(&(*other).into(), factor),
910        }
911
912        new
913    }
914}
915
916impl EuclideanDistance for Color {
917    fn distance_squared(&self, other: &Self) -> f32 {
918        match self {
919            Color::Srgba(x) => x.distance_squared(&(*other).into()),
920            Color::LinearRgba(x) => x.distance_squared(&(*other).into()),
921            Color::Hsla(x) => ChosenColorSpace::from(*x).distance_squared(&(*other).into()),
922            Color::Hsva(x) => ChosenColorSpace::from(*x).distance_squared(&(*other).into()),
923            Color::Hwba(x) => ChosenColorSpace::from(*x).distance_squared(&(*other).into()),
924            Color::Laba(x) => ChosenColorSpace::from(*x).distance_squared(&(*other).into()),
925            Color::Lcha(x) => ChosenColorSpace::from(*x).distance_squared(&(*other).into()),
926            Color::Oklaba(x) => x.distance_squared(&(*other).into()),
927            Color::Oklcha(x) => x.distance_squared(&(*other).into()),
928            Color::Xyza(x) => ChosenColorSpace::from(*x).distance_squared(&(*other).into()),
929        }
930    }
931}
932
933impl TryStableInterpolate for Color {
934    type Error = MismatchedUnitsError;
935
936    fn try_interpolate_stable(&self, other: &Self, t: f32) -> Result<Self, Self::Error> {
937        match (self, other) {
938            (Color::Srgba(a), Color::Srgba(b)) => Ok(Color::Srgba(a.mix(b, t))),
939            (Color::LinearRgba(a), Color::LinearRgba(b)) => Ok(Color::LinearRgba(a.mix(b, t))),
940            (Color::Hsla(a), Color::Hsla(b)) => Ok(Color::Hsla(a.mix(b, t))),
941            (Color::Hsva(a), Color::Hsva(b)) => Ok(Color::Hsva(a.mix(b, t))),
942            (Color::Hwba(a), Color::Hwba(b)) => Ok(Color::Hwba(a.mix(b, t))),
943            (Color::Laba(a), Color::Laba(b)) => Ok(Color::Laba(a.mix(b, t))),
944            (Color::Lcha(a), Color::Lcha(b)) => Ok(Color::Lcha(a.mix(b, t))),
945            (Color::Oklaba(a), Color::Oklaba(b)) => Ok(Color::Oklaba(a.mix(b, t))),
946            (Color::Oklcha(a), Color::Oklcha(b)) => Ok(Color::Oklcha(a.mix(b, t))),
947            (Color::Xyza(a), Color::Xyza(b)) => Ok(Color::Xyza(a.mix(b, t))),
948            _ => Err(MismatchedUnitsError),
949        }
950    }
951}