Add Saturation trait to bevy_color (#18202)
# Objective - Allow for convenient access and mutation of color saturation providing following the `Hue`, `Luminance` traits. - `with_saturation()` builder method - `saturation()` to get the saturation of a `Color` - `set_saturation()` to set the saturation of a mutable `Color` ## Solution - Defined `Saturation` trait in `color_ops.rs` - Implemented `Saturation` on `Hsla` and `Hsva` - Implemented `Saturation` on `Color` which proxies to other color space impls. - In the case of colorspaces which don't have native saturation components the color is converted to 'Hsla` internally ## Testing - Empirically tested --- ## Showcase ```rust fn next_golden(&mut self) -> Color { self.current .rotate_hue((1.0 / GOLDEN_RATIO) * 360.0) .with_saturation(self.rand_saturation()) .with_luminance(self.rand_luminance()) .into() } ``` --------- Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
This commit is contained in:
parent
65a9e6fd9f
commit
4e2dc4b15f
@ -1,6 +1,6 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
color_difference::EuclideanDistance, Alpha, Hsla, Hsva, Hue, Hwba, Laba, Lcha, LinearRgba,
|
color_difference::EuclideanDistance, Alpha, Hsla, Hsva, Hue, Hwba, Laba, Lcha, LinearRgba,
|
||||||
Luminance, Mix, Oklaba, Oklcha, Srgba, StandardColor, Xyza,
|
Luminance, Mix, Oklaba, Oklcha, Saturation, Srgba, StandardColor, Xyza,
|
||||||
};
|
};
|
||||||
#[cfg(feature = "bevy_reflect")]
|
#[cfg(feature = "bevy_reflect")]
|
||||||
use bevy_reflect::prelude::*;
|
use bevy_reflect::prelude::*;
|
||||||
@ -810,6 +810,44 @@ impl Hue for Color {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Saturation for Color {
|
||||||
|
fn with_saturation(&self, saturation: f32) -> Self {
|
||||||
|
let mut new = *self;
|
||||||
|
|
||||||
|
match &mut new {
|
||||||
|
Color::Srgba(x) => Hsla::from(*x).with_saturation(saturation).into(),
|
||||||
|
Color::LinearRgba(x) => Hsla::from(*x).with_saturation(saturation).into(),
|
||||||
|
Color::Hsla(x) => x.with_saturation(saturation).into(),
|
||||||
|
Color::Hsva(x) => x.with_saturation(saturation).into(),
|
||||||
|
Color::Hwba(x) => Hsla::from(*x).with_saturation(saturation).into(),
|
||||||
|
Color::Laba(x) => Hsla::from(*x).with_saturation(saturation).into(),
|
||||||
|
Color::Lcha(x) => Hsla::from(*x).with_saturation(saturation).into(),
|
||||||
|
Color::Oklaba(x) => Hsla::from(*x).with_saturation(saturation).into(),
|
||||||
|
Color::Oklcha(x) => Hsla::from(*x).with_saturation(saturation).into(),
|
||||||
|
Color::Xyza(x) => Hsla::from(*x).with_saturation(saturation).into(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn saturation(&self) -> f32 {
|
||||||
|
match self {
|
||||||
|
Color::Srgba(x) => Hsla::from(*x).saturation(),
|
||||||
|
Color::LinearRgba(x) => Hsla::from(*x).saturation(),
|
||||||
|
Color::Hsla(x) => x.saturation(),
|
||||||
|
Color::Hsva(x) => x.saturation(),
|
||||||
|
Color::Hwba(x) => Hsla::from(*x).saturation(),
|
||||||
|
Color::Laba(x) => Hsla::from(*x).saturation(),
|
||||||
|
Color::Lcha(x) => Hsla::from(*x).saturation(),
|
||||||
|
Color::Oklaba(x) => Hsla::from(*x).saturation(),
|
||||||
|
Color::Oklcha(x) => Hsla::from(*x).saturation(),
|
||||||
|
Color::Xyza(x) => Hsla::from(*x).saturation(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_saturation(&mut self, saturation: f32) {
|
||||||
|
*self = self.with_saturation(saturation);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Mix for Color {
|
impl Mix for Color {
|
||||||
fn mix(&self, other: &Self, factor: f32) -> Self {
|
fn mix(&self, other: &Self, factor: f32) -> Self {
|
||||||
let mut new = *self;
|
let mut new = *self;
|
||||||
|
@ -95,6 +95,21 @@ pub trait Hue: Sized {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Trait for manipulating the saturation of a color.
|
||||||
|
///
|
||||||
|
/// When working with color spaces that do not have native saturation components
|
||||||
|
/// the operations are performed in [`crate::Hsla`].
|
||||||
|
pub trait Saturation: Sized {
|
||||||
|
/// Return a new version of this color with the saturation channel set to the given value.
|
||||||
|
fn with_saturation(&self, saturation: f32) -> Self;
|
||||||
|
|
||||||
|
/// Return the saturation of this color [0.0, 1.0].
|
||||||
|
fn saturation(&self) -> f32;
|
||||||
|
|
||||||
|
/// Sets the saturation of this color.
|
||||||
|
fn set_saturation(&mut self, saturation: f32);
|
||||||
|
}
|
||||||
|
|
||||||
/// Trait with methods for converting colors to non-color types
|
/// Trait with methods for converting colors to non-color types
|
||||||
pub trait ColorToComponents {
|
pub trait ColorToComponents {
|
||||||
/// Convert to an f32 array
|
/// Convert to an f32 array
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
Alpha, ColorToComponents, Gray, Hsva, Hue, Hwba, Lcha, LinearRgba, Luminance, Mix, Srgba,
|
Alpha, ColorToComponents, Gray, Hsva, Hue, Hwba, Lcha, LinearRgba, Luminance, Mix, Saturation,
|
||||||
StandardColor, Xyza,
|
Srgba, StandardColor, Xyza,
|
||||||
};
|
};
|
||||||
use bevy_math::{Vec3, Vec4};
|
use bevy_math::{Vec3, Vec4};
|
||||||
#[cfg(feature = "bevy_reflect")]
|
#[cfg(feature = "bevy_reflect")]
|
||||||
@ -159,6 +159,26 @@ impl Hue for Hsla {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Saturation for Hsla {
|
||||||
|
#[inline]
|
||||||
|
fn with_saturation(&self, saturation: f32) -> Self {
|
||||||
|
Self {
|
||||||
|
saturation,
|
||||||
|
..*self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn saturation(&self) -> f32 {
|
||||||
|
self.saturation
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn set_saturation(&mut self, saturation: f32) {
|
||||||
|
self.saturation = saturation;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Luminance for Hsla {
|
impl Luminance for Hsla {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn with_luminance(&self, lightness: f32) -> Self {
|
fn with_luminance(&self, lightness: f32) -> Self {
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
Alpha, ColorToComponents, Gray, Hue, Hwba, Lcha, LinearRgba, Mix, Srgba, StandardColor, Xyza,
|
Alpha, ColorToComponents, Gray, Hue, Hwba, Lcha, LinearRgba, Mix, Saturation, Srgba,
|
||||||
|
StandardColor, Xyza,
|
||||||
};
|
};
|
||||||
use bevy_math::{Vec3, Vec4};
|
use bevy_math::{Vec3, Vec4};
|
||||||
#[cfg(feature = "bevy_reflect")]
|
#[cfg(feature = "bevy_reflect")]
|
||||||
@ -129,6 +130,26 @@ impl Hue for Hsva {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Saturation for Hsva {
|
||||||
|
#[inline]
|
||||||
|
fn with_saturation(&self, saturation: f32) -> Self {
|
||||||
|
Self {
|
||||||
|
saturation,
|
||||||
|
..*self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn saturation(&self) -> f32 {
|
||||||
|
self.saturation
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn set_saturation(&mut self, saturation: f32) {
|
||||||
|
self.saturation = saturation;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl From<Hsva> for Hwba {
|
impl From<Hsva> for Hwba {
|
||||||
fn from(
|
fn from(
|
||||||
Hsva {
|
Hsva {
|
||||||
|
Loading…
Reference in New Issue
Block a user