Add LCH(ab) color space to bevy_render::color::Color (#7483)
				
					
				
			# Objective - Fixes #766 ## Solution - Add a new `Lcha` member to `bevy_render::color::Color` enum --- ## Changelog - Add a new `Lcha` member to `bevy_render::color::Color` enum - Add `bevy_render::color::LchRepresentation` struct
This commit is contained in:
		
							parent
							
								
									5b930c8486
								
							
						
					
					
						commit
						7b7b34f635
					
				| @ -102,6 +102,137 @@ impl HslRepresentation { | |||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | pub struct LchRepresentation; | ||||||
|  | impl LchRepresentation { | ||||||
|  |     // References available at http://brucelindbloom.com/ in the "Math" section
 | ||||||
|  | 
 | ||||||
|  |     // CIE Constants
 | ||||||
|  |     // http://brucelindbloom.com/index.html?LContinuity.html (16) (17)
 | ||||||
|  |     const CIE_EPSILON: f32 = 216.0 / 24389.0; | ||||||
|  |     const CIE_KAPPA: f32 = 24389.0 / 27.0; | ||||||
|  |     // D65 White Reference:
 | ||||||
|  |     // https://en.wikipedia.org/wiki/Illuminant_D65#Definition
 | ||||||
|  |     const D65_WHITE_X: f32 = 0.95047; | ||||||
|  |     const D65_WHITE_Y: f32 = 1.0; | ||||||
|  |     const D65_WHITE_Z: f32 = 1.08883; | ||||||
|  | 
 | ||||||
|  |     /// converts a color in LCH space to sRGB space
 | ||||||
|  |     #[inline] | ||||||
|  |     pub fn lch_to_nonlinear_srgb(lightness: f32, chroma: f32, hue: f32) -> [f32; 3] { | ||||||
|  |         let lightness = lightness * 100.0; | ||||||
|  |         let chroma = chroma * 100.0; | ||||||
|  | 
 | ||||||
|  |         // convert LCH to Lab
 | ||||||
|  |         // http://www.brucelindbloom.com/index.html?Eqn_LCH_to_Lab.html
 | ||||||
|  |         let l = lightness; | ||||||
|  |         let a = chroma * hue.to_radians().cos(); | ||||||
|  |         let b = chroma * hue.to_radians().sin(); | ||||||
|  | 
 | ||||||
|  |         // convert Lab to XYZ
 | ||||||
|  |         // http://www.brucelindbloom.com/index.html?Eqn_Lab_to_XYZ.html
 | ||||||
|  |         let fy = (l + 16.0) / 116.0; | ||||||
|  |         let fx = a / 500.0 + fy; | ||||||
|  |         let fz = fy - b / 200.0; | ||||||
|  |         let xr = { | ||||||
|  |             let fx3 = fx.powf(3.0); | ||||||
|  | 
 | ||||||
|  |             if fx3 > Self::CIE_EPSILON { | ||||||
|  |                 fx3 | ||||||
|  |             } else { | ||||||
|  |                 (116.0 * fx - 16.0) / Self::CIE_KAPPA | ||||||
|  |             } | ||||||
|  |         }; | ||||||
|  |         let yr = if l > Self::CIE_EPSILON * Self::CIE_KAPPA { | ||||||
|  |             ((l + 16.0) / 116.0).powf(3.0) | ||||||
|  |         } else { | ||||||
|  |             l / Self::CIE_KAPPA | ||||||
|  |         }; | ||||||
|  |         let zr = { | ||||||
|  |             let fz3 = fz.powf(3.0); | ||||||
|  | 
 | ||||||
|  |             if fz3 > Self::CIE_EPSILON { | ||||||
|  |                 fz3 | ||||||
|  |             } else { | ||||||
|  |                 (116.0 * fz - 16.0) / Self::CIE_KAPPA | ||||||
|  |             } | ||||||
|  |         }; | ||||||
|  |         let x = xr * Self::D65_WHITE_X; | ||||||
|  |         let y = yr * Self::D65_WHITE_Y; | ||||||
|  |         let z = zr * Self::D65_WHITE_Z; | ||||||
|  | 
 | ||||||
|  |         // XYZ to sRGB
 | ||||||
|  |         // http://www.brucelindbloom.com/index.html?Eqn_XYZ_to_RGB.html
 | ||||||
|  |         // http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html (sRGB, XYZ to RGB [M]-1)
 | ||||||
|  |         let red = x * 3.2404542 + y * -1.5371385 + z * -0.4985314; | ||||||
|  |         let green = x * -0.969266 + y * 1.8760108 + z * 0.041556; | ||||||
|  |         let blue = x * 0.0556434 + y * -0.2040259 + z * 1.0572252; | ||||||
|  | 
 | ||||||
|  |         [ | ||||||
|  |             red.linear_to_nonlinear_srgb().max(0.0).min(1.0), | ||||||
|  |             green.linear_to_nonlinear_srgb().max(0.0).min(1.0), | ||||||
|  |             blue.linear_to_nonlinear_srgb().max(0.0).min(1.0), | ||||||
|  |         ] | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /// converts a color in sRGB space to LCH space
 | ||||||
|  |     #[inline] | ||||||
|  |     pub fn nonlinear_srgb_to_lch([red, green, blue]: [f32; 3]) -> (f32, f32, f32) { | ||||||
|  |         // RGB to XYZ
 | ||||||
|  |         // http://www.brucelindbloom.com/index.html?Eqn_RGB_to_XYZ.html
 | ||||||
|  |         let red = red.nonlinear_to_linear_srgb(); | ||||||
|  |         let green = green.nonlinear_to_linear_srgb(); | ||||||
|  |         let blue = blue.nonlinear_to_linear_srgb(); | ||||||
|  | 
 | ||||||
|  |         // http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html (sRGB, RGB to XYZ [M])
 | ||||||
|  |         let x = red * 0.4124564 + green * 0.3575761 + blue * 0.1804375; | ||||||
|  |         let y = red * 0.2126729 + green * 0.7151522 + blue * 0.072175; | ||||||
|  |         let z = red * 0.0193339 + green * 0.119192 + blue * 0.9503041; | ||||||
|  | 
 | ||||||
|  |         // XYZ to Lab
 | ||||||
|  |         // http://www.brucelindbloom.com/index.html?Eqn_XYZ_to_Lab.html
 | ||||||
|  |         let xr = x / Self::D65_WHITE_X; | ||||||
|  |         let yr = y / Self::D65_WHITE_Y; | ||||||
|  |         let zr = z / Self::D65_WHITE_Z; | ||||||
|  |         let fx = if xr > Self::CIE_EPSILON { | ||||||
|  |             xr.cbrt() | ||||||
|  |         } else { | ||||||
|  |             (Self::CIE_KAPPA * xr + 16.0) / 116.0 | ||||||
|  |         }; | ||||||
|  |         let fy = if yr > Self::CIE_EPSILON { | ||||||
|  |             yr.cbrt() | ||||||
|  |         } else { | ||||||
|  |             (Self::CIE_KAPPA * yr + 16.0) / 116.0 | ||||||
|  |         }; | ||||||
|  |         let fz = if yr > Self::CIE_EPSILON { | ||||||
|  |             zr.cbrt() | ||||||
|  |         } else { | ||||||
|  |             (Self::CIE_KAPPA * zr + 16.0) / 116.0 | ||||||
|  |         }; | ||||||
|  |         let l = 116.0 * fy - 16.0; | ||||||
|  |         let a = 500.0 * (fx - fy); | ||||||
|  |         let b = 200.0 * (fy - fz); | ||||||
|  | 
 | ||||||
|  |         // Lab to LCH
 | ||||||
|  |         // http://www.brucelindbloom.com/index.html?Eqn_Lab_to_LCH.html
 | ||||||
|  |         let c = (a.powf(2.0) + b.powf(2.0)).sqrt(); | ||||||
|  |         let h = { | ||||||
|  |             let h = b.to_radians().atan2(a.to_radians()).to_degrees(); | ||||||
|  | 
 | ||||||
|  |             if h < 0.0 { | ||||||
|  |                 h + 360.0 | ||||||
|  |             } else { | ||||||
|  |                 h | ||||||
|  |             } | ||||||
|  |         }; | ||||||
|  | 
 | ||||||
|  |         ( | ||||||
|  |             (l / 100.0).max(0.0).min(1.5), | ||||||
|  |             (c / 100.0).max(0.0).min(1.5), | ||||||
|  |             h, | ||||||
|  |         ) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
| #[cfg(test)] | #[cfg(test)] | ||||||
| mod test { | mod test { | ||||||
|     use super::*; |     use super::*; | ||||||
| @ -214,4 +345,90 @@ mod test { | |||||||
|         assert_eq!((saturation * 100.0).round() as u32, 83); |         assert_eq!((saturation * 100.0).round() as u32, 83); | ||||||
|         assert_eq!((lightness * 100.0).round() as u32, 51); |         assert_eq!((lightness * 100.0).round() as u32, 51); | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|  |     #[test] | ||||||
|  |     fn lch_to_srgb() { | ||||||
|  |         // "truth" from http://www.brucelindbloom.com/ColorCalculator.html
 | ||||||
|  | 
 | ||||||
|  |         // black
 | ||||||
|  |         let (lightness, chroma, hue) = (0.0, 0.0, 0.0); | ||||||
|  |         let [r, g, b] = LchRepresentation::lch_to_nonlinear_srgb(lightness, chroma, hue); | ||||||
|  |         assert_eq!((r * 100.0).round() as u32, 0); | ||||||
|  |         assert_eq!((g * 100.0).round() as u32, 0); | ||||||
|  |         assert_eq!((b * 100.0).round() as u32, 0); | ||||||
|  | 
 | ||||||
|  |         // white
 | ||||||
|  |         let (lightness, chroma, hue) = (1.0, 0.0, 0.0); | ||||||
|  |         let [r, g, b] = LchRepresentation::lch_to_nonlinear_srgb(lightness, chroma, hue); | ||||||
|  |         assert_eq!((r * 100.0).round() as u32, 100); | ||||||
|  |         assert_eq!((g * 100.0).round() as u32, 100); | ||||||
|  |         assert_eq!((b * 100.0).round() as u32, 100); | ||||||
|  | 
 | ||||||
|  |         let (lightness, chroma, hue) = (0.501236, 0.777514, 327.6608); | ||||||
|  |         let [r, g, b] = LchRepresentation::lch_to_nonlinear_srgb(lightness, chroma, hue); | ||||||
|  |         assert_eq!((r * 100.0).round() as u32, 75); | ||||||
|  |         assert_eq!((g * 100.0).round() as u32, 25); | ||||||
|  |         assert_eq!((b * 100.0).round() as u32, 75); | ||||||
|  | 
 | ||||||
|  |         // a red
 | ||||||
|  |         let (lightness, chroma, hue) = (0.487122, 0.999531, 318.7684); | ||||||
|  |         let [r, g, b] = LchRepresentation::lch_to_nonlinear_srgb(lightness, chroma, hue); | ||||||
|  |         assert_eq!((r * 100.0).round() as u32, 70); | ||||||
|  |         assert_eq!((g * 100.0).round() as u32, 19); | ||||||
|  |         assert_eq!((b * 100.0).round() as u32, 90); | ||||||
|  | 
 | ||||||
|  |         // a green
 | ||||||
|  |         let (lightness, chroma, hue) = (0.732929, 0.560925, 164.3216); | ||||||
|  |         let [r, g, b] = LchRepresentation::lch_to_nonlinear_srgb(lightness, chroma, hue); | ||||||
|  |         assert_eq!((r * 100.0).round() as u32, 10); | ||||||
|  |         assert_eq!((g * 100.0).round() as u32, 80); | ||||||
|  |         assert_eq!((b * 100.0).round() as u32, 59); | ||||||
|  | 
 | ||||||
|  |         // a blue
 | ||||||
|  |         let (lightness, chroma, hue) = (0.335030, 1.176923, 306.7828); | ||||||
|  |         let [r, g, b] = LchRepresentation::lch_to_nonlinear_srgb(lightness, chroma, hue); | ||||||
|  |         assert_eq!((r * 100.0).round() as u32, 25); | ||||||
|  |         assert_eq!((g * 100.0).round() as u32, 10); | ||||||
|  |         assert_eq!((b * 100.0).round() as u32, 92); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     #[test] | ||||||
|  |     fn srgb_to_lch() { | ||||||
|  |         // "truth" from http://www.brucelindbloom.com/ColorCalculator.html
 | ||||||
|  | 
 | ||||||
|  |         // black
 | ||||||
|  |         let (lightness, chroma, hue) = LchRepresentation::nonlinear_srgb_to_lch([0.0, 0.0, 0.0]); | ||||||
|  |         assert_eq!((lightness * 100.0).round() as u32, 0); | ||||||
|  |         assert_eq!((chroma * 100.0).round() as u32, 0); | ||||||
|  |         assert_eq!(hue.round() as u32, 0); | ||||||
|  | 
 | ||||||
|  |         // white
 | ||||||
|  |         let (lightness, chroma, hue) = LchRepresentation::nonlinear_srgb_to_lch([1.0, 1.0, 1.0]); | ||||||
|  |         assert_eq!((lightness * 100.0).round() as u32, 100); | ||||||
|  |         assert_eq!((chroma * 100.0).round() as u32, 0); | ||||||
|  |         assert_eq!(hue.round() as u32, 0); | ||||||
|  | 
 | ||||||
|  |         let (lightness, chroma, hue) = LchRepresentation::nonlinear_srgb_to_lch([0.75, 0.25, 0.75]); | ||||||
|  |         assert_eq!((lightness * 100.0).round() as u32, 50); | ||||||
|  |         assert_eq!((chroma * 100.0).round() as u32, 78); | ||||||
|  |         assert_eq!(hue.round() as u32, 328); | ||||||
|  | 
 | ||||||
|  |         // a red
 | ||||||
|  |         let (lightness, chroma, hue) = LchRepresentation::nonlinear_srgb_to_lch([0.70, 0.19, 0.90]); | ||||||
|  |         assert_eq!((lightness * 100.0).round() as u32, 49); | ||||||
|  |         assert_eq!((chroma * 100.0).round() as u32, 100); | ||||||
|  |         assert_eq!(hue.round() as u32, 319); | ||||||
|  | 
 | ||||||
|  |         // a green
 | ||||||
|  |         let (lightness, chroma, hue) = LchRepresentation::nonlinear_srgb_to_lch([0.10, 0.80, 0.59]); | ||||||
|  |         assert_eq!((lightness * 100.0).round() as u32, 73); | ||||||
|  |         assert_eq!((chroma * 100.0).round() as u32, 56); | ||||||
|  |         assert_eq!(hue.round() as u32, 164); | ||||||
|  | 
 | ||||||
|  |         // a blue
 | ||||||
|  |         let (lightness, chroma, hue) = LchRepresentation::nonlinear_srgb_to_lch([0.25, 0.10, 0.92]); | ||||||
|  |         assert_eq!((lightness * 100.0).round() as u32, 34); | ||||||
|  |         assert_eq!((chroma * 100.0).round() as u32, 118); | ||||||
|  |         assert_eq!(hue.round() as u32, 307); | ||||||
|  |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -44,6 +44,17 @@ pub enum Color { | |||||||
|         /// Alpha channel. [0.0, 1.0]
 |         /// Alpha channel. [0.0, 1.0]
 | ||||||
|         alpha: f32, |         alpha: f32, | ||||||
|     }, |     }, | ||||||
|  |     /// LCH(ab) (lightness, chroma, hue) color with an alpha channel
 | ||||||
|  |     Lcha { | ||||||
|  |         /// Lightness channel. [0.0, 1.5]
 | ||||||
|  |         lightness: f32, | ||||||
|  |         /// Chroma channel. [0.0, 1.5]
 | ||||||
|  |         chroma: f32, | ||||||
|  |         /// Hue channel. [0.0, 360.0]
 | ||||||
|  |         hue: f32, | ||||||
|  |         /// Alpha channel. [0.0, 1.0]
 | ||||||
|  |         alpha: f32, | ||||||
|  |     }, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl Color { | impl Color { | ||||||
| @ -401,7 +412,8 @@ impl Color { | |||||||
|         match self { |         match self { | ||||||
|             Color::Rgba { alpha, .. } |             Color::Rgba { alpha, .. } | ||||||
|             | Color::RgbaLinear { alpha, .. } |             | Color::RgbaLinear { alpha, .. } | ||||||
|             | Color::Hsla { alpha, .. } => *alpha, |             | Color::Hsla { alpha, .. } | ||||||
|  |             | Color::Lcha { alpha, .. } => *alpha, | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| @ -410,7 +422,8 @@ impl Color { | |||||||
|         match self { |         match self { | ||||||
|             Color::Rgba { alpha, .. } |             Color::Rgba { alpha, .. } | ||||||
|             | Color::RgbaLinear { alpha, .. } |             | Color::RgbaLinear { alpha, .. } | ||||||
|             | Color::Hsla { alpha, .. } => { |             | Color::Hsla { alpha, .. } | ||||||
|  |             | Color::Lcha { alpha, .. } => { | ||||||
|                 *alpha = a; |                 *alpha = a; | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
| @ -454,6 +467,22 @@ impl Color { | |||||||
|                     alpha: *alpha, |                     alpha: *alpha, | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|  |             Color::Lcha { | ||||||
|  |                 lightness, | ||||||
|  |                 chroma, | ||||||
|  |                 hue, | ||||||
|  |                 alpha, | ||||||
|  |             } => { | ||||||
|  |                 let [red, green, blue] = | ||||||
|  |                     LchRepresentation::lch_to_nonlinear_srgb(*lightness, *chroma, *hue); | ||||||
|  | 
 | ||||||
|  |                 Color::Rgba { | ||||||
|  |                     red, | ||||||
|  |                     green, | ||||||
|  |                     blue, | ||||||
|  |                     alpha: *alpha, | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| @ -487,6 +516,22 @@ impl Color { | |||||||
|                     alpha: *alpha, |                     alpha: *alpha, | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|  |             Color::Lcha { | ||||||
|  |                 lightness, | ||||||
|  |                 chroma, | ||||||
|  |                 hue, | ||||||
|  |                 alpha, | ||||||
|  |             } => { | ||||||
|  |                 let [red, green, blue] = | ||||||
|  |                     LchRepresentation::lch_to_nonlinear_srgb(*lightness, *chroma, *hue); | ||||||
|  | 
 | ||||||
|  |                 Color::Rgba { | ||||||
|  |                     red: red.nonlinear_to_linear_srgb(), | ||||||
|  |                     green: green.nonlinear_to_linear_srgb(), | ||||||
|  |                     blue: blue.nonlinear_to_linear_srgb(), | ||||||
|  |                     alpha: *alpha, | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| @ -527,6 +572,22 @@ impl Color { | |||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|             Color::Hsla { .. } => *self, |             Color::Hsla { .. } => *self, | ||||||
|  |             Color::Lcha { | ||||||
|  |                 lightness, | ||||||
|  |                 chroma, | ||||||
|  |                 hue, | ||||||
|  |                 alpha, | ||||||
|  |             } => { | ||||||
|  |                 let rgb = LchRepresentation::lch_to_nonlinear_srgb(*lightness, *chroma, *hue); | ||||||
|  |                 let (hue, saturation, lightness) = HslRepresentation::nonlinear_srgb_to_hsl(rgb); | ||||||
|  | 
 | ||||||
|  |                 Color::Hsla { | ||||||
|  |                     hue, | ||||||
|  |                     saturation, | ||||||
|  |                     lightness, | ||||||
|  |                     alpha: *alpha, | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| @ -560,6 +621,17 @@ impl Color { | |||||||
|                     HslRepresentation::hsl_to_nonlinear_srgb(hue, saturation, lightness); |                     HslRepresentation::hsl_to_nonlinear_srgb(hue, saturation, lightness); | ||||||
|                 [red, green, blue, alpha] |                 [red, green, blue, alpha] | ||||||
|             } |             } | ||||||
|  |             Color::Lcha { | ||||||
|  |                 lightness, | ||||||
|  |                 chroma, | ||||||
|  |                 hue, | ||||||
|  |                 alpha, | ||||||
|  |             } => { | ||||||
|  |                 let [red, green, blue] = | ||||||
|  |                     LchRepresentation::lch_to_nonlinear_srgb(lightness, chroma, hue); | ||||||
|  | 
 | ||||||
|  |                 [red, green, blue, alpha] | ||||||
|  |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| @ -599,6 +671,22 @@ impl Color { | |||||||
|                     alpha, |                     alpha, | ||||||
|                 ] |                 ] | ||||||
|             } |             } | ||||||
|  |             Color::Lcha { | ||||||
|  |                 lightness, | ||||||
|  |                 chroma, | ||||||
|  |                 hue, | ||||||
|  |                 alpha, | ||||||
|  |             } => { | ||||||
|  |                 let [red, green, blue] = | ||||||
|  |                     LchRepresentation::lch_to_nonlinear_srgb(lightness, chroma, hue); | ||||||
|  | 
 | ||||||
|  |                 [ | ||||||
|  |                     red.nonlinear_to_linear_srgb(), | ||||||
|  |                     green.nonlinear_to_linear_srgb(), | ||||||
|  |                     blue.nonlinear_to_linear_srgb(), | ||||||
|  |                     alpha, | ||||||
|  |                 ] | ||||||
|  |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| @ -634,6 +722,63 @@ impl Color { | |||||||
|                 lightness, |                 lightness, | ||||||
|                 alpha, |                 alpha, | ||||||
|             } => [hue, saturation, lightness, alpha], |             } => [hue, saturation, lightness, alpha], | ||||||
|  |             Color::Lcha { | ||||||
|  |                 lightness, | ||||||
|  |                 chroma, | ||||||
|  |                 hue, | ||||||
|  |                 alpha, | ||||||
|  |             } => { | ||||||
|  |                 let rgb = LchRepresentation::lch_to_nonlinear_srgb(lightness, chroma, hue); | ||||||
|  |                 let (hue, saturation, lightness) = HslRepresentation::nonlinear_srgb_to_hsl(rgb); | ||||||
|  | 
 | ||||||
|  |                 [hue, saturation, lightness, alpha] | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /// Converts a `Color` to a `[f32; 4]` from LCH colorspace
 | ||||||
|  |     pub fn as_lch_f32(self: Color) -> [f32; 4] { | ||||||
|  |         match self { | ||||||
|  |             Color::Rgba { | ||||||
|  |                 red, | ||||||
|  |                 green, | ||||||
|  |                 blue, | ||||||
|  |                 alpha, | ||||||
|  |             } => { | ||||||
|  |                 let (lightness, chroma, hue) = | ||||||
|  |                     LchRepresentation::nonlinear_srgb_to_lch([red, green, blue]); | ||||||
|  |                 [lightness, chroma, hue, alpha] | ||||||
|  |             } | ||||||
|  |             Color::RgbaLinear { | ||||||
|  |                 red, | ||||||
|  |                 green, | ||||||
|  |                 blue, | ||||||
|  |                 alpha, | ||||||
|  |             } => { | ||||||
|  |                 let (lightness, chroma, hue) = LchRepresentation::nonlinear_srgb_to_lch([ | ||||||
|  |                     red.linear_to_nonlinear_srgb(), | ||||||
|  |                     green.linear_to_nonlinear_srgb(), | ||||||
|  |                     blue.linear_to_nonlinear_srgb(), | ||||||
|  |                 ]); | ||||||
|  |                 [lightness, chroma, hue, alpha] | ||||||
|  |             } | ||||||
|  |             Color::Hsla { | ||||||
|  |                 hue, | ||||||
|  |                 saturation, | ||||||
|  |                 lightness, | ||||||
|  |                 alpha, | ||||||
|  |             } => { | ||||||
|  |                 let rgb = HslRepresentation::hsl_to_nonlinear_srgb(hue, saturation, lightness); | ||||||
|  |                 let (lightness, chroma, hue) = LchRepresentation::nonlinear_srgb_to_lch(rgb); | ||||||
|  | 
 | ||||||
|  |                 [lightness, chroma, hue, alpha] | ||||||
|  |             } | ||||||
|  |             Color::Lcha { | ||||||
|  |                 lightness, | ||||||
|  |                 chroma, | ||||||
|  |                 hue, | ||||||
|  |                 alpha, | ||||||
|  |             } => [lightness, chroma, hue, alpha], | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| @ -680,6 +825,22 @@ impl Color { | |||||||
|                     (alpha * 255.0) as u8, |                     (alpha * 255.0) as u8, | ||||||
|                 ]) |                 ]) | ||||||
|             } |             } | ||||||
|  |             Color::Lcha { | ||||||
|  |                 lightness, | ||||||
|  |                 chroma, | ||||||
|  |                 hue, | ||||||
|  |                 alpha, | ||||||
|  |             } => { | ||||||
|  |                 let [red, green, blue] = | ||||||
|  |                     LchRepresentation::lch_to_nonlinear_srgb(lightness, chroma, hue); | ||||||
|  | 
 | ||||||
|  |                 u32::from_le_bytes([ | ||||||
|  |                     (red * 255.0) as u8, | ||||||
|  |                     (green * 255.0) as u8, | ||||||
|  |                     (blue * 255.0) as u8, | ||||||
|  |                     (alpha * 255.0) as u8, | ||||||
|  |                 ]) | ||||||
|  |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| @ -726,6 +887,22 @@ impl Color { | |||||||
|                     (alpha * 255.0) as u8, |                     (alpha * 255.0) as u8, | ||||||
|                 ]) |                 ]) | ||||||
|             } |             } | ||||||
|  |             Color::Lcha { | ||||||
|  |                 lightness, | ||||||
|  |                 chroma, | ||||||
|  |                 hue, | ||||||
|  |                 alpha, | ||||||
|  |             } => { | ||||||
|  |                 let [red, green, blue] = | ||||||
|  |                     LchRepresentation::lch_to_nonlinear_srgb(lightness, chroma, hue); | ||||||
|  | 
 | ||||||
|  |                 u32::from_le_bytes([ | ||||||
|  |                     (red.nonlinear_to_linear_srgb() * 255.0) as u8, | ||||||
|  |                     (green.nonlinear_to_linear_srgb() * 255.0) as u8, | ||||||
|  |                     (blue.nonlinear_to_linear_srgb() * 255.0) as u8, | ||||||
|  |                     (alpha * 255.0) as u8, | ||||||
|  |                 ]) | ||||||
|  |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
| @ -775,6 +952,18 @@ impl AddAssign<Color> for Color { | |||||||
|                 *lightness += rhs[2]; |                 *lightness += rhs[2]; | ||||||
|                 *alpha += rhs[3]; |                 *alpha += rhs[3]; | ||||||
|             } |             } | ||||||
|  |             Color::Lcha { | ||||||
|  |                 lightness, | ||||||
|  |                 chroma, | ||||||
|  |                 hue, | ||||||
|  |                 alpha, | ||||||
|  |             } => { | ||||||
|  |                 let rhs = rhs.as_lch_f32(); | ||||||
|  |                 *lightness += rhs[0]; | ||||||
|  |                 *chroma += rhs[1]; | ||||||
|  |                 *hue += rhs[2]; | ||||||
|  |                 *alpha += rhs[3]; | ||||||
|  |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
| @ -826,6 +1015,21 @@ impl Add<Color> for Color { | |||||||
|                     alpha: alpha + rhs[3], |                     alpha: alpha + rhs[3], | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|  |             Color::Lcha { | ||||||
|  |                 lightness, | ||||||
|  |                 chroma, | ||||||
|  |                 hue, | ||||||
|  |                 alpha, | ||||||
|  |             } => { | ||||||
|  |                 let rhs = rhs.as_lch_f32(); | ||||||
|  | 
 | ||||||
|  |                 Color::Lcha { | ||||||
|  |                     lightness: lightness + rhs[0], | ||||||
|  |                     chroma: chroma + rhs[1], | ||||||
|  |                     hue: hue + rhs[2], | ||||||
|  |                     alpha: alpha + rhs[3], | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
| @ -936,6 +1140,17 @@ impl Mul<f32> for Color { | |||||||
|                 lightness: lightness * rhs, |                 lightness: lightness * rhs, | ||||||
|                 alpha, |                 alpha, | ||||||
|             }, |             }, | ||||||
|  |             Color::Lcha { | ||||||
|  |                 lightness, | ||||||
|  |                 chroma, | ||||||
|  |                 hue, | ||||||
|  |                 alpha, | ||||||
|  |             } => Color::Lcha { | ||||||
|  |                 lightness: lightness * rhs, | ||||||
|  |                 chroma: chroma * rhs, | ||||||
|  |                 hue: hue * rhs, | ||||||
|  |                 alpha, | ||||||
|  |             }, | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
| @ -963,6 +1178,16 @@ impl MulAssign<f32> for Color { | |||||||
|                 *saturation *= rhs; |                 *saturation *= rhs; | ||||||
|                 *lightness *= rhs; |                 *lightness *= rhs; | ||||||
|             } |             } | ||||||
|  |             Color::Lcha { | ||||||
|  |                 lightness, | ||||||
|  |                 chroma, | ||||||
|  |                 hue, | ||||||
|  |                 .. | ||||||
|  |             } => { | ||||||
|  |                 *lightness *= rhs; | ||||||
|  |                 *chroma *= rhs; | ||||||
|  |                 *hue *= rhs; | ||||||
|  |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
| @ -1005,6 +1230,17 @@ impl Mul<Vec4> for Color { | |||||||
|                 lightness: lightness * rhs.z, |                 lightness: lightness * rhs.z, | ||||||
|                 alpha: alpha * rhs.w, |                 alpha: alpha * rhs.w, | ||||||
|             }, |             }, | ||||||
|  |             Color::Lcha { | ||||||
|  |                 lightness, | ||||||
|  |                 chroma, | ||||||
|  |                 hue, | ||||||
|  |                 alpha, | ||||||
|  |             } => Color::Lcha { | ||||||
|  |                 lightness: lightness * rhs.x, | ||||||
|  |                 chroma: chroma * rhs.y, | ||||||
|  |                 hue: hue * rhs.z, | ||||||
|  |                 alpha: alpha * rhs.w, | ||||||
|  |             }, | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
| @ -1040,6 +1276,17 @@ impl MulAssign<Vec4> for Color { | |||||||
|                 *lightness *= rhs.z; |                 *lightness *= rhs.z; | ||||||
|                 *alpha *= rhs.w; |                 *alpha *= rhs.w; | ||||||
|             } |             } | ||||||
|  |             Color::Lcha { | ||||||
|  |                 lightness, | ||||||
|  |                 chroma, | ||||||
|  |                 hue, | ||||||
|  |                 alpha, | ||||||
|  |             } => { | ||||||
|  |                 *lightness *= rhs.x; | ||||||
|  |                 *chroma *= rhs.y; | ||||||
|  |                 *hue *= rhs.z; | ||||||
|  |                 *alpha *= rhs.w; | ||||||
|  |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
| @ -1082,6 +1329,17 @@ impl Mul<Vec3> for Color { | |||||||
|                 lightness: lightness * rhs.z, |                 lightness: lightness * rhs.z, | ||||||
|                 alpha, |                 alpha, | ||||||
|             }, |             }, | ||||||
|  |             Color::Lcha { | ||||||
|  |                 lightness, | ||||||
|  |                 chroma, | ||||||
|  |                 hue, | ||||||
|  |                 alpha, | ||||||
|  |             } => Color::Lcha { | ||||||
|  |                 lightness: lightness * rhs.x, | ||||||
|  |                 chroma: chroma * rhs.y, | ||||||
|  |                 hue: hue * rhs.z, | ||||||
|  |                 alpha, | ||||||
|  |             }, | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
| @ -1109,6 +1367,16 @@ impl MulAssign<Vec3> for Color { | |||||||
|                 *saturation *= rhs.y; |                 *saturation *= rhs.y; | ||||||
|                 *lightness *= rhs.z; |                 *lightness *= rhs.z; | ||||||
|             } |             } | ||||||
|  |             Color::Lcha { | ||||||
|  |                 lightness, | ||||||
|  |                 chroma, | ||||||
|  |                 hue, | ||||||
|  |                 .. | ||||||
|  |             } => { | ||||||
|  |                 *lightness *= rhs.x; | ||||||
|  |                 *chroma *= rhs.y; | ||||||
|  |                 *hue *= rhs.z; | ||||||
|  |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
| @ -1151,6 +1419,17 @@ impl Mul<[f32; 4]> for Color { | |||||||
|                 lightness: lightness * rhs[2], |                 lightness: lightness * rhs[2], | ||||||
|                 alpha: alpha * rhs[3], |                 alpha: alpha * rhs[3], | ||||||
|             }, |             }, | ||||||
|  |             Color::Lcha { | ||||||
|  |                 lightness, | ||||||
|  |                 chroma, | ||||||
|  |                 hue, | ||||||
|  |                 alpha, | ||||||
|  |             } => Color::Lcha { | ||||||
|  |                 lightness: lightness * rhs[0], | ||||||
|  |                 chroma: chroma * rhs[1], | ||||||
|  |                 hue: hue * rhs[2], | ||||||
|  |                 alpha: alpha * rhs[3], | ||||||
|  |             }, | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
| @ -1186,6 +1465,17 @@ impl MulAssign<[f32; 4]> for Color { | |||||||
|                 *lightness *= rhs[2]; |                 *lightness *= rhs[2]; | ||||||
|                 *alpha *= rhs[3]; |                 *alpha *= rhs[3]; | ||||||
|             } |             } | ||||||
|  |             Color::Lcha { | ||||||
|  |                 lightness, | ||||||
|  |                 chroma, | ||||||
|  |                 hue, | ||||||
|  |                 alpha, | ||||||
|  |             } => { | ||||||
|  |                 *lightness *= rhs[0]; | ||||||
|  |                 *chroma *= rhs[1]; | ||||||
|  |                 *hue *= rhs[2]; | ||||||
|  |                 *alpha *= rhs[3]; | ||||||
|  |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
| @ -1228,6 +1518,17 @@ impl Mul<[f32; 3]> for Color { | |||||||
|                 lightness: lightness * rhs[2], |                 lightness: lightness * rhs[2], | ||||||
|                 alpha, |                 alpha, | ||||||
|             }, |             }, | ||||||
|  |             Color::Lcha { | ||||||
|  |                 lightness, | ||||||
|  |                 chroma, | ||||||
|  |                 hue, | ||||||
|  |                 alpha, | ||||||
|  |             } => Color::Lcha { | ||||||
|  |                 lightness: lightness * rhs[0], | ||||||
|  |                 chroma: chroma * rhs[1], | ||||||
|  |                 hue: hue * rhs[2], | ||||||
|  |                 alpha, | ||||||
|  |             }, | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
| @ -1255,6 +1556,16 @@ impl MulAssign<[f32; 3]> for Color { | |||||||
|                 *saturation *= rhs[1]; |                 *saturation *= rhs[1]; | ||||||
|                 *lightness *= rhs[2]; |                 *lightness *= rhs[2]; | ||||||
|             } |             } | ||||||
|  |             Color::Lcha { | ||||||
|  |                 lightness, | ||||||
|  |                 chroma, | ||||||
|  |                 hue, | ||||||
|  |                 .. | ||||||
|  |             } => { | ||||||
|  |                 *lightness *= rhs[0]; | ||||||
|  |                 *chroma *= rhs[1]; | ||||||
|  |                 *hue *= rhs[2]; | ||||||
|  |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user
	 Ludwig DUBOS
						Ludwig DUBOS