Added a Grey trait, and implementations on baked-in colors. Fixes #13206 (#13237)

Added a Grey trait to allow colors to create a generic "grey" color.

This currently assumes the color spaces follow the same gradient, which
I'm pretty sure isn't true, but it should make a "grey-ish" color
relative to the provided intensity.

# Objective

- Implements #13206 

## Solution

- A small `Grey` trait was added and implemented for the common color
kinds.

## Testing

- Currently untested, unit tests exposed the non-linear relation between
colors. I am debating adding an example to show this, as I have no idea
what color space represents what relation of grey, and I figure others
may be similarly confused.

## Changelog

- The `Grey` trait was added, and the corresponding `grey` 

## BREAKING CHANGES

The const qualifier for LinearRGBA::gray was removed (the symbol still
exists via a trait, it's just not const anymore)
This commit is contained in:
Daniel Miller 2024-05-26 05:53:50 -07:00 committed by GitHub
parent 383314ef62
commit 1d29f8e6f6
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
12 changed files with 101 additions and 24 deletions

View file

@ -42,6 +42,19 @@ pub trait Mix: Sized {
}
}
/// Trait for returning a grayscale color of a provided lightness.
pub trait Gray: Mix + Sized {
/// A pure black color.
const BLACK: Self;
/// A pure white color.
const WHITE: Self;
/// Returns a grey color with the provided lightness from (0.0 - 1.0). 0 is black, 1 is white.
fn gray(lightness: f32) -> Self {
Self::BLACK.mix(&Self::WHITE, lightness)
}
}
/// Methods for manipulating alpha values.
pub trait Alpha: Sized {
/// Return a new version of this color with the given alpha value.
@ -112,6 +125,8 @@ pub(crate) fn lerp_hue(a: f32, b: f32, t: f32) -> f32 {
#[cfg(test)]
mod tests {
use std::fmt::Debug;
use super::*;
use crate::{testing::assert_approx_eq, Hsla};
@ -145,4 +160,25 @@ mod tests {
assert_approx_eq!(lerp_hue(350., 10., 0.5), 0., 0.001);
assert_approx_eq!(lerp_hue(350., 10., 0.75), 5., 0.001);
}
fn verify_gray<Col>()
where
Col: Gray + Debug + PartialEq,
{
assert_eq!(Col::gray(0.), Col::BLACK);
assert_eq!(Col::gray(1.), Col::WHITE);
}
#[test]
fn test_gray() {
verify_gray::<crate::Hsla>();
verify_gray::<crate::Hsva>();
verify_gray::<crate::Hwba>();
verify_gray::<crate::Laba>();
verify_gray::<crate::Lcha>();
verify_gray::<crate::LinearRgba>();
verify_gray::<crate::Oklaba>();
verify_gray::<crate::Oklcha>();
verify_gray::<crate::Xyza>();
}
}

View file

@ -1,5 +1,5 @@
use crate::{
Alpha, ColorToComponents, Hsva, Hue, Hwba, Lcha, LinearRgba, Luminance, Mix, Srgba,
Alpha, ColorToComponents, Gray, Hsva, Hue, Hwba, Lcha, LinearRgba, Luminance, Mix, Srgba,
StandardColor, Xyza,
};
use bevy_math::{Vec3, Vec4};
@ -119,6 +119,11 @@ impl Mix for Hsla {
}
}
impl Gray for Hsla {
const BLACK: Self = Self::new(0., 0., 0., 1.);
const WHITE: Self = Self::new(0., 0., 1., 1.);
}
impl Alpha for Hsla {
#[inline]
fn with_alpha(&self, alpha: f32) -> Self {

View file

@ -1,5 +1,5 @@
use crate::{
Alpha, ColorToComponents, Hue, Hwba, Lcha, LinearRgba, Mix, Srgba, StandardColor, Xyza,
Alpha, ColorToComponents, Gray, Hue, Hwba, Lcha, LinearRgba, Mix, Srgba, StandardColor, Xyza,
};
use bevy_math::{Vec3, Vec4};
use bevy_reflect::prelude::*;
@ -89,6 +89,11 @@ impl Mix for Hsva {
}
}
impl Gray for Hsva {
const BLACK: Self = Self::new(0., 0., 0., 1.);
const WHITE: Self = Self::new(0., 0., 1., 1.);
}
impl Alpha for Hsva {
#[inline]
fn with_alpha(&self, alpha: f32) -> Self {

View file

@ -2,7 +2,9 @@
//! in [_HWB - A More Intuitive Hue-Based Color Model_] by _Smith et al_.
//!
//! [_HWB - A More Intuitive Hue-Based Color Model_]: https://web.archive.org/web/20240226005220/http://alvyray.com/Papers/CG/HWB_JGTv208.pdf
use crate::{Alpha, ColorToComponents, Hue, Lcha, LinearRgba, Mix, Srgba, StandardColor, Xyza};
use crate::{
Alpha, ColorToComponents, Gray, Hue, Lcha, LinearRgba, Mix, Srgba, StandardColor, Xyza,
};
use bevy_math::{Vec3, Vec4};
use bevy_reflect::prelude::*;
@ -91,6 +93,11 @@ impl Mix for Hwba {
}
}
impl Gray for Hwba {
const BLACK: Self = Self::new(0., 0., 1., 1.);
const WHITE: Self = Self::new(0., 1., 0., 1.);
}
impl Alpha for Hwba {
#[inline]
fn with_alpha(&self, alpha: f32) -> Self {

View file

@ -1,5 +1,5 @@
use crate::{
impl_componentwise_vector_space, Alpha, ColorToComponents, Hsla, Hsva, Hwba, LinearRgba,
impl_componentwise_vector_space, Alpha, ColorToComponents, Gray, Hsla, Hsva, Hwba, LinearRgba,
Luminance, Mix, Oklaba, Srgba, StandardColor, Xyza,
};
use bevy_math::{Vec3, Vec4};
@ -101,6 +101,11 @@ impl Mix for Laba {
}
}
impl Gray for Laba {
const BLACK: Self = Self::new(0., 0., 0., 1.);
const WHITE: Self = Self::new(1., 0., 0., 1.);
}
impl Alpha for Laba {
#[inline]
fn with_alpha(&self, alpha: f32) -> Self {

View file

@ -1,5 +1,6 @@
use crate::{
Alpha, ColorToComponents, Hue, Laba, LinearRgba, Luminance, Mix, Srgba, StandardColor, Xyza,
Alpha, ColorToComponents, Gray, Hue, Laba, LinearRgba, Luminance, Mix, Srgba, StandardColor,
Xyza,
};
use bevy_math::{Vec3, Vec4};
use bevy_reflect::prelude::*;
@ -122,6 +123,11 @@ impl Mix for Lcha {
}
}
impl Gray for Lcha {
const BLACK: Self = Self::new(0.0, 0.0, 0.0000136603785, 1.0);
const WHITE: Self = Self::new(1.0, 0.0, 0.0000136603785, 1.0);
}
impl Alpha for Lcha {
#[inline]
fn with_alpha(&self, alpha: f32) -> Self {

View file

@ -1,6 +1,6 @@
use crate::{
color_difference::EuclideanDistance, impl_componentwise_vector_space, Alpha, ColorToComponents,
Luminance, Mix, StandardColor,
Gray, Luminance, Mix, StandardColor,
};
use bevy_math::{Vec3, Vec4};
use bevy_reflect::prelude::*;
@ -121,18 +121,6 @@ impl LinearRgba {
}
}
/// Construct a new [`LinearRgba`] color with the same value for all channels and an alpha of 1.0.
///
/// A value of 0.0 is black, and a value of 1.0 is white.
pub const fn gray(value: f32) -> Self {
Self {
red: value,
green: value,
blue: value,
alpha: 1.0,
}
}
/// Return a copy of this color with the red channel set to the given value.
pub const fn with_red(self, red: f32) -> Self {
Self { red, ..self }
@ -236,6 +224,11 @@ impl Mix for LinearRgba {
}
}
impl Gray for LinearRgba {
const BLACK: Self = Self::BLACK;
const WHITE: Self = Self::WHITE;
}
impl Alpha for LinearRgba {
#[inline]
fn with_alpha(&self, alpha: f32) -> Self {

View file

@ -1,6 +1,6 @@
use crate::{
color_difference::EuclideanDistance, impl_componentwise_vector_space, Alpha, ColorToComponents,
Hsla, Hsva, Hwba, Lcha, LinearRgba, Luminance, Mix, Srgba, StandardColor, Xyza,
Gray, Hsla, Hsva, Hwba, Lcha, LinearRgba, Luminance, Mix, Srgba, StandardColor, Xyza,
};
use bevy_math::{Vec3, Vec4};
use bevy_reflect::prelude::*;
@ -101,6 +101,11 @@ impl Mix for Oklaba {
}
}
impl Gray for Oklaba {
const BLACK: Self = Self::new(0., 0., 0., 1.);
const WHITE: Self = Self::new(1.0, 0.0, 0.000000059604645, 1.0);
}
impl Alpha for Oklaba {
#[inline]
fn with_alpha(&self, alpha: f32) -> Self {

View file

@ -1,6 +1,6 @@
use crate::{
color_difference::EuclideanDistance, Alpha, ColorToComponents, Hsla, Hsva, Hue, Hwba, Laba,
Lcha, LinearRgba, Luminance, Mix, Oklaba, Srgba, StandardColor, Xyza,
color_difference::EuclideanDistance, Alpha, ColorToComponents, Gray, Hsla, Hsva, Hue, Hwba,
Laba, Lcha, LinearRgba, Luminance, Mix, Oklaba, Srgba, StandardColor, Xyza,
};
use bevy_math::{Vec3, Vec4};
use bevy_reflect::prelude::*;
@ -119,6 +119,11 @@ impl Mix for Oklcha {
}
}
impl Gray for Oklcha {
const BLACK: Self = Self::new(0., 0., 0., 1.);
const WHITE: Self = Self::new(1.0, 0.000000059604645, 90.0, 1.0);
}
impl Alpha for Oklcha {
#[inline]
fn with_alpha(&self, alpha: f32) -> Self {

View file

@ -1,6 +1,6 @@
use crate::color_difference::EuclideanDistance;
use crate::{
impl_componentwise_vector_space, Alpha, ColorToComponents, LinearRgba, Luminance, Mix,
impl_componentwise_vector_space, Alpha, ColorToComponents, Gray, LinearRgba, Luminance, Mix,
StandardColor, Xyza,
};
use bevy_math::{Vec3, Vec4};
@ -314,6 +314,11 @@ impl EuclideanDistance for Srgba {
}
}
impl Gray for Srgba {
const BLACK: Self = Self::BLACK;
const WHITE: Self = Self::WHITE;
}
impl ColorToComponents for Srgba {
fn to_f32_array(self) -> [f32; 4] {
[self.red, self.green, self.blue, self.alpha]

View file

@ -1,5 +1,5 @@
use crate::{
impl_componentwise_vector_space, Alpha, ColorToComponents, LinearRgba, Luminance, Mix,
impl_componentwise_vector_space, Alpha, ColorToComponents, Gray, LinearRgba, Luminance, Mix,
StandardColor,
};
use bevy_math::{Vec3, Vec4};
@ -144,6 +144,11 @@ impl Mix for Xyza {
}
}
impl Gray for Xyza {
const BLACK: Self = Self::new(0., 0., 0., 1.);
const WHITE: Self = Self::new(0.95047, 1.0, 1.08883, 1.0);
}
impl ColorToComponents for Xyza {
fn to_f32_array(self) -> [f32; 4] {
[self.x, self.y, self.z, self.alpha]

View file

@ -2,7 +2,7 @@ mod downsampling_pipeline;
mod settings;
mod upsampling_pipeline;
use bevy_color::LinearRgba;
use bevy_color::{Gray, LinearRgba};
pub use settings::{BloomCompositeMode, BloomPrefilterSettings, BloomSettings};
use crate::{