Skip to content

avm2: Implement display-list 3D compose, rotation, and hit tests - #25101

Open
antonylavelle wants to merge 4 commits into
ruffle-rs:masterfrom
antonylavelle:avm2-rotation-xy
Open

antonylavelle wants to merge 4 commits into
ruffle-rs:masterfrom
antonylavelle:avm2-rotation-xy

Conversation

@antonylavelle

Copy link
Copy Markdown

Description

This gets Flash 10 display-list 3D (rotationX / rotationY / z) drawing and hit-testing close enough that Microboats plays correctly. That Armor Games racer is the biggest example of Flash 2.5D I know of: a 2D camera look-at, then the whole world pitched with rotationX, plus standing trackside props (rotationX = 90).

What changed:

  • Compose local matrix3D as Flash Euler T * Rz * Ry * Rx * S, and concatenate that through the transform stack.
  • Scale world z with the viewport (HiDPI / ShowAll) so perspective uses stage-pixel focal length instead of looking zoomed out.
  • Skip 2D AABB render culling when a transform uses 3D, so pitched tiles are not dropped while they are still on screen.
  • Keep DisplayObject.rotation in [-180, 180] for 2D, but unwrapped once matrix3D is active, so heading lerps (Microboats boats / chase cam) do not reverse at ±180°.
  • Union the perspective-projected silhouette into world_bounds / hitTestObject, so Microboats' onScreen (hitTestObject vs a stage rectangle) still shows obstacles that sit off the 2D stage after camera pitch.
  • Setting rotationZ now enters display-list 3D the same way rotationX does.

Assisted-by: Cursor.

Testing

  • Played Microboats (SWF10, 600×440) in the macOS desktop player: camera pitch, trackside 3D, heading through 180°, and in-track obstacles.
  • Added tests/tests/swfs/avm2/displayobject_3d (Asc). It traces 2D vs 3D rotation wrapping, Euler matrix3D order, and hitTestObject for a clip at y = 500 after rotationX = -60.
  • Caveat: output.txt is from Ruffle, not yet captured from the Flash Player debugger. That should be re-run in FP and replaced if any line differs (especially 3D rotation wrapping and hitTestObject).

Checklist

  • I, a human, have self-reviewed this PR and fully understand the changes within.
  • I have made or updated tests where possible.
  • All of my commits are properly scoped, compile successfully, and pass all tests.
  • This PR does not make sense to split up into smaller PRs.
  • An LLM was involved in the authoring of this code.

Flash DisplayObject.matrix3D is T * Rz * Ry * Rx * S (recompose
with Orientation3D.EULER_ANGLES). Concatenate that through the
transform stack so rotationX/Y and z affect drawing.

Scale world z by the viewport's 2D scale (HiDPI, ShowAll) before
perspective, matching Flash's stage-pixel focal length. Skip 2D
AABB render culling when a transform uses 3D; pitched tiles can
be on screen while their unprojected bounds miss the viewport.

Assisted-by: Cursor
2D rotation still wraps into [-180, 180]. Once matrix3D is
active, return the native cache so a lerp toward an unbounded
heading does not reverse at ±180°.

Assisted-by: Cursor
Union the perspective-projected silhouette with the 2D AABB when
rotationX/Y or z is in the parent chain. Games such as Microboats
hide track obstacles with hitTestObject against a stage rectangle,
which misses 2D-offstage clips that the pitch brings on screen.

Setting rotationZ now enters display-list 3D like rotationX.

Assisted-by: Cursor
Trace 2D vs 3D rotation wrapping, matrix3D Euler order, and
hitTestObject of a clip that is below the stage in 2D but on
screen after rotationX.

Assisted-by: Cursor
@Lord-McSweeney

Copy link
Copy Markdown
Member

This PR does not make sense to split up into smaller PRs.

This includes a lot of changes, please split it into smaller PRs. e.g. one to support hook up rotationX/rotationY/rotationZ to Matrix3D, one to support rendering Matrix3D, etc.

@antonylavelle

antonylavelle commented Nov 4, 2026 via email

Copy link
Copy Markdown
Author

@danielhjacobs danielhjacobs added A-avm2 Area: AVM2 (ActionScript 3) T-compat Type: Compatibility with Flash Player labels Nov 5, 2026
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.

3 participants