core: Move compare from BitmapData to bitmap_data_operations

This commit is contained in:
Nathan Adams 2023-03-24 12:20:57 +01:00
parent 8a0cb4685e
commit 2c65f23eb8
3 changed files with 75 additions and 55 deletions

View File

@ -1365,10 +1365,8 @@ pub fn compare<'gc>(
return Ok(BITMAP_DISPOSED.into()); return Ok(BITMAP_DISPOSED.into());
} }
let this_bitmap_data = this_bitmap_data.bitmap_data(); let this_bitmap_data = this_bitmap_data.bitmap_data_wrapper();
let this_bitmap_data = this_bitmap_data.read(); let other_bitmap_data = other_bitmap_data.bitmap_data_wrapper();
let other_bitmap_data = other_bitmap_data.bitmap_data();
let other_bitmap_data = other_bitmap_data.read();
if this_bitmap_data.width() != other_bitmap_data.width() { if this_bitmap_data.width() != other_bitmap_data.width() {
return Ok(DIFFERENT_WIDTHS.into()); return Ok(DIFFERENT_WIDTHS.into());
@ -1378,7 +1376,7 @@ pub fn compare<'gc>(
return Ok(DIFFERENT_HEIGHTS.into()); return Ok(DIFFERENT_HEIGHTS.into());
} }
match BitmapData::compare(&this_bitmap_data, &other_bitmap_data) { match bitmap_data_operations::compare(this_bitmap_data, other_bitmap_data) {
Some(bitmap_data) => Ok(BitmapDataObject::with_bitmap_data( Some(bitmap_data) => Ok(BitmapDataObject::with_bitmap_data(
activation.context.gc_context, activation.context.gc_context,
activation.context.avm1.prototypes().bitmap_data, activation.context.avm1.prototypes().bitmap_data,

View File

@ -450,6 +450,24 @@ impl<'gc> BitmapData<'gc> {
self.set_cpu_dirty(PixelRegion::for_whole_size(width, height)); self.set_cpu_dirty(PixelRegion::for_whole_size(width, height));
} }
pub fn new_with_pixels(
width: u32,
height: u32,
transparency: bool,
pixels: Vec<Color>,
) -> Self {
Self {
pixels,
width,
height,
transparency,
bitmap_handle: None,
avm2_object: None,
disposed: false,
dirty_state: DirtyState::Clean,
}
}
pub fn check_valid( pub fn check_valid(
&self, &self,
activation: &mut crate::avm2::Activation<'_, 'gc>, activation: &mut crate::avm2::Activation<'_, 'gc>,
@ -839,56 +857,6 @@ impl<'gc> BitmapData<'gc> {
} }
} }
/// Compare two BitmapData objects.
/// Returns `None` if the bitmaps are equivalent.
pub fn compare(bitmap: &Self, other: &Self) -> Option<Self> {
// This function expects that the two bitmaps have the same dimensions.
// TODO: Relax this assumption and return a special value instead?
debug_assert_eq!(bitmap.width, other.width);
debug_assert_eq!(bitmap.height, other.height);
let mut different = false;
let pixels = bitmap
.pixels
.iter()
.zip(&other.pixels)
.map(|(bitmap_pixel, other_pixel)| {
let bitmap_pixel = bitmap_pixel.to_un_multiplied_alpha();
let other_pixel = other_pixel.to_un_multiplied_alpha();
if bitmap_pixel == other_pixel {
Color::argb(0, 0, 0, 0)
} else if bitmap_pixel.with_alpha(0) != other_pixel.with_alpha(0) {
different = true;
Color::argb(
0xff,
bitmap_pixel.red().wrapping_sub(other_pixel.red()),
bitmap_pixel.green().wrapping_sub(other_pixel.green()),
bitmap_pixel.blue().wrapping_sub(other_pixel.blue()),
)
} else {
different = true;
let alpha = bitmap_pixel.alpha().wrapping_sub(other_pixel.alpha());
Color::argb(alpha, alpha, alpha, alpha)
}
})
.collect();
if different {
Some(Self {
pixels,
width: bitmap.width,
height: bitmap.height,
transparency: true,
bitmap_handle: None,
avm2_object: None,
disposed: false,
dirty_state: DirtyState::Clean,
})
} else {
None
}
}
pub fn object2(&self) -> Avm2Value<'gc> { pub fn object2(&self) -> Avm2Value<'gc> {
self.avm2_object self.avm2_object
.map(|o| o.into()) .map(|o| o.into())

View File

@ -672,3 +672,57 @@ pub fn palette_map<'gc>(
dirty_region.clamp(write.width(), write.height()); dirty_region.clamp(write.width(), write.height());
write.set_cpu_dirty(dirty_region); write.set_cpu_dirty(dirty_region);
} }
/// Compare two BitmapData objects.
/// Returns `None` if the bitmaps are equivalent.
pub fn compare<'gc>(
left: BitmapDataWrapper<'gc>,
right: BitmapDataWrapper<'gc>,
) -> Option<BitmapData<'gc>> {
// This function expects that the two bitmaps have the same dimensions.
// TODO: Relax this assumption and return a special value instead?
debug_assert_eq!(left.width(), right.width());
debug_assert_eq!(left.height(), right.height());
let left = left.sync();
let left = left.read();
let right = right.sync();
let right = right.read();
let mut different = false;
let pixels = left
.pixels()
.iter()
.zip(right.pixels())
.map(|(bitmap_pixel, other_pixel)| {
let bitmap_pixel = bitmap_pixel.to_un_multiplied_alpha();
let other_pixel = other_pixel.to_un_multiplied_alpha();
if bitmap_pixel == other_pixel {
Color::argb(0, 0, 0, 0)
} else if bitmap_pixel.with_alpha(0) != other_pixel.with_alpha(0) {
different = true;
Color::argb(
0xff,
bitmap_pixel.red().wrapping_sub(other_pixel.red()),
bitmap_pixel.green().wrapping_sub(other_pixel.green()),
bitmap_pixel.blue().wrapping_sub(other_pixel.blue()),
)
} else {
different = true;
let alpha = bitmap_pixel.alpha().wrapping_sub(other_pixel.alpha());
Color::argb(alpha, alpha, alpha, alpha)
}
})
.collect();
if different {
Some(BitmapData::new_with_pixels(
left.width(),
left.height(),
true,
pixels,
))
} else {
None
}
}