diff --git a/core/src/avm1/globals/bitmap_data.rs b/core/src/avm1/globals/bitmap_data.rs index f2c1c7d2928ef..62872fbaa6666 100644 --- a/core/src/avm1/globals/bitmap_data.rs +++ b/core/src/avm1/globals/bitmap_data.rs @@ -577,6 +577,7 @@ fn draw<'gc>( Transform { matrix, color_transform, + tz: 0.0, }, smoothing, blend_mode, diff --git a/core/src/avm2/globals/flash/display/display_object.rs b/core/src/avm2/globals/flash/display/display_object.rs index 0ade10498bdcb..94f2aac356581 100644 --- a/core/src/avm2/globals/flash/display/display_object.rs +++ b/core/src/avm2/globals/flash/display/display_object.rs @@ -412,20 +412,30 @@ pub fn set_y<'gc>( } pub fn get_z<'gc>( - activation: &mut Activation<'_, 'gc>, - _this: Value<'gc>, + _activation: &mut Activation<'_, 'gc>, + this: Value<'gc>, _args: &[Value<'gc>], ) -> Result, Error<'gc>> { - avm2_stub_getter!(activation, "flash.display.DisplayObject", "z"); - Ok(0.into()) + let this = this.as_object().unwrap(); + + if let Some(dobj) = this.as_display_object() { + return Ok(dobj.z().into()); + } + Ok(Value::Undefined) } pub fn set_z<'gc>( activation: &mut Activation<'_, 'gc>, - _this: Value<'gc>, - _args: &[Value<'gc>], + this: Value<'gc>, + args: &[Value<'gc>], ) -> Result, Error<'gc>> { - avm2_stub_setter!(activation, "flash.display.DisplayObject", "z"); + let this = this.as_object().unwrap(); + + if let Some(dobj) = this.as_display_object() { + let z = args.get_f64(activation, 0)?; + dobj.set_z(activation.gc(), z); + dobj.base_mut(activation.gc()).set_has_matrix3d_stub(true); + } Ok(Value::Undefined) } diff --git a/core/src/avm2/globals/flash/geom/transform.rs b/core/src/avm2/globals/flash/geom/transform.rs index 21e36f213da7d..e9f597e9f5519 100644 --- a/core/src/avm2/globals/flash/geom/transform.rs +++ b/core/src/avm2/globals/flash/geom/transform.rs @@ -339,7 +339,8 @@ pub fn get_matrix_3d<'gc>( let display_object = get_display_object(this); if display_object.base().has_matrix3d_stub() { let matrix = *get_display_object(this).base().matrix(); - let matrix3d = Matrix3D::from(matrix); + let mut matrix3d = Matrix3D::from(matrix); + matrix3d.set_tz(display_object.z()); matrix3d_to_object(matrix3d, activation) } else { Ok(Value::Null) @@ -359,17 +360,19 @@ pub fn set_matrix_3d<'gc>( let display_object = get_display_object(this); - let (matrix, has_matrix3d) = { + let (matrix, has_matrix3d, tz) = { match args.try_get_object(activation, 0) { Some(obj) => { let matrix3d = object_to_matrix3d(obj, activation)?; let matrix = Matrix::from(matrix3d); - (matrix, true) + let tz = matrix3d.tz(); + (matrix, true, tz) } - None => (Matrix::IDENTITY, false), + None => (Matrix::IDENTITY, false, 0.0), } }; + display_object.base_mut(activation.gc()).set_matrix_tz(tz); display_object.set_matrix(activation.gc(), matrix); if let Some(parent) = display_object.parent() { // Self-transform changes are automatically handled, diff --git a/core/src/display_object.rs b/core/src/display_object.rs index 7019148ece55c..51a308ba802bb 100644 --- a/core/src/display_object.rs +++ b/core/src/display_object.rs @@ -336,6 +336,14 @@ impl<'gc> DisplayObjectBase<'gc> { &mut self.transform.matrix } + pub fn matrix_tz(&mut self) -> f64 { + self.transform.tz + } + + pub fn set_matrix_tz(&mut self, tz: f64) { + self.transform.tz = tz; + } + pub fn set_matrix(&mut self, matrix: Matrix) { self.transform.matrix = matrix; self.set_scale_rotation_cached(false); @@ -375,6 +383,17 @@ impl<'gc> DisplayObjectBase<'gc> { changed } + fn z(&self) -> f64 { + self.transform.tz + } + + fn set_z(&mut self, tz: f64) -> bool { + let changed = self.matrix_tz() != tz; + self.set_transformed_by_script(true); + self.set_matrix_tz(tz); + changed + } + /// Caches the scale and rotation factors for this display object, if necessary. /// Calculating these requires heavy trig ops, so we only do it when `_xscale`, `_yscale` or /// `_rotation` is accessed. @@ -941,6 +960,7 @@ pub fn render_base<'gc>(this: DisplayObject<'gc>, context: &mut RenderContext<'_ ty: -offset_y, ..cache_info.base_transform.matrix }, + tz: 0.0, }); let mut offscreen_context = RenderContext { renderer: context.renderer, @@ -973,6 +993,7 @@ pub fn render_base<'gc>(this: DisplayObject<'gc>, context: &mut RenderContext<'_ ..Default::default() }, color_transform: cache_info.base_transform.color_transform, + tz: context.transform_stack.transform().tz, }, true, PixelSnapping::Always, // cacheAsBitmap forces pixel snapping @@ -1045,6 +1066,7 @@ pub fn apply_standard_mask_and_scroll<'gc, F>( context.transform_stack.push(&Transform { matrix: Matrix::translate(-rect.x_min, -rect.y_min), color_transform: Default::default(), + tz: 0.0, }); } @@ -1373,6 +1395,25 @@ pub trait TDisplayObject<'gc>: } } + /// The `z` position in pixels of this display object in local space. + /// Returned by the `_z`/`z` ActionScript properties. + fn z(&self) -> f64 { + self.base().z() + } + + /// Sets the `z` position of this display object in local space. + /// Set by the `_z`/`z` ActionScript properties. + /// This invalidates any ancestors cacheAsBitmap automatically. + fn set_z(&self, gc_context: &Mutation<'gc>, z: f64) { + if self.base_mut(gc_context).set_z(z) { + if let Some(parent) = self.parent() { + // Self-transform changes are automatically handled, + // we only want to inform ancestors to avoid unnecessary invalidations for tx/ty + parent.invalidate_cached_bitmap(gc_context); + } + } + } + /// The rotation in degrees this display object in local space. /// Returned by the `_rotation`/`rotation` ActionScript properties. fn rotation(&self, gc_context: &Mutation<'gc>) -> Degrees { diff --git a/core/src/display_object/edit_text.rs b/core/src/display_object/edit_text.rs index 499da572f318d..c2c608269ddf5 100644 --- a/core/src/display_object/edit_text.rs +++ b/core/src/display_object/edit_text.rs @@ -1255,6 +1255,7 @@ impl<'gc> EditText<'gc> { context.transform_stack.push(&Transform { matrix: transform.matrix, color_transform: ColorTransform::IDENTITY, + tz: 0.0, }); } else { context.transform_stack.push(transform); diff --git a/core/src/display_object/stage.rs b/core/src/display_object/stage.rs index b109974c9c883..e411542ec441a 100644 --- a/core/src/display_object/stage.rs +++ b/core/src/display_object/stage.rs @@ -834,6 +834,7 @@ impl<'gc> TDisplayObject<'gc> for Stage<'gc> { context.transform_stack.push(&Transform { matrix: self.0.read().viewport_matrix, color_transform: Default::default(), + tz: 0.0, }); // All of our Stage3D instances get rendered *underneath* the main stage. diff --git a/render/src/matrix3d.rs b/render/src/matrix3d.rs index 862f8d742fbb2..bd8801a23b5df 100644 --- a/render/src/matrix3d.rs +++ b/render/src/matrix3d.rs @@ -48,3 +48,37 @@ impl From for Matrix { } } } + +impl Matrix3D { + pub const ZERO: Self = Self { + raw_data: [0.0; 16], + }; + pub const IDENTITY: Self = Self { + raw_data: [ + 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, + ], + }; + + pub fn tz(&self) -> f64 { + self.raw_data[14] + } + pub fn set_tz(&mut self, tz: f64) { + self.raw_data[14] = tz; + } +} + +impl std::ops::Mul for Matrix3D { + type Output = Self; + + fn mul(self, rhs: Self) -> Self::Output { + let mut res = Matrix3D::ZERO; + for i in 0..4 { + for j in 0..4 { + for k in 0..4 { + res.raw_data[i + 4 * j] += self.raw_data[i + 4 * k] * rhs.raw_data[k + 4 * j]; + } + } + } + res + } +} diff --git a/render/src/transform.rs b/render/src/transform.rs index 47fb749bd016c..8b89cc191fed1 100644 --- a/render/src/transform.rs +++ b/render/src/transform.rs @@ -6,6 +6,7 @@ use swf::ColorTransform; #[derive(Clone, Debug, Default)] pub struct Transform { pub matrix: Matrix, + pub tz: f64, pub color_transform: ColorTransform, } @@ -20,9 +21,11 @@ impl TransformStack { let cur_transform = self.transform(); let matrix = cur_transform.matrix * transform.matrix; let color_transform = cur_transform.color_transform * transform.color_transform; + let tz = cur_transform.tz + transform.tz; self.0.push(Transform { matrix, color_transform, + tz, }); } diff --git a/render/wgpu/shaders/blend/alpha.wgsl b/render/wgpu/shaders/blend/alpha.wgsl index 6da3470e4579e..29b8434f81ee1 100644 --- a/render/wgpu/shaders/blend/alpha.wgsl +++ b/render/wgpu/shaders/blend/alpha.wgsl @@ -12,8 +12,8 @@ struct VertexOutput { @vertex fn main_vertex(in: common__VertexInput) -> VertexOutput { - let pos = common__globals.view_matrix * transforms.world_matrix * vec4(in.position.x, in.position.y, 1.0, 1.0); - let uv = vec2((pos.x + 1.0) / 2.0, -((pos.y - 1.0) / 2.0)); + let pos = common__globals.view_matrix * transforms.world_matrix * vec4(in.position.x, in.position.y, 0.0, 1.0); + let uv = vec2(in.position.xy); return VertexOutput(pos, uv); } diff --git a/render/wgpu/shaders/blend/darken.wgsl b/render/wgpu/shaders/blend/darken.wgsl index d28787ec63467..af4163a11e69f 100644 --- a/render/wgpu/shaders/blend/darken.wgsl +++ b/render/wgpu/shaders/blend/darken.wgsl @@ -12,8 +12,8 @@ struct VertexOutput { @vertex fn main_vertex(in: common__VertexInput) -> VertexOutput { - let pos = common__globals.view_matrix * transforms.world_matrix * vec4(in.position.x, in.position.y, 1.0, 1.0); - let uv = vec2((pos.x + 1.0) / 2.0, -((pos.y - 1.0) / 2.0)); + let pos = common__globals.view_matrix * transforms.world_matrix * vec4(in.position.x, in.position.y, 0.0, 1.0); + let uv = vec2(in.position.xy); return VertexOutput(pos, uv); } diff --git a/render/wgpu/shaders/blend/difference.wgsl b/render/wgpu/shaders/blend/difference.wgsl index 5aea5b4921266..d174ae818c8d5 100644 --- a/render/wgpu/shaders/blend/difference.wgsl +++ b/render/wgpu/shaders/blend/difference.wgsl @@ -12,8 +12,8 @@ struct VertexOutput { @vertex fn main_vertex(in: common__VertexInput) -> VertexOutput { - let pos = common__globals.view_matrix * transforms.world_matrix * vec4(in.position.x, in.position.y, 1.0, 1.0); - let uv = vec2((pos.x + 1.0) / 2.0, -((pos.y - 1.0) / 2.0)); + let pos = common__globals.view_matrix * transforms.world_matrix * vec4(in.position.x, in.position.y, 0.0, 1.0); + let uv = vec2(in.position.xy); return VertexOutput(pos, uv); } diff --git a/render/wgpu/shaders/blend/erase.wgsl b/render/wgpu/shaders/blend/erase.wgsl index bed157c8b09c7..c476b63ff1bea 100644 --- a/render/wgpu/shaders/blend/erase.wgsl +++ b/render/wgpu/shaders/blend/erase.wgsl @@ -12,8 +12,8 @@ struct VertexOutput { @vertex fn main_vertex(in: common__VertexInput) -> VertexOutput { - let pos = common__globals.view_matrix * transforms.world_matrix * vec4(in.position.x, in.position.y, 1.0, 1.0); - let uv = vec2((pos.x + 1.0) / 2.0, -((pos.y - 1.0) / 2.0)); + let pos = common__globals.view_matrix * transforms.world_matrix * vec4(in.position.x, in.position.y, 0.0, 1.0); + let uv = vec2(in.position.xy); return VertexOutput(pos, uv); } diff --git a/render/wgpu/shaders/blend/hardlight.wgsl b/render/wgpu/shaders/blend/hardlight.wgsl index 3312cb03d7685..babd9778559f4 100644 --- a/render/wgpu/shaders/blend/hardlight.wgsl +++ b/render/wgpu/shaders/blend/hardlight.wgsl @@ -12,8 +12,8 @@ struct VertexOutput { @vertex fn main_vertex(in: common__VertexInput) -> VertexOutput { - let pos = common__globals.view_matrix * transforms.world_matrix * vec4(in.position.x, in.position.y, 1.0, 1.0); - let uv = vec2((pos.x + 1.0) / 2.0, -((pos.y - 1.0) / 2.0)); + let pos = common__globals.view_matrix * transforms.world_matrix * vec4(in.position.x, in.position.y, 0.0, 1.0); + let uv = vec2(in.position.xy); return VertexOutput(pos, uv); } diff --git a/render/wgpu/shaders/blend/invert.wgsl b/render/wgpu/shaders/blend/invert.wgsl index 06e2093c875c2..45046d4fd55ef 100644 --- a/render/wgpu/shaders/blend/invert.wgsl +++ b/render/wgpu/shaders/blend/invert.wgsl @@ -12,8 +12,8 @@ struct VertexOutput { @vertex fn main_vertex(in: common__VertexInput) -> VertexOutput { - let pos = common__globals.view_matrix * transforms.world_matrix * vec4(in.position.x, in.position.y, 1.0, 1.0); - let uv = vec2((pos.x + 1.0) / 2.0, -((pos.y - 1.0) / 2.0)); + let pos = common__globals.view_matrix * transforms.world_matrix * vec4(in.position.x, in.position.y, 0.0, 1.0); + let uv = vec2(in.position.xy); return VertexOutput(pos, uv); } diff --git a/render/wgpu/shaders/blend/lighten.wgsl b/render/wgpu/shaders/blend/lighten.wgsl index 83d24fb42fe55..b7dcf43001cd1 100644 --- a/render/wgpu/shaders/blend/lighten.wgsl +++ b/render/wgpu/shaders/blend/lighten.wgsl @@ -12,8 +12,8 @@ struct VertexOutput { @vertex fn main_vertex(in: common__VertexInput) -> VertexOutput { - let pos = common__globals.view_matrix * transforms.world_matrix * vec4(in.position.x, in.position.y, 1.0, 1.0); - let uv = vec2((pos.x + 1.0) / 2.0, -((pos.y - 1.0) / 2.0)); + let pos = common__globals.view_matrix * transforms.world_matrix * vec4(in.position.x, in.position.y, 0.0, 1.0); + let uv = vec2(in.position.xy); return VertexOutput(pos, uv); } diff --git a/render/wgpu/shaders/blend/multiply.wgsl b/render/wgpu/shaders/blend/multiply.wgsl index 186409701ac99..d83cd084b5148 100644 --- a/render/wgpu/shaders/blend/multiply.wgsl +++ b/render/wgpu/shaders/blend/multiply.wgsl @@ -12,8 +12,8 @@ struct VertexOutput { @vertex fn main_vertex(in: common__VertexInput) -> VertexOutput { - let pos = common__globals.view_matrix * transforms.world_matrix * vec4(in.position.x, in.position.y, 1.0, 1.0); - let uv = vec2((pos.x + 1.0) / 2.0, -((pos.y - 1.0) / 2.0)); + let pos = common__globals.view_matrix * transforms.world_matrix * vec4(in.position.x, in.position.y, 0.0, 1.0); + let uv = vec2(in.position.xy); return VertexOutput(pos, uv); } diff --git a/render/wgpu/shaders/blend/overlay.wgsl b/render/wgpu/shaders/blend/overlay.wgsl index 0a938f1192b54..9d330b18eba8c 100644 --- a/render/wgpu/shaders/blend/overlay.wgsl +++ b/render/wgpu/shaders/blend/overlay.wgsl @@ -12,8 +12,8 @@ struct VertexOutput { @vertex fn main_vertex(in: common__VertexInput) -> VertexOutput { - let pos = common__globals.view_matrix * transforms.world_matrix * vec4(in.position.x, in.position.y, 1.0, 1.0); - let uv = vec2((pos.x + 1.0) / 2.0, -((pos.y - 1.0) / 2.0)); + let pos = common__globals.view_matrix * transforms.world_matrix * vec4(in.position.x, in.position.y, 0.0, 1.0); + let uv = vec2(in.position.xy); return VertexOutput(pos, uv); } diff --git a/render/wgpu/src/globals.rs b/render/wgpu/src/globals.rs index c3b22332fcb41..973f11a3688b3 100644 --- a/render/wgpu/src/globals.rs +++ b/render/wgpu/src/globals.rs @@ -1,5 +1,6 @@ //use super::utils::create_debug_label; use bytemuck::{Pod, Zeroable}; +use ruffle_render::matrix3d::Matrix3D; use wgpu::util::DeviceExt; #[derive(Debug)] @@ -21,16 +22,82 @@ impl Globals { viewport_width: u32, viewport_height: u32, ) -> Self { + let view_matrix = Matrix3D { + raw_data: [ + 1.0 / (viewport_width as f64 / 2.0), + 0.0, + 0.0, + 0.0, + 0.0, + -1.0 / (viewport_height as f64 / 2.0), + 0.0, + 0.0, + 0.0, + 0.0, + 1.0 / (viewport_width as f64 / 2.0), + 0.0, + -1.0, + 1.0, + 0.0, + 1.0, + ], + }; + + let projection_matrix = { + // TODO: Here, just the fixed default value is used. + // This should support variable values derived for each display object. + let field_of_view = 55.0; + + let focal_length = { + let deg2rad = f64::acos(-1.0) / 180.0; + let rad = field_of_view / 2.0 * deg2rad; + f64::cos(rad) / f64::sin(rad) + }; + + let perspective_projection = { + let mut m = Matrix3D::IDENTITY; + m.raw_data[0] = focal_length; + m.raw_data[5] = focal_length; + m.raw_data[10] = focal_length; + m.raw_data[11] = 1.0; + m.raw_data[14] = 0.0; + m.raw_data[15] = 0.0; + m + }; + let move_coord = { + // AS3 places Viewpoint at (0, 0, -focalLength). + + let mut m = Matrix3D::IDENTITY; + m.raw_data[14] = focal_length; + // TODO: Consider PerspectiveProjection.projectionCenter. + m + }; + let move_coord_back = { + let mut m = Matrix3D::IDENTITY; + m.raw_data[10] = 0.0; + // TODO: Consider PerspectiveProjection.projectionCenter. + m + }; + move_coord_back * perspective_projection * move_coord + }; + + let matrix = projection_matrix * view_matrix; + let matrix = { + let mut m = [[0.0; 4]; 4]; + #[allow(clippy::needless_range_loop)] + for i in 0..4 { + for j in 0..4 { + m[j][i] = matrix.raw_data[i + 4 * j] as f32; + } + } + m + }; + let temp_label = create_debug_label!("Globals buffer"); let buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor { label: temp_label.as_deref(), contents: bytemuck::cast_slice(&[GlobalsUniform { - view_matrix: [ - [1.0 / (viewport_width as f32 / 2.0), 0.0, 0.0, 0.0], - [0.0, -1.0 / (viewport_height as f32 / 2.0), 0.0, 0.0], - [0.0, 0.0, 1.0, 0.0], - [-1.0, 1.0, 0.0, 1.0], - ], + view_matrix: matrix, }]), usage: wgpu::BufferUsages::UNIFORM, }); diff --git a/render/wgpu/src/surface/commands.rs b/render/wgpu/src/surface/commands.rs index 1dab0515a7b6c..636b7dc4e8e0c 100644 --- a/render/wgpu/src/surface/commands.rs +++ b/render/wgpu/src/surface/commands.rs @@ -564,6 +564,7 @@ impl<'a> WgpuCommandHandler<'a> { fn add_to_current( &mut self, matrix: Matrix, + tz: f64, color_transform: ColorTransform, command_builder: impl FnOnce(wgpu::DynamicOffset) -> DrawCommand, ) { @@ -575,7 +576,7 @@ impl<'a> WgpuCommandHandler<'a> { [ matrix.tx.to_pixels() as f32, matrix.ty.to_pixels() as f32, - 0.0, + tz as f32, 1.0, ], ], @@ -642,6 +643,7 @@ impl CommandHandler for WgpuCommandHandler<'_> { let transform = Transform { matrix: Matrix::scale(target.width() as f32, target.height() as f32), color_transform: Default::default(), + tz: 0.0, }; let texture = target.take_color_texture(); let bind_group = @@ -673,6 +675,7 @@ impl CommandHandler for WgpuCommandHandler<'_> { }); self.add_to_current( transform.matrix, + transform.tz, transform.color_transform, |transform_buffer| DrawCommand::RenderTexture { _texture: texture, @@ -726,15 +729,18 @@ impl CommandHandler for WgpuCommandHandler<'_> { texture.texture.height() as f32, ); } - self.add_to_current(matrix, transform.color_transform, |transform_buffer| { - DrawCommand::RenderBitmap { + self.add_to_current( + matrix, + transform.tz, + transform.color_transform, + |transform_buffer| DrawCommand::RenderBitmap { bitmap, transform_buffer, smoothing, blend_mode: TrivialBlend::Normal, render_stage3d: false, - } - }); + }, + ); } fn render_stage3d(&mut self, bitmap: BitmapHandle, transform: Transform) { let mut matrix = transform.matrix; @@ -745,20 +751,24 @@ impl CommandHandler for WgpuCommandHandler<'_> { texture.texture.height() as f32, ); } - self.add_to_current(matrix, transform.color_transform, |transform_buffer| { - DrawCommand::RenderBitmap { + self.add_to_current( + matrix, + transform.tz, + transform.color_transform, + |transform_buffer| DrawCommand::RenderBitmap { bitmap, transform_buffer, smoothing: false, blend_mode: TrivialBlend::Normal, render_stage3d: true, - } - }); + }, + ); } fn render_shape(&mut self, shape: ShapeHandle, transform: Transform) { self.add_to_current( transform.matrix, + transform.tz, transform.color_transform, |transform_buffer| DrawCommand::RenderShape { shape, @@ -770,6 +780,7 @@ impl CommandHandler for WgpuCommandHandler<'_> { fn draw_rect(&mut self, color: Color, matrix: Matrix) { self.add_to_current( matrix, + 0.0, ColorTransform::multiply_from(color), |transform_buffer| DrawCommand::DrawRect { transform_buffer }, ); @@ -785,6 +796,7 @@ impl CommandHandler for WgpuCommandHandler<'_> { matrix.ty += Twips::HALF_PX; self.add_to_current( matrix, + 0.0, ColorTransform::multiply_from(color), |transform_buffer| DrawCommand::DrawLine { transform_buffer }, ); @@ -801,6 +813,7 @@ impl CommandHandler for WgpuCommandHandler<'_> { matrix.ty += Twips::HALF_PX; self.add_to_current( matrix, + 0.0, ColorTransform::multiply_from(color), |transform_buffer| DrawCommand::DrawLineRect { transform_buffer }, ); diff --git a/tests/tests/swfs/avm2/displayobject_z/Test.as b/tests/tests/swfs/avm2/displayobject_z/Test.as new file mode 100644 index 0000000000000..02ac4f037a69f --- /dev/null +++ b/tests/tests/swfs/avm2/displayobject_z/Test.as @@ -0,0 +1,88 @@ +package { + import flash.display.*; + import flash.text.*; + import flash.geom.*; + + [SWF(width="500", height="500")] + public class Test extends Sprite { + public function Test() { + super(); + + stage.scaleMode = StageScaleMode.NO_SCALE; + + testSetZ(); + trace(""); + + testImageComparison(); + trace(""); + + } + + private function testSetZ() : void { + var sprite: Sprite = new Sprite(); + + trace("// SetZ: default parameters"); + trace("sprite.z", sprite.z); + trace("sprite.transform.matrix", sprite.transform.matrix); + trace("sprite.transform.matrix3D", sprite.transform.matrix3D); + + trace("// SetZ: set .z=50"); + sprite.z = 50; + trace("sprite.z", sprite.z); + trace("sprite.transform.matrix", sprite.transform.matrix); + trace("sprite.transform.matrix3D", sprite.transform.matrix3D); + trace("sprite.transform.matrix3D.rawData", sprite.transform.matrix3D.rawData); + + trace("// SetZ: set .transform.matrix3D=null"); + sprite.transform.matrix3D = null; + trace("sprite.z", sprite.z); + trace("sprite.transform.matrix", sprite.transform.matrix); + trace("sprite.transform.matrix3D", sprite.transform.matrix3D); + + trace("// SetZ: set .transform.matrix=null"); + sprite.transform.matrix = null; + trace("sprite.z", sprite.z); + trace("sprite.transform.matrix", sprite.transform.matrix); + trace("sprite.transform.matrix3D", sprite.transform.matrix3D); + trace("sprite.transform.matrix3D.rawData", sprite.transform.matrix3D.rawData); + } + + private function testImageComparison() : void { + var s : Sprite = new Sprite(); + stage.addChild(s); + + for (var i:int = 0; i < 8; i++) { + // top-left + var bd1 : BitmapData = new BitmapData(100, 100, false, 0xFF00FF - 0x220000 * i); + var b1 : Bitmap = new Bitmap(bd1); + b1.z = 50 * i; + s.addChild(b1); + + // center + var bd2 : BitmapData = new BitmapData(100, 100, false, 0xFFFF00 - 0x220000 * i); + var b2 : Bitmap = new Bitmap(bd2); + b2.x = (stage.stageWidth - bd2.width) / 2; + b2.y = (stage.stageHeight - bd2.height) / 2; + b2.z = 50 * i; + s.addChild(b2); + + // bottom + var bd3 : BitmapData = new BitmapData(100, 100, false, 0x00FFFF - 0x000022 * i); + var b3 : Bitmap = new Bitmap(bd3); + b3.x = (stage.stageWidth - bd3.width) / 2; + b3.y = (stage.stageHeight - bd3.height); + b3.z = 50 * i; + s.addChild(b3); + } + + for (var j:int = 0; j < 100; j++) { + var bd4 : BitmapData = new BitmapData(100, 100, false, 0x000000); + var b4 : Bitmap = new Bitmap(bd4); + b4.x = stage.stageWidth - bd4.width; + b4.y = stage.stageHeight - bd4.height; + b4.z = 500 * j; + s.addChild(b4); + } + } + } +} diff --git a/tests/tests/swfs/avm2/displayobject_z/output.expected.png b/tests/tests/swfs/avm2/displayobject_z/output.expected.png new file mode 100644 index 0000000000000..c916fd62b11d9 Binary files /dev/null and b/tests/tests/swfs/avm2/displayobject_z/output.expected.png differ diff --git a/tests/tests/swfs/avm2/displayobject_z/output.txt b/tests/tests/swfs/avm2/displayobject_z/output.txt new file mode 100644 index 0000000000000..aed6bc904ada8 --- /dev/null +++ b/tests/tests/swfs/avm2/displayobject_z/output.txt @@ -0,0 +1,20 @@ +// SetZ: default parameters +sprite.z 0 +sprite.transform.matrix (a=1, b=0, c=0, d=1, tx=0, ty=0) +sprite.transform.matrix3D null +// SetZ: set .z=50 +sprite.z 50 +sprite.transform.matrix null +sprite.transform.matrix3D [object Matrix3D] +sprite.transform.matrix3D.rawData 1,0,0,0,0,1,0,0,0,0,1,0,0,0,50,1 +// SetZ: set .transform.matrix3D=null +sprite.z 0 +sprite.transform.matrix (a=1, b=0, c=0, d=1, tx=0, ty=0) +sprite.transform.matrix3D null +// SetZ: set .transform.matrix=null +sprite.z 0 +sprite.transform.matrix null +sprite.transform.matrix3D [object Matrix3D] +sprite.transform.matrix3D.rawData 1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1 + + diff --git a/tests/tests/swfs/avm2/displayobject_z/test.swf b/tests/tests/swfs/avm2/displayobject_z/test.swf new file mode 100644 index 0000000000000..7ccccbe7eb6e5 Binary files /dev/null and b/tests/tests/swfs/avm2/displayobject_z/test.swf differ diff --git a/tests/tests/swfs/avm2/displayobject_z/test.toml b/tests/tests/swfs/avm2/displayobject_z/test.toml new file mode 100644 index 0000000000000..31b949d6e1a74 --- /dev/null +++ b/tests/tests/swfs/avm2/displayobject_z/test.toml @@ -0,0 +1,8 @@ +num_frames = 1 + +[image_comparisons.output] +tolerance = 10 +max_outliers = 5000 # FIXME: High max_outliers. FP renders objects with a matrix3D transformation in a different way from 2D objects especially around the object edges. + +[player_options] +with_renderer = { optional = true, sample_count = 4 } diff --git a/tests/tests/swfs/avm2/geom_transform/Test.as b/tests/tests/swfs/avm2/geom_transform/Test.as index 43c7529f2bad6..b7d1e95decb3e 100644 --- a/tests/tests/swfs/avm2/geom_transform/Test.as +++ b/tests/tests/swfs/avm2/geom_transform/Test.as @@ -84,7 +84,7 @@ package { trace("mat3D.rawData", mat3D.rawData); trace("// sprite3D: update mat3D"); - mat3D.copyFrom(new Matrix3D(new [2,3,0,0,4,5,0,0,0,0,1,0,6,7,0,1])); // FIXME: z values shouldn't be zero (0) for test coverage. Unsupported now. + mat3D.copyFrom(new Matrix3D(new [2,3,0,0,4,5,0,0,0,0,1,0,6,7,8,1])); // FIXME: z values shouldn't be zero (0) for test coverage. Unsupported now. trace("sprite3D.transform.matrix", sprite3D.transform.matrix); trace("sprite3D.transform.matrix3D", sprite3D.transform.matrix3D); //// FIXME: mat3D update should be applied to transform.matrix3D immediately @@ -200,7 +200,7 @@ package { var bd4 : BitmapData = new BitmapData(50, 50, false, 0x0000FF); var b4 : Bitmap = new Bitmap(bd4); m.identity(); - m.appendTranslation(50, 50, 0); + m.appendTranslation(50, 50, 100); b4.transform.matrix3D = m.clone(); s4.addChild(b4); addChild(s4); @@ -214,7 +214,7 @@ package { m.identity(); m.appendScale(2, 3, 1); m.appendRotation(30, Vector3D.Z_AXIS); - m.appendTranslation(50, 50, 0); + m.appendTranslation(50, 50, 100); b5.transform.matrix3D = m.clone(); s5.addChild(b5); addChild(s5); diff --git a/tests/tests/swfs/avm2/geom_transform/output.expected.png b/tests/tests/swfs/avm2/geom_transform/output.expected.png index 2670e8c6a1493..f9c0bc22417c4 100644 Binary files a/tests/tests/swfs/avm2/geom_transform/output.expected.png and b/tests/tests/swfs/avm2/geom_transform/output.expected.png differ diff --git a/tests/tests/swfs/avm2/geom_transform/output.txt b/tests/tests/swfs/avm2/geom_transform/output.txt index e254e495ab5a6..b0d5b82aa2805 100644 --- a/tests/tests/swfs/avm2/geom_transform/output.txt +++ b/tests/tests/swfs/avm2/geom_transform/output.txt @@ -35,21 +35,21 @@ mat3D.rawData 1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1 // sprite3D: update mat3D sprite3D.transform.matrix null sprite3D.transform.matrix3D [object Matrix3D] -mat3D.rawData 2,3,0,0,4,5,0,0,0,0,1,0,6,7,0,1 +mat3D.rawData 2,3,0,0,4,5,0,0,0,0,1,0,6,7,8,1 // sprite3D: .matrix3D = mat3D sprite3D.transform.matrix null sprite3D.transform.matrix3D [object Matrix3D] -sprite3D.transform.matrix3D.rawData 2,3,0,0,4,5,0,0,0,0,1,0,6,7,0,1 -mat3D.rawData 2,3,0,0,4,5,0,0,0,0,1,0,6,7,0,1 +sprite3D.transform.matrix3D.rawData 2,3,0,0,4,5,0,0,0,0,1,0,6,7,8,1 +mat3D.rawData 2,3,0,0,4,5,0,0,0,0,1,0,6,7,8,1 // sprite3D: .matrix = null sprite3D.transform.matrix null sprite3D.transform.matrix3D [object Matrix3D] -sprite3D.transform.matrix3D.rawData 2,3,0,0,4,5,0,0,0,0,1,0,6,7,0,1 -mat3D.rawData 2,3,0,0,4,5,0,0,0,0,1,0,6,7,0,1 +sprite3D.transform.matrix3D.rawData 2,3,0,0,4,5,0,0,0,0,1,0,6,7,8,1 +mat3D.rawData 2,3,0,0,4,5,0,0,0,0,1,0,6,7,8,1 // sprite3D: set x = 30, y = 50 sprite3D.transform.matrix null sprite3D.transform.matrix3D [object Matrix3D] -sprite3D.transform.matrix3D.rawData 2,3,0,0,4,5,0,0,0,0,1,0,30,50,0,1 +sprite3D.transform.matrix3D.rawData 2,3,0,0,4,5,0,0,0,0,1,0,30,50,8,1 // sprite3D: .matrix3D = null sprite3D.transform.matrix (a=1, b=0, c=0, d=1, tx=0, ty=0) sprite3D.transform.matrix3D null diff --git a/tests/tests/swfs/avm2/geom_transform/test.swf b/tests/tests/swfs/avm2/geom_transform/test.swf index b14357aa60539..57ddd7a17c07c 100644 Binary files a/tests/tests/swfs/avm2/geom_transform/test.swf and b/tests/tests/swfs/avm2/geom_transform/test.swf differ