diff --git a/crates/bevy_color/src/color.rs b/crates/bevy_color/src/color.rs index 1cc7ccf8e4..3186c0b5d1 100644 --- a/crates/bevy_color/src/color.rs +++ b/crates/bevy_color/src/color.rs @@ -1,10 +1,14 @@ -use crate::{Hsla, Lcha, LinearRgba, Oklaba, Srgba}; +use crate::{Alpha, Hsla, Lcha, LinearRgba, Oklaba, Srgba, StandardColor}; +use bevy_reflect::{Reflect, ReflectDeserialize, ReflectSerialize}; +use bevy_render::color::Color as LegacyColor; +use serde::{Deserialize, Serialize}; /// An enumerated type that can represent any of the color types in this crate. /// /// This is useful when you need to store a color in a data structure that can't be generic over /// the color type. -#[derive(Debug, Clone, Copy, PartialEq)] +#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize, Reflect)] +#[reflect(PartialEq, Serialize, Deserialize)] pub enum Color { /// A color in the sRGB color space with alpha. Srgba(Srgba), @@ -18,6 +22,8 @@ pub enum Color { Oklaba(Oklaba), } +impl StandardColor for Color {} + impl Color { /// Return the color as a linear RGBA color. pub fn linear(&self) -> LinearRgba { @@ -37,6 +43,32 @@ impl Default for Color { } } +impl Alpha for Color { + fn with_alpha(&self, alpha: f32) -> Self { + let mut new = *self; + + match &mut new { + Color::Srgba(x) => *x = x.with_alpha(alpha), + Color::LinearRgba(x) => *x = x.with_alpha(alpha), + Color::Hsla(x) => *x = x.with_alpha(alpha), + Color::Lcha(x) => *x = x.with_alpha(alpha), + Color::Oklaba(x) => *x = x.with_alpha(alpha), + } + + new + } + + fn alpha(&self) -> f32 { + match self { + Color::Srgba(x) => x.alpha(), + Color::LinearRgba(x) => x.alpha(), + Color::Hsla(x) => x.alpha(), + Color::Lcha(x) => x.alpha(), + Color::Oklaba(x) => x.alpha(), + } + } +} + impl From for Color { fn from(value: Srgba) -> Self { Self::Srgba(value) @@ -126,3 +158,26 @@ impl From for Oklaba { } } } + +impl From for Color { + fn from(value: LegacyColor) -> Self { + match value { + LegacyColor::Rgba { .. } => Srgba::from(value).into(), + LegacyColor::RgbaLinear { .. } => LinearRgba::from(value).into(), + LegacyColor::Hsla { .. } => Hsla::from(value).into(), + LegacyColor::Lcha { .. } => Lcha::from(value).into(), + } + } +} + +impl From for LegacyColor { + 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(), + } + } +} diff --git a/crates/bevy_color/src/hsla.rs b/crates/bevy_color/src/hsla.rs index 2f2267d534..c6bd8a2a64 100644 --- a/crates/bevy_color/src/hsla.rs +++ b/crates/bevy_color/src/hsla.rs @@ -1,4 +1,4 @@ -use crate::{Alpha, LinearRgba, Luminance, Mix, Srgba}; +use crate::{Alpha, Lcha, LinearRgba, Luminance, Mix, Oklaba, Srgba, StandardColor}; use bevy_reflect::{Reflect, ReflectDeserialize, ReflectSerialize}; use bevy_render::color::HslRepresentation; use serde::{Deserialize, Serialize}; @@ -17,6 +17,8 @@ pub struct Hsla { pub alpha: f32, } +impl StandardColor for Hsla {} + impl Hsla { /// Construct a new [`Hsla`] color from components. /// @@ -119,12 +121,6 @@ impl From for Hsla { } } -impl From for Hsla { - fn from(value: LinearRgba) -> Self { - Hsla::from(Srgba::from(value)) - } -} - impl From for bevy_render::color::Color { fn from(value: Hsla) -> Self { bevy_render::color::Color::Hsla { @@ -150,6 +146,24 @@ impl From for Hsla { } } +impl From for Hsla { + fn from(value: LinearRgba) -> Self { + Srgba::from(value).into() + } +} + +impl From for Hsla { + fn from(value: Oklaba) -> Self { + Srgba::from(value).into() + } +} + +impl From for Hsla { + fn from(value: Lcha) -> Self { + Srgba::from(value).into() + } +} + #[cfg(test)] mod tests { use super::*; diff --git a/crates/bevy_color/src/lcha.rs b/crates/bevy_color/src/lcha.rs index f1712f92b6..7cc6cdb180 100644 --- a/crates/bevy_color/src/lcha.rs +++ b/crates/bevy_color/src/lcha.rs @@ -1,4 +1,4 @@ -use crate::{Alpha, LinearRgba, Luminance, Mix, Srgba}; +use crate::{Alpha, Hsla, LinearRgba, Luminance, Mix, Oklaba, Srgba, StandardColor}; use bevy_reflect::{Reflect, ReflectDeserialize, ReflectSerialize}; use bevy_render::color::LchRepresentation; use serde::{Deserialize, Serialize}; @@ -17,6 +17,8 @@ pub struct Lcha { pub alpha: f32, } +impl StandardColor for Lcha {} + impl Lcha { /// Construct a new [`Lcha`] color from components. /// @@ -165,6 +167,18 @@ impl From for Lcha { } } +impl From for Lcha { + fn from(value: Oklaba) -> Self { + Srgba::from(value).into() + } +} + +impl From for Lcha { + fn from(value: Hsla) -> Self { + Srgba::from(value).into() + } +} + #[cfg(test)] mod tests { use super::*; diff --git a/crates/bevy_color/src/lib.rs b/crates/bevy_color/src/lib.rs index f731c0b8d7..1864743bc6 100644 --- a/crates/bevy_color/src/lib.rs +++ b/crates/bevy_color/src/lib.rs @@ -87,3 +87,25 @@ pub use lcha::*; pub use linear_rgba::*; pub use oklaba::*; pub use srgba::*; + +use bevy_render::color::Color as LegacyColor; + +/// Describes the traits that a color should implement for consistency. +pub(crate) trait StandardColor +where + Self: core::fmt::Debug, + Self: Clone + Copy, + Self: PartialEq, + Self: serde::Serialize + for<'a> serde::Deserialize<'a>, + Self: bevy_reflect::Reflect, + Self: Default, + Self: From + Into, + Self: From + Into, + Self: From + Into, + Self: From + Into, + Self: From + Into, + Self: From + Into, + Self: From + Into, + Self: Alpha, +{ +} diff --git a/crates/bevy_color/src/linear_rgba.rs b/crates/bevy_color/src/linear_rgba.rs index 9d4c8a1cc0..942d7951fb 100644 --- a/crates/bevy_color/src/linear_rgba.rs +++ b/crates/bevy_color/src/linear_rgba.rs @@ -1,5 +1,6 @@ use crate::{ color_difference::EuclideanDistance, oklaba::Oklaba, Alpha, Hsla, Luminance, Mix, Srgba, + StandardColor, }; use bevy_math::Vec4; use bevy_reflect::{Reflect, ReflectDeserialize, ReflectSerialize}; @@ -20,6 +21,8 @@ pub struct LinearRgba { pub alpha: f32, } +impl StandardColor for LinearRgba {} + impl LinearRgba { /// Construct a new [`LinearRgba`] color from components. pub const fn new(red: f32, green: f32, blue: f32, alpha: f32) -> Self { diff --git a/crates/bevy_color/src/oklaba.rs b/crates/bevy_color/src/oklaba.rs index d77237ae80..062a502291 100644 --- a/crates/bevy_color/src/oklaba.rs +++ b/crates/bevy_color/src/oklaba.rs @@ -1,5 +1,9 @@ -use crate::{color_difference::EuclideanDistance, Alpha, LinearRgba, Luminance, Mix, Srgba}; +use crate::{ + color_difference::EuclideanDistance, Alpha, Hsla, Lcha, LinearRgba, Luminance, Mix, Srgba, + StandardColor, +}; use bevy_reflect::{Reflect, ReflectDeserialize, ReflectSerialize}; +use bevy_render::color::Color as LegacyColor; use serde::{Deserialize, Serialize}; /// Color in Oklaba color space, with alpha @@ -16,6 +20,8 @@ pub struct Oklaba { pub alpha: f32, } +impl StandardColor for Oklaba {} + impl Oklaba { /// Construct a new [`Oklaba`] color from components. /// @@ -132,6 +138,30 @@ impl From for Oklaba { } } +impl From for Oklaba { + fn from(value: Lcha) -> Self { + LinearRgba::from(value).into() + } +} + +impl From for Oklaba { + fn from(value: Hsla) -> Self { + LinearRgba::from(value).into() + } +} + +impl From for Oklaba { + fn from(value: LegacyColor) -> Self { + LinearRgba::from(value).into() + } +} + +impl From for LegacyColor { + fn from(value: Oklaba) -> Self { + LinearRgba::from(value).into() + } +} + #[cfg(test)] mod tests { use super::*; diff --git a/crates/bevy_color/src/srgba.rs b/crates/bevy_color/src/srgba.rs index 3795399f4e..31f64bde6f 100644 --- a/crates/bevy_color/src/srgba.rs +++ b/crates/bevy_color/src/srgba.rs @@ -1,6 +1,6 @@ use crate::color_difference::EuclideanDistance; use crate::oklaba::Oklaba; -use crate::{Alpha, Hsla, LinearRgba, Luminance, Mix}; +use crate::{Alpha, Hsla, LinearRgba, Luminance, Mix, StandardColor}; use bevy_math::Vec4; use bevy_reflect::{Reflect, ReflectDeserialize, ReflectSerialize}; use bevy_render::color::{HexColorError, HslRepresentation, SrgbColorSpace}; @@ -20,6 +20,8 @@ pub struct Srgba { pub alpha: f32, } +impl StandardColor for Srgba {} + impl Srgba { // The standard VGA colors, with alpha set to 1.0. // https://en.wikipedia.org/wiki/Web_colors#Basic_colors