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