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