diff --git a/core/src/avm1/globals/bitmap_data.rs b/core/src/avm1/globals/bitmap_data.rs index ac9024af6..40d1d149f 100644 --- a/core/src/avm1/globals/bitmap_data.rs +++ b/core/src/avm1/globals/bitmap_data.rs @@ -605,17 +605,16 @@ pub fn color_transform<'gc>( .get("height", activation)? .coerce_to_f64(activation)? as i32; - let min_x = x.max(0) as u32; - let end_x = (x + width) as u32; - let min_y = y.max(0) as u32; - let end_y = (y + height) as u32; + let x_min = x.max(0) as u32; + let x_max = (x + width) as u32; + let y_min = y.max(0) as u32; + let y_max = (y + height) as u32; if let Some(color_transform) = color_transform.as_color_transform_object() { - let params = color_transform.get_params(); bitmap_data .bitmap_data() .write(activation.context.gc_context) - .color_transform(min_x, min_y, end_x, end_y, ¶ms); + .color_transform(x_min, y_min, x_max, y_max, color_transform.into()); } return Ok(Value::Undefined); diff --git a/core/src/avm1/object/color_transform_object.rs b/core/src/avm1/object/color_transform_object.rs index b17762a95..8c212b673 100644 --- a/core/src/avm1/object/color_transform_object.rs +++ b/core/src/avm1/object/color_transform_object.rs @@ -1,9 +1,10 @@ use crate::add_field_accessors; use crate::avm1::{Object, ScriptObject, TObject}; -use crate::bitmap::color_transform_params::ColorTransformParams; use crate::impl_custom_object; use gc_arena::{Collect, GcCell, MutationContext}; +use ruffle_render::color_transform::ColorTransform; use std::fmt; +use swf::Fixed8; /// A ColorTransform #[derive(Clone, Copy, Collect)] @@ -15,21 +16,29 @@ pub struct ColorTransformObject<'gc>(GcCell<'gc, ColorTransformData<'gc>>); pub struct ColorTransformData<'gc> { /// The underlying script object. base: ScriptObject<'gc>, - params: ColorTransformParams, + + red_multiplier: f64, + green_multiplier: f64, + blue_multiplier: f64, + alpha_multiplier: f64, + red_offset: f64, + green_offset: f64, + blue_offset: f64, + alpha_offset: f64, } impl fmt::Debug for ColorTransformObject<'_> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let this = self.0.read(); f.debug_struct("ColorTransform") - .field("redMultiplier", &this.params.red_multiplier) - .field("greenMultiplier", &this.params.green_multiplier) - .field("blueMultiplier", &this.params.blue_multiplier) - .field("alphaMultiplier", &this.params.alpha_multiplier) - .field("redOffset", &this.params.red_offset) - .field("greenOffset", &this.params.green_offset) - .field("blueOffset", &this.params.blue_offset) - .field("alphaOffset", &this.params.alpha_offset) + .field("redMultiplier", &this.red_multiplier) + .field("greenMultiplier", &this.green_multiplier) + .field("blueMultiplier", &this.blue_multiplier) + .field("alphaMultiplier", &this.alpha_multiplier) + .field("redOffset", &this.red_offset) + .field("greenOffset", &this.green_offset) + .field("blueOffset", &this.blue_offset) + .field("alphaOffset", &this.alpha_offset) .finish() } } @@ -43,50 +52,42 @@ impl<'gc> ColorTransformObject<'gc> { gc_context, ColorTransformData { base: ScriptObject::new(gc_context, proto), - params: ColorTransformParams { - red_multiplier: 0.0, - green_multiplier: 0.0, - blue_multiplier: 0.0, - alpha_multiplier: 0.0, - red_offset: 0.0, - green_offset: 0.0, - blue_offset: 0.0, - alpha_offset: 0.0, - }, + red_multiplier: 0.0, + green_multiplier: 0.0, + blue_multiplier: 0.0, + alpha_multiplier: 0.0, + red_offset: 0.0, + green_offset: 0.0, + blue_offset: 0.0, + alpha_offset: 0.0, }, )) } add_field_accessors!( - [set_params, get_params, params, ColorTransformParams], - [ - set_red_multiplier, - get_red_multiplier, - params.red_multiplier, - f64 - ], + [set_red_multiplier, get_red_multiplier, red_multiplier, f64], [ set_green_multiplier, get_green_multiplier, - params.green_multiplier, + green_multiplier, f64 ], [ set_blue_multiplier, get_blue_multiplier, - params.blue_multiplier, + blue_multiplier, f64 ], [ set_alpha_multiplier, get_alpha_multiplier, - params.alpha_multiplier, + alpha_multiplier, f64 ], - [set_red_offset, get_red_offset, params.red_offset, f64], - [set_green_offset, get_green_offset, params.green_offset, f64], - [set_blue_offset, get_blue_offset, params.blue_offset, f64], - [set_alpha_offset, get_alpha_offset, params.alpha_offset, f64], + [set_red_offset, get_red_offset, red_offset, f64], + [set_green_offset, get_green_offset, green_offset, f64], + [set_blue_offset, get_blue_offset, blue_offset, f64], + [set_alpha_offset, get_alpha_offset, alpha_offset, f64], ); } @@ -95,3 +96,18 @@ impl<'gc> TObject<'gc> for ColorTransformObject<'gc> { bare_object(as_color_transform_object -> ColorTransformObject::empty_color_transform_object); }); } + +impl From> for ColorTransform { + fn from(object: ColorTransformObject) -> Self { + Self { + r_mult: Fixed8::from_f64(object.get_red_multiplier()), + g_mult: Fixed8::from_f64(object.get_green_multiplier()), + b_mult: Fixed8::from_f64(object.get_blue_multiplier()), + a_mult: Fixed8::from_f64(object.get_alpha_multiplier()), + r_add: object.get_red_offset() as i16, + g_add: object.get_green_offset() as i16, + b_add: object.get_blue_offset() as i16, + a_add: object.get_alpha_offset() as i16, + } + } +} diff --git a/core/src/bitmap.rs b/core/src/bitmap.rs index 13f8c590a..7daf4e506 100644 --- a/core/src/bitmap.rs +++ b/core/src/bitmap.rs @@ -1,5 +1,4 @@ pub mod bitmap_data; -pub mod color_transform_params; pub mod turbulence; /// Determine if a particular bitmap data size is valid. diff --git a/core/src/bitmap/bitmap_data.rs b/core/src/bitmap/bitmap_data.rs index 3ef2bebbc..345f4d687 100644 --- a/core/src/bitmap/bitmap_data.rs +++ b/core/src/bitmap/bitmap_data.rs @@ -1,19 +1,18 @@ -use gc_arena::{Collect, GcCell}; -use swf::BlendMode; - use crate::avm2::{Object as Avm2Object, Value as Avm2Value}; -use crate::bitmap::color_transform_params::ColorTransformParams; use crate::bitmap::turbulence::Turbulence; use crate::context::RenderContext; use crate::context::UpdateContext; use crate::display_object::DisplayObject; use crate::display_object::TDisplayObject; use bitflags::bitflags; +use gc_arena::{Collect, GcCell}; use ruffle_render::backend::RenderBackend; use ruffle_render::bitmap::{Bitmap, BitmapFormat, BitmapHandle}; +use ruffle_render::color_transform::ColorTransform; use ruffle_render::commands::{CommandHandler, CommandList}; use ruffle_render::transform::Transform; use std::ops::Range; +use swf::BlendMode; /// An implementation of the Lehmer/Park-Miller random number generator /// Uses the fixed parameters m = 2,147,483,647 and a = 16,807 @@ -131,6 +130,22 @@ impl From for Color { } } +impl From for Color { + fn from(c: swf::Color) -> Self { + Self::argb(c.a, c.r, c.g, c.b) + } +} + +impl From for swf::Color { + fn from(c: Color) -> Self { + let r = c.red(); + let g = c.green(); + let b = c.blue(); + let a = c.alpha(); + Self { r, g, b, a } + } +} + bitflags! { pub struct ChannelOptions: u8 { const RED = 1 << 0; @@ -490,33 +505,22 @@ impl<'gc> BitmapData<'gc> { pub fn color_transform( &mut self, - min_x: u32, - min_y: u32, - end_x: u32, - end_y: u32, - color_transform: &ColorTransformParams, + x_min: u32, + y_min: u32, + x_max: u32, + y_max: u32, + color_transform: ColorTransform, ) { - for x in min_x..end_x.min(self.width()) { - for y in min_y..end_y.min(self.height()) { - let color = self - .get_pixel_raw(x, y) - .unwrap_or_else(|| 0.into()) - .to_un_multiplied_alpha(); + for x in x_min..x_max.min(self.width()) { + for y in y_min..y_max.min(self.height()) { + let color = self.get_pixel_raw(x, y).unwrap().to_un_multiplied_alpha(); - let alpha = ((color.alpha() as f32 * color_transform.alpha_multiplier as f32) - + color_transform.alpha_offset as f32) as u8; - let red = ((color.red() as f32 * color_transform.red_multiplier as f32) - + color_transform.red_offset as f32) as u8; - let green = ((color.green() as f32 * color_transform.green_multiplier as f32) - + color_transform.green_offset as f32) as u8; - let blue = ((color.blue() as f32 * color_transform.blue_multiplier as f32) - + color_transform.blue_offset as f32) as u8; + let color = color_transform * swf::Color::from(color); self.set_pixel32_raw( x, y, - Color::argb(alpha, red, green, blue) - .to_premultiplied_alpha(self.transparency()), + Color::from(color).to_premultiplied_alpha(self.transparency()), ) } } diff --git a/core/src/bitmap/color_transform_params.rs b/core/src/bitmap/color_transform_params.rs deleted file mode 100644 index c3696e90c..000000000 --- a/core/src/bitmap/color_transform_params.rs +++ /dev/null @@ -1,14 +0,0 @@ -use gc_arena::Collect; - -#[derive(Copy, Clone, Collect)] -#[collect(no_drop)] -pub struct ColorTransformParams { - pub red_multiplier: f64, - pub green_multiplier: f64, - pub blue_multiplier: f64, - pub alpha_multiplier: f64, - pub red_offset: f64, - pub green_offset: f64, - pub blue_offset: f64, - pub alpha_offset: f64, -} diff --git a/render/src/color_transform.rs b/render/src/color_transform.rs index 51bd40598..ff544fead 100644 --- a/render/src/color_transform.rs +++ b/render/src/color_transform.rs @@ -1,4 +1,5 @@ -use swf::Fixed8; +use std::ops::{Mul, MulAssign}; +use swf::{Color, Fixed8}; #[derive(Clone, Copy, Debug, Eq, PartialEq)] pub struct ColorTransform { @@ -28,17 +29,16 @@ impl From for ColorTransform { } impl ColorTransform { - #[allow(clippy::float_cmp)] - pub fn is_identity(&self) -> bool { - self.r_mult.is_one() - && self.g_mult.is_one() - && self.b_mult.is_one() - && self.a_mult.is_one() - && self.r_add == 0 - && self.g_add == 0 - && self.b_add == 0 - && self.a_add == 0 - } + pub const IDENTITY: Self = Self { + r_mult: Fixed8::ONE, + b_mult: Fixed8::ONE, + g_mult: Fixed8::ONE, + a_mult: Fixed8::ONE, + r_add: 0, + b_add: 0, + g_add: 0, + a_add: 0, + }; /// Returns the multiplicative component of this color transform in RGBA order /// with the values normalized [0.0, 1.0]. @@ -63,7 +63,7 @@ impl ColorTransform { } /// Sets the multiplicate component of this color transform. - pub fn set_mult_color(&mut self, color: &swf::Color) { + pub fn set_mult_color(&mut self, color: &Color) { self.r_mult = Fixed8::from_f32(f32::from(color.r) / 255.0); self.g_mult = Fixed8::from_f32(f32::from(color.g) / 255.0); self.b_mult = Fixed8::from_f32(f32::from(color.b) / 255.0); @@ -72,29 +72,20 @@ impl ColorTransform { } impl Default for ColorTransform { - fn default() -> ColorTransform { - ColorTransform { - r_mult: Fixed8::ONE, - b_mult: Fixed8::ONE, - g_mult: Fixed8::ONE, - a_mult: Fixed8::ONE, - r_add: 0, - b_add: 0, - g_add: 0, - a_add: 0, - } + fn default() -> Self { + Self::IDENTITY } } -impl std::ops::Mul for ColorTransform { +impl Mul for ColorTransform { type Output = Self; + fn mul(self, rhs: Self) -> Self { - ColorTransform { + Self { r_mult: self.r_mult.wrapping_mul(rhs.r_mult), g_mult: self.g_mult.wrapping_mul(rhs.g_mult), b_mult: self.b_mult.wrapping_mul(rhs.b_mult), a_mult: self.a_mult.wrapping_mul(rhs.a_mult), - r_add: self .r_add .wrapping_add(self.r_mult.wrapping_mul_int(rhs.r_add)), @@ -111,8 +102,32 @@ impl std::ops::Mul for ColorTransform { } } -impl std::ops::MulAssign for ColorTransform { +impl MulAssign for ColorTransform { fn mul_assign(&mut self, rhs: Self) { *self = *self * rhs; } } + +impl Mul for ColorTransform { + type Output = Color; + + fn mul(self, mut color: Color) -> Color { + color.r = self + .r_mult + .wrapping_mul_int(i16::from(color.r)) + .wrapping_add(self.r_add) as u8; + color.g = self + .g_mult + .wrapping_mul_int(i16::from(color.g)) + .wrapping_add(self.g_add) as u8; + color.b = self + .b_mult + .wrapping_mul_int(i16::from(color.b)) + .wrapping_add(self.b_add) as u8; + color.a = self + .a_mult + .wrapping_mul_int(i16::from(color.a)) + .wrapping_add(self.a_add) as u8; + color + } +}