diff --git a/crates/bevy_gltf/src/loader.rs b/crates/bevy_gltf/src/loader.rs index abdbc1a3cbe50..bc1f3c3615a33 100644 --- a/crates/bevy_gltf/src/loader.rs +++ b/crates/bevy_gltf/src/loader.rs @@ -998,7 +998,7 @@ fn load_node( gltf::khr_lights_punctual::Kind::Directional => { let mut entity = parent.spawn(DirectionalLightBundle { 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 // lights in lux (lm/m^2) which is what we need. illuminance: light.intensity(), @@ -1018,7 +1018,7 @@ fn load_node( gltf::khr_lights_punctual::Kind::Point => { let mut entity = parent.spawn(PointLightBundle { 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 // candela (lm/sr) which is luminous intensity and we need luminous power. // For a point light, luminous power = 4 * pi * luminous intensity @@ -1044,7 +1044,7 @@ fn load_node( } => { let mut entity = parent.spawn(SpotLightBundle { 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 // candela (lm/sr) which is luminous intensity and we need luminous power. // For a spot light, we map luminous power = 4 * pi * luminous intensity diff --git a/crates/bevy_render/src/color/mod.rs b/crates/bevy_render/src/color/mod.rs index b4139b8787482..dbe28a11acce6 100644 --- a/crates/bevy_render/src/color/mod.rs +++ b/crates/bevy_render/src/color/mod.rs @@ -5,7 +5,7 @@ pub use colorspace::*; use bevy_math::{Vec3, Vec4}; use bevy_reflect::{Reflect, ReflectDeserialize, ReflectSerialize}; use serde::{Deserialize, Serialize}; -use std::ops::{Add, AddAssign, Mul, MulAssign}; +use std::ops::{Add, Mul, MulAssign}; use thiserror::Error; #[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize, Reflect)] @@ -1102,69 +1102,184 @@ impl Color { } } } -} -impl Default for Color { - fn default() -> Self { - Color::WHITE + /// New `Color` from `[f32; 4]` (or a type that can be converted into them) with RGB representation in sRGB colorspace. + #[inline] + 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 for Color { - fn add_assign(&mut self, rhs: Color) { - match self { + /// New `Color` from `[f32; 3]` (or a type that can be converted into them) with RGB representation in sRGB colorspace. + #[inline] + 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 { red, green, blue, alpha, - } => { - let rhs = rhs.as_rgba_f32(); - *red += rhs[0]; - *green += rhs[1]; - *blue += rhs[2]; - *alpha += rhs[3]; - } + } => Vec4::new(red, green, blue, alpha), + _ => unreachable!(), + } + } + + /// 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 { red, green, blue, alpha, - } => { - let rhs = rhs.as_linear_rgba_f32(); - *red += rhs[0]; - *green += rhs[1]; - *blue += rhs[2]; - *alpha += rhs[3]; - } + } => Vec4::new(red, green, blue, alpha), + _ => unreachable!(), + } + } + + /// 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 { hue, saturation, lightness, alpha, - } => { - let rhs = rhs.as_hsla_f32(); - *hue += rhs[0]; - *saturation += rhs[1]; - *lightness += rhs[2]; - *alpha += rhs[3]; - } + } => Vec4::new(hue, saturation, lightness, alpha), + _ => unreachable!(), + } + } + + /// 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 { lightness, chroma, hue, alpha, - } => { - let rhs = rhs.as_lcha_f32(); - *lightness += rhs[0]; - *chroma += rhs[1]; - *hue += rhs[2]; - *alpha += rhs[3]; - } + } => Vec4::new(lightness, chroma, hue, alpha), + _ => unreachable!(), + } + } + + /// 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 for Color { type Output = Color; @@ -1219,7 +1334,6 @@ impl Add for Color { alpha, } => { let rhs = rhs.as_lcha_f32(); - Color::Lcha { lightness: lightness + rhs[0], chroma: chroma + rhs[1], @@ -1231,53 +1345,6 @@ impl Add for Color { } } -impl AddAssign for Color { - fn add_assign(&mut self, rhs: Vec4) { - let rhs: Color = rhs.into(); - *self += rhs; - } -} - -impl Add for Color { - type Output = Color; - - fn add(self, rhs: Vec4) -> Self::Output { - let rhs: Color = rhs.into(); - self + rhs - } -} - -impl From 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 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 for Color { - fn from(vec4: Vec4) -> Self { - Color::rgba(vec4.x, vec4.y, vec4.z, vec4.w) - } -} - impl From for wgpu::Color { fn from(color: Color) -> Self { if let Color::RgbaLinear { @@ -1909,15 +1976,15 @@ mod tests { #[test] fn conversions_vec4() { 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); assert_eq!( starting_color * transformation, - Color::from(starting_vec4 * transformation), + Color::rgba_from_array(starting_vec4 * transformation) ); } diff --git a/examples/ui/ui_material.rs b/examples/ui/ui_material.rs index 82a2509f83678..aa57f411923e8 100644 --- a/examples/ui/ui_material.rs +++ b/examples/ui/ui_material.rs @@ -17,7 +17,7 @@ fn update(time: Res