Skip to content

Fix TilemapGPULayer ignoring tile rotation#7338

Open
moufmouf wants to merge 1 commit into
phaserjs:masterfrom
moufmouf:fix/tilemapgpulayer-tile-rotation
Open

Fix TilemapGPULayer ignoring tile rotation#7338
moufmouf wants to merge 1 commit into
phaserjs:masterfrom
moufmouf:fix/tilemapgpulayer-tile-rotation

Conversation

@moufmouf

@moufmouf moufmouf commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

This PR (delete as applicable)

  • Fixes a bug

TilemapGPULayer rendered rotated tiles unrotated. Tiled encodes 90-degree tile rotations using the anti-diagonal flip flag, which the parser resolves into tile.rotation (0, 90, 180 or 270 degrees) plus tile.flipX. But generateLayerDataTexture only packed flipX/flipY into the layer-data texture and dropped rotation entirely, so the shader had no way to know a tile was rotated.

The visible result: any tile placed with a rotation (a very common way to build directional art such as arrows from a single base tile) rendered in its un-rotated orientation, and multi-tile rotated sprites appeared torn apart.

Before (the arrow, split on 2 tiles, is not rotated):
image

After:
image

Note that the CPU TilemapLayer renders these correctly (its TransformerTile applies element.rotation), so it only affected the GPU layer.

The fix: Encode the rotation as a 0-3 quadrant in bits 24-25 of the layer-data texel, and in the fragment shader rotate the sampling UV about the tile centre before applying the flip flags - matching the CPU path's Rotate . Flip composition. The empty/animated/flip flags are unaffected: the new bits are below them and mod(flags, 4.0) isolates the quadrant cleanly.

I also opened a repro here: phaserjs/examples#409

TilemapGPULayer rendered rotated tiles unrotated. Tiled encodes 90-degree
tile rotations using the anti-diagonal flip flag, which the parser resolves
into `tile.rotation` (0, 90, 180 or 270 degrees) plus `tile.flipX`. But
`generateLayerDataTexture` only packed `flipX`/`flipY` into the layer-data
texture and dropped `rotation` entirely, so the shader had no way to know a
tile was rotated.

The visible result: any tile placed with a rotation (a very common way to
build directional art such as arrows from a single base tile) rendered in
its un-rotated orientation, and multi-tile rotated sprites appeared torn
apart. The CPU `TilemapLayer` renders these correctly (its `TransformerTile`
applies `element.rotation`), so it only affected the GPU layer.

Encode the rotation as a 0-3 quadrant in bits 24-25 of the layer-data texel,
and in the fragment shader rotate the sampling UV about the tile centre
before applying the flip flags - matching the CPU path's `Rotate . Flip`
composition. The empty/animated/flip flags are unaffected: the new bits are
below them and `mod(flags, 4.0)` isolates the quadrant cleanly.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant