From 033081a49e50dd4d6f59da722dfa1f204764fc1c Mon Sep 17 00:00:00 2001 From: gered Date: Sun, 30 Apr 2023 16:57:19 -0400 Subject: [PATCH] add color blending for ARGBu8x4 --- ggdt/src/graphics/color.rs | 53 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/ggdt/src/graphics/color.rs b/ggdt/src/graphics/color.rs index 119c2bc..6950d03 100644 --- a/ggdt/src/graphics/color.rs +++ b/ggdt/src/graphics/color.rs @@ -611,6 +611,25 @@ impl ARGBu8x4 { } #[inline] + fn blend_components(strength: u8, src: Self, dest: Self) -> Self { + let strength = simd::u16x4::splat(strength as u16); + let max = simd::u16x4::splat(255); + ARGBu8x4((((src.0.cast() * strength) + (dest.0.cast() * (max - strength))) / max).cast()) + } + + #[inline] + pub fn blend(&self, dest: Self) -> Self { + ARGBu8x4::blend_components(self.a(), *self, dest) + } + + #[inline] + pub fn blend_with_alpha(&self, dest: Self, alpha: u8) -> Self { + let alpha = ((alpha as u16 * self.a() as u16) / 255) as u8; + let mut blended = ARGBu8x4::blend_components(alpha, *self, dest); + blended.set_a(alpha); + blended + } + pub fn lerp(&self, other: Self, t: f32) -> Self { ARGBu8x4((self.0.cast() + (other.0 - self.0).cast() * simd::f32x4::splat(t)).cast()) } @@ -943,6 +962,40 @@ mod tests { ); } + #[test] + #[rustfmt::skip] + fn argbu8x4_blending() { + // TODO: for .blend(), is this really the behaviour we want? the output value's alpha + // is blended, but the source color's alpha is what is ultimately used to control + // the blend operation. what is best here? the output RGB color looks correct at + // any rate, just not sure what the proper output alpha component *should* be in + // all cases. + + assert_eq!([0xff, 0x11, 0x22, 0x33], ARGBu8x4::from(0xff112233).blend(ARGBu8x4::from(0xff555555)).to_array()); + assert_eq!([0xbf, 0x33, 0x3b, 0x44], ARGBu8x4::from(0x7f112233).blend(ARGBu8x4::from(0xff555555)).to_array()); + assert_eq!([0xff, 0x55, 0x55, 0x55], ARGBu8x4::from(0x00112233).blend(ARGBu8x4::from(0xff555555)).to_array()); + + assert_eq!([0xff, 0x11, 0x22, 0x33], ARGBu8x4::from(0xff112233).blend(ARGBu8x4::from(0x7f555555)).to_array()); + assert_eq!([0x7f, 0x33, 0x3b, 0x44], ARGBu8x4::from(0x7f112233).blend(ARGBu8x4::from(0x7f555555)).to_array()); + assert_eq!([0x7f, 0x55, 0x55, 0x55], ARGBu8x4::from(0x00112233).blend(ARGBu8x4::from(0x7f555555)).to_array()); + + assert_eq!([0xff, 0x11, 0x22, 0x33], ARGBu8x4::from(0xff112233).blend_with_alpha(ARGBu8x4::from(0xff555555), 255).to_array()); + assert_eq!([0x7f, 0x33, 0x3b, 0x44], ARGBu8x4::from(0x7f112233).blend_with_alpha(ARGBu8x4::from(0xff555555), 255).to_array()); + assert_eq!([0x00, 0x55, 0x55, 0x55], ARGBu8x4::from(0x00112233).blend_with_alpha(ARGBu8x4::from(0xff555555), 255).to_array()); + + assert_eq!([0xff, 0x11, 0x22, 0x33], ARGBu8x4::from(0xff112233).blend_with_alpha(ARGBu8x4::from(0x7f555555), 255).to_array()); + assert_eq!([0x7f, 0x33, 0x3b, 0x44], ARGBu8x4::from(0x7f112233).blend_with_alpha(ARGBu8x4::from(0x7f555555), 255).to_array()); + assert_eq!([0x00, 0x55, 0x55, 0x55], ARGBu8x4::from(0x00112233).blend_with_alpha(ARGBu8x4::from(0x7f555555), 255).to_array()); + + assert_eq!([0x80, 0x32, 0x3b, 0x43], ARGBu8x4::from(0xff112233).blend_with_alpha(ARGBu8x4::from(0xff555555), 128).to_array()); + assert_eq!([0x3f, 0x44, 0x48, 0x4c], ARGBu8x4::from(0x7f112233).blend_with_alpha(ARGBu8x4::from(0xff555555), 128).to_array()); + assert_eq!([0x00, 0x55, 0x55, 0x55], ARGBu8x4::from(0x00112233).blend_with_alpha(ARGBu8x4::from(0xff555555), 128).to_array()); + + assert_eq!([0x00, 0x55, 0x55, 0x55], ARGBu8x4::from(0xff112233).blend_with_alpha(ARGBu8x4::from(0xff555555), 0).to_array()); + assert_eq!([0x00, 0x55, 0x55, 0x55], ARGBu8x4::from(0x7f112233).blend_with_alpha(ARGBu8x4::from(0xff555555), 0).to_array()); + assert_eq!([0x00, 0x55, 0x55, 0x55], ARGBu8x4::from(0x00112233).blend_with_alpha(ARGBu8x4::from(0xff555555), 0).to_array()); + } + #[test] fn argbf32x4() { let mut color = ARGBf32x4(simd::f32x4::from_array([0.5, 0.1, 0.2, 0.3]));