From 743f05c4c00e4734daccda1721ca4f52bd5dfa3c Mon Sep 17 00:00:00 2001 From: tigregalis Date: Fri, 16 Oct 2020 23:18:19 +0800 Subject: [PATCH 1/4] two-way conversions between `Color`-`Vec4` and `Color`-`[f32; 4]` - use `impl From` instead of `impl Into` --- crates/bevy_render/src/color.rs | 42 +++++++++++++++++++++++++++++---- 1 file changed, 37 insertions(+), 5 deletions(-) diff --git a/crates/bevy_render/src/color.rs b/crates/bevy_render/src/color.rs index 75aefb9e301ac..98929fa829017 100644 --- a/crates/bevy_render/src/color.rs +++ b/crates/bevy_render/src/color.rs @@ -248,6 +248,43 @@ impl Add for Color { } } +impl From<[f32; 4]> for Color { + fn from([red, green, blue, alpha]: [f32; 4]) -> Self { + Color { + red, + green, + blue, + alpha, + } + } +} + +impl From for [f32; 4] { + fn from( + Color { + red, + green, + blue, + alpha, + }: Color, + ) -> Self { + [red, green, blue, alpha] + } +} + +impl From for Vec4 { + fn from( + Color { + red, + green, + blue, + alpha, + }: Color, + ) -> Self { + Vec4::new(red, green, blue, alpha) + } +} + impl From for Color { fn from(vec4: Vec4) -> Self { Color { @@ -259,11 +296,6 @@ impl From for Color { } } -impl Into<[f32; 4]> for Color { - fn into(self) -> [f32; 4] { - [self.red, self.green, self.blue, self.alpha] - } -} impl Mul for Color { type Output = Color; From f616950778cbc84f69f06abe8949403b198279f2 Mon Sep 17 00:00:00 2001 From: tigregalis Date: Sat, 17 Oct 2020 12:54:29 +0800 Subject: [PATCH 2/4] into `Color` use `rgba` constructor, from `Color` use getters. added `impl From<[f32; 4]> for ColorSource` for consistency. --- crates/bevy_render/src/color.rs | 48 +++++++++++---------------------- 1 file changed, 15 insertions(+), 33 deletions(-) diff --git a/crates/bevy_render/src/color.rs b/crates/bevy_render/src/color.rs index 98929fa829017..37446a0b5d397 100644 --- a/crates/bevy_render/src/color.rs +++ b/crates/bevy_render/src/color.rs @@ -248,51 +248,27 @@ impl Add for Color { } } -impl From<[f32; 4]> for Color { - fn from([red, green, blue, alpha]: [f32; 4]) -> Self { - Color { - red, - green, - blue, - alpha, - } +impl From for [f32; 4] { + fn from(color: Color) -> Self { + [color.r(), color.g(), color.b(), color.a()] } } -impl From for [f32; 4] { - fn from( - Color { - red, - green, - blue, - alpha, - }: Color, - ) -> Self { - [red, green, blue, alpha] +impl From<[f32; 4]> for Color { + fn from([r, g, b, a]: [f32; 4]) -> Self { + Color::rgba(r, g, b, a) } } impl From for Vec4 { - fn from( - Color { - red, - green, - blue, - alpha, - }: Color, - ) -> Self { - Vec4::new(red, green, blue, alpha) + fn from(color: Color) -> Self { + Vec4::new(color.r(), color.g(), color.b(), color.a()) } } impl From for Color { fn from(vec4: Vec4) -> Self { - Color { - red: vec4.x(), - green: vec4.y(), - blue: vec4.z(), - alpha: vec4.w(), - } + Color::rgba(vec4.x(), vec4.y(), vec4.z(), vec4.w()) } } @@ -383,6 +359,12 @@ pub enum ColorSource { Texture(Handle), } +impl From<[f32; 4]> for ColorSource { + fn from(f32s: [f32; 4]) -> Self { + ColorSource::Color(f32s.into()) + } +} + impl From for ColorSource { fn from(vec4: Vec4) -> Self { ColorSource::Color(vec4.into()) From a8c580bd1a8b015da7dc2cb82b5f3d35b58acb6a Mon Sep 17 00:00:00 2001 From: tigregalis Date: Mon, 19 Oct 2020 09:27:27 +0800 Subject: [PATCH 3/4] impl `Mul`/`MulAssign` assuming non-linear sRGB, added tests, added docs --- crates/bevy_render/src/color.rs | 245 +++++++++++++++++++++++++++----- 1 file changed, 210 insertions(+), 35 deletions(-) diff --git a/crates/bevy_render/src/color.rs b/crates/bevy_render/src/color.rs index 37446a0b5d397..4de5def50ab0c 100644 --- a/crates/bevy_render/src/color.rs +++ b/crates/bevy_render/src/color.rs @@ -11,6 +11,8 @@ use bevy_property::Property; use serde::{Deserialize, Serialize}; use std::ops::{Add, AddAssign, Mul, MulAssign}; +// TODO: Separate types for non-linear sRGB and linear sRGB, with conversions between +// see comment on bevy issue #688 https://github.com/bevyengine/bevy/pull/688#issuecomment-711414011 /// RGBA color in the Linear sRGB colorspace (often colloquially referred to as "linear", "RGB", or "linear RGB"). #[repr(C)] #[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize, Property)] @@ -75,6 +77,7 @@ impl Color { } } + /// New ``Color`` from sRGB colorspace. pub fn hex>(hex: T) -> Result { let hex = hex.as_ref(); @@ -133,72 +136,89 @@ impl Color { red: self.red.nonlinear_to_linear_srgb(), green: self.green.nonlinear_to_linear_srgb(), blue: self.blue.nonlinear_to_linear_srgb(), - alpha: self.alpha, //alpha is always linear + alpha: self.alpha, // alpha is always linear } } - // non-linear-sRGB Component Getter + + /// Get red in sRGB colorspace. pub fn r(&self) -> f32 { self.red.linear_to_nonlinear_srgb() } + /// Get green in sRGB colorspace. pub fn g(&self) -> f32 { self.green.linear_to_nonlinear_srgb() } + /// Get blue in sRGB colorspace. pub fn b(&self) -> f32 { self.blue.linear_to_nonlinear_srgb() } // linear-sRGB Component Getter - pub fn g_linear(&self) -> f32 { - self.green - } - + + /// Get red in linear colorspace. pub fn r_linear(&self) -> f32 { self.red } + /// Get green in linear colorspace. + pub fn g_linear(&self) -> f32 { + self.green + } + + /// Get blue in linear colorspace. pub fn b_linear(&self) -> f32 { self.blue } + /// Get alpha. pub fn a(&self) -> f32 { self.alpha } // non-linear-sRGB Component Setter + + /// Set red in sRGB colorspace. pub fn set_r(&mut self, r: f32) -> &mut Self { self.red = r.nonlinear_to_linear_srgb(); self } + /// Set green in sRGB colorspace. pub fn set_g(&mut self, g: f32) -> &mut Self { self.green = g.nonlinear_to_linear_srgb(); self } + /// Set blue in sRGB colorspace. pub fn set_b(&mut self, b: f32) -> &mut Self { self.blue = b.nonlinear_to_linear_srgb(); self } // linear-sRGB Component Setter + + /// Set red in linear colorspace. pub fn set_r_linear(&mut self, r: f32) -> &mut Self { self.red = r; self } + /// Set green in linear colorspace. pub fn set_g_linear(&mut self, g: f32) -> &mut Self { self.green = g; self } + /// Set blue in linear colorspace. pub fn set_b_linear(&mut self, b: f32) -> &mut Self { self.blue = b; self } + /// Set alpha. pub fn set_a(&mut self, a: f32) -> &mut Self { self.alpha = a; self @@ -276,21 +296,20 @@ impl Mul for Color { type Output = Color; fn mul(self, rhs: f32) -> Self::Output { - Color { - red: self.red * rhs, - green: self.green * rhs, - blue: self.blue * rhs, - alpha: self.alpha * rhs, - } + Color::rgba( + self.r() * rhs, + self.g() * rhs, + self.b() * rhs, + self.a(), + ) } } impl MulAssign for Color { fn mul_assign(&mut self, rhs: f32) { - self.red *= rhs; - self.green *= rhs; - self.blue *= rhs; - self.alpha *= rhs; + self.set_r(self.r() * rhs); + self.set_g(self.g() * rhs); + self.set_b(self.b() * rhs); } } @@ -298,21 +317,21 @@ impl Mul for Color { type Output = Color; fn mul(self, rhs: Vec4) -> Self::Output { - Color { - red: self.red * rhs.x(), - green: self.green * rhs.y(), - blue: self.blue * rhs.z(), - alpha: self.alpha * rhs.w(), - } + Color::rgba( + self.r() * rhs.x(), + self.g() * rhs.y(), + self.b() * rhs.z(), + self.a() * rhs.w(), + ) } } impl MulAssign for Color { fn mul_assign(&mut self, rhs: Vec4) { - self.red *= rhs.x(); - self.green *= rhs.y(); - self.blue *= rhs.z(); - self.alpha *= rhs.w(); + self.set_r(self.r() * rhs.x()); + self.set_g(self.g() * rhs.y()); + self.set_b(self.b() * rhs.z()); + self.set_a(self.a() * rhs.w()); } } @@ -320,20 +339,63 @@ impl Mul for Color { type Output = Color; fn mul(self, rhs: Vec3) -> Self::Output { - Color { - red: self.red * rhs.x(), - green: self.green * rhs.y(), - blue: self.blue * rhs.z(), - alpha: self.alpha, - } + Color::rgba( + self.r() * rhs.x(), + self.g() * rhs.y(), + self.b() * rhs.z(), + self.a(), + ) } } impl MulAssign for Color { fn mul_assign(&mut self, rhs: Vec3) { - self.red *= rhs.x(); - self.green *= rhs.y(); - self.blue *= rhs.z(); + self.set_r(self.r() * rhs.x()); + self.set_g(self.g() * rhs.y()); + self.set_b(self.b() * rhs.z()); + } +} + +impl Mul<[f32; 4]> for Color { + type Output = Color; + + fn mul(self, [r, g, b, a]: [f32; 4]) -> Self::Output { + Color::rgba( + self.r() * r, + self.g() * g, + self.b() * b, + self.a() * a, + ) + } +} + +impl MulAssign<[f32; 4]> for Color { + fn mul_assign(&mut self, [r, g, b, a]: [f32; 4]) { + self.set_r(self.r() * r); + self.set_g(self.g() * g); + self.set_b(self.b() * b); + self.set_a(self.a() * a); + } +} + +impl Mul<[f32; 3]> for Color { + type Output = Color; + + fn mul(self, [r, g, b]: [f32; 3]) -> Self::Output { + Color::rgba( + self.r() * r, + self.g() * g, + self.b() * b, + self.a(), + ) + } +} + +impl MulAssign<[f32; 3]> for Color { + fn mul_assign(&mut self, [r, g, b]: [f32; 3]) { + self.set_r(self.r() * r); + self.set_g(self.g() * g); + self.set_b(self.b() * b); } } @@ -455,3 +517,116 @@ fn test_hex_color() { assert!(Color::hex("1234567890").is_err()); } + +#[test] +fn test_conversions_vec4() { + let starting_vec4 = Vec4::new(0.4, 0.5, 0.6, 1.0); + let starting_color = Color::from(starting_vec4); + + assert_eq!( + starting_vec4, + Vec4::from(starting_color), + ); + + let transformation = Vec4::new(0.5, 0.5, 0.5, 1.0); + + assert_eq!( + starting_color * transformation, + Color::from(starting_vec4 * transformation), + ); +} + +#[test] +fn test_mul_and_mulassign_f32() { + let transformation = 0.5; + let starting_color = Color::rgba(0.4, 0.5, 0.6, 1.0); + + assert_eq!( + starting_color * transformation, + Color::rgba(0.4 * 0.5, 0.5 * 0.5, 0.6 * 0.5, 1.0), + ); + + let mut mutated_color = starting_color; + mutated_color *= transformation; + + assert_eq!( + starting_color * transformation, + mutated_color, + ); +} + +#[test] +fn test_mul_and_mulassign_f32by3() { + let transformation = [0.4, 0.5, 0.6]; + let starting_color = Color::rgba(0.4, 0.5, 0.6, 1.0); + + assert_eq!( + starting_color * transformation, + Color::rgba(0.4 * 0.4, 0.5 * 0.5, 0.6 * 0.6, 1.0), + ); + + let mut mutated_color = starting_color; + mutated_color *= transformation; + + assert_eq!( + starting_color * transformation, + mutated_color, + ); +} + +#[test] +fn test_mul_and_mulassign_f32by4() { + let transformation = [0.4, 0.5, 0.6, 0.9]; + let starting_color = Color::rgba(0.4, 0.5, 0.6, 1.0); + + assert_eq!( + starting_color * transformation, + Color::rgba(0.4 * 0.4, 0.5 * 0.5, 0.6 * 0.6, 1.0 * 0.9), + ); + + let mut mutated_color = starting_color; + mutated_color *= transformation; + + assert_eq!( + starting_color * transformation, + mutated_color, + ); +} + +#[test] +fn test_mul_and_mulassign_vec3() { + let transformation = Vec3::new(0.2, 0.3, 0.4); + let starting_color = Color::rgba(0.4, 0.5, 0.6, 1.0); + + assert_eq!( + starting_color * transformation, + Color::rgba(0.4 * 0.2, 0.5 * 0.3, 0.6 * 0.4, 1.0), + ); + + let mut mutated_color = starting_color; + mutated_color *= transformation; + + assert_eq!( + starting_color * transformation, + mutated_color, + ); +} + +#[test] +fn test_mul_and_mulassign_vec4() { + let transformation = Vec4::new(0.2, 0.3, 0.4, 0.5); + let starting_color = Color::rgba(0.4, 0.5, 0.6, 1.0); + + assert_eq!( + starting_color * transformation, + Color::rgba(0.4 * 0.2, 0.5 * 0.3, 0.6 * 0.4, 1.0 * 0.5), + ); + + let mut mutated_color = starting_color; + mutated_color *= transformation; + + assert_eq!( + starting_color * transformation, + mutated_color, + ); +} From c666e034e43d9d1633fad0e956e254a6bcae8f4f Mon Sep 17 00:00:00 2001 From: tigregalis Date: Mon, 19 Oct 2020 11:54:03 +0800 Subject: [PATCH 4/4] format --- crates/bevy_render/src/color.rs | 56 +++++++-------------------------- 1 file changed, 12 insertions(+), 44 deletions(-) diff --git a/crates/bevy_render/src/color.rs b/crates/bevy_render/src/color.rs index 84b40b93e4105..40f7019c2277f 100644 --- a/crates/bevy_render/src/color.rs +++ b/crates/bevy_render/src/color.rs @@ -140,6 +140,7 @@ impl Color { alpha: self.alpha, // alpha is always linear } } + // non-linear-sRGB Component Getter /// Get red in sRGB colorspace. @@ -158,7 +159,7 @@ impl Color { } // linear-sRGB Component Getter - + /// Get red in linear colorspace. pub fn r_linear(&self) -> f32 { self.red @@ -180,7 +181,7 @@ impl Color { } // non-linear-sRGB Component Setter - + /// Set red in sRGB colorspace. pub fn set_r(&mut self, r: f32) -> &mut Self { self.red = r.nonlinear_to_linear_srgb(); @@ -297,12 +298,7 @@ impl Mul for Color { type Output = Color; fn mul(self, rhs: f32) -> Self::Output { - Color::rgba( - self.r() * rhs, - self.g() * rhs, - self.b() * rhs, - self.a(), - ) + Color::rgba(self.r() * rhs, self.g() * rhs, self.b() * rhs, self.a()) } } @@ -361,12 +357,7 @@ impl Mul<[f32; 4]> for Color { type Output = Color; fn mul(self, [r, g, b, a]: [f32; 4]) -> Self::Output { - Color::rgba( - self.r() * r, - self.g() * g, - self.b() * b, - self.a() * a, - ) + Color::rgba(self.r() * r, self.g() * g, self.b() * b, self.a() * a) } } @@ -383,12 +374,7 @@ impl Mul<[f32; 3]> for Color { type Output = Color; fn mul(self, [r, g, b]: [f32; 3]) -> Self::Output { - Color::rgba( - self.r() * r, - self.g() * g, - self.b() * b, - self.a(), - ) + Color::rgba(self.r() * r, self.g() * g, self.b() * b, self.a()) } } @@ -524,10 +510,7 @@ fn test_conversions_vec4() { let starting_vec4 = Vec4::new(0.4, 0.5, 0.6, 1.0); let starting_color = Color::from(starting_vec4); - assert_eq!( - starting_vec4, - Vec4::from(starting_color), - ); + assert_eq!(starting_vec4, Vec4::from(starting_color),); let transformation = Vec4::new(0.5, 0.5, 0.5, 1.0); @@ -550,10 +533,7 @@ fn test_mul_and_mulassign_f32() { let mut mutated_color = starting_color; mutated_color *= transformation; - assert_eq!( - starting_color * transformation, - mutated_color, - ); + assert_eq!(starting_color * transformation, mutated_color,); } #[test] @@ -569,10 +549,7 @@ fn test_mul_and_mulassign_f32by3() { let mut mutated_color = starting_color; mutated_color *= transformation; - assert_eq!( - starting_color * transformation, - mutated_color, - ); + assert_eq!(starting_color * transformation, mutated_color,); } #[test] @@ -588,10 +565,7 @@ fn test_mul_and_mulassign_f32by4() { let mut mutated_color = starting_color; mutated_color *= transformation; - assert_eq!( - starting_color * transformation, - mutated_color, - ); + assert_eq!(starting_color * transformation, mutated_color,); } #[test] @@ -607,10 +581,7 @@ fn test_mul_and_mulassign_vec3() { let mut mutated_color = starting_color; mutated_color *= transformation; - assert_eq!( - starting_color * transformation, - mutated_color, - ); + assert_eq!(starting_color * transformation, mutated_color,); } #[test] @@ -626,8 +597,5 @@ fn test_mul_and_mulassign_vec4() { let mut mutated_color = starting_color; mutated_color *= transformation; - assert_eq!( - starting_color * transformation, - mutated_color, - ); + assert_eq!(starting_color * transformation, mutated_color,); }