Explicit color conversion methods (#10321)
# Objective Closes #10319 ## Changelog * Added a new `Color::rgba_from_array([f32; 4]) -> Color` method. * Added a new `Color::rgb_from_array([f32; 3]) -> Color` method. * Added a new `Color::rgba_linear_from_array([f32; 4]) -> Color` method. * Added a new `Color::rgb_linear_from_array([f32; 3]) -> Color` method. * Added a new `Color::hsla_from_array([f32; 4]) -> Color` method. * Added a new `Color::hsl_from_array([f32; 3]) -> Color` method. * Added a new `Color::lcha_from_array([f32; 4]) -> Color` method. * Added a new `Color::lch_from_array([f32; 3]) -> Color` method. * Added a new `Color::rgba_to_vec4(&self) -> Vec4` method. * Added a new `Color::rgba_to_array(&self) -> [f32; 4]` method. * Added a new `Color::rgb_to_vec3(&self) -> Vec3` method. * Added a new `Color::rgb_to_array(&self) -> [f32; 3]` method. * Added a new `Color::rgba_linear_to_vec4(&self) -> Vec4` method. * Added a new `Color::rgba_linear_to_array(&self) -> [f32; 4]` method. * Added a new `Color::rgb_linear_to_vec3(&self) -> Vec3` method. * Added a new `Color::rgb_linear_to_array(&self) -> [f32; 3]` method. * Added a new `Color::hsla_to_vec4(&self) -> Vec4` method. * Added a new `Color::hsla_to_array(&self) -> [f32; 4]` method. * Added a new `Color::hsl_to_vec3(&self) -> Vec3` method. * Added a new `Color::hsl_to_array(&self) -> [f32; 3]` method. * Added a new `Color::lcha_to_vec4(&self) -> Vec4` method. * Added a new `Color::lcha_to_array(&self) -> [f32; 4]` method. * Added a new `Color::lch_to_vec3(&self) -> Vec3` method. * Added a new `Color::lch_to_array(&self) -> [f32; 3]` method. ## Migration Guide `Color::from(Vec4)` is now `Color::rgba_from_array(impl Into<[f32; 4]>)` `Vec4::from(Color)` is now `Color::rgba_to_vec4(&self)` Before: ```rust let color_vec4 = Vec4::new(0.5, 0.5, 0.5); let color_from_vec4 = Color::from(color_vec4); let color_array = [0.5, 0.5, 0.5]; let color_from_array = Color::from(color_array); ``` After: ```rust let color_vec4 = Vec4::new(0.5, 0.5, 0.5); let color_from_vec4 = Color::rgba_from_array(color_vec4); let color_array = [0.5, 0.5, 0.5]; let color_from_array = Color::rgba_from_array(color_array); ```
This commit is contained in:
parent
dcfae72386
commit
cbcd826612
@ -998,7 +998,7 @@ fn load_node(
|
|||||||
gltf::khr_lights_punctual::Kind::Directional => {
|
gltf::khr_lights_punctual::Kind::Directional => {
|
||||||
let mut entity = parent.spawn(DirectionalLightBundle {
|
let mut entity = parent.spawn(DirectionalLightBundle {
|
||||||
directional_light: DirectionalLight {
|
directional_light: DirectionalLight {
|
||||||
color: Color::from(light.color()),
|
color: Color::rgb_from_array(light.color()),
|
||||||
// NOTE: KHR_punctual_lights defines the intensity units for directional
|
// NOTE: KHR_punctual_lights defines the intensity units for directional
|
||||||
// lights in lux (lm/m^2) which is what we need.
|
// lights in lux (lm/m^2) which is what we need.
|
||||||
illuminance: light.intensity(),
|
illuminance: light.intensity(),
|
||||||
@ -1018,7 +1018,7 @@ fn load_node(
|
|||||||
gltf::khr_lights_punctual::Kind::Point => {
|
gltf::khr_lights_punctual::Kind::Point => {
|
||||||
let mut entity = parent.spawn(PointLightBundle {
|
let mut entity = parent.spawn(PointLightBundle {
|
||||||
point_light: PointLight {
|
point_light: PointLight {
|
||||||
color: Color::from(light.color()),
|
color: Color::rgb_from_array(light.color()),
|
||||||
// NOTE: KHR_punctual_lights defines the intensity units for point lights in
|
// NOTE: KHR_punctual_lights defines the intensity units for point lights in
|
||||||
// candela (lm/sr) which is luminous intensity and we need luminous power.
|
// candela (lm/sr) which is luminous intensity and we need luminous power.
|
||||||
// For a point light, luminous power = 4 * pi * luminous intensity
|
// For a point light, luminous power = 4 * pi * luminous intensity
|
||||||
@ -1044,7 +1044,7 @@ fn load_node(
|
|||||||
} => {
|
} => {
|
||||||
let mut entity = parent.spawn(SpotLightBundle {
|
let mut entity = parent.spawn(SpotLightBundle {
|
||||||
spot_light: SpotLight {
|
spot_light: SpotLight {
|
||||||
color: Color::from(light.color()),
|
color: Color::rgb_from_array(light.color()),
|
||||||
// NOTE: KHR_punctual_lights defines the intensity units for spot lights in
|
// NOTE: KHR_punctual_lights defines the intensity units for spot lights in
|
||||||
// candela (lm/sr) which is luminous intensity and we need luminous power.
|
// candela (lm/sr) which is luminous intensity and we need luminous power.
|
||||||
// For a spot light, we map luminous power = 4 * pi * luminous intensity
|
// For a spot light, we map luminous power = 4 * pi * luminous intensity
|
||||||
|
@ -5,7 +5,7 @@ pub use colorspace::*;
|
|||||||
use bevy_math::{Vec3, Vec4};
|
use bevy_math::{Vec3, Vec4};
|
||||||
use bevy_reflect::{Reflect, ReflectDeserialize, ReflectSerialize};
|
use bevy_reflect::{Reflect, ReflectDeserialize, ReflectSerialize};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::ops::{Add, AddAssign, Mul, MulAssign};
|
use std::ops::{Add, Mul, MulAssign};
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize, Reflect)]
|
#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize, Reflect)]
|
||||||
@ -1102,67 +1102,182 @@ impl Color {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for Color {
|
/// New `Color` from `[f32; 4]` (or a type that can be converted into them) with RGB representation in sRGB colorspace.
|
||||||
fn default() -> Self {
|
#[inline]
|
||||||
Color::WHITE
|
pub fn rgba_from_array(arr: impl Into<[f32; 4]>) -> Self {
|
||||||
|
let [r, g, b, a]: [f32; 4] = arr.into();
|
||||||
|
Color::rgba(r, g, b, a)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl AddAssign<Color> for Color {
|
/// New `Color` from `[f32; 3]` (or a type that can be converted into them) with RGB representation in sRGB colorspace.
|
||||||
fn add_assign(&mut self, rhs: Color) {
|
#[inline]
|
||||||
match self {
|
pub fn rgb_from_array(arr: impl Into<[f32; 3]>) -> Self {
|
||||||
|
let [r, g, b]: [f32; 3] = arr.into();
|
||||||
|
Color::rgb(r, g, b)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// New `Color` from `[f32; 4]` (or a type that can be converted into them) with RGB representation in linear RGB colorspace.
|
||||||
|
#[inline]
|
||||||
|
pub fn rgba_linear_from_array(arr: impl Into<[f32; 4]>) -> Self {
|
||||||
|
let [r, g, b, a]: [f32; 4] = arr.into();
|
||||||
|
Color::rgba_linear(r, g, b, a)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// New `Color` from `[f32; 3]` (or a type that can be converted into them) with RGB representation in linear RGB colorspace.
|
||||||
|
#[inline]
|
||||||
|
pub fn rgb_linear_from_array(arr: impl Into<[f32; 3]>) -> Self {
|
||||||
|
let [r, g, b]: [f32; 3] = arr.into();
|
||||||
|
Color::rgb_linear(r, g, b)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// New `Color` from `[f32; 4]` (or a type that can be converted into them) with HSL representation in sRGB colorspace.
|
||||||
|
#[inline]
|
||||||
|
pub fn hsla_from_array(arr: impl Into<[f32; 4]>) -> Self {
|
||||||
|
let [h, s, l, a]: [f32; 4] = arr.into();
|
||||||
|
Color::hsla(h, s, l, a)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// New `Color` from `[f32; 3]` (or a type that can be converted into them) with HSL representation in sRGB colorspace.
|
||||||
|
#[inline]
|
||||||
|
pub fn hsl_from_array(arr: impl Into<[f32; 3]>) -> Self {
|
||||||
|
let [h, s, l]: [f32; 3] = arr.into();
|
||||||
|
Color::hsl(h, s, l)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// New `Color` from `[f32; 4]` (or a type that can be converted into them) with LCH representation in sRGB colorspace.
|
||||||
|
#[inline]
|
||||||
|
pub fn lcha_from_array(arr: impl Into<[f32; 4]>) -> Self {
|
||||||
|
let [l, c, h, a]: [f32; 4] = arr.into();
|
||||||
|
Color::lcha(l, c, h, a)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// New `Color` from `[f32; 3]` (or a type that can be converted into them) with LCH representation in sRGB colorspace.
|
||||||
|
#[inline]
|
||||||
|
pub fn lch_from_array(arr: impl Into<[f32; 3]>) -> Self {
|
||||||
|
let [l, c, h]: [f32; 3] = arr.into();
|
||||||
|
Color::lch(l, c, h)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Convert `Color` to RGBA and return as `Vec4`.
|
||||||
|
#[inline]
|
||||||
|
pub fn rgba_to_vec4(&self) -> Vec4 {
|
||||||
|
let color = self.as_rgba();
|
||||||
|
match color {
|
||||||
Color::Rgba {
|
Color::Rgba {
|
||||||
red,
|
red,
|
||||||
green,
|
green,
|
||||||
blue,
|
blue,
|
||||||
alpha,
|
alpha,
|
||||||
} => {
|
} => Vec4::new(red, green, blue, alpha),
|
||||||
let rhs = rhs.as_rgba_f32();
|
_ => unreachable!(),
|
||||||
*red += rhs[0];
|
}
|
||||||
*green += rhs[1];
|
}
|
||||||
*blue += rhs[2];
|
|
||||||
*alpha += rhs[3];
|
/// Convert `Color` to RGBA and return as `Vec3`.
|
||||||
}
|
#[inline]
|
||||||
|
pub fn rgb_to_vec3(&self) -> Vec3 {
|
||||||
|
let color = self.as_rgba();
|
||||||
|
match color {
|
||||||
|
Color::Rgba {
|
||||||
|
red, green, blue, ..
|
||||||
|
} => Vec3::new(red, green, blue),
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Convert `Color` to linear RGBA and return as `Vec4`.
|
||||||
|
#[inline]
|
||||||
|
pub fn rgba_linear_to_vec4(&self) -> Vec4 {
|
||||||
|
let color = self.as_rgba_linear();
|
||||||
|
match color {
|
||||||
Color::RgbaLinear {
|
Color::RgbaLinear {
|
||||||
red,
|
red,
|
||||||
green,
|
green,
|
||||||
blue,
|
blue,
|
||||||
alpha,
|
alpha,
|
||||||
} => {
|
} => Vec4::new(red, green, blue, alpha),
|
||||||
let rhs = rhs.as_linear_rgba_f32();
|
_ => unreachable!(),
|
||||||
*red += rhs[0];
|
}
|
||||||
*green += rhs[1];
|
}
|
||||||
*blue += rhs[2];
|
|
||||||
*alpha += rhs[3];
|
/// Convert `Color` to linear RGBA and return as `Vec3`.
|
||||||
}
|
#[inline]
|
||||||
|
pub fn rgb_linear_to_vec3(&self) -> Vec3 {
|
||||||
|
let color = self.as_rgba_linear();
|
||||||
|
match color {
|
||||||
|
Color::RgbaLinear {
|
||||||
|
red, green, blue, ..
|
||||||
|
} => Vec3::new(red, green, blue),
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Convert `Color` to HSLA and return as `Vec4`.
|
||||||
|
#[inline]
|
||||||
|
pub fn hsla_to_vec4(&self) -> Vec4 {
|
||||||
|
let color = self.as_hsla();
|
||||||
|
match color {
|
||||||
Color::Hsla {
|
Color::Hsla {
|
||||||
hue,
|
hue,
|
||||||
saturation,
|
saturation,
|
||||||
lightness,
|
lightness,
|
||||||
alpha,
|
alpha,
|
||||||
} => {
|
} => Vec4::new(hue, saturation, lightness, alpha),
|
||||||
let rhs = rhs.as_hsla_f32();
|
_ => unreachable!(),
|
||||||
*hue += rhs[0];
|
}
|
||||||
*saturation += rhs[1];
|
}
|
||||||
*lightness += rhs[2];
|
|
||||||
*alpha += rhs[3];
|
/// Convert `Color` to HSLA and return as `Vec3`.
|
||||||
}
|
#[inline]
|
||||||
|
pub fn hsl_to_vec3(&self) -> Vec3 {
|
||||||
|
let color = self.as_hsla();
|
||||||
|
match color {
|
||||||
|
Color::Hsla {
|
||||||
|
hue,
|
||||||
|
saturation,
|
||||||
|
lightness,
|
||||||
|
..
|
||||||
|
} => Vec3::new(hue, saturation, lightness),
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Convert `Color` to LCHA and return as `Vec4`.
|
||||||
|
#[inline]
|
||||||
|
pub fn lcha_to_vec4(&self) -> Vec4 {
|
||||||
|
let color = self.as_lcha();
|
||||||
|
match color {
|
||||||
Color::Lcha {
|
Color::Lcha {
|
||||||
lightness,
|
lightness,
|
||||||
chroma,
|
chroma,
|
||||||
hue,
|
hue,
|
||||||
alpha,
|
alpha,
|
||||||
} => {
|
} => Vec4::new(lightness, chroma, hue, alpha),
|
||||||
let rhs = rhs.as_lcha_f32();
|
_ => unreachable!(),
|
||||||
*lightness += rhs[0];
|
|
||||||
*chroma += rhs[1];
|
|
||||||
*hue += rhs[2];
|
|
||||||
*alpha += rhs[3];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Convert `Color` to LCHA and return as `Vec3`.
|
||||||
|
#[inline]
|
||||||
|
pub fn lch_to_vec3(&self) -> Vec3 {
|
||||||
|
let color = self.as_lcha();
|
||||||
|
match color {
|
||||||
|
Color::Lcha {
|
||||||
|
lightness,
|
||||||
|
chroma,
|
||||||
|
hue,
|
||||||
|
..
|
||||||
|
} => Vec3::new(lightness, chroma, hue),
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for Color {
|
||||||
|
fn default() -> Self {
|
||||||
|
Color::WHITE
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Add<Color> for Color {
|
impl Add<Color> for Color {
|
||||||
@ -1219,7 +1334,6 @@ impl Add<Color> for Color {
|
|||||||
alpha,
|
alpha,
|
||||||
} => {
|
} => {
|
||||||
let rhs = rhs.as_lcha_f32();
|
let rhs = rhs.as_lcha_f32();
|
||||||
|
|
||||||
Color::Lcha {
|
Color::Lcha {
|
||||||
lightness: lightness + rhs[0],
|
lightness: lightness + rhs[0],
|
||||||
chroma: chroma + rhs[1],
|
chroma: chroma + rhs[1],
|
||||||
@ -1231,53 +1345,6 @@ impl Add<Color> for Color {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AddAssign<Vec4> for Color {
|
|
||||||
fn add_assign(&mut self, rhs: Vec4) {
|
|
||||||
let rhs: Color = rhs.into();
|
|
||||||
*self += rhs;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Add<Vec4> for Color {
|
|
||||||
type Output = Color;
|
|
||||||
|
|
||||||
fn add(self, rhs: Vec4) -> Self::Output {
|
|
||||||
let rhs: Color = rhs.into();
|
|
||||||
self + rhs
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<Color> for [f32; 4] {
|
|
||||||
fn from(color: Color) -> Self {
|
|
||||||
color.as_rgba_f32()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<[f32; 4]> for Color {
|
|
||||||
fn from([r, g, b, a]: [f32; 4]) -> Self {
|
|
||||||
Color::rgba(r, g, b, a)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<[f32; 3]> for Color {
|
|
||||||
fn from([r, g, b]: [f32; 3]) -> Self {
|
|
||||||
Color::rgb(r, g, b)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<Color> for Vec4 {
|
|
||||||
fn from(color: Color) -> Self {
|
|
||||||
let color: [f32; 4] = color.into();
|
|
||||||
Vec4::new(color[0], color[1], color[2], color[3])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<Vec4> for Color {
|
|
||||||
fn from(vec4: Vec4) -> Self {
|
|
||||||
Color::rgba(vec4.x, vec4.y, vec4.z, vec4.w)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<Color> for wgpu::Color {
|
impl From<Color> for wgpu::Color {
|
||||||
fn from(color: Color) -> Self {
|
fn from(color: Color) -> Self {
|
||||||
if let Color::RgbaLinear {
|
if let Color::RgbaLinear {
|
||||||
@ -1909,15 +1976,15 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn conversions_vec4() {
|
fn conversions_vec4() {
|
||||||
let starting_vec4 = Vec4::new(0.4, 0.5, 0.6, 1.0);
|
let starting_vec4 = Vec4::new(0.4, 0.5, 0.6, 1.0);
|
||||||
let starting_color = Color::from(starting_vec4);
|
let starting_color = Color::rgba_from_array(starting_vec4);
|
||||||
|
|
||||||
assert_eq!(starting_vec4, Vec4::from(starting_color));
|
assert_eq!(starting_vec4, starting_color.rgba_to_vec4());
|
||||||
|
|
||||||
let transformation = Vec4::new(0.5, 0.5, 0.5, 1.0);
|
let transformation = Vec4::new(0.5, 0.5, 0.5, 1.0);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
starting_color * transformation,
|
starting_color * transformation,
|
||||||
Color::from(starting_vec4 * transformation),
|
Color::rgba_from_array(starting_vec4 * transformation)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,7 +17,7 @@ fn update(time: Res<Time>, mut ui_materials: ResMut<Assets<CustomUiMaterial>>) {
|
|||||||
for (_, material) in ui_materials.iter_mut() {
|
for (_, material) in ui_materials.iter_mut() {
|
||||||
// rainbow color effect
|
// rainbow color effect
|
||||||
let new_color = Color::hsl((time.elapsed_seconds() * 60.0) % 360.0, 1., 0.5);
|
let new_color = Color::hsl((time.elapsed_seconds() * 60.0) % 360.0, 1., 0.5);
|
||||||
material.color = new_color.into();
|
material.color = new_color.rgba_to_vec4();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -45,7 +45,7 @@ fn setup(mut commands: Commands, mut ui_materials: ResMut<Assets<CustomUiMateria
|
|||||||
..default()
|
..default()
|
||||||
},
|
},
|
||||||
material: ui_materials.add(CustomUiMaterial {
|
material: ui_materials.add(CustomUiMaterial {
|
||||||
color: Color::WHITE.into(),
|
color: Color::WHITE.rgba_to_vec4(),
|
||||||
}),
|
}),
|
||||||
..default()
|
..default()
|
||||||
});
|
});
|
||||||
|
Loading…
Reference in New Issue
Block a user