bevy_color: Added Xyza Colour Space (#12079)
# Objective Add XYZ colour space. This will be most useful as a conversion step when working with other (more common) colour spaces. See [Wikipedia](https://en.wikipedia.org/wiki/CIE_1931_color_space) for details on this space. ## Solution - Added `Xyza` to `Color` and as its own type. --- ## Changelog - Added `Xyza` type. - Added `Color::Xyza` variant. ## Migration Guide - `Color` enum now has an additional member, `Xyza`. Convert it to any other type to handle this case in match statements.
This commit is contained in:
parent
65267dd1f9
commit
972ca62831
@ -1,4 +1,4 @@
|
|||||||
use palette::{Hsl, IntoColor, Lch, LinSrgb, Oklab, Srgb};
|
use palette::{Hsl, IntoColor, Lch, LinSrgb, Oklab, Srgb, Xyz};
|
||||||
|
|
||||||
const TEST_COLORS: &[(f32, f32, f32, &str)] = &[
|
const TEST_COLORS: &[(f32, f32, f32, &str)] = &[
|
||||||
(0., 0., 0., "black"),
|
(0., 0., 0., "black"),
|
||||||
@ -25,7 +25,7 @@ fn main() {
|
|||||||
println!(
|
println!(
|
||||||
"// Generated by gen_tests. Do not edit.
|
"// Generated by gen_tests. Do not edit.
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
use crate::{{Hsla, Srgba, LinearRgba, Oklaba, Lcha}};
|
use crate::{{Hsla, Srgba, LinearRgba, Oklaba, Lcha, Xyza}};
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
pub struct TestColor {{
|
pub struct TestColor {{
|
||||||
@ -35,6 +35,7 @@ pub struct TestColor {{
|
|||||||
pub hsl: Hsla,
|
pub hsl: Hsla,
|
||||||
pub lch: Lcha,
|
pub lch: Lcha,
|
||||||
pub oklab: Oklaba,
|
pub oklab: Oklaba,
|
||||||
|
pub xyz: Xyza,
|
||||||
}}
|
}}
|
||||||
"
|
"
|
||||||
);
|
);
|
||||||
@ -48,6 +49,7 @@ pub struct TestColor {{
|
|||||||
let hsl: Hsl = srgb.into_color();
|
let hsl: Hsl = srgb.into_color();
|
||||||
let lch: Lch = srgb.into_color();
|
let lch: Lch = srgb.into_color();
|
||||||
let oklab: Oklab = srgb.into_color();
|
let oklab: Oklab = srgb.into_color();
|
||||||
|
let xyz: Xyz = srgb.into_color();
|
||||||
println!(" // {name}");
|
println!(" // {name}");
|
||||||
println!(
|
println!(
|
||||||
" TestColor {{
|
" TestColor {{
|
||||||
@ -57,6 +59,7 @@ pub struct TestColor {{
|
|||||||
hsl: Hsla::new({}, {}, {}, 1.0),
|
hsl: Hsla::new({}, {}, {}, 1.0),
|
||||||
lch: Lcha::new({}, {}, {}, 1.0),
|
lch: Lcha::new({}, {}, {}, 1.0),
|
||||||
oklab: Oklaba::new({}, {}, {}, 1.0),
|
oklab: Oklaba::new({}, {}, {}, 1.0),
|
||||||
|
xyz: Xyza::new({}, {}, {}, 1.0),
|
||||||
}},",
|
}},",
|
||||||
VariablePrecision(srgb.red),
|
VariablePrecision(srgb.red),
|
||||||
VariablePrecision(srgb.green),
|
VariablePrecision(srgb.green),
|
||||||
@ -73,6 +76,9 @@ pub struct TestColor {{
|
|||||||
VariablePrecision(oklab.l),
|
VariablePrecision(oklab.l),
|
||||||
VariablePrecision(oklab.a),
|
VariablePrecision(oklab.a),
|
||||||
VariablePrecision(oklab.b),
|
VariablePrecision(oklab.b),
|
||||||
|
VariablePrecision(xyz.x),
|
||||||
|
VariablePrecision(xyz.y),
|
||||||
|
VariablePrecision(xyz.z),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
println!("];");
|
println!("];");
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
use crate::{Alpha, Hsla, Lcha, LinearRgba, Oklaba, Srgba, StandardColor};
|
use crate::{Alpha, Hsla, Lcha, LinearRgba, Oklaba, Srgba, StandardColor, Xyza};
|
||||||
use bevy_reflect::{Reflect, ReflectDeserialize, ReflectSerialize};
|
use bevy_reflect::{Reflect, ReflectDeserialize, ReflectSerialize};
|
||||||
use bevy_render::color::Color as LegacyColor;
|
use bevy_render::color::Color as LegacyColor;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
@ -20,6 +20,8 @@ pub enum Color {
|
|||||||
Lcha(Lcha),
|
Lcha(Lcha),
|
||||||
/// A color in the Oklaba color space with alpha.
|
/// A color in the Oklaba color space with alpha.
|
||||||
Oklaba(Oklaba),
|
Oklaba(Oklaba),
|
||||||
|
/// A color in the XYZ color space with alpha.
|
||||||
|
Xyza(Xyza),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl StandardColor for Color {}
|
impl StandardColor for Color {}
|
||||||
@ -33,6 +35,7 @@ impl Color {
|
|||||||
Color::Hsla(hsla) => (*hsla).into(),
|
Color::Hsla(hsla) => (*hsla).into(),
|
||||||
Color::Lcha(lcha) => (*lcha).into(),
|
Color::Lcha(lcha) => (*lcha).into(),
|
||||||
Color::Oklaba(oklab) => (*oklab).into(),
|
Color::Oklaba(oklab) => (*oklab).into(),
|
||||||
|
Color::Xyza(xyza) => (*xyza).into(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -53,6 +56,7 @@ impl Alpha for Color {
|
|||||||
Color::Hsla(x) => *x = x.with_alpha(alpha),
|
Color::Hsla(x) => *x = x.with_alpha(alpha),
|
||||||
Color::Lcha(x) => *x = x.with_alpha(alpha),
|
Color::Lcha(x) => *x = x.with_alpha(alpha),
|
||||||
Color::Oklaba(x) => *x = x.with_alpha(alpha),
|
Color::Oklaba(x) => *x = x.with_alpha(alpha),
|
||||||
|
Color::Xyza(x) => *x = x.with_alpha(alpha),
|
||||||
}
|
}
|
||||||
|
|
||||||
new
|
new
|
||||||
@ -65,6 +69,7 @@ impl Alpha for Color {
|
|||||||
Color::Hsla(x) => x.alpha(),
|
Color::Hsla(x) => x.alpha(),
|
||||||
Color::Lcha(x) => x.alpha(),
|
Color::Lcha(x) => x.alpha(),
|
||||||
Color::Oklaba(x) => x.alpha(),
|
Color::Oklaba(x) => x.alpha(),
|
||||||
|
Color::Xyza(x) => x.alpha(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -99,6 +104,12 @@ impl From<Lcha> for Color {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<Xyza> for Color {
|
||||||
|
fn from(value: Xyza) -> Self {
|
||||||
|
Self::Xyza(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl From<Color> for Srgba {
|
impl From<Color> for Srgba {
|
||||||
fn from(value: Color) -> Self {
|
fn from(value: Color) -> Self {
|
||||||
match value {
|
match value {
|
||||||
@ -107,6 +118,7 @@ impl From<Color> for Srgba {
|
|||||||
Color::Hsla(hsla) => hsla.into(),
|
Color::Hsla(hsla) => hsla.into(),
|
||||||
Color::Lcha(lcha) => lcha.into(),
|
Color::Lcha(lcha) => lcha.into(),
|
||||||
Color::Oklaba(oklab) => oklab.into(),
|
Color::Oklaba(oklab) => oklab.into(),
|
||||||
|
Color::Xyza(xyza) => xyza.into(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -119,6 +131,7 @@ impl From<Color> for LinearRgba {
|
|||||||
Color::Hsla(hsla) => hsla.into(),
|
Color::Hsla(hsla) => hsla.into(),
|
||||||
Color::Lcha(lcha) => lcha.into(),
|
Color::Lcha(lcha) => lcha.into(),
|
||||||
Color::Oklaba(oklab) => oklab.into(),
|
Color::Oklaba(oklab) => oklab.into(),
|
||||||
|
Color::Xyza(xyza) => xyza.into(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -131,6 +144,7 @@ impl From<Color> for Hsla {
|
|||||||
Color::Hsla(hsla) => hsla,
|
Color::Hsla(hsla) => hsla,
|
||||||
Color::Lcha(lcha) => LinearRgba::from(lcha).into(),
|
Color::Lcha(lcha) => LinearRgba::from(lcha).into(),
|
||||||
Color::Oklaba(oklab) => LinearRgba::from(oklab).into(),
|
Color::Oklaba(oklab) => LinearRgba::from(oklab).into(),
|
||||||
|
Color::Xyza(xyza) => LinearRgba::from(xyza).into(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -143,6 +157,7 @@ impl From<Color> for Lcha {
|
|||||||
Color::Hsla(hsla) => Srgba::from(hsla).into(),
|
Color::Hsla(hsla) => Srgba::from(hsla).into(),
|
||||||
Color::Lcha(lcha) => lcha,
|
Color::Lcha(lcha) => lcha,
|
||||||
Color::Oklaba(oklab) => LinearRgba::from(oklab).into(),
|
Color::Oklaba(oklab) => LinearRgba::from(oklab).into(),
|
||||||
|
Color::Xyza(xyza) => LinearRgba::from(xyza).into(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -155,6 +170,20 @@ impl From<Color> for Oklaba {
|
|||||||
Color::Hsla(hsla) => Srgba::from(hsla).into(),
|
Color::Hsla(hsla) => Srgba::from(hsla).into(),
|
||||||
Color::Lcha(lcha) => LinearRgba::from(lcha).into(),
|
Color::Lcha(lcha) => LinearRgba::from(lcha).into(),
|
||||||
Color::Oklaba(oklab) => oklab,
|
Color::Oklaba(oklab) => oklab,
|
||||||
|
Color::Xyza(xyza) => LinearRgba::from(xyza).into(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Color> for Xyza {
|
||||||
|
fn from(value: Color) -> Self {
|
||||||
|
match value {
|
||||||
|
Color::Srgba(x) => x.into(),
|
||||||
|
Color::LinearRgba(x) => x.into(),
|
||||||
|
Color::Hsla(x) => x.into(),
|
||||||
|
Color::Lcha(x) => x.into(),
|
||||||
|
Color::Oklaba(x) => x.into(),
|
||||||
|
Color::Xyza(xyza) => xyza,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -178,6 +207,7 @@ impl From<Color> for LegacyColor {
|
|||||||
Color::Hsla(x) => x.into(),
|
Color::Hsla(x) => x.into(),
|
||||||
Color::Lcha(x) => x.into(),
|
Color::Lcha(x) => x.into(),
|
||||||
Color::Oklaba(x) => x.into(),
|
Color::Oklaba(x) => x.into(),
|
||||||
|
Color::Xyza(x) => x.into(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,6 +7,7 @@
|
|||||||
//! - [`Hsla`] (hue, saturation, lightness, alpha)
|
//! - [`Hsla`] (hue, saturation, lightness, alpha)
|
||||||
//! - [`Lcha`] (lightness, chroma, hue, alpha)
|
//! - [`Lcha`] (lightness, chroma, hue, alpha)
|
||||||
//! - [`Oklaba`] (lightness, a-axis, b-axis, alpha)
|
//! - [`Oklaba`] (lightness, a-axis, b-axis, alpha)
|
||||||
|
//! - [`Xyza`] (x-axis, y-axis, z-axis, alpha)
|
||||||
//!
|
//!
|
||||||
//! Each of these color spaces is represented as a distinct Rust type.
|
//! Each of these color spaces is represented as a distinct Rust type.
|
||||||
//!
|
//!
|
||||||
@ -35,6 +36,10 @@
|
|||||||
//! for tasks such as color correction and image analysis, where it is important to be able
|
//! for tasks such as color correction and image analysis, where it is important to be able
|
||||||
//! to do things like change color saturation without causing hue shifts.
|
//! to do things like change color saturation without causing hue shifts.
|
||||||
//!
|
//!
|
||||||
|
//! XYZ is a foundational space commonly used in the definition of other more modern color
|
||||||
|
//! spaces. The space is more formally known as CIE 1931, where the `x` and `z` axes represent
|
||||||
|
//! a form of chromaticity, while `y` defines an illuminance level.
|
||||||
|
//!
|
||||||
//! See also the [Wikipedia article on color spaces](https://en.wikipedia.org/wiki/Color_space).
|
//! See also the [Wikipedia article on color spaces](https://en.wikipedia.org/wiki/Color_space).
|
||||||
//!
|
//!
|
||||||
//! # Conversions
|
//! # Conversions
|
||||||
@ -78,6 +83,7 @@ mod srgba;
|
|||||||
mod test_colors;
|
mod test_colors;
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod testing;
|
mod testing;
|
||||||
|
mod xyza;
|
||||||
|
|
||||||
pub use color::*;
|
pub use color::*;
|
||||||
pub use color_ops::*;
|
pub use color_ops::*;
|
||||||
@ -87,6 +93,7 @@ pub use lcha::*;
|
|||||||
pub use linear_rgba::*;
|
pub use linear_rgba::*;
|
||||||
pub use oklaba::*;
|
pub use oklaba::*;
|
||||||
pub use srgba::*;
|
pub use srgba::*;
|
||||||
|
pub use xyza::*;
|
||||||
|
|
||||||
use bevy_render::color::Color as LegacyColor;
|
use bevy_render::color::Color as LegacyColor;
|
||||||
|
|
||||||
@ -106,6 +113,7 @@ where
|
|||||||
Self: From<Hsla> + Into<Hsla>,
|
Self: From<Hsla> + Into<Hsla>,
|
||||||
Self: From<Lcha> + Into<Lcha>,
|
Self: From<Lcha> + Into<Lcha>,
|
||||||
Self: From<Oklaba> + Into<Oklaba>,
|
Self: From<Oklaba> + Into<Oklaba>,
|
||||||
|
Self: From<Xyza> + Into<Xyza>,
|
||||||
Self: Alpha,
|
Self: Alpha,
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
// Generated by gen_tests. Do not edit.
|
// Generated by gen_tests. Do not edit.
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
use crate::{Hsla, Lcha, LinearRgba, Oklaba, Srgba};
|
use crate::{Hsla, Lcha, LinearRgba, Oklaba, Srgba, Xyza};
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
pub struct TestColor {
|
pub struct TestColor {
|
||||||
@ -10,6 +10,7 @@ pub struct TestColor {
|
|||||||
pub hsl: Hsla,
|
pub hsl: Hsla,
|
||||||
pub lch: Lcha,
|
pub lch: Lcha,
|
||||||
pub oklab: Oklaba,
|
pub oklab: Oklaba,
|
||||||
|
pub xyz: Xyza,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Table of equivalent colors in various color spaces
|
// Table of equivalent colors in various color spaces
|
||||||
@ -23,6 +24,7 @@ pub const TEST_COLORS: &[TestColor] = &[
|
|||||||
hsl: Hsla::new(0.0, 0.0, 0.0, 1.0),
|
hsl: Hsla::new(0.0, 0.0, 0.0, 1.0),
|
||||||
lch: Lcha::new(0.0, 0.0, 0.0000136603785, 1.0),
|
lch: Lcha::new(0.0, 0.0, 0.0000136603785, 1.0),
|
||||||
oklab: Oklaba::new(0.0, 0.0, 0.0, 1.0),
|
oklab: Oklaba::new(0.0, 0.0, 0.0, 1.0),
|
||||||
|
xyz: Xyza::new(0.0, 0.0, 0.0, 1.0),
|
||||||
},
|
},
|
||||||
// white
|
// white
|
||||||
TestColor {
|
TestColor {
|
||||||
@ -32,6 +34,7 @@ pub const TEST_COLORS: &[TestColor] = &[
|
|||||||
hsl: Hsla::new(0.0, 0.0, 1.0, 1.0),
|
hsl: Hsla::new(0.0, 0.0, 1.0, 1.0),
|
||||||
lch: Lcha::new(1.0, 0.0, 0.0000136603785, 1.0),
|
lch: Lcha::new(1.0, 0.0, 0.0000136603785, 1.0),
|
||||||
oklab: Oklaba::new(1.0, 0.0, 0.000000059604645, 1.0),
|
oklab: Oklaba::new(1.0, 0.0, 0.000000059604645, 1.0),
|
||||||
|
xyz: Xyza::new(0.95047, 1.0, 1.08883, 1.0),
|
||||||
},
|
},
|
||||||
// red
|
// red
|
||||||
TestColor {
|
TestColor {
|
||||||
@ -41,6 +44,7 @@ pub const TEST_COLORS: &[TestColor] = &[
|
|||||||
hsl: Hsla::new(0.0, 1.0, 0.5, 1.0),
|
hsl: Hsla::new(0.0, 1.0, 0.5, 1.0),
|
||||||
lch: Lcha::new(0.53240794, 1.0455177, 39.99901, 1.0),
|
lch: Lcha::new(0.53240794, 1.0455177, 39.99901, 1.0),
|
||||||
oklab: Oklaba::new(0.6279554, 0.22486295, 0.1258463, 1.0),
|
oklab: Oklaba::new(0.6279554, 0.22486295, 0.1258463, 1.0),
|
||||||
|
xyz: Xyza::new(0.4124564, 0.2126729, 0.0193339, 1.0),
|
||||||
},
|
},
|
||||||
// green
|
// green
|
||||||
TestColor {
|
TestColor {
|
||||||
@ -50,6 +54,7 @@ pub const TEST_COLORS: &[TestColor] = &[
|
|||||||
hsl: Hsla::new(120.0, 1.0, 0.5, 1.0),
|
hsl: Hsla::new(120.0, 1.0, 0.5, 1.0),
|
||||||
lch: Lcha::new(0.87734723, 1.1977587, 136.01595, 1.0),
|
lch: Lcha::new(0.87734723, 1.1977587, 136.01595, 1.0),
|
||||||
oklab: Oklaba::new(0.8664396, -0.2338874, 0.1794985, 1.0),
|
oklab: Oklaba::new(0.8664396, -0.2338874, 0.1794985, 1.0),
|
||||||
|
xyz: Xyza::new(0.3575761, 0.7151522, 0.119192, 1.0),
|
||||||
},
|
},
|
||||||
// blue
|
// blue
|
||||||
TestColor {
|
TestColor {
|
||||||
@ -59,6 +64,7 @@ pub const TEST_COLORS: &[TestColor] = &[
|
|||||||
hsl: Hsla::new(240.0, 1.0, 0.5, 1.0),
|
hsl: Hsla::new(240.0, 1.0, 0.5, 1.0),
|
||||||
lch: Lcha::new(0.32297012, 1.3380761, 306.28494, 1.0),
|
lch: Lcha::new(0.32297012, 1.3380761, 306.28494, 1.0),
|
||||||
oklab: Oklaba::new(0.4520137, -0.032456964, -0.31152815, 1.0),
|
oklab: Oklaba::new(0.4520137, -0.032456964, -0.31152815, 1.0),
|
||||||
|
xyz: Xyza::new(0.1804375, 0.072175, 0.9503041, 1.0),
|
||||||
},
|
},
|
||||||
// yellow
|
// yellow
|
||||||
TestColor {
|
TestColor {
|
||||||
@ -68,6 +74,7 @@ pub const TEST_COLORS: &[TestColor] = &[
|
|||||||
hsl: Hsla::new(60.0, 1.0, 0.5, 1.0),
|
hsl: Hsla::new(60.0, 1.0, 0.5, 1.0),
|
||||||
lch: Lcha::new(0.9713927, 0.96905375, 102.85126, 1.0),
|
lch: Lcha::new(0.9713927, 0.96905375, 102.85126, 1.0),
|
||||||
oklab: Oklaba::new(0.9679827, -0.07136908, 0.19856972, 1.0),
|
oklab: Oklaba::new(0.9679827, -0.07136908, 0.19856972, 1.0),
|
||||||
|
xyz: Xyza::new(0.7700325, 0.9278251, 0.1385259, 1.0),
|
||||||
},
|
},
|
||||||
// magenta
|
// magenta
|
||||||
TestColor {
|
TestColor {
|
||||||
@ -77,6 +84,7 @@ pub const TEST_COLORS: &[TestColor] = &[
|
|||||||
hsl: Hsla::new(300.0, 1.0, 0.5, 1.0),
|
hsl: Hsla::new(300.0, 1.0, 0.5, 1.0),
|
||||||
lch: Lcha::new(0.6032421, 1.1554068, 328.23495, 1.0),
|
lch: Lcha::new(0.6032421, 1.1554068, 328.23495, 1.0),
|
||||||
oklab: Oklaba::new(0.7016738, 0.27456632, -0.16915613, 1.0),
|
oklab: Oklaba::new(0.7016738, 0.27456632, -0.16915613, 1.0),
|
||||||
|
xyz: Xyza::new(0.5928939, 0.28484792, 0.969638, 1.0),
|
||||||
},
|
},
|
||||||
// cyan
|
// cyan
|
||||||
TestColor {
|
TestColor {
|
||||||
@ -86,6 +94,7 @@ pub const TEST_COLORS: &[TestColor] = &[
|
|||||||
hsl: Hsla::new(180.0, 1.0, 0.5, 1.0),
|
hsl: Hsla::new(180.0, 1.0, 0.5, 1.0),
|
||||||
lch: Lcha::new(0.9111322, 0.50120866, 196.37614, 1.0),
|
lch: Lcha::new(0.9111322, 0.50120866, 196.37614, 1.0),
|
||||||
oklab: Oklaba::new(0.90539926, -0.1494439, -0.039398134, 1.0),
|
oklab: Oklaba::new(0.90539926, -0.1494439, -0.039398134, 1.0),
|
||||||
|
xyz: Xyza::new(0.5380136, 0.78732723, 1.069496, 1.0),
|
||||||
},
|
},
|
||||||
// gray
|
// gray
|
||||||
TestColor {
|
TestColor {
|
||||||
@ -95,6 +104,7 @@ pub const TEST_COLORS: &[TestColor] = &[
|
|||||||
hsl: Hsla::new(0.0, 0.0, 0.5, 1.0),
|
hsl: Hsla::new(0.0, 0.0, 0.5, 1.0),
|
||||||
lch: Lcha::new(0.5338897, 0.00000011920929, 90.0, 1.0),
|
lch: Lcha::new(0.5338897, 0.00000011920929, 90.0, 1.0),
|
||||||
oklab: Oklaba::new(0.5981807, 0.00000011920929, 0.0, 1.0),
|
oklab: Oklaba::new(0.5981807, 0.00000011920929, 0.0, 1.0),
|
||||||
|
xyz: Xyza::new(0.2034397, 0.21404117, 0.23305441, 1.0),
|
||||||
},
|
},
|
||||||
// olive
|
// olive
|
||||||
TestColor {
|
TestColor {
|
||||||
@ -104,6 +114,7 @@ pub const TEST_COLORS: &[TestColor] = &[
|
|||||||
hsl: Hsla::new(60.0, 1.0, 0.25, 1.0),
|
hsl: Hsla::new(60.0, 1.0, 0.25, 1.0),
|
||||||
lch: Lcha::new(0.51677734, 0.57966936, 102.851265, 1.0),
|
lch: Lcha::new(0.51677734, 0.57966936, 102.851265, 1.0),
|
||||||
oklab: Oklaba::new(0.57902855, -0.042691574, 0.11878061, 1.0),
|
oklab: Oklaba::new(0.57902855, -0.042691574, 0.11878061, 1.0),
|
||||||
|
xyz: Xyza::new(0.16481864, 0.19859275, 0.029650241, 1.0),
|
||||||
},
|
},
|
||||||
// purple
|
// purple
|
||||||
TestColor {
|
TestColor {
|
||||||
@ -113,6 +124,7 @@ pub const TEST_COLORS: &[TestColor] = &[
|
|||||||
hsl: Hsla::new(300.0, 1.0, 0.25, 1.0),
|
hsl: Hsla::new(300.0, 1.0, 0.25, 1.0),
|
||||||
lch: Lcha::new(0.29655674, 0.69114214, 328.23495, 1.0),
|
lch: Lcha::new(0.29655674, 0.69114214, 328.23495, 1.0),
|
||||||
oklab: Oklaba::new(0.41972777, 0.1642403, -0.10118592, 1.0),
|
oklab: Oklaba::new(0.41972777, 0.1642403, -0.10118592, 1.0),
|
||||||
|
xyz: Xyza::new(0.12690368, 0.060969174, 0.20754242, 1.0),
|
||||||
},
|
},
|
||||||
// teal
|
// teal
|
||||||
TestColor {
|
TestColor {
|
||||||
@ -122,6 +134,7 @@ pub const TEST_COLORS: &[TestColor] = &[
|
|||||||
hsl: Hsla::new(180.0, 1.0, 0.25, 1.0),
|
hsl: Hsla::new(180.0, 1.0, 0.25, 1.0),
|
||||||
lch: Lcha::new(0.48073065, 0.29981336, 196.37614, 1.0),
|
lch: Lcha::new(0.48073065, 0.29981336, 196.37614, 1.0),
|
||||||
oklab: Oklaba::new(0.54159236, -0.08939436, -0.02356726, 1.0),
|
oklab: Oklaba::new(0.54159236, -0.08939436, -0.02356726, 1.0),
|
||||||
|
xyz: Xyza::new(0.11515705, 0.16852042, 0.22891617, 1.0),
|
||||||
},
|
},
|
||||||
// maroon
|
// maroon
|
||||||
TestColor {
|
TestColor {
|
||||||
@ -131,6 +144,7 @@ pub const TEST_COLORS: &[TestColor] = &[
|
|||||||
hsl: Hsla::new(0.0, 1.0, 0.25, 1.0),
|
hsl: Hsla::new(0.0, 1.0, 0.25, 1.0),
|
||||||
lch: Lcha::new(0.2541851, 0.61091745, 38.350803, 1.0),
|
lch: Lcha::new(0.2541851, 0.61091745, 38.350803, 1.0),
|
||||||
oklab: Oklaba::new(0.3756308, 0.13450874, 0.07527886, 1.0),
|
oklab: Oklaba::new(0.3756308, 0.13450874, 0.07527886, 1.0),
|
||||||
|
xyz: Xyza::new(0.08828264, 0.045520753, 0.0041382504, 1.0),
|
||||||
},
|
},
|
||||||
// lime
|
// lime
|
||||||
TestColor {
|
TestColor {
|
||||||
@ -140,6 +154,7 @@ pub const TEST_COLORS: &[TestColor] = &[
|
|||||||
hsl: Hsla::new(120.0, 1.0, 0.25, 1.0),
|
hsl: Hsla::new(120.0, 1.0, 0.25, 1.0),
|
||||||
lch: Lcha::new(0.46052113, 0.71647626, 136.01596, 1.0),
|
lch: Lcha::new(0.46052113, 0.71647626, 136.01596, 1.0),
|
||||||
oklab: Oklaba::new(0.5182875, -0.13990697, 0.10737252, 1.0),
|
oklab: Oklaba::new(0.5182875, -0.13990697, 0.10737252, 1.0),
|
||||||
|
xyz: Xyza::new(0.076536, 0.153072, 0.025511991, 1.0),
|
||||||
},
|
},
|
||||||
// navy
|
// navy
|
||||||
TestColor {
|
TestColor {
|
||||||
@ -149,6 +164,7 @@ pub const TEST_COLORS: &[TestColor] = &[
|
|||||||
hsl: Hsla::new(240.0, 1.0, 0.25, 1.0),
|
hsl: Hsla::new(240.0, 1.0, 0.25, 1.0),
|
||||||
lch: Lcha::new(0.12890343, 0.8004114, 306.28494, 1.0),
|
lch: Lcha::new(0.12890343, 0.8004114, 306.28494, 1.0),
|
||||||
oklab: Oklaba::new(0.27038592, -0.01941514, -0.18635012, 1.0),
|
oklab: Oklaba::new(0.27038592, -0.01941514, -0.18635012, 1.0),
|
||||||
|
xyz: Xyza::new(0.03862105, 0.01544842, 0.20340417, 1.0),
|
||||||
},
|
},
|
||||||
// orange
|
// orange
|
||||||
TestColor {
|
TestColor {
|
||||||
@ -158,6 +174,7 @@ pub const TEST_COLORS: &[TestColor] = &[
|
|||||||
hsl: Hsla::new(60.0, 1.0, 0.25, 1.0),
|
hsl: Hsla::new(60.0, 1.0, 0.25, 1.0),
|
||||||
lch: Lcha::new(0.51677734, 0.57966936, 102.851265, 1.0),
|
lch: Lcha::new(0.51677734, 0.57966936, 102.851265, 1.0),
|
||||||
oklab: Oklaba::new(0.57902855, -0.042691574, 0.11878061, 1.0),
|
oklab: Oklaba::new(0.57902855, -0.042691574, 0.11878061, 1.0),
|
||||||
|
xyz: Xyza::new(0.16481864, 0.19859275, 0.029650241, 1.0),
|
||||||
},
|
},
|
||||||
// fuchsia
|
// fuchsia
|
||||||
TestColor {
|
TestColor {
|
||||||
@ -167,6 +184,7 @@ pub const TEST_COLORS: &[TestColor] = &[
|
|||||||
hsl: Hsla::new(300.0, 1.0, 0.25, 1.0),
|
hsl: Hsla::new(300.0, 1.0, 0.25, 1.0),
|
||||||
lch: Lcha::new(0.29655674, 0.69114214, 328.23495, 1.0),
|
lch: Lcha::new(0.29655674, 0.69114214, 328.23495, 1.0),
|
||||||
oklab: Oklaba::new(0.41972777, 0.1642403, -0.10118592, 1.0),
|
oklab: Oklaba::new(0.41972777, 0.1642403, -0.10118592, 1.0),
|
||||||
|
xyz: Xyza::new(0.12690368, 0.060969174, 0.20754242, 1.0),
|
||||||
},
|
},
|
||||||
// aqua
|
// aqua
|
||||||
TestColor {
|
TestColor {
|
||||||
@ -176,5 +194,6 @@ pub const TEST_COLORS: &[TestColor] = &[
|
|||||||
hsl: Hsla::new(180.0, 1.0, 0.25, 1.0),
|
hsl: Hsla::new(180.0, 1.0, 0.25, 1.0),
|
||||||
lch: Lcha::new(0.48073065, 0.29981336, 196.37614, 1.0),
|
lch: Lcha::new(0.48073065, 0.29981336, 196.37614, 1.0),
|
||||||
oklab: Oklaba::new(0.54159236, -0.08939436, -0.02356726, 1.0),
|
oklab: Oklaba::new(0.54159236, -0.08939436, -0.02356726, 1.0),
|
||||||
|
xyz: Xyza::new(0.11515705, 0.16852042, 0.22891617, 1.0),
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|||||||
245
crates/bevy_color/src/xyza.rs
Normal file
245
crates/bevy_color/src/xyza.rs
Normal file
@ -0,0 +1,245 @@
|
|||||||
|
use crate::{Alpha, Hsla, Lcha, LinearRgba, Luminance, Mix, Oklaba, Srgba, StandardColor};
|
||||||
|
use bevy_reflect::{Reflect, ReflectDeserialize, ReflectSerialize};
|
||||||
|
use bevy_render::color::Color;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
/// [CIE 1931](https://en.wikipedia.org/wiki/CIE_1931_color_space) color space, also known as XYZ, with an alpha channel.
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize, Reflect)]
|
||||||
|
#[reflect(PartialEq, Serialize, Deserialize)]
|
||||||
|
pub struct Xyza {
|
||||||
|
/// The x-axis. [0.0, 1.0]
|
||||||
|
pub x: f32,
|
||||||
|
/// The y-axis, intended to represent luminance. [0.0, 1.0]
|
||||||
|
pub y: f32,
|
||||||
|
/// The z-axis. [0.0, 1.0]
|
||||||
|
pub z: f32,
|
||||||
|
/// The alpha channel. [0.0, 1.0]
|
||||||
|
pub alpha: f32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl StandardColor for Xyza {}
|
||||||
|
|
||||||
|
impl Xyza {
|
||||||
|
/// Construct a new [`Xyza`] color from components.
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
///
|
||||||
|
/// * `x` - x-axis. [0.0, 1.0]
|
||||||
|
/// * `y` - y-axis. [0.0, 1.0]
|
||||||
|
/// * `z` - z-axis. [0.0, 1.0]
|
||||||
|
/// * `alpha` - Alpha channel. [0.0, 1.0]
|
||||||
|
pub const fn new(x: f32, y: f32, z: f32, alpha: f32) -> Self {
|
||||||
|
Self { x, y, z, alpha }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Construct a new [`Xyza`] color from (x, y, z) components, with the default alpha (1.0).
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
///
|
||||||
|
/// * `x` - x-axis. [0.0, 1.0]
|
||||||
|
/// * `y` - y-axis. [0.0, 1.0]
|
||||||
|
/// * `z` - z-axis. [0.0, 1.0]
|
||||||
|
pub const fn rgb(x: f32, y: f32, z: f32) -> Self {
|
||||||
|
Self {
|
||||||
|
x,
|
||||||
|
y,
|
||||||
|
z,
|
||||||
|
alpha: 1.0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for Xyza {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::new(0., 0., 0., 1.)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Alpha for Xyza {
|
||||||
|
#[inline]
|
||||||
|
fn with_alpha(&self, alpha: f32) -> Self {
|
||||||
|
Self { alpha, ..*self }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn alpha(&self) -> f32 {
|
||||||
|
self.alpha
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Luminance for Xyza {
|
||||||
|
#[inline]
|
||||||
|
fn with_luminance(&self, lightness: f32) -> Self {
|
||||||
|
Self {
|
||||||
|
y: lightness,
|
||||||
|
..*self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn luminance(&self) -> f32 {
|
||||||
|
self.y
|
||||||
|
}
|
||||||
|
|
||||||
|
fn darker(&self, amount: f32) -> Self {
|
||||||
|
Self {
|
||||||
|
y: (self.y - amount).clamp(0., 1.),
|
||||||
|
..*self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn lighter(&self, amount: f32) -> Self {
|
||||||
|
Self {
|
||||||
|
y: (self.y + amount).min(1.),
|
||||||
|
..*self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Mix for Xyza {
|
||||||
|
#[inline]
|
||||||
|
fn mix(&self, other: &Self, factor: f32) -> Self {
|
||||||
|
let n_factor = 1.0 - factor;
|
||||||
|
Self {
|
||||||
|
x: self.x * n_factor + other.x * factor,
|
||||||
|
y: self.y * n_factor + other.y * factor,
|
||||||
|
z: self.z * n_factor + other.z * factor,
|
||||||
|
alpha: self.alpha * n_factor + other.alpha * factor,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<LinearRgba> for Xyza {
|
||||||
|
fn from(
|
||||||
|
LinearRgba {
|
||||||
|
red,
|
||||||
|
green,
|
||||||
|
blue,
|
||||||
|
alpha,
|
||||||
|
}: LinearRgba,
|
||||||
|
) -> Self {
|
||||||
|
// Linear sRGB to XYZ
|
||||||
|
// http://www.brucelindbloom.com/index.html?Eqn_XYZ_to_RGB.html
|
||||||
|
// http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html (sRGB, RGB to XYZ [M])
|
||||||
|
let r = red;
|
||||||
|
let g = green;
|
||||||
|
let b = blue;
|
||||||
|
|
||||||
|
let x = r * 0.4124564 + g * 0.3575761 + b * 0.1804375;
|
||||||
|
let y = r * 0.2126729 + g * 0.7151522 + b * 0.072175;
|
||||||
|
let z = r * 0.0193339 + g * 0.119192 + b * 0.9503041;
|
||||||
|
|
||||||
|
Xyza::new(x, y, z, alpha)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Xyza> for LinearRgba {
|
||||||
|
fn from(Xyza { x, y, z, alpha }: Xyza) -> Self {
|
||||||
|
// XYZ to Linear 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 r = x * 3.2404542 + y * -1.5371385 + z * -0.4985314;
|
||||||
|
let g = x * -0.969266 + y * 1.8760108 + z * 0.041556;
|
||||||
|
let b = x * 0.0556434 + y * -0.2040259 + z * 1.0572252;
|
||||||
|
|
||||||
|
LinearRgba::new(r, g, b, alpha)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Srgba> for Xyza {
|
||||||
|
fn from(value: Srgba) -> Self {
|
||||||
|
LinearRgba::from(value).into()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Xyza> for Srgba {
|
||||||
|
fn from(value: Xyza) -> Self {
|
||||||
|
LinearRgba::from(value).into()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Hsla> for Xyza {
|
||||||
|
fn from(value: Hsla) -> Self {
|
||||||
|
LinearRgba::from(value).into()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Xyza> for Hsla {
|
||||||
|
fn from(value: Xyza) -> Self {
|
||||||
|
LinearRgba::from(value).into()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Lcha> for Xyza {
|
||||||
|
fn from(value: Lcha) -> Self {
|
||||||
|
LinearRgba::from(value).into()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Xyza> for Lcha {
|
||||||
|
fn from(value: Xyza) -> Self {
|
||||||
|
LinearRgba::from(value).into()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Oklaba> for Xyza {
|
||||||
|
fn from(value: Oklaba) -> Self {
|
||||||
|
LinearRgba::from(value).into()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Xyza> for Oklaba {
|
||||||
|
fn from(value: Xyza) -> Self {
|
||||||
|
LinearRgba::from(value).into()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Color> for Xyza {
|
||||||
|
fn from(value: Color) -> Self {
|
||||||
|
LinearRgba::from(value).into()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Xyza> for Color {
|
||||||
|
fn from(value: Xyza) -> Self {
|
||||||
|
LinearRgba::from(value).into()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
use crate::{
|
||||||
|
color_difference::EuclideanDistance, test_colors::TEST_COLORS, testing::assert_approx_eq,
|
||||||
|
Srgba,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_to_from_srgba() {
|
||||||
|
let xyza = Xyza::new(0.5, 0.5, 0.5, 1.0);
|
||||||
|
let srgba: Srgba = xyza.into();
|
||||||
|
let xyza2: Xyza = srgba.into();
|
||||||
|
assert_approx_eq!(xyza.x, xyza2.x, 0.001);
|
||||||
|
assert_approx_eq!(xyza.y, xyza2.y, 0.001);
|
||||||
|
assert_approx_eq!(xyza.z, xyza2.z, 0.001);
|
||||||
|
assert_approx_eq!(xyza.alpha, xyza2.alpha, 0.001);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_to_from_srgba_2() {
|
||||||
|
for color in TEST_COLORS.iter() {
|
||||||
|
let rgb2: Srgba = (color.xyz).into();
|
||||||
|
let xyz2: Xyza = (color.rgb).into();
|
||||||
|
assert!(
|
||||||
|
color.rgb.distance(&rgb2) < 0.00001,
|
||||||
|
"{}: {:?} != {:?}",
|
||||||
|
color.name,
|
||||||
|
color.rgb,
|
||||||
|
rgb2
|
||||||
|
);
|
||||||
|
assert_approx_eq!(color.xyz.x, xyz2.x, 0.001);
|
||||||
|
assert_approx_eq!(color.xyz.y, xyz2.y, 0.001);
|
||||||
|
assert_approx_eq!(color.xyz.z, xyz2.z, 0.001);
|
||||||
|
assert_approx_eq!(color.xyz.alpha, xyz2.alpha, 0.001);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user