bevy_color/
lib.rs

1#![cfg_attr(docsrs, feature(doc_auto_cfg))]
2#![forbid(unsafe_code)]
3#![doc(
4    html_logo_url = "https://bevyengine.org/assets/icon.png",
5    html_favicon_url = "https://bevyengine.org/assets/icon.png"
6)]
7
8//! Representations of colors in various color spaces.
9//!
10//! This crate provides a number of color representations, including:
11//!
12//! - [`Srgba`] (standard RGBA, with gamma correction)
13//! - [`LinearRgba`] (linear RGBA, without gamma correction)
14//! - [`Hsla`] (hue, saturation, lightness, alpha)
15//! - [`Hsva`] (hue, saturation, value, alpha)
16//! - [`Hwba`] (hue, whiteness, blackness, alpha)
17//! - [`Laba`] (lightness, a-axis, b-axis, alpha)
18//! - [`Lcha`] (lightness, chroma, hue, alpha)
19//! - [`Oklaba`] (lightness, a-axis, b-axis, alpha)
20//! - [`Oklcha`] (lightness, chroma, hue, alpha)
21//! - [`Xyza`] (x-axis, y-axis, z-axis, alpha)
22//!
23//! Each of these color spaces is represented as a distinct Rust type.
24//!
25//! # Color Space Usage
26//!
27//! Rendering engines typically use linear RGBA colors, which allow for physically accurate
28//! lighting calculations. However, linear RGBA colors are not perceptually uniform, because
29//! both human eyes and computer monitors have non-linear responses to light. "Standard" RGBA
30//! represents an industry-wide compromise designed to encode colors in a way that looks good to
31//! humans in as few bits as possible, but it is not suitable for lighting calculations.
32//!
33//! Most image file formats and scene graph formats use standard RGBA, because graphic design
34//! tools are intended to be used by humans. However, 3D lighting calculations operate in linear
35//! RGBA, so it is important to convert standard colors to linear before sending them to the GPU.
36//! Most Bevy APIs will handle this conversion automatically, but if you are writing a custom
37//! shader, you will need to do this conversion yourself.
38//!
39//! HSL and LCH are "cylindrical" color spaces, which means they represent colors as a combination
40//! of hue, saturation, and lightness (or chroma). These color spaces are useful for working
41//! with colors in an artistic way - for example, when creating gradients or color palettes.
42//! A gradient in HSL space from red to violet will produce a rainbow. The LCH color space is
43//! more perceptually accurate than HSL, but is less intuitive to work with.
44//!
45//! HSV and HWB are very closely related to HSL in their derivation, having identical definitions for
46//! hue. Where HSL uses saturation and lightness, HSV uses a slightly modified definition of saturation,
47//! and an analog of lightness in the form of value. In contrast, HWB instead uses whiteness and blackness
48//! parameters, which can be used to lighten and darken a particular hue respectively.
49//!
50//! Oklab and Oklch are perceptually uniform color spaces that are designed to be used for tasks such
51//! as image processing. They are not as widely used as the other color spaces, but are useful
52//! for tasks such as color correction and image analysis, where it is important to be able
53//! to do things like change color saturation without causing hue shifts.
54//!
55//! XYZ is a foundational space commonly used in the definition of other more modern color
56//! spaces. The space is more formally known as CIE 1931, where the `x` and `z` axes represent
57//! a form of chromaticity, while `y` defines an illuminance level.
58//!
59//! See also the [Wikipedia article on color spaces](https://en.wikipedia.org/wiki/Color_space).
60//!
61#![doc = include_str!("../docs/conversion.md")]
62//! <div>
63#![doc = include_str!("../docs/diagrams/model_graph.svg")]
64//! </div>
65//!
66//! # Other Utilities
67//!
68//! The crate also provides a number of color operations, such as blending, color difference,
69//! and color range operations.
70//!
71//! In addition, there is a [`Color`] enum that can represent any of the color
72//! types in this crate. This is useful when you need to store a color in a data structure
73//! that can't be generic over the color type.
74//!
75//! Color types that are either physically or perceptually linear also implement `Add<Self>`, `Sub<Self>`, `Mul<f32>` and `Div<f32>`
76//! allowing you to use them with splines.
77//!
78//! Please note that most often adding or subtracting colors is not what you may want.
79//! Please have a look at other operations like blending, lightening or mixing colors using e.g. [`Mix`] or [`Luminance`] instead.
80//!
81//! # Example
82//!
83//! ```
84//! use bevy_color::{Srgba, Hsla};
85//!
86//! let srgba = Srgba::new(0.5, 0.2, 0.8, 1.0);
87//! let hsla: Hsla = srgba.into();
88//!
89//! println!("Srgba: {:?}", srgba);
90//! println!("Hsla: {:?}", hsla);
91//! ```
92
93mod color;
94pub mod color_difference;
95mod color_ops;
96mod color_range;
97mod hsla;
98mod hsva;
99mod hwba;
100mod laba;
101mod lcha;
102mod linear_rgba;
103mod oklaba;
104mod oklcha;
105pub mod palettes;
106mod srgba;
107#[cfg(test)]
108mod test_colors;
109#[cfg(test)]
110mod testing;
111mod xyza;
112
113/// Commonly used color types and traits.
114pub mod prelude {
115    pub use crate::color::*;
116    pub use crate::color_ops::*;
117    pub use crate::hsla::*;
118    pub use crate::hsva::*;
119    pub use crate::hwba::*;
120    pub use crate::laba::*;
121    pub use crate::lcha::*;
122    pub use crate::linear_rgba::*;
123    pub use crate::oklaba::*;
124    pub use crate::oklcha::*;
125    pub use crate::srgba::*;
126    pub use crate::xyza::*;
127}
128
129pub use color::*;
130pub use color_ops::*;
131pub use color_range::*;
132pub use hsla::*;
133pub use hsva::*;
134pub use hwba::*;
135pub use laba::*;
136pub use lcha::*;
137pub use linear_rgba::*;
138pub use oklaba::*;
139pub use oklcha::*;
140pub use srgba::*;
141pub use xyza::*;
142
143/// Describes the traits that a color should implement for consistency.
144#[allow(dead_code)] // This is an internal marker trait used to ensure that our color types impl the required traits
145pub(crate) trait StandardColor
146where
147    Self: core::fmt::Debug,
148    Self: Clone + Copy,
149    Self: PartialEq,
150    Self: bevy_reflect::Reflect,
151    Self: Default,
152    Self: From<Color> + Into<Color>,
153    Self: From<Srgba> + Into<Srgba>,
154    Self: From<LinearRgba> + Into<LinearRgba>,
155    Self: From<Hsla> + Into<Hsla>,
156    Self: From<Hsva> + Into<Hsva>,
157    Self: From<Hwba> + Into<Hwba>,
158    Self: From<Laba> + Into<Laba>,
159    Self: From<Lcha> + Into<Lcha>,
160    Self: From<Oklaba> + Into<Oklaba>,
161    Self: From<Oklcha> + Into<Oklcha>,
162    Self: From<Xyza> + Into<Xyza>,
163    Self: Alpha,
164{
165}
166
167macro_rules! impl_componentwise_vector_space {
168    ($ty: ident, [$($element: ident),+]) => {
169        impl std::ops::Add<Self> for $ty {
170            type Output = Self;
171
172            fn add(self, rhs: Self) -> Self::Output {
173                Self::Output {
174                    $($element: self.$element + rhs.$element,)+
175                }
176            }
177        }
178
179        impl std::ops::AddAssign<Self> for $ty {
180            fn add_assign(&mut self, rhs: Self) {
181                *self = *self + rhs;
182            }
183        }
184
185        impl std::ops::Neg for $ty {
186            type Output = Self;
187
188            fn neg(self) -> Self::Output {
189                Self::Output {
190                    $($element: -self.$element,)+
191                }
192            }
193        }
194
195        impl std::ops::Sub<Self> for $ty {
196            type Output = Self;
197
198            fn sub(self, rhs: Self) -> Self::Output {
199                Self::Output {
200                    $($element: self.$element - rhs.$element,)+
201                }
202            }
203        }
204
205        impl std::ops::SubAssign<Self> for $ty {
206            fn sub_assign(&mut self, rhs: Self) {
207                *self = *self - rhs;
208            }
209        }
210
211        impl std::ops::Mul<f32> for $ty {
212            type Output = Self;
213
214            fn mul(self, rhs: f32) -> Self::Output {
215                Self::Output {
216                    $($element: self.$element * rhs,)+
217                }
218            }
219        }
220
221        impl std::ops::Mul<$ty> for f32 {
222            type Output = $ty;
223
224            fn mul(self, rhs: $ty) -> Self::Output {
225                Self::Output {
226                    $($element: self * rhs.$element,)+
227                }
228            }
229        }
230
231        impl std::ops::MulAssign<f32> for $ty {
232            fn mul_assign(&mut self, rhs: f32) {
233                *self = *self * rhs;
234            }
235        }
236
237        impl std::ops::Div<f32> for $ty {
238            type Output = Self;
239
240            fn div(self, rhs: f32) -> Self::Output {
241                Self::Output {
242                    $($element: self.$element / rhs,)+
243                }
244            }
245        }
246
247        impl std::ops::DivAssign<f32> for $ty {
248            fn div_assign(&mut self, rhs: f32) {
249                *self = *self / rhs;
250            }
251        }
252
253        impl bevy_math::VectorSpace for $ty {
254            const ZERO: Self = Self {
255                $($element: 0.0,)+
256            };
257        }
258    };
259}
260
261pub(crate) use impl_componentwise_vector_space;