Skip to content

Commit

Permalink
avm2: Implement mode_3d switch in Transform
Browse files Browse the repository at this point in the history
  • Loading branch information
cookie-s committed Dec 7, 2024
1 parent 11bbf00 commit b879581
Show file tree
Hide file tree
Showing 10 changed files with 106 additions and 21 deletions.
1 change: 1 addition & 0 deletions core/src/avm1/globals/bitmap_data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -568,6 +568,7 @@ fn draw<'gc>(
Transform {
matrix,
color_transform,
mode_3d: Default::default(),
},
smoothing,
blend_mode,
Expand Down
26 changes: 22 additions & 4 deletions core/src/avm2/globals/flash/geom/transform.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,11 @@ pub fn get_matrix_3d<'gc>(
// Support native Matrix3D.
avm2_stub_getter!(activation, "flash.geom.Transform", "matrix3D");

let matrix = *get_display_object(this, activation)?.base().matrix();
let dobj = get_display_object(this, activation)?;
if !dobj.base().mode_3d() {
return Ok(Value::Null);
}
let matrix = *dobj.base().matrix();
let matrix3d = Matrix3D::from(matrix);
matrix3d_to_object(matrix3d, activation)
}
Expand All @@ -75,16 +79,28 @@ pub fn set_matrix_3d<'gc>(

let matrix3d = object_to_matrix3d(args.get_object(activation, 0, "value")?, activation)?;
let matrix = Matrix::from(matrix3d);
let matrix = matrix_to_object(matrix, activation)?;
set_matrix(activation, this, &[matrix])

let dobj = get_display_object(this, activation)?;
dobj.set_matrix(activation.context.gc_context, matrix);
if let Some(parent) = dobj.parent() {
// Self-transform changes are automatically handled,
// we only want to inform ancestors to avoid unnecessary invalidations for tx/ty
parent.invalidate_cached_bitmap(activation.context.gc_context);
}
dobj.set_mode_3d(activation.context.gc_context, true);
Ok(Value::Undefined)
}

pub fn get_matrix<'gc>(
activation: &mut Activation<'_, 'gc>,
this: Object<'gc>,
_args: &[Value<'gc>],
) -> Result<Value<'gc>, Error<'gc>> {
let matrix = *get_display_object(this, activation)?.base().matrix();
let dobj = get_display_object(this, activation)?;
if dobj.base().mode_3d() {
return Ok(Value::Null);
}
let matrix = *dobj.base().matrix();
matrix_to_object(matrix, activation)
}

Expand All @@ -97,13 +113,15 @@ pub fn set_matrix<'gc>(
// null when trying to get the matrix- but the DO's actual transform matrix will
// remain its previous non-null value.
let matrix = object_to_matrix(args.get_object(activation, 0, "value")?, activation)?;

let dobj = get_display_object(this, activation)?;
dobj.set_matrix(activation.context.gc_context, matrix);
if let Some(parent) = dobj.parent() {
// Self-transform changes are automatically handled,
// we only want to inform ancestors to avoid unnecessary invalidations for tx/ty
parent.invalidate_cached_bitmap(activation.context.gc_context);
}
dobj.set_mode_3d(activation.context.gc_context, false);
Ok(Value::Undefined)
}

Expand Down
17 changes: 16 additions & 1 deletion core/src/display_object.rs
Original file line number Diff line number Diff line change
Expand Up @@ -328,6 +328,14 @@ impl<'gc> DisplayObjectBase<'gc> {
&self.transform
}

pub fn mode_3d(&self) -> bool {
self.transform.mode_3d
}

pub fn set_mode_3d(&mut self, mode_3d: bool) {
self.transform.mode_3d = mode_3d;
}

pub fn matrix(&self) -> &Matrix {
&self.transform.matrix
}
Expand Down Expand Up @@ -917,12 +925,13 @@ pub fn render_base<'gc>(this: DisplayObject<'gc>, context: &mut RenderContext<'_
if cache_info.dirty {
let mut transform_stack = TransformStack::new();
transform_stack.push(&Transform {
color_transform: Default::default(),
matrix: Matrix {
tx: -offset_x,
ty: -offset_y,
..cache_info.base_transform.matrix
},
color_transform: Default::default(),
mode_3d: Default::default(),
});
let mut offscreen_context = RenderContext {
renderer: context.renderer,
Expand Down Expand Up @@ -955,6 +964,7 @@ pub fn render_base<'gc>(this: DisplayObject<'gc>, context: &mut RenderContext<'_
..Default::default()
},
color_transform: cache_info.base_transform.color_transform,
mode_3d: Default::default(),
},
true,
PixelSnapping::Always, // cacheAsBitmap forces pixel snapping
Expand Down Expand Up @@ -1027,6 +1037,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(),
mode_3d: Default::default(),
});
}

Expand Down Expand Up @@ -1233,6 +1244,10 @@ pub trait TDisplayObject<'gc>:
self.base_mut(gc_context).set_matrix(matrix);
}

fn set_mode_3d(&self, gc_context: &Mutation<'gc>, mode_3d: bool) {
self.base_mut(gc_context).set_mode_3d(mode_3d);
}

/// Sets the color transform of this object.
/// This does NOT invalidate the cache, as it's often used with other operations.
/// It is the callers responsibility to do so.
Expand Down
1 change: 1 addition & 0 deletions core/src/display_object/edit_text.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1161,6 +1161,7 @@ impl<'gc> EditText<'gc> {
context.transform_stack.push(&Transform {
matrix: transform.matrix,
color_transform: ColorTransform::IDENTITY,
mode_3d: Default::default(),
});
} else {
context.transform_stack.push(transform);
Expand Down
1 change: 1 addition & 0 deletions core/src/display_object/stage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -829,6 +829,7 @@ impl<'gc> TDisplayObject<'gc> for Stage<'gc> {
context.transform_stack.push(&Transform {
matrix: self.0.read().viewport_matrix,
color_transform: Default::default(),
mode_3d: Default::default(),
});

// All of our Stage3D instances get rendered *underneath* the main stage.
Expand Down
2 changes: 2 additions & 0 deletions render/src/transform.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use swf::ColorTransform;
/// This includes both the transformation matrix and the color transform.
#[derive(Clone, Debug, Default)]
pub struct Transform {
pub mode_3d: bool, // Indicate whether the latest set matrix is 3D or not.
pub matrix: Matrix,
pub color_transform: ColorTransform,
}
Expand All @@ -23,6 +24,7 @@ impl TransformStack {
self.0.push(Transform {
matrix,
color_transform,
..Default::default()
});
}

Expand Down
1 change: 1 addition & 0 deletions render/wgpu/src/surface/commands.rs
Original file line number Diff line number Diff line change
Expand Up @@ -642,6 +642,7 @@ impl CommandHandler for WgpuCommandHandler<'_> {
let transform = Transform {
matrix: Matrix::scale(target.width() as f32, target.height() as f32),
color_transform: Default::default(),
mode_3d: Default::default(),
};
let texture = target.take_color_texture();
let bind_group =
Expand Down
65 changes: 54 additions & 11 deletions tests/tests/swfs/avm2/geom_transform/Test.as
Original file line number Diff line number Diff line change
Expand Up @@ -14,19 +14,26 @@ package {
test3D();
trace("");

testCopy2D();
trace("");

//// FIXME: transformation copy is unsupported now.
// testCopy3D();
// trace("");

testImageComparison();
}

private function test2D() : void {
var sprite2D : Sprite = new Sprite();
var mat2D : Matrix = new Matrix();
mat2D.identity();

trace("// sprite2D: new Sprite has null matrix3D and valid matrix");
trace("sprite2D.transform.matrix", sprite2D.transform.matrix);
trace("sprite2D.transform.matrix3D", sprite2D.transform.matrix3D);

trace("// sprite2D: set identity matrix");
var mat2D : Matrix = new Matrix();
mat2D.identity();
sprite2D.transform.matrix = mat2D;
trace("sprite2D.transform.matrix", sprite2D.transform.matrix);
trace("sprite2D.transform.matrix3D", sprite2D.transform.matrix3D);
Expand All @@ -42,25 +49,61 @@ package {

private function test3D() : void {
var sprite3D : Sprite = new Sprite();
var mat3D : Matrix3D = new Matrix3D();
mat3D.identity();

trace("// sprite3D: set identity matrix3D");
var mat3D : Matrix3D = new Matrix3D();
mat3D.identity();
sprite3D.transform.matrix3D = mat3D;
trace("sprite3D.transform.matrix", sprite3D.transform.matrix);
trace("sprite3D.transform.matrix3D", sprite3D.transform.matrix3D);
trace("sprite3D.transform.matrix3D.rawData", sprite3D.transform.matrix3D.rawData);
trace("mat3D.rawData", mat3D.rawData);

trace("// sprite3D: set x = 30, y = 50");
sprite3D.x = 30;
sprite3D.y = 50;
trace("sprite3D.transform.matrix", sprite3D.transform.matrix);
trace("sprite3D.transform.matrix3D", sprite3D.transform.matrix3D);
trace("sprite3D.transform.matrix3D.rawData", sprite3D.transform.matrix3D.rawData);
trace("mat3D.rawData", mat3D.rawData);
//// FIXME: matrix3D.rawData should be updated by x/y update.
// trace("// sprite3D: set x = 30, y = 50");
// sprite3D.x = 30;
// sprite3D.y = 50;
// trace("sprite3D.transform.matrix", sprite3D.transform.matrix);
// trace("sprite3D.transform.matrix3D", sprite3D.transform.matrix3D);
// trace("sprite3D.transform.matrix3D.rawData", sprite3D.transform.matrix3D.rawData);
// trace("mat3D", mat3D);
}

private function testCopy2D() : void {
var sprite1 : Sprite = new Sprite();
var sprite2 : Sprite = new Sprite();

trace("// Copy2D");
var mat2D : Matrix = new Matrix(1, 2, 3, 4, 5, 6);
sprite1.transform.matrix = mat2D;
sprite2.transform = sprite1.transform;
trace("sprite1.transform.matrix", sprite1.transform.matrix);
trace("sprite1.transform.matrix3D", sprite1.transform.matrix3D);
trace("sprite2.transform.matrix", sprite2.transform.matrix);
trace("sprite2.transform.matrix3D", sprite2.transform.matrix3D);
}

//// FIXME
// private function testCopy3D() : void {
// var sprite1 : Sprite = new Sprite();
// var sprite2 : Sprite = new Sprite();
//
// trace("// Copy3D");
// var mat3D : Matrix3D = new Matrix3D();
// mat3D.appendRotation(1, Vector3D.Z_AXIS);
// mat3D.appendScale(2, 3, 4);
// mat3D.appendTranslation(5, 6, 7);
// sprite1.transform.matrix3D = mat3D;
// sprite2.transform = sprite1.transform;
// trace("sprite1.transform.matrix", sprite1.transform.matrix);
// trace("sprite1.transform.matrix3D", sprite1.transform.matrix3D);
// trace("sprite1.transform.matrix3D.rawData", sprite1.transform.matrix3D.rawData);
// trace("sprite2.transform.matrix", sprite2.transform.matrix);
// trace("sprite2.transform.matrix3D", sprite2.transform.matrix3D);
// trace("sprite2.transform.matrix3D.rawData", sprite2.transform.matrix3D.rawData);
// }


private function testImageComparison() : void {
var m : Matrix3D = new Matrix3D();

Expand Down
13 changes: 8 additions & 5 deletions tests/tests/swfs/avm2/geom_transform/output.txt
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,16 @@ mat2D (a=1, b=0, c=0, d=1, tx=0, ty=0)
sprite2D.transform.matrix (a=1, b=0, c=0, d=1, tx=30, ty=50)
sprite2D.transform.matrix3D null
mat2D (a=1, b=0, c=0, d=1, tx=0, ty=0)

// sprite3D: set identity matrix3D
sprite3D.transform.matrix null
sprite3D.transform.matrix3D [object Matrix3D]
sprite3D.transform.matrix3D.rawData 1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1
mat3D.rawData 1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1
// sprite3D: set x = 30, y = 50
sprite3D.transform.matrix null
sprite3D.transform.matrix3D [object Matrix3D]
sprite3D.transform.matrix3D.rawData 1,0,0,0,0,1,0,0,0,0,1,0,30,50,0,1
mat3D.rawData 1,0,0,0,0,1,0,0,0,0,1,0,30,50,0,1

// Copy2D
sprite1.transform.matrix (a=1, b=2, c=3, d=4, tx=5, ty=6)
sprite1.transform.matrix3D null
sprite2.transform.matrix (a=1, b=2, c=3, d=4, tx=5, ty=6)
sprite2.transform.matrix3D null

Binary file modified tests/tests/swfs/avm2/geom_transform/test.swf
Binary file not shown.

0 comments on commit b879581

Please sign in to comment.