Color maths 4 (#12575)
# Objective - Fixes #12202 ## Solution - This PR implements componentwise (including alpha) addition, subtraction and scalar multiplication/division for some color types. - The mentioned color types are `Laba`, `Oklaba`, `LinearRgba` and `Xyza` as all of them are either physically or perceptually linear as mentioned by @alice-i-cecile in the issue. --- ## Changelog - Scalar mul/div for `LinearRgba` may modify alpha now. ## Migration Guide - Users of scalar mul/div for `LinearRgba` need to be aware of the change and maybe use the `.clamp()` methods or manually set the `alpha` channel.
This commit is contained in:
parent
e7a31d000e
commit
d7372f2c75
@ -1,6 +1,6 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
Alpha, ClampColor, Hsla, Hsva, Hwba, LinearRgba, Luminance, Mix, Oklaba, Srgba, StandardColor,
|
impl_componentwise_point, Alpha, ClampColor, Hsla, Hsva, Hwba, LinearRgba, Luminance, Mix,
|
||||||
Xyza,
|
Oklaba, Srgba, StandardColor, Xyza,
|
||||||
};
|
};
|
||||||
use bevy_reflect::prelude::*;
|
use bevy_reflect::prelude::*;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
@ -25,6 +25,8 @@ pub struct Laba {
|
|||||||
|
|
||||||
impl StandardColor for Laba {}
|
impl StandardColor for Laba {}
|
||||||
|
|
||||||
|
impl_componentwise_point!(Laba, [lightness, a, b, alpha]);
|
||||||
|
|
||||||
impl Laba {
|
impl Laba {
|
||||||
/// Construct a new [`Laba`] color from components.
|
/// Construct a new [`Laba`] color from components.
|
||||||
///
|
///
|
||||||
|
|||||||
@ -65,6 +65,12 @@
|
|||||||
//! types in this crate. This is useful when you need to store a color in a data structure
|
//! 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.
|
//! that can't be generic over the color type.
|
||||||
//!
|
//!
|
||||||
|
//! Color types that are either physically or perceptually linear also implement `Add<Self>`, `Sub<Self>`, `Mul<f32>` and `Div<f32>`
|
||||||
|
//! allowing you to use them with splines.
|
||||||
|
//!
|
||||||
|
//! Please note that most often adding or subtracting colors is not what you may want.
|
||||||
|
//! Please have a look at other operations like blending, lightening or mixing colors using e.g. [`Mix`] or [`Luminance`] instead.
|
||||||
|
//!
|
||||||
//! # Example
|
//! # Example
|
||||||
//!
|
//!
|
||||||
//! ```
|
//! ```
|
||||||
@ -151,3 +157,61 @@ where
|
|||||||
Self: Alpha,
|
Self: Alpha,
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
macro_rules! impl_componentwise_point {
|
||||||
|
($ty: ident, [$($element: ident),+]) => {
|
||||||
|
impl std::ops::Add<Self> for $ty {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
fn add(self, rhs: Self) -> Self::Output {
|
||||||
|
Self::Output {
|
||||||
|
$($element: self.$element + rhs.$element,)+
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::ops::Sub<Self> for $ty {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
fn sub(self, rhs: Self) -> Self::Output {
|
||||||
|
Self::Output {
|
||||||
|
$($element: self.$element - rhs.$element,)+
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::ops::Mul<f32> for $ty {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
fn mul(self, rhs: f32) -> Self::Output {
|
||||||
|
Self::Output {
|
||||||
|
$($element: self.$element * rhs,)+
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::ops::Mul<$ty> for f32 {
|
||||||
|
type Output = $ty;
|
||||||
|
|
||||||
|
fn mul(self, rhs: $ty) -> Self::Output {
|
||||||
|
Self::Output {
|
||||||
|
$($element: self * rhs.$element,)+
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::ops::Div<f32> for $ty {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
fn div(self, rhs: f32) -> Self::Output {
|
||||||
|
Self::Output {
|
||||||
|
$($element: self.$element / rhs,)+
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl bevy_math::cubic_splines::Point for $ty {}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) use impl_componentwise_point;
|
||||||
|
|||||||
@ -1,7 +1,6 @@
|
|||||||
use std::ops::{Div, Mul};
|
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
color_difference::EuclideanDistance, Alpha, ClampColor, Luminance, Mix, StandardColor,
|
color_difference::EuclideanDistance, impl_componentwise_point, Alpha, ClampColor, Luminance,
|
||||||
|
Mix, StandardColor,
|
||||||
};
|
};
|
||||||
use bevy_math::Vec4;
|
use bevy_math::Vec4;
|
||||||
use bevy_reflect::prelude::*;
|
use bevy_reflect::prelude::*;
|
||||||
@ -29,6 +28,8 @@ pub struct LinearRgba {
|
|||||||
|
|
||||||
impl StandardColor for LinearRgba {}
|
impl StandardColor for LinearRgba {}
|
||||||
|
|
||||||
|
impl_componentwise_point!(LinearRgba, [red, green, blue, alpha]);
|
||||||
|
|
||||||
impl LinearRgba {
|
impl LinearRgba {
|
||||||
/// A fully black color with full alpha.
|
/// A fully black color with full alpha.
|
||||||
pub const BLACK: Self = Self {
|
pub const BLACK: Self = Self {
|
||||||
@ -299,48 +300,6 @@ impl From<LinearRgba> for wgpu::Color {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// All color channels are scaled directly,
|
|
||||||
/// but alpha is unchanged.
|
|
||||||
///
|
|
||||||
/// Values are not clamped.
|
|
||||||
impl Mul<f32> for LinearRgba {
|
|
||||||
type Output = Self;
|
|
||||||
|
|
||||||
fn mul(self, rhs: f32) -> Self {
|
|
||||||
Self {
|
|
||||||
red: self.red * rhs,
|
|
||||||
green: self.green * rhs,
|
|
||||||
blue: self.blue * rhs,
|
|
||||||
alpha: self.alpha,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Mul<LinearRgba> for f32 {
|
|
||||||
type Output = LinearRgba;
|
|
||||||
|
|
||||||
fn mul(self, rhs: LinearRgba) -> LinearRgba {
|
|
||||||
rhs * self
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// All color channels are scaled directly,
|
|
||||||
/// but alpha is unchanged.
|
|
||||||
///
|
|
||||||
/// Values are not clamped.
|
|
||||||
impl Div<f32> for LinearRgba {
|
|
||||||
type Output = Self;
|
|
||||||
|
|
||||||
fn div(self, rhs: f32) -> Self {
|
|
||||||
Self {
|
|
||||||
red: self.red / rhs,
|
|
||||||
green: self.green / rhs,
|
|
||||||
blue: self.blue / rhs,
|
|
||||||
alpha: self.alpha,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// [`LinearRgba`] is intended to be used with shaders
|
// [`LinearRgba`] is intended to be used with shaders
|
||||||
// So it's the only color type that implements [`ShaderType`] to make it easier to use inside shaders
|
// So it's the only color type that implements [`ShaderType`] to make it easier to use inside shaders
|
||||||
impl encase::ShaderType for LinearRgba {
|
impl encase::ShaderType for LinearRgba {
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
color_difference::EuclideanDistance, Alpha, ClampColor, Hsla, Hsva, Hwba, Lcha, LinearRgba,
|
color_difference::EuclideanDistance, impl_componentwise_point, Alpha, ClampColor, Hsla, Hsva,
|
||||||
Luminance, Mix, Srgba, StandardColor, Xyza,
|
Hwba, Lcha, LinearRgba, Luminance, Mix, Srgba, StandardColor, Xyza,
|
||||||
};
|
};
|
||||||
use bevy_reflect::prelude::*;
|
use bevy_reflect::prelude::*;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
@ -25,6 +25,8 @@ pub struct Oklaba {
|
|||||||
|
|
||||||
impl StandardColor for Oklaba {}
|
impl StandardColor for Oklaba {}
|
||||||
|
|
||||||
|
impl_componentwise_point!(Oklaba, [lightness, a, b, alpha]);
|
||||||
|
|
||||||
impl Oklaba {
|
impl Oklaba {
|
||||||
/// Construct a new [`Oklaba`] color from components.
|
/// Construct a new [`Oklaba`] color from components.
|
||||||
///
|
///
|
||||||
|
|||||||
@ -1,4 +1,6 @@
|
|||||||
use crate::{Alpha, ClampColor, LinearRgba, Luminance, Mix, StandardColor};
|
use crate::{
|
||||||
|
impl_componentwise_point, Alpha, ClampColor, LinearRgba, Luminance, Mix, StandardColor,
|
||||||
|
};
|
||||||
use bevy_reflect::prelude::*;
|
use bevy_reflect::prelude::*;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
@ -22,6 +24,8 @@ pub struct Xyza {
|
|||||||
|
|
||||||
impl StandardColor for Xyza {}
|
impl StandardColor for Xyza {}
|
||||||
|
|
||||||
|
impl_componentwise_point!(Xyza, [x, y, z, alpha]);
|
||||||
|
|
||||||
impl Xyza {
|
impl Xyza {
|
||||||
/// Construct a new [`Xyza`] color from components.
|
/// Construct a new [`Xyza`] color from components.
|
||||||
///
|
///
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user