core: Move color_transform from BitmapData to bitmap_data_operations

This commit is contained in:
Nathan Adams 2023-03-24 11:41:33 +01:00
parent 43716bbdc7
commit f476968693
4 changed files with 74 additions and 50 deletions

View File

@ -630,10 +630,15 @@ pub fn color_transform<'gc>(
None => return Ok((-3).into()),
};
bitmap_data
.bitmap_data()
.write(activation.context.gc_context)
.color_transform(x_min, y_min, x_max, y_max, &color_transform.into());
bitmap_data_operations::color_transform(
&mut activation.context,
bitmap_data.bitmap_data_wrapper(),
x_min,
y_min,
x_max,
y_max,
&color_transform.into(),
);
}
}
}

View File

@ -578,8 +578,7 @@ pub fn color_transform<'gc>(
this: Option<Object<'gc>>,
args: &[Value<'gc>],
) -> Result<Value<'gc>, Error<'gc>> {
if let Some(bitmap_data) = this.and_then(|t| t.as_bitmap_data()) {
let mut bitmap_data = bitmap_data.write(activation.context.gc_context);
if let Some(bitmap_data) = this.and_then(|t| t.as_bitmap_data_wrapper()) {
if !bitmap_data.disposed() {
// TODO: Re-use `object_to_rectangle` in `movie_clip.rs`.
let rectangle = args.get_object(activation, 0, "rect")?;
@ -607,7 +606,16 @@ pub fn color_transform<'gc>(
color_transform,
activation,
)?;
bitmap_data.color_transform(x_min, y_min, x_max, y_max, &color_transform);
bitmap_data_operations::color_transform(
&mut activation.context,
bitmap_data,
x_min,
y_min,
x_max,
y_max,
&color_transform,
);
}
}

View File

@ -15,7 +15,7 @@ use ruffle_render::quality::StageQuality;
use ruffle_render::transform::Transform;
use ruffle_wstr::WStr;
use std::ops::Range;
use swf::{BlendMode, ColorTransform, Fixed8, Rectangle, Twips};
use swf::{BlendMode, Rectangle, Twips};
use tracing::instrument;
/// An implementation of the Lehmer/Park-Miller random number generator
@ -622,48 +622,6 @@ impl<'gc> BitmapData<'gc> {
self.pixels[(x + y * self.width()) as usize]
}
pub fn color_transform(
&mut self,
x_min: u32,
y_min: u32,
x_max: u32,
y_max: u32,
color_transform: &ColorTransform,
) {
// Flash bug: applying a color transform with only an alpha multiplier > 1 has no effect.
if color_transform.r_multiply != Fixed8::ONE
|| color_transform.g_multiply != Fixed8::ONE
|| color_transform.b_multiply != Fixed8::ONE
|| color_transform.a_multiply < Fixed8::ONE
|| color_transform.r_add != 0
|| color_transform.g_add != 0
|| color_transform.b_add != 0
|| color_transform.a_add != 0
{
let x_max = x_max.min(self.width());
let y_max = y_max.min(self.height());
if x_max > 0 && y_max > 0 {
for x in x_min..x_max {
for y in y_min..y_max {
let color = self.get_pixel32_raw(x, y).to_un_multiplied_alpha();
let color = color_transform * swf::Color::from(color);
self.set_pixel32_raw(
x,
y,
Color::from(color).to_premultiplied_alpha(self.transparency()),
)
}
}
self.set_cpu_dirty(PixelRegion::encompassing_pixels(
(x_min, y_min),
(x_max - 1, y_max - 1),
));
}
}
}
pub fn color_bounds_rect(
&self,
find_color: bool,

View File

@ -3,6 +3,7 @@ use crate::bitmap::turbulence::Turbulence;
use crate::context::UpdateContext;
use gc_arena::GcCell;
use ruffle_render::bitmap::PixelRegion;
use swf::{ColorTransform, Fixed8};
/// AVM1 and AVM2 have a shared set of operations they can perform on BitmapDatas.
/// Instead of directly manipulating the BitmapData in each place, they should call
@ -410,3 +411,55 @@ pub fn copy_channel<'gc>(
dirty_region.clamp(write.width(), write.height());
write.set_cpu_dirty(dirty_region);
}
pub fn color_transform<'gc>(
context: &mut UpdateContext<'_, 'gc>,
target: BitmapDataWrapper<'gc>,
x_min: u32,
y_min: u32,
x_max: u32,
y_max: u32,
color_transform: &ColorTransform,
) {
// Flash bug: applying a color transform with only an alpha multiplier > 1 has no effect.
if color_transform.r_multiply == Fixed8::ONE
&& color_transform.g_multiply == Fixed8::ONE
&& color_transform.b_multiply == Fixed8::ONE
&& color_transform.a_multiply >= Fixed8::ONE
&& color_transform.r_add == 0
&& color_transform.g_add == 0
&& color_transform.b_add == 0
&& color_transform.a_add == 0
{
return;
}
let x_max = x_max.min(target.width());
let y_max = y_max.min(target.height());
if x_max == 0 || y_max == 0 {
return;
}
let target = target.sync();
let mut write = target.write(context.gc_context);
let transparency = write.transparency();
for x in x_min..x_max {
for y in y_min..y_max {
let color = write.get_pixel32_raw(x, y).to_un_multiplied_alpha();
let color = color_transform * swf::Color::from(color);
write.set_pixel32_raw(
x,
y,
Color::from(color).to_premultiplied_alpha(transparency),
)
}
}
write.set_cpu_dirty(PixelRegion::encompassing_pixels(
(x_min, y_min),
(x_max - 1, y_max - 1),
));
}