Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

avm2: Implement Matrix3D with 2D support only #18810

Conversation

cookie-s
Copy link
Contributor

@cookie-s cookie-s commented Nov 30, 2024

Partially resolves #8033 .

Screenshots

The comparison of screenshots for the first two frames mentioned in #8033 . (Please ignore background differences because those are not at the exact same frames.)

Ruffle website demo (2024-11-30) This PR Adobe Flash Player 32

image
image

Description

This PR replace stubs for flash.geom.Transform.matrix3D getter/setter with an actual implementation of Matrix3D with limited support.

This implementation is just a proxy to the existing 2D matrix implementation. Therefore transformations beyond 2D transformation works differently from the expected result.

@cookie-s cookie-s marked this pull request as ready for review November 30, 2024 16:22
core/src/prelude.rs Outdated Show resolved Hide resolved
@cookie-s cookie-s force-pushed the matrix3d-transformation-with-2d-support-only branch 2 times, most recently from 31c6e11 to 14bcef1 Compare December 1, 2024 02:07
@kjarosh kjarosh added A-avm2 Area: AVM2 (ActionScript 3) T-compat Type: Compatibility with Flash Player labels Dec 1, 2024
Copy link
Member

@kjarosh kjarosh left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, thank you and welcome!

Replace stubs for flash.geom.Transform.matrix3D getter/setter with an
actual implementation of Matrix3D with limited support.

This implementation is just a proxy to the existing 2D matrix
implementation. Therefore transformations beyond 2D transformation works
differently from the expected result.
3D Matrix transformations are not yet fully supported.
@Lord-McSweeney Lord-McSweeney force-pushed the matrix3d-transformation-with-2d-support-only branch from 242f757 to 8f52116 Compare December 1, 2024 23:55
@Lord-McSweeney Lord-McSweeney enabled auto-merge (squash) December 1, 2024 23:57
@Lord-McSweeney Lord-McSweeney merged commit 858fceb into ruffle-rs:master Dec 2, 2024
22 checks passed
@cookie-s cookie-s deleted the matrix3d-transformation-with-2d-support-only branch December 4, 2024 01:20
@kjarosh
Copy link
Member

kjarosh commented Dec 5, 2024

This PR unfortunately introduces a regression by breaking the getter of matrix3D, because an array of 16 arguments is passed to the constructor instead of a vector with 16 elements.

The following patch fixes that but the getter still always returns an object instead of returning null by default.

diff --git a/core/src/avm2/globals/flash/geom/transform.rs b/core/src/avm2/globals/flash/geom/transform.rs
index 104a34a09..759238484 100644
--- a/core/src/avm2/globals/flash/geom/transform.rs
+++ b/core/src/avm2/globals/flash/geom/transform.rs
@@ -1,5 +1,7 @@
 use crate::avm2::globals::slots::*;
+use crate::avm2::object::VectorObject;
 use crate::avm2::parameters::ParametersExt;
+use crate::avm2::vector::VectorStorage;
 use crate::avm2::{Activation, Error, Object, TObject, Value};
 use crate::display_object::TDisplayObject;
 use crate::prelude::{DisplayObject, Matrix, Twips};
@@ -209,12 +211,17 @@ fn matrix3d_to_object<'gc>(
     matrix: Matrix3D,
     activation: &mut Activation<'_, 'gc>,
 ) -> Result<Value<'gc>, Error<'gc>> {
-    let args = matrix.raw_data.map(Into::into);
+    let value_type = activation.avm2().class_defs().number;
+    let mut raw_data_storage = VectorStorage::new(16, true, Some(value_type), activation);
+    for (i, data) in matrix.raw_data.iter().enumerate() {
+        raw_data_storage.set(i, Value::Number(*data), activation)?;
+    }
+    let vector = VectorObject::from_vector(raw_data_storage, activation)?.into();
     let object = activation
         .avm2()
         .classes()
         .matrix3d
-        .construct(activation, &args)?;
+        .construct(activation, &[vector])?;
     Ok(object.into())
 }
 

@kjarosh
Copy link
Member

kjarosh commented Dec 5, 2024

I'm sorry @cookie-s! We have to consider reverting it :(

To be merged again, it will need a test + the patch posted by me above + 2D/3D switch to cover the following property (source: https://docs.ruffle.rs/en_US/FlashPlatform/reference/actionscript/3/flash/geom/Transform.html#matrix3D).

If the matrix property is set to a value (not null), the matrix3D property is null. And if the matrix3D property is set to a value (not null), the matrix property is null.

@adrian17
Copy link
Collaborator

adrian17 commented Dec 5, 2024

but the getter still always returns an object instead of returning null by default

More specifically: after some research, turns out that transform.matrix3D behaves exactly opposite to transform.matrix - while the latter can be implemented with just getter/setter returning a new object, the former is a real object with a similar DisplayObject binding as Transform itself - transform.matrix3D always returns the same object, and its values are bound to the DisplayObject, as in:

var mat = movieclip.transform.matrix3D;
movieclip.x = 50;
trace(mat.rawData); // shows 50

This is also required for

movieclip.transform.matrix3D.appendTranslation(5, 5, 0);

to work (which is again opposite to .matrix, where this style of code would explicitly not work in FP - as in, it'd just be a noop)

@cookie-s
Copy link
Contributor Author

cookie-s commented Dec 7, 2024

@kjarosh Thank you for letting me know and providing the patch!
I have made a new PR to address your points: #18888

@adrian17 Thank you, that's very interesting observation. After your comment, I checked the reference closely and found
https://airsdk.dev/reference/actionscript/3.0/flash/display/DisplayObject.html#transform

Each of the transform object's properties is itself an object. This concept is important because the only way to set new values for the matrix or colorTransform objects is to create a new object and copy that object into the transform.matrix or transform.colorTransform property.

For example, to increase the tx value of a display object's matrix, you must make a copy of the entire matrix object, then copy the new object into the matrix property of the transform object:

   var myMatrix:Matrix = myDisplayObject.transform.matrix;  
   myMatrix.tx += 10; 
   myDisplayObject.transform.matrix = myMatrix;  

You cannot directly set the tx property. The following code has no effect on myDisplayObject:

   myDisplayObject.transform.matrix.tx += 10;

It mentions the transform.matrix or transform.colorTransform but transform.matrix3D is probably not included in this sentence?
Sorry I couldn't support movieclip.transform.matrix3D.appendTranslation(5, 5, 0); in #18888 but this information was helpful to understand a possible underlying design.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-avm2 Area: AVM2 (ActionScript 3) T-compat Type: Compatibility with Flash Player
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants