flame icon indicating copy to clipboard operation
flame copied to clipboard

Flame Tiled: Batch caching by image name leads to incorrect painting.

Open jtmcdole opened this issue 3 years ago • 2 comments

Current bug behaviour

Tiled maps multiple images (either multiple atlases, or multiple single-sourced images) will not render correctly in staggered modes. It may not operate correctly in other modes as well.

Expected behaviour

Maps that match what Tiled renders.

Steps to reproduce

  1. Create a tiled map (isometric, staggered, x-asis, even or odd).
  2. Use multiple, oversized images for the tileset (for overlapping). a. A good CC-0 set: kenny.nl
  3. Place images such that the overlap.

More information

What Flame does today is optimized for batch rendering (performance), but that means map authors need to know about the limitations. A quick rundown of what happens:

  1. flame_tiled creates a SpriteBatch for every image in the tiled map. Images can be N*(Atlas||Single Image).
  2. These batches are stored in a map keyed on the source file name (_cachedSpriteBatches)
  3. While sweeping each layer, and then sweeping each row, and then sweeping each tile in the row, the batch is looked up.
  4. "cache tiles": transforms generated from the layer->row->tile are stored for each image, not for each tile (batch.addTransform)
  5. render loop: walk over all visible layers. walk over all cached batches (remember: this is image keys, not tile keyed). call sprite batch render.

What could be done about it?

  1. You tell everyone in documentation and perhaps runtime warning: don't use multiple images/atlases when generating tiled maps.
  2. We could collapse every image into an image atlas on load and have only one atlas to draw from for every layer.
  3. Convert RenderableTileMap to not actual render - just do all the parallax / shifting / tile layout. Leave the render step to another class that flips between sprite batching or sprite painting depending on map conditions.

Option 1 seems harsh, but not uncommon - its an optimization build step. Option 2 could lead to increased load times, higher memory usage - flips could double that if incorrectly handled. 2D-rect-bin packing is NP-hard. Option 3 could be a bit of work, but also might lead to easier to animate tiles, or positioning players on the maps.

The goal is to go from randomly having this: image

To having this: image

Which is achievable with option 1 for now.

jtmcdole avatar Sep 11 '22 00:09 jtmcdole

wssy on discord also suggested dynamically creating new batches could also be a solution.

jtmcdole avatar Sep 11 '22 03:09 jtmcdole

Generating a single Atlas from all the images in a layer works and appears performant. I know the Atlas is made one per layer - further optimizations would be to make one and only one Atlas for the map.

image

jtmcdole avatar Sep 11 '22 05:09 jtmcdole