From a166f34078ebb1b64d4548eec1ad077af795bd77 Mon Sep 17 00:00:00 2001 From: jimmy b Date: Sun, 28 Apr 2024 11:39:21 -0500 Subject: [PATCH] Fixes incorrect rendering of flipped animation tiles --- .../Renderers/TiledMapAnimatedLayerModel.cs | 6 +- .../TiledMapAnimatedLayerModelBuilder.cs | 7 +- .../Renderers/TiledMapModelBuilder.cs | 2 + .../Renderers/TiledMapRenderer.cs | 4 +- .../TiledMapTilesetAnimatedTile.cs | 8 ++ .../TiledMapTilesetTileAnimationFrame.cs | 99 ++++++++++++++++++- 6 files changed, 119 insertions(+), 7 deletions(-) diff --git a/src/cs/MonoGame.Extended.Tiled/Renderers/TiledMapAnimatedLayerModel.cs b/src/cs/MonoGame.Extended.Tiled/Renderers/TiledMapAnimatedLayerModel.cs index d7e5c0cf..4d9a1fcd 100644 --- a/src/cs/MonoGame.Extended.Tiled/Renderers/TiledMapAnimatedLayerModel.cs +++ b/src/cs/MonoGame.Extended.Tiled/Renderers/TiledMapAnimatedLayerModel.cs @@ -4,15 +4,17 @@ namespace MonoGame.Extended.Tiled.Renderers { public sealed class TiledMapAnimatedLayerModel : TiledMapLayerModel { - public TiledMapAnimatedLayerModel(GraphicsDevice graphicsDevice, Texture2D texture, VertexPositionTexture[] vertices, ushort[] indices, TiledMapTilesetAnimatedTile[] animatedTilesetTiles) + public TiledMapAnimatedLayerModel(GraphicsDevice graphicsDevice, Texture2D texture, VertexPositionTexture[] vertices, ushort[] indices, TiledMapTilesetAnimatedTile[] animatedTilesetTiles, TiledMapTileFlipFlags[] animatedTilesetTileFlipFlags) : base(graphicsDevice, texture, vertices, indices) { Vertices = vertices; AnimatedTilesetTiles = animatedTilesetTiles; + AnimatedTilesetFlipFlags = animatedTilesetTileFlipFlags; } public VertexPositionTexture[] Vertices { get; } public TiledMapTilesetAnimatedTile[] AnimatedTilesetTiles { get; } + public TiledMapTileFlipFlags[] AnimatedTilesetFlipFlags { get; } protected override VertexBuffer CreateVertexBuffer(GraphicsDevice graphicsDevice, int vertexCount) { @@ -24,4 +26,4 @@ namespace MonoGame.Extended.Tiled.Renderers return new DynamicIndexBuffer(graphicsDevice, IndexElementSize.SixteenBits, indexCount, BufferUsage.WriteOnly); ; } } -} \ No newline at end of file +} diff --git a/src/cs/MonoGame.Extended.Tiled/Renderers/TiledMapAnimatedLayerModelBuilder.cs b/src/cs/MonoGame.Extended.Tiled/Renderers/TiledMapAnimatedLayerModelBuilder.cs index ccb37abb..7afcc217 100644 --- a/src/cs/MonoGame.Extended.Tiled/Renderers/TiledMapAnimatedLayerModelBuilder.cs +++ b/src/cs/MonoGame.Extended.Tiled/Renderers/TiledMapAnimatedLayerModelBuilder.cs @@ -8,18 +8,21 @@ namespace MonoGame.Extended.Tiled.Renderers public TiledMapAnimatedLayerModelBuilder() { AnimatedTilesetTiles = new List(); + AnimatedTilesetFlipFlags = new List(); } public List AnimatedTilesetTiles { get; } + public List AnimatedTilesetFlipFlags { get; } protected override void ClearBuffers() { AnimatedTilesetTiles.Clear(); + AnimatedTilesetFlipFlags.Clear(); } protected override TiledMapAnimatedLayerModel CreateModel(GraphicsDevice graphicsDevice, Texture2D texture) { - return new TiledMapAnimatedLayerModel(graphicsDevice, texture, Vertices.ToArray(), Indices.ToArray(), AnimatedTilesetTiles.ToArray()); + return new TiledMapAnimatedLayerModel(graphicsDevice, texture, Vertices.ToArray(), Indices.ToArray(), AnimatedTilesetTiles.ToArray(), AnimatedTilesetFlipFlags.ToArray()); } } -} \ No newline at end of file +} diff --git a/src/cs/MonoGame.Extended.Tiled/Renderers/TiledMapModelBuilder.cs b/src/cs/MonoGame.Extended.Tiled/Renderers/TiledMapModelBuilder.cs index b7319456..b96925e3 100644 --- a/src/cs/MonoGame.Extended.Tiled/Renderers/TiledMapModelBuilder.cs +++ b/src/cs/MonoGame.Extended.Tiled/Renderers/TiledMapModelBuilder.cs @@ -66,7 +66,9 @@ namespace MonoGame.Extended.Tiled.Renderers if (tilesetTile is TiledMapTilesetAnimatedTile animatedTilesetTile) { animatedLayerBuilder.AddSprite(texture, position, sourceRectangle, flipFlags); + animatedTilesetTile.CreateTextureRotations(tileset, flipFlags); animatedLayerBuilder.AnimatedTilesetTiles.Add(animatedTilesetTile); + animatedLayerBuilder.AnimatedTilesetFlipFlags.Add(flipFlags); if (animatedLayerBuilder.IsFull) layerModels.Add(animatedLayerBuilder.Build(_graphicsDevice, texture)); diff --git a/src/cs/MonoGame.Extended.Tiled/Renderers/TiledMapRenderer.cs b/src/cs/MonoGame.Extended.Tiled/Renderers/TiledMapRenderer.cs index 5254dae1..c76a0846 100644 --- a/src/cs/MonoGame.Extended.Tiled/Renderers/TiledMapRenderer.cs +++ b/src/cs/MonoGame.Extended.Tiled/Renderers/TiledMapRenderer.cs @@ -62,9 +62,9 @@ namespace MonoGame.Extended.Tiled.Renderers { var verticesPointer = fixedVerticesPointer; - foreach (var animatedTile in animatedModel.AnimatedTilesetTiles) + for (int i = 0; i < animatedModel.AnimatedTilesetTiles.Length; i++) { - var currentFrameTextureCoordinates = animatedTile.CurrentAnimationFrame.TextureCoordinates; + var currentFrameTextureCoordinates = animatedModel.AnimatedTilesetTiles[i].CurrentAnimationFrame.GetTextureCoordinates(animatedModel.AnimatedTilesetFlipFlags[i]); // ReSharper disable ArrangeRedundantParentheses (*verticesPointer++).TextureCoordinate = currentFrameTextureCoordinates[0]; diff --git a/src/cs/MonoGame.Extended.Tiled/TiledMapTilesetAnimatedTile.cs b/src/cs/MonoGame.Extended.Tiled/TiledMapTilesetAnimatedTile.cs index 395f2d0b..1bbb770b 100644 --- a/src/cs/MonoGame.Extended.Tiled/TiledMapTilesetAnimatedTile.cs +++ b/src/cs/MonoGame.Extended.Tiled/TiledMapTilesetAnimatedTile.cs @@ -23,6 +23,14 @@ namespace MonoGame.Extended.Tiled CurrentAnimationFrame = AnimationFrames[0]; } + public void CreateTextureRotations(TiledMapTileset tileset, TiledMapTileFlipFlags flipFlags) + { + for (int i = 0; i < AnimationFrames.Count; i++) + { + AnimationFrames[i].CreateTextureRotations(tileset, flipFlags); + } + } + public void Update(GameTime gameTime) { _timer += gameTime.ElapsedGameTime; diff --git a/src/cs/MonoGame.Extended.Tiled/TiledMapTilesetTileAnimationFrame.cs b/src/cs/MonoGame.Extended.Tiled/TiledMapTilesetTileAnimationFrame.cs index f35c8528..9dbca802 100644 --- a/src/cs/MonoGame.Extended.Tiled/TiledMapTilesetTileAnimationFrame.cs +++ b/src/cs/MonoGame.Extended.Tiled/TiledMapTilesetTileAnimationFrame.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using Microsoft.Xna.Framework; namespace MonoGame.Extended.Tiled @@ -8,6 +9,7 @@ namespace MonoGame.Extended.Tiled public readonly int LocalTileIdentifier; public readonly TimeSpan Duration; public readonly Vector2[] TextureCoordinates; + private readonly Dictionary _flipDictionary = new Dictionary(); internal TiledMapTilesetTileAnimationFrame(TiledMapTileset tileset, int localTileIdentifier, int durationInMilliseconds) { @@ -17,6 +19,101 @@ namespace MonoGame.Extended.Tiled CreateTextureCoordinates(tileset); } + public Vector2[] GetTextureCoordinates(TiledMapTileFlipFlags flipFlags) + { + if (!_flipDictionary.TryGetValue(flipFlags, out Vector2[] flippedTextureCoordiantes)) + { + return TextureCoordinates; + } + else + { + return flippedTextureCoordiantes; + } + } + + public void CreateTextureRotations(TiledMapTileset tileset, TiledMapTileFlipFlags flipFlags) + { + if (!_flipDictionary.ContainsKey(flipFlags)) + { + if (flipFlags == TiledMapTileFlipFlags.None) + { + _flipDictionary.Add(flipFlags, TextureCoordinates); + } + else + { + _flipDictionary.Add(flipFlags, TransformTextureCoordinates(tileset, flipFlags)); + } + } + } + + public Vector2[] TransformTextureCoordinates(TiledMapTileset tileset, TiledMapTileFlipFlags flipFlags) + { + var sourceRectangle = tileset.GetTileRegion(LocalTileIdentifier); + var texture = tileset.Texture; + var texelLeft = (float)sourceRectangle.X / texture.Width; + var texelTop = (float)sourceRectangle.Y / texture.Height; + var texelRight = (sourceRectangle.X + sourceRectangle.Width) / (float)texture.Width; + var texelBottom = (sourceRectangle.Y + sourceRectangle.Height) / (float)texture.Height; + + var flipDiagonally = (flipFlags & TiledMapTileFlipFlags.FlipDiagonally) != 0; + var flipHorizontally = (flipFlags & TiledMapTileFlipFlags.FlipHorizontally) != 0; + var flipVertically = (flipFlags & TiledMapTileFlipFlags.FlipVertically) != 0; + var transform = new Vector2[4]; + + transform[0].X = texelLeft; + transform[0].Y = texelTop; + + transform[1].X = texelRight; + transform[1].Y = texelTop; + + transform[2].X = texelLeft; + transform[2].Y = texelBottom; + + transform[3].X = texelRight; + transform[3].Y = texelBottom; + + if (flipDiagonally) + { + FloatHelper.Swap(ref transform[1].X, ref transform[2].X); + FloatHelper.Swap(ref transform[1].Y, ref transform[2].Y); + } + + if (flipHorizontally) + { + if (flipDiagonally) + { + FloatHelper.Swap(ref transform[0].Y, ref transform[1].Y); + FloatHelper.Swap(ref transform[2].Y, ref transform[3].Y); + } + else + { + FloatHelper.Swap(ref transform[0].X, ref transform[1].X); + FloatHelper.Swap(ref transform[2].X, ref transform[3].X); + } + } + + if (flipVertically) + { + if (flipDiagonally) + { + FloatHelper.Swap(ref transform[0].X, ref transform[2].X); + FloatHelper.Swap(ref transform[1].X, ref transform[3].X); + } + else + { + FloatHelper.Swap(ref transform[0].Y, ref transform[2].Y); + FloatHelper.Swap(ref transform[1].Y, ref transform[3].Y); + } + } + + transform[0] = transform[0]; + transform[1] = transform[1]; + transform[2] = transform[2]; + transform[3] = transform[3]; + + return transform; + } + private void CreateTextureCoordinates(TiledMapTileset tileset) { var sourceRectangle = tileset.GetTileRegion(LocalTileIdentifier); @@ -44,4 +141,4 @@ namespace MonoGame.Extended.Tiled return $"{LocalTileIdentifier}:{Duration}"; } } -} \ No newline at end of file +}