diff --git a/CHANGELOG.md b/CHANGELOG.md index 4335441de397c5ee6fcf13cc9cc54f17f73ba05a..d28dd7b787b92a738545e77ff614dbb96b761350 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,6 +22,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Removed `Tweenable::stop()`. Tweenables do not have a "stop" state anymore, they are only either active or completed. The playback state is only relevant on the `Animator` or `AssetAnimator` which controls them. +### Fixed + +- Fixed a bug with the alpha value of colored lenses being too large (`TextColorLens`, `SpriteColorLens`, `ColorMaterialColorLens`). + ## [0.3.1] - 2022-02-12 ### Added diff --git a/src/lens.rs b/src/lens.rs index d527b29f0eb22df0ae1cebd0bac0914940a41ff3..2f7104bdefb33dc58e1bda99259d7e006f8cb5f2 100644 --- a/src/lens.rs +++ b/src/lens.rs @@ -54,8 +54,11 @@ pub struct TextColorLens { impl Lens<Text> for TextColorLens { fn lerp(&mut self, target: &mut Text, ratio: f32) { - let value = self.start + (self.end + self.start * -1.0) * ratio; - target.sections[self.section].style.color = value; + // Note: Add<f32> for Color affects alpha, but not Mul<f32>. So use Vec4 for consistency. + let start: Vec4 = self.start.into(); + let end: Vec4 = self.end.into(); + let value = start.lerp(end, ratio); + target.sections[self.section].style.color = value.into(); } } @@ -160,8 +163,11 @@ pub struct ColorMaterialColorLens { impl Lens<ColorMaterial> for ColorMaterialColorLens { fn lerp(&mut self, target: &mut ColorMaterial, ratio: f32) { - let value = self.start + (self.end + self.start * -1.) * ratio; - target.color = value; + // Note: Add<f32> for Color affects alpha, but not Mul<f32>. So use Vec4 for consistency. + let start: Vec4 = self.start.into(); + let end: Vec4 = self.end.into(); + let value = start.lerp(end, ratio); + target.color = value.into(); } } @@ -179,7 +185,158 @@ pub struct SpriteColorLens { impl Lens<Sprite> for SpriteColorLens { fn lerp(&mut self, target: &mut Sprite, ratio: f32) { - let value = self.start + (self.end + self.start * -1.) * ratio; - target.color = value; + // Note: Add<f32> for Color affects alpha, but not Mul<f32>. So use Vec4 for consistency. + let start: Vec4 = self.start.into(); + let end: Vec4 = self.end.into(); + let value = start.lerp(end, ratio); + target.color = value.into(); + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn text_color() { + let mut lens = TextColorLens { + start: Color::RED, + end: Color::BLUE, + section: 0, + }; + let mut text = Text::with_section("", Default::default(), Default::default()); + + lens.lerp(&mut text, 0.); + assert_eq!(text.sections[0].style.color, Color::RED); + + lens.lerp(&mut text, 1.); + assert_eq!(text.sections[0].style.color, Color::BLUE); + + lens.lerp(&mut text, 0.3); + assert_eq!(text.sections[0].style.color, Color::rgba(0.7, 0., 0.3, 1.0)); + } + + #[test] + fn transform_position() { + let mut lens = TransformPositionLens { + start: Vec3::ZERO, + end: Vec3::new(1., 2., -4.), + }; + let mut transform = Transform::default(); + + lens.lerp(&mut transform, 0.); + assert!(transform.translation.abs_diff_eq(Vec3::ZERO, 1e-5)); + assert!(transform.rotation.abs_diff_eq(Quat::IDENTITY, 1e-5)); + assert!(transform.scale.abs_diff_eq(Vec3::ONE, 1e-5)); + + lens.lerp(&mut transform, 1.); + assert!(transform + .translation + .abs_diff_eq(Vec3::new(1., 2., -4.), 1e-5)); + assert!(transform.rotation.abs_diff_eq(Quat::IDENTITY, 1e-5)); + assert!(transform.scale.abs_diff_eq(Vec3::ONE, 1e-5)); + + lens.lerp(&mut transform, 0.3); + assert!(transform + .translation + .abs_diff_eq(Vec3::new(0.3, 0.6, -1.2), 1e-5)); + assert!(transform.rotation.abs_diff_eq(Quat::IDENTITY, 1e-5)); + assert!(transform.scale.abs_diff_eq(Vec3::ONE, 1e-5)); + } + + #[test] + fn transform_rotation() { + let mut lens = TransformRotationLens { + start: Quat::IDENTITY, + end: Quat::from_rotation_z(100_f32.to_radians()), + }; + let mut transform = Transform::default(); + + lens.lerp(&mut transform, 0.); + assert!(transform.translation.abs_diff_eq(Vec3::ZERO, 1e-5)); + assert!(transform.rotation.abs_diff_eq(Quat::IDENTITY, 1e-5)); + assert!(transform.scale.abs_diff_eq(Vec3::ONE, 1e-5)); + + lens.lerp(&mut transform, 1.); + assert!(transform.translation.abs_diff_eq(Vec3::ZERO, 1e-5)); + assert!(transform + .rotation + .abs_diff_eq(Quat::from_rotation_z(100_f32.to_radians()), 1e-5)); + assert!(transform.scale.abs_diff_eq(Vec3::ONE, 1e-5)); + + lens.lerp(&mut transform, 0.3); + assert!(transform.translation.abs_diff_eq(Vec3::ZERO, 1e-5)); + assert!(transform + .rotation + .abs_diff_eq(Quat::from_rotation_z(30_f32.to_radians()), 1e-5)); + assert!(transform.scale.abs_diff_eq(Vec3::ONE, 1e-5)); + } + + #[test] + fn transform_scale() { + let mut lens = TransformScaleLens { + start: Vec3::ZERO, + end: Vec3::new(1., 2., -4.), + }; + let mut transform = Transform::default(); + + lens.lerp(&mut transform, 0.); + assert!(transform.translation.abs_diff_eq(Vec3::ZERO, 1e-5)); + assert!(transform.rotation.abs_diff_eq(Quat::IDENTITY, 1e-5)); + assert!(transform.scale.abs_diff_eq(Vec3::ZERO, 1e-5)); + + lens.lerp(&mut transform, 1.); + assert!(transform.translation.abs_diff_eq(Vec3::ZERO, 1e-5)); + assert!(transform.rotation.abs_diff_eq(Quat::IDENTITY, 1e-5)); + assert!(transform.scale.abs_diff_eq(Vec3::new(1., 2., -4.), 1e-5)); + + lens.lerp(&mut transform, 0.3); + assert!(transform.translation.abs_diff_eq(Vec3::ZERO, 1e-5)); + assert!(transform.rotation.abs_diff_eq(Quat::IDENTITY, 1e-5)); + assert!(transform.scale.abs_diff_eq(Vec3::new(0.3, 0.6, -1.2), 1e-5)); + } + + #[test] + fn colormaterial_color() { + let mut lens = ColorMaterialColorLens { + start: Color::RED, + end: Color::BLUE, + }; + let mut mat = ColorMaterial { + color: Color::WHITE, + texture: None, + }; + + lens.lerp(&mut mat, 0.); + assert_eq!(mat.color, Color::RED); + + lens.lerp(&mut mat, 1.); + assert_eq!(mat.color, Color::BLUE); + + lens.lerp(&mut mat, 0.3); + assert_eq!(mat.color, Color::rgba(0.7, 0., 0.3, 1.0)); + } + + #[test] + fn sprite_color() { + let mut lens = SpriteColorLens { + start: Color::RED, + end: Color::BLUE, + }; + let mut sprite = Sprite { + color: Color::WHITE, + flip_x: false, + flip_y: false, + custom_size: None, + }; + + lens.lerp(&mut sprite, 0.); + assert_eq!(sprite.color, Color::RED); + + lens.lerp(&mut sprite, 1.); + assert_eq!(sprite.color, Color::BLUE); + + lens.lerp(&mut sprite, 0.3); + assert_eq!(sprite.color, Color::rgba(0.7, 0., 0.3, 1.0)); } }