diff --git a/core/src/avm1/globals/bitmap_data.rs b/core/src/avm1/globals/bitmap_data.rs index 87f10ba5d..ac9024af6 100644 --- a/core/src/avm1/globals/bitmap_data.rs +++ b/core/src/avm1/globals/bitmap_data.rs @@ -789,6 +789,16 @@ pub fn copy_pixels<'gc>( if let Some(src_bitmap) = source_bitmap.as_bitmap_data_object() { if !src_bitmap.disposed() { + let merge_alpha = if args.len() >= 6 { + Some( + args.get(5) + .unwrap_or(&Value::Undefined) + .as_bool(activation.swf_version()), + ) + } else { + None + }; + // dealing with object aliasing... let src_bitmap_clone: BitmapData; // only initialized if source is the same object as self let src_bitmap_data_cell = src_bitmap.bitmap_data(); @@ -802,62 +812,53 @@ pub fn copy_pixels<'gc>( &src_bitmap_gc_ref }; - if args.len() >= 5 { - let alpha_point = args - .get(4) - .unwrap_or(&Value::Undefined) - .coerce_to_object(activation); + let alpha_bitmap = args + .get(3) + .unwrap_or(&Value::Undefined) + .coerce_to_object(activation); - let alpha_x = alpha_point - .get("x", activation)? - .coerce_to_f64(activation)? - as i32; + if let Some(alpha_bitmap) = alpha_bitmap.as_bitmap_data_object() { + if !alpha_bitmap.disposed() { + let alpha_point = args + .get(4) + .unwrap_or(&Value::Undefined) + .coerce_to_object(activation); - let alpha_y = alpha_point - .get("y", activation)? - .coerce_to_f64(activation)? - as i32; + let alpha_x = alpha_point + .get("x", activation)? + .coerce_to_f64(activation)? + as i32; - let alpha_bitmap = args - .get(3) - .unwrap_or(&Value::Undefined) - .coerce_to_object(activation); + let alpha_y = alpha_point + .get("y", activation)? + .coerce_to_f64(activation)? + as i32; - if let Some(alpha_bitmap) = alpha_bitmap.as_bitmap_data_object() { - if !alpha_bitmap.disposed() { - // dealing with aliasing the same way as for the source - let alpha_bitmap_clone: BitmapData; - let alpha_bitmap_data_cell = alpha_bitmap.bitmap_data(); - let alpha_bitmap_gc_ref; - let alpha_bitmap_ref = if GcCell::ptr_eq( - alpha_bitmap.bitmap_data(), - bitmap_data.bitmap_data(), - ) { - alpha_bitmap_clone = alpha_bitmap_data_cell.read().clone(); - &alpha_bitmap_clone - } else { - alpha_bitmap_gc_ref = alpha_bitmap_data_cell.read(); - &alpha_bitmap_gc_ref - }; + // dealing with aliasing the same way as for the source + let alpha_bitmap_clone: BitmapData; + let alpha_bitmap_data_cell = alpha_bitmap.bitmap_data(); + let alpha_bitmap_gc_ref; + let alpha_bitmap_ref = if GcCell::ptr_eq( + alpha_bitmap.bitmap_data(), + bitmap_data.bitmap_data(), + ) { + alpha_bitmap_clone = alpha_bitmap_data_cell.read().clone(); + &alpha_bitmap_clone + } else { + alpha_bitmap_gc_ref = alpha_bitmap_data_cell.read(); + &alpha_bitmap_gc_ref + }; - let merge_alpha = if args.len() >= 6 { - args.get(5) - .unwrap_or(&Value::Undefined) - .as_bool(activation.swf_version()) - } else { - true - }; - - bitmap_data - .bitmap_data() - .write(activation.context.gc_context) - .copy_pixels( - source_bitmap_ref, - (src_min_x, src_min_y, src_width, src_height), - (dest_x, dest_y), - Some((alpha_bitmap_ref, (alpha_x, alpha_y), merge_alpha)), - ); - } + bitmap_data + .bitmap_data() + .write(activation.context.gc_context) + .copy_pixels( + source_bitmap_ref, + (src_min_x, src_min_y, src_width, src_height), + (dest_x, dest_y), + Some((alpha_bitmap_ref, (alpha_x, alpha_y))), + merge_alpha.unwrap_or(true), + ); } } else { bitmap_data @@ -868,6 +869,9 @@ pub fn copy_pixels<'gc>( (src_min_x, src_min_y, src_width, src_height), (dest_x, dest_y), None, + // Despite what the docs claim, mergeAlpa appears to be treated as 'false' + // when no 'alphaBitmap' is specified (e.g. only 3 args are passed) + merge_alpha.unwrap_or(false), ); } } diff --git a/core/src/avm2/globals/flash/display/bitmapdata.rs b/core/src/avm2/globals/flash/display/bitmapdata.rs index a5d2981cb..3f1bc428c 100644 --- a/core/src/avm2/globals/flash/display/bitmapdata.rs +++ b/core/src/avm2/globals/flash/display/bitmapdata.rs @@ -254,18 +254,62 @@ pub fn copy_pixels<'gc>( &src_bitmap_gc_ref }; + let mut alpha_source = None; + if args.len() >= 4 { - log::warn!("BitmapData.copyPixels - alpha not implemented"); + if let Some(alpha_bitmap) = args + .get(3) + .and_then(|o| o.as_object()) + .and_then(|o| o.as_bitmap_data()) + { + // Testing shows that a null/undefined 'alphaPoint' parameter is treated + // as 'new Point(0, 0)' + let mut x = 0; + let mut y = 0; + + if let Ok(alpha_point) = args + .get(4) + .unwrap_or(&Value::Undefined) + .coerce_to_object(activation) + { + x = alpha_point + .get_property(&Multiname::public("x"), activation)? + .coerce_to_i32(activation)?; + y = alpha_point + .get_property(&Multiname::public("y"), activation)? + .coerce_to_i32(activation)?; + } + + alpha_source = Some((alpha_bitmap, (x, y))); + } } - bitmap_data - .write(activation.context.gc_context) - .copy_pixels( - source_bitmap_ref, - (src_min_x, src_min_y, src_width, src_height), - (dest_x, dest_y), - None, - ); + let merge_alpha = args + .get(5) + .unwrap_or(&Value::Bool(false)) + .coerce_to_boolean(); + + if let Some((alpha_bitmap, alpha_point)) = alpha_source { + bitmap_data + .write(activation.context.gc_context) + .copy_pixels( + source_bitmap_ref, + (src_min_x, src_min_y, src_width, src_height), + (dest_x, dest_y), + Some((&*alpha_bitmap.read(), alpha_point)), + merge_alpha, + ); + } else { + bitmap_data + .write(activation.context.gc_context) + .copy_pixels( + source_bitmap_ref, + (src_min_x, src_min_y, src_width, src_height), + (dest_x, dest_y), + None, + merge_alpha, + ); + } } } diff --git a/core/src/bitmap/bitmap_data.rs b/core/src/bitmap/bitmap_data.rs index 25052dde3..2a5296fd2 100644 --- a/core/src/bitmap/bitmap_data.rs +++ b/core/src/bitmap/bitmap_data.rs @@ -559,7 +559,8 @@ impl<'gc> BitmapData<'gc> { source_bitmap: &Self, src_rect: (i32, i32, i32, i32), dest_point: (i32, i32), - alpha_source: Option<(&Self, (i32, i32), bool)>, + alpha_source: Option<(&Self, (i32, i32))>, + merge_alpha: bool, ) { let (src_min_x, src_min_y, src_width, src_height) = src_rect; let (dest_min_x, dest_min_y) = dest_point; @@ -581,8 +582,7 @@ impl<'gc> BitmapData<'gc> { let mut dest_color = self.get_pixel_raw(dest_x as u32, dest_y as u32).unwrap(); - if let Some((alpha_bitmap, (alpha_min_x, alpha_min_y), merge_alpha)) = alpha_source - { + if let Some((alpha_bitmap, (alpha_min_x, alpha_min_y))) = alpha_source { let alpha_x = src_x - src_min_x + alpha_min_x; let alpha_y = src_y - src_min_y + alpha_min_y; @@ -627,11 +627,16 @@ impl<'gc> BitmapData<'gc> { intermediate_color }; } else { - dest_color = if source_bitmap.transparency && !self.transparency { - dest_color.blend_over(&source_color) - } else { - source_color - }; + dest_color = + if (source_bitmap.transparency && !self.transparency) || merge_alpha { + dest_color.blend_over(&source_color) + } else { + source_color + }; + + if !self.transparency { + dest_color = dest_color.with_alpha(0xFF) + } } self.set_pixel32_raw(dest_x as u32, dest_y as u32, dest_color); diff --git a/tests/tests/regression_tests.rs b/tests/tests/regression_tests.rs index d809dbf59..c080b7958 100644 --- a/tests/tests/regression_tests.rs +++ b/tests/tests/regression_tests.rs @@ -189,6 +189,7 @@ swf_tests! { (as3_astypelate, "avm2/astypelate", 1), (as3_bitand, "avm2/bitand", 1), (as3_bitmap_constr, "avm2/bitmap_constr", 1), + (as3_bitmapdata_copypixels, "avm2/bitmapdata_copypixels", 2, img = true), #[ignore] (as3_bitmap_properties, "avm2/bitmap_properties", 1), (as3_bitmap_timeline, "avm2/bitmap_timeline", 1), (as3_bitmapdata_constr, "avm2/bitmapdata_constr", 1), @@ -1328,6 +1329,7 @@ fn test_swf_approx( expected_captures.len(), "Differing numbers of regex captures" ); + // Each capture group (other than group 0, which is always the entire regex // match) represents a floating-point value for (actual_val, expected_val) in actual_captures diff --git a/tests/tests/swfs/avm1/bitmap_data_copypixels/BitmapCopyPixels.as b/tests/tests/swfs/avm1/bitmap_data_copypixels/BitmapCopyPixels.as index 8fc7bae40..807358876 100644 --- a/tests/tests/swfs/avm1/bitmap_data_copypixels/BitmapCopyPixels.as +++ b/tests/tests/swfs/avm1/bitmap_data_copypixels/BitmapCopyPixels.as @@ -1,7 +1,8 @@ -import flash.display.BitmapData; +import flash.display.BitmapData; import flash.geom.Rectangle; import flash.geom.Point; + class BitmapCopyPixels { static function plop(mc : MovieClip, sx : Number, sy : Number, @@ -27,7 +28,7 @@ class BitmapCopyPixels { src_img._x = sx + 110; src_img._y = sy + 20; - dest.copyPixels(src, new Rectangle(0,0,80,20), new Point(10, 10)); + dest.copyPixels(src, new Rectangle(0,0,80,20), new Point(10, 10)); var alpha:BitmapData = new BitmapData(40, 20, transp_alpha, 0x66884422); @@ -41,7 +42,71 @@ class BitmapCopyPixels { dest.copyPixels(src, new Rectangle(0,0,80,20), new Point(10, 50), alpha, new Point(0,0), merge); } - static function main(mc) { + public static function test(mc) { + // These values are straight alpha. + // BitmapData internally converts to premultiplied alpha, + // and converts back to straight alpha in 'getPixel'. This results + // in rounding, which Ruffle currently doesn't match. These values + // were chosen to produce the same rounded result in Flash and Ruffle. + // FIXME - determine the correct roudning behavior to use for Ruffle, + // and test that a 'getPixel/setPixel' round-trip always agrees between + // Flash and Ruffle. + var target = new BitmapData(5, 5, true, 0x45112233); + var source = new BitmapData(5, 5, true, 0x22445566); + var otherSource = new BitmapData(5, 5, true, 0x80aabbcc); + + target.copyPixels(source, new Rectangle(0, 0, 2, 2), new Point(0, 0), null, null, true); + target.copyPixels(otherSource, new Rectangle(0, 0, 1, 1), new Point(4, 4), null, null, false); + for (var py = 0; py < target.height; py++) { + var line = ""; + for (var px = 0; px < target.height; px++) { + line += target.getPixel32(px, py).toString(16) + " "; + } + trace(line); + } + + + var transparent = new BitmapData(1, 1, false, 0x80FFFFFF); + var nonTransparent = new BitmapData(1, 1, false, 0x0); + var transparentSource = new BitmapData(1, 1, true, 0xF00E0E0E); + + trace("transparentSource: " + transparentSource.getPixel32(0, 0).toString(16)); + + trace("Non-transparent testing"); + + var nonTransparentSource = new BitmapData(1, 1, false, 0x80020406); + trace("Original pixel: " + nonTransparent.getPixel32(0, 0).toString(16)); + + nonTransparent.copyPixels(transparentSource, new Rectangle(0, 0, 1, 1), new Point(0, 0), null, null, false); + trace("transparent source mergeAlpha=false " + nonTransparent.getPixel32(0, 0).toString(16)); + + nonTransparent.copyPixels(transparentSource, new Rectangle(0, 0, 1, 1), new Point(0, 0), null, null, true); + trace("transparent source mergeAlpha=true " + nonTransparent.getPixel32(0, 0).toString(16)); + + nonTransparent.copyPixels(nonTransparentSource, new Rectangle(0, 0, 1, 1), new Point(0, 0), null, null, false); + trace("nontransparent source mergeAlpha=false " + nonTransparent.getPixel32(0, 0).toString(16)); + + nonTransparent.copyPixels(nonTransparentSource, new Rectangle(0, 0, 1, 1), new Point(0, 0), null, null, true); + trace("nontransparent source mergeAlpha=true " + nonTransparent.getPixel32(0, 0).toString(16)); + + trace(""); + trace("Transparent testing"); + trace("Original pixel: " + transparent.getPixel32(0, 0).toString(16)); + + // FIXME - enable these when Ruffle rounding is correct + + //transparent.copyPixels(transparentSource, new Rectangle(0, 0, 1, 1), new Point(0, 0), null, null, false); + //trace("transparent source mergeAlpha=false " + transparent.getPixel32(0, 0).toString(16)); + + //transparent.copyPixels(transparentSource, new Rectangle(0, 0, 1, 1), new Point(0, 0), null, null, true); + //trace("transparent source mergeAlpha=true " + transparent.getPixel32(0, 0).toString(16)); + + transparent.copyPixels(nonTransparentSource, new Rectangle(0, 0, 1, 1), new Point(0, 0), null, null, false); + trace("nontransparent source mergeAlpha=false " + transparent.getPixel32(0, 0).toString(16)); + + transparent.copyPixels(nonTransparentSource, new Rectangle(0, 0, 1, 1), new Point(0, 0), null, null, true); + trace("nontransparent source mergeAlpha=true " + transparent.getPixel32(0, 0).toString(16)); + BitmapCopyPixels.plop(mc, 10, 20, true, true, true , false); BitmapCopyPixels.plop(mc, 210, 20, true, true, false , false); BitmapCopyPixels.plop(mc, 410, 20, true, false, true , false); @@ -63,4 +128,4 @@ class BitmapCopyPixels { BitmapCopyPixels.plop(mc, 410, 720, false, false, true , true); BitmapCopyPixels.plop(mc, 610, 720, false, false, false , true); } -} \ No newline at end of file +} diff --git a/tests/tests/swfs/avm1/bitmap_data_copypixels/expected-linux-Vulkan.png b/tests/tests/swfs/avm1/bitmap_data_copypixels/expected-linux-Vulkan.png index 559700172..fe590b2a3 100644 Binary files a/tests/tests/swfs/avm1/bitmap_data_copypixels/expected-linux-Vulkan.png and b/tests/tests/swfs/avm1/bitmap_data_copypixels/expected-linux-Vulkan.png differ diff --git a/tests/tests/swfs/avm1/bitmap_data_copypixels/expected-windows-Dx12.png b/tests/tests/swfs/avm1/bitmap_data_copypixels/expected-windows-Dx12.png index 559700172..fe590b2a3 100644 Binary files a/tests/tests/swfs/avm1/bitmap_data_copypixels/expected-windows-Dx12.png and b/tests/tests/swfs/avm1/bitmap_data_copypixels/expected-windows-Dx12.png differ diff --git a/tests/tests/swfs/avm1/bitmap_data_copypixels/output.txt b/tests/tests/swfs/avm1/bitmap_data_copypixels/output.txt index e69de29bb..9ef9fb674 100644 --- a/tests/tests/swfs/avm1/bitmap_data_copypixels/output.txt +++ b/tests/tests/swfs/avm1/bitmap_data_copypixels/output.txt @@ -0,0 +1,17 @@ +5d243147 5d243147 45122134 45122134 45122134 +5d243147 5d243147 45122134 45122134 45122134 +45122134 45122134 45122134 45122134 45122134 +45122134 45122134 45122134 45122134 45122134 +45122134 45122134 45122134 45122134 -7f564435 +transparentSource: -ff1f1f2 +Non-transparent testing +Original pixel: -1000000 +transparent source mergeAlpha=false -f2f2f3 +transparent source mergeAlpha=true -f2f2f3 +nontransparent source mergeAlpha=false -fdfbfa +nontransparent source mergeAlpha=true -fdfbfa + +Transparent testing +Original pixel: -1 +nontransparent source mergeAlpha=false -fdfbfa +nontransparent source mergeAlpha=true -fdfbfa diff --git a/tests/tests/swfs/avm1/bitmap_data_copypixels/test.fla b/tests/tests/swfs/avm1/bitmap_data_copypixels/test.fla new file mode 100644 index 000000000..cce78b8c0 Binary files /dev/null and b/tests/tests/swfs/avm1/bitmap_data_copypixels/test.fla differ diff --git a/tests/tests/swfs/avm1/bitmap_data_copypixels/test.swf b/tests/tests/swfs/avm1/bitmap_data_copypixels/test.swf index d3634c80a..75eb93cb4 100644 Binary files a/tests/tests/swfs/avm1/bitmap_data_copypixels/test.swf and b/tests/tests/swfs/avm1/bitmap_data_copypixels/test.swf differ diff --git a/tests/tests/swfs/avm2/bitmapdata_copypixels/Test.as b/tests/tests/swfs/avm2/bitmapdata_copypixels/Test.as new file mode 100644 index 000000000..027bb178d --- /dev/null +++ b/tests/tests/swfs/avm2/bitmapdata_copypixels/Test.as @@ -0,0 +1,150 @@ +package { + import flash.display.BitmapData; + import flash.geom.Rectangle; + import flash.geom.Point; + import flash.display.Bitmap; + import flash.display.Stage; + + public class Test { + public function Test(stage: Stage) { + // These values are straight alpha. + // BitmapData internally converts to premultiplied alpha, + // and converts back to straight alpha in 'getPixel'. This results + // in rounding, which Ruffle currently doesn't match. These values + // were chosen to produce the same rounded result in Flash and Ruffle. + // FIXME - determine the correct roudning behavior to use for Ruffle, + // and test that a 'getPixel/setPixel' round-trip always agrees between + // Flash and Ruffle. + var target = new BitmapData(5, 5, true, 0x45112233); + var source = new BitmapData(5, 5, true, 0x22445566); + var otherSource = new BitmapData(5, 5, true, 0x80aabbcc); + + target.copyPixels(source, new Rectangle(0, 0, 2, 2), new Point(0, 0), null, null, true); + target.copyPixels(otherSource, new Rectangle(0, 0, 1, 1), new Point(4, 4), null, null, false); + + printImage(target); + + + var transparent = new BitmapData(1, 1, false, 0x80FFFFFF); + var nonTransparent = new BitmapData(1, 1, false, 0x0); + var transparentSource = new BitmapData(1, 1, true, 0xF00E0E0E); + + trace("transparentSource: " + transparentSource.getPixel32(0, 0).toString(16)); + + trace("Non-transparent testing"); + + var nonTransparentSource = new BitmapData(1, 1, false, 0x80020406); + trace("Original pixel: " + nonTransparent.getPixel32(0, 0).toString(16)); + + nonTransparent.copyPixels(transparentSource, new Rectangle(0, 0, 1, 1), new Point(0, 0), null, null, false); + trace("transparent source mergeAlpha=false " + nonTransparent.getPixel32(0, 0).toString(16)); + + nonTransparent.copyPixels(transparentSource, new Rectangle(0, 0, 1, 1), new Point(0, 0), null, null, true); + trace("transparent source mergeAlpha=true " + nonTransparent.getPixel32(0, 0).toString(16)); + + nonTransparent.copyPixels(nonTransparentSource, new Rectangle(0, 0, 1, 1), new Point(0, 0), null, null, false); + trace("nontransparent source mergeAlpha=false " + nonTransparent.getPixel32(0, 0).toString(16)); + + nonTransparent.copyPixels(nonTransparentSource, new Rectangle(0, 0, 1, 1), new Point(0, 0), null, null, true); + trace("nontransparent source mergeAlpha=true " + nonTransparent.getPixel32(0, 0).toString(16)); + + trace(); + trace("Transparent testing"); + trace("Original pixel: " + transparent.getPixel32(0, 0).toString(16)); + + // FIXME - enable these when Ruffle rounding is correct + + //transparent.copyPixels(transparentSource, new Rectangle(0, 0, 1, 1), new Point(0, 0), null, null, false); + //trace("transparent source mergeAlpha=false " + transparent.getPixel32(0, 0).toString(16)); + + //transparent.copyPixels(transparentSource, new Rectangle(0, 0, 1, 1), new Point(0, 0), null, null, true); + //trace("transparent source mergeAlpha=true " + transparent.getPixel32(0, 0).toString(16)); + + transparent.copyPixels(nonTransparentSource, new Rectangle(0, 0, 1, 1), new Point(0, 0), null, null, false); + trace("nontransparent source mergeAlpha=false " + transparent.getPixel32(0, 0).toString(16)); + + transparent.copyPixels(nonTransparentSource, new Rectangle(0, 0, 1, 1), new Point(0, 0), null, null, true); + trace("nontransparent source mergeAlpha=true " + transparent.getPixel32(0, 0).toString(16)); + + plop(stage, 10, 20, true, true, true , false); + plop(stage, 210, 20, true, true, false , false); + plop(stage, 410, 20, true, false, true , false); + plop(stage, 610, 20, true, false, false , false); + + plop(stage, 10, 220, false, true, true , false); + plop(stage, 210, 220, false, true, false , false); + plop(stage, 410, 220, false, false, true , false); + plop(stage, 610, 220, false, false, false , false); + + + plop(stage, 10, 520, true, true, true , true); + plop(stage, 210, 520, true, true, false , true); + plop(stage, 410, 520, true, false, true , true); + plop(stage, 610, 520, true, false, false , true); + + plop(stage, 10, 720, false, true, true , true); + plop(stage, 210, 720, false, true, false , true); + plop(stage, 410, 720, false, false, true , true); + plop(stage, 610, 720, false, false, false , true); + + var weirdDest = new BitmapData(5, 5, true, 0); + var weirdSource = new BitmapData(5, 5, false, 0x800000); + var weirdAlphaSource = new BitmapData(5, 5, true, 0xff112233); + weirdAlphaSource.fillRect(new Rectangle(3, 3, 2, 2), 0xaabbccdd); + + trace("Copy with alphaPoint=undefined:"); + + // Specifying an alphaPoint of 'undefined' should use 'new Point(0, 0)'' + weirdDest.copyPixels(weirdSource, new Rectangle(0, 0, 2, 2), new Point(0, 0), weirdAlphaSource, undefined, true); + printImage(weirdDest); + } + + static function printImage(target:BitmapData) { + for (var py = 0; py < target.height; py++) { + var line = ""; + for (var px = 0; px < target.height; px++) { + line += target.getPixel32(px, py).toString(16) + " "; + } + trace(line); + } + } + + static function plop(stage: Stage, sx : Number, sy : Number, + transp_src : Boolean, transp_dest : Boolean, transp_alpha : Boolean, + merge: Boolean) { + + var dest:BitmapData = new BitmapData(100, 100, transp_dest, 0xBBFF0000); + dest.fillRect(new Rectangle(20,10, 20, 80), 0x8888FF00); + dest.fillRect(new Rectangle(50,10, 20, 80), 0x220088FF); + + var dest_img = new Bitmap(dest); + + dest_img.x = sx; + dest_img.y = sy; + + + var src:BitmapData = new BitmapData(80, 20, transp_src, 0x44888888); + var src_img = new Bitmap(src); + src.fillRect(new Rectangle(5, 5, 10, 10), 0xAA2288DD); + + src_img.x = sx + 110; + src_img.y = sy + 20; + + dest.copyPixels(src, new Rectangle(0,0,80,20), new Point(10, 10)); + + + var alpha:BitmapData = new BitmapData(40, 20, transp_alpha, 0x66884422); + var alpha_img = new Bitmap(alpha); + alpha.fillRect(new Rectangle(4, 8, 12, 30), 0xEE8844DD); + + alpha_img.x = sx + 110; + alpha_img.y = sy + 60; + + dest.copyPixels(src, new Rectangle(0,0,80,20), new Point(10, 50), alpha, new Point(0,0), merge); + + stage.addChild(dest_img); + stage.addChild(src_img); + stage.addChild(alpha_img); + } + } +} diff --git a/tests/tests/swfs/avm1/bitmap_data_copypixels/actual-linux-Vulkan.png b/tests/tests/swfs/avm2/bitmapdata_copypixels/expected-linux-Vulkan.png similarity index 100% rename from tests/tests/swfs/avm1/bitmap_data_copypixels/actual-linux-Vulkan.png rename to tests/tests/swfs/avm2/bitmapdata_copypixels/expected-linux-Vulkan.png diff --git a/tests/tests/swfs/avm2/bitmapdata_copypixels/expected-windows-Dx12.png b/tests/tests/swfs/avm2/bitmapdata_copypixels/expected-windows-Dx12.png new file mode 100644 index 000000000..fe590b2a3 Binary files /dev/null and b/tests/tests/swfs/avm2/bitmapdata_copypixels/expected-windows-Dx12.png differ diff --git a/tests/tests/swfs/avm2/bitmapdata_copypixels/output.txt b/tests/tests/swfs/avm2/bitmapdata_copypixels/output.txt new file mode 100644 index 000000000..56c9c7d3c --- /dev/null +++ b/tests/tests/swfs/avm2/bitmapdata_copypixels/output.txt @@ -0,0 +1,23 @@ +5d243147 5d243147 45122134 45122134 45122134 +5d243147 5d243147 45122134 45122134 45122134 +45122134 45122134 45122134 45122134 45122134 +45122134 45122134 45122134 45122134 45122134 +45122134 45122134 45122134 45122134 80a9bbcb +transparentSource: f00e0e0e +Non-transparent testing +Original pixel: ff000000 +transparent source mergeAlpha=false ff0d0d0d +transparent source mergeAlpha=true ff0d0d0d +nontransparent source mergeAlpha=false ff020406 +nontransparent source mergeAlpha=true ff020406 + +Transparent testing +Original pixel: ffffffff +nontransparent source mergeAlpha=false ff020406 +nontransparent source mergeAlpha=true ff020406 +Copy with alphaPoint=undefined: +ff800000 ff800000 0 0 0 +ff800000 ff800000 0 0 0 +0 0 0 0 0 +0 0 0 0 0 +0 0 0 0 0 diff --git a/tests/tests/swfs/avm2/bitmapdata_copypixels/test.fla b/tests/tests/swfs/avm2/bitmapdata_copypixels/test.fla new file mode 100644 index 000000000..fe905b371 Binary files /dev/null and b/tests/tests/swfs/avm2/bitmapdata_copypixels/test.fla differ diff --git a/tests/tests/swfs/avm2/bitmapdata_copypixels/test.swf b/tests/tests/swfs/avm2/bitmapdata_copypixels/test.swf new file mode 100644 index 000000000..53ae8ce2b Binary files /dev/null and b/tests/tests/swfs/avm2/bitmapdata_copypixels/test.swf differ