diff options
Diffstat (limited to 'Plugins/MonoGame.Extended/source/MonoGame.Extended.Tiled/Renderers')
10 files changed, 656 insertions, 0 deletions
diff --git a/Plugins/MonoGame.Extended/source/MonoGame.Extended.Tiled/Renderers/TiledMapAnimatedLayerModel.cs b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Tiled/Renderers/TiledMapAnimatedLayerModel.cs new file mode 100644 index 0000000..791819a --- /dev/null +++ b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Tiled/Renderers/TiledMapAnimatedLayerModel.cs @@ -0,0 +1,32 @@ +using Microsoft.Xna.Framework.Graphics; +using System; + +namespace MonoGame.Extended.Tiled.Renderers +{ + public sealed class TiledMapAnimatedLayerModel : TiledMapLayerModel + { + 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; } + private readonly TiledMapTileFlipFlags[] _animatedTilesetFlipFlags; + + public ReadOnlySpan<TiledMapTileFlipFlags> AnimatedTilesetFlipFlags => _animatedTilesetFlipFlags; + + protected override VertexBuffer CreateVertexBuffer(GraphicsDevice graphicsDevice, int vertexCount) + { + return new DynamicVertexBuffer(graphicsDevice, VertexPositionTexture.VertexDeclaration, vertexCount, BufferUsage.WriteOnly); + } + + protected override IndexBuffer CreateIndexBuffer(GraphicsDevice graphicsDevice, int indexCount) + { + return new DynamicIndexBuffer(graphicsDevice, IndexElementSize.SixteenBits, indexCount, BufferUsage.WriteOnly); ; + } + } +} diff --git a/Plugins/MonoGame.Extended/source/MonoGame.Extended.Tiled/Renderers/TiledMapAnimatedLayerModelBuilder.cs b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Tiled/Renderers/TiledMapAnimatedLayerModelBuilder.cs new file mode 100644 index 0000000..7afcc21 --- /dev/null +++ b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Tiled/Renderers/TiledMapAnimatedLayerModelBuilder.cs @@ -0,0 +1,28 @@ +using System.Collections.Generic; +using Microsoft.Xna.Framework.Graphics; + +namespace MonoGame.Extended.Tiled.Renderers +{ + public class TiledMapAnimatedLayerModelBuilder : TiledMapLayerModelBuilder<TiledMapAnimatedLayerModel> + { + public TiledMapAnimatedLayerModelBuilder() + { + AnimatedTilesetTiles = new List<TiledMapTilesetAnimatedTile>(); + AnimatedTilesetFlipFlags = new List<TiledMapTileFlipFlags>(); + } + + public List<TiledMapTilesetAnimatedTile> AnimatedTilesetTiles { get; } + public List<TiledMapTileFlipFlags> 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(), AnimatedTilesetFlipFlags.ToArray()); + } + } +} diff --git a/Plugins/MonoGame.Extended/source/MonoGame.Extended.Tiled/Renderers/TiledMapEffect.cs b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Tiled/Renderers/TiledMapEffect.cs new file mode 100644 index 0000000..b24e2e9 --- /dev/null +++ b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Tiled/Renderers/TiledMapEffect.cs @@ -0,0 +1,37 @@ +using Microsoft.Xna.Framework.Graphics; +using MonoGame.Extended.Graphics.Effects; + +namespace MonoGame.Extended.Tiled.Renderers +{ + public interface ITiledMapEffect : IEffectMatrices, ITextureEffect + { + float Alpha { get; set; } + } + + public class TiledMapEffect : DefaultEffect, ITiledMapEffect + { + public TiledMapEffect(GraphicsDevice graphicsDevice) + : base(graphicsDevice) + { + Initialize(); + } + + public TiledMapEffect(GraphicsDevice graphicsDevice, byte[] byteCode) + : base(graphicsDevice, byteCode) + { + Initialize(); + } + + public TiledMapEffect(Effect cloneSource) + : base(cloneSource) + { + Initialize(); + } + + private void Initialize() + { + VertexColorEnabled = false; + TextureEnabled = true; + } + } +} diff --git a/Plugins/MonoGame.Extended/source/MonoGame.Extended.Tiled/Renderers/TiledMapLayerModel.cs b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Tiled/Renderers/TiledMapLayerModel.cs new file mode 100644 index 0000000..f837e1a --- /dev/null +++ b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Tiled/Renderers/TiledMapLayerModel.cs @@ -0,0 +1,38 @@ +using System; +using Microsoft.Xna.Framework.Graphics; + +namespace MonoGame.Extended.Tiled.Renderers +{ + public abstract class TiledMapLayerModel : IDisposable + { + protected TiledMapLayerModel(GraphicsDevice graphicsDevice, Texture2D texture, VertexPositionTexture[] vertices, ushort[] indices) + { + Texture = texture; + + // ReSharper disable once VirtualMemberCallInConstructor + VertexBuffer = CreateVertexBuffer(graphicsDevice, vertices.Length); + VertexBuffer.SetData(vertices, 0, vertices.Length); + + // ReSharper disable once VirtualMemberCallInConstructor + IndexBuffer = CreateIndexBuffer(graphicsDevice, indices.Length); + IndexBuffer.SetData(indices, 0, indices.Length); + + TriangleCount = indices.Length / 3; + } + + public void Dispose() + { + IndexBuffer.Dispose(); + VertexBuffer.Dispose(); + } + + public Texture2D Texture { get; } + public VertexBuffer VertexBuffer { get; } + public IndexBuffer IndexBuffer { get; } + public int TriangleCount { get; } + + protected abstract VertexBuffer CreateVertexBuffer(GraphicsDevice graphicsDevice, int vertexCount); + protected abstract IndexBuffer CreateIndexBuffer(GraphicsDevice graphicsDevice, int indexCount); + + } +}
\ No newline at end of file diff --git a/Plugins/MonoGame.Extended/source/MonoGame.Extended.Tiled/Renderers/TiledMapLayerModelBuilder.cs b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Tiled/Renderers/TiledMapLayerModelBuilder.cs new file mode 100644 index 0000000..fbc99d6 --- /dev/null +++ b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Tiled/Renderers/TiledMapLayerModelBuilder.cs @@ -0,0 +1,125 @@ +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Graphics; + +namespace MonoGame.Extended.Tiled.Renderers +{ + public abstract class TiledMapLayerModelBuilder<T> + { + protected TiledMapLayerModelBuilder() + { + Indices = new List<ushort>(); + Vertices = new List<VertexPositionTexture>(); + } + + public List<ushort> Indices { get; } + public List<VertexPositionTexture> Vertices { get; } + public bool IsFull => Vertices.Count + TiledMapHelper.VerticesPerTile >= TiledMapHelper.MaximumVerticesPerModel; + public bool IsBuildable => Vertices.Any(); + + protected abstract void ClearBuffers(); + protected abstract T CreateModel(GraphicsDevice graphicsDevice, Texture2D texture); + + public T Build(GraphicsDevice graphicsDevice, Texture2D texture) + { + var model = CreateModel(graphicsDevice, texture); + Vertices.Clear(); + Indices.Clear(); + ClearBuffers(); + return model; + } + + public void AddSprite(Texture2D texture, Point2 position, Rectangle sourceRectangle, TiledMapTileFlipFlags flipFlags) + { + Indices.AddRange(CreateTileIndices(Vertices.Count)); + Debug.Assert(Indices.Count <= TiledMapHelper.MaximumIndicesPerModel); + + Vertices.AddRange(CreateVertices(texture, position, sourceRectangle, flipFlags)); + Debug.Assert(Vertices.Count <= TiledMapHelper.MaximumVerticesPerModel); + } + + private static IEnumerable<VertexPositionTexture> CreateVertices(Texture2D texture, Vector2 position, Rectangle sourceRectangle, TiledMapTileFlipFlags flags = TiledMapTileFlipFlags.None) + { + var reciprocalWidth = 1f / texture.Width; + var reciprocalHeight = 1f / texture.Height; + var texelLeft = sourceRectangle.X * reciprocalWidth; + var texelTop = sourceRectangle.Y * reciprocalHeight; + var texelRight = (sourceRectangle.X + sourceRectangle.Width) * reciprocalWidth; + var texelBottom = (sourceRectangle.Y + sourceRectangle.Height) * reciprocalHeight; + + VertexPositionTexture vertexTopLeft, vertexTopRight, vertexBottomLeft, vertexBottomRight; + + vertexTopLeft.Position = new Vector3(position, 0); + vertexTopRight.Position = new Vector3(position + new Vector2(sourceRectangle.Width, 0), 0); + vertexBottomLeft.Position = new Vector3(position + new Vector2(0, sourceRectangle.Height), 0); + vertexBottomRight.Position = new Vector3(position + new Vector2(sourceRectangle.Width, sourceRectangle.Height), 0); + + vertexTopLeft.TextureCoordinate.Y = texelTop; + vertexTopLeft.TextureCoordinate.X = texelLeft; + + vertexTopRight.TextureCoordinate.Y = texelTop; + vertexTopRight.TextureCoordinate.X = texelRight; + + vertexBottomLeft.TextureCoordinate.Y = texelBottom; + vertexBottomLeft.TextureCoordinate.X = texelLeft; + + vertexBottomRight.TextureCoordinate.Y = texelBottom; + vertexBottomRight.TextureCoordinate.X = texelRight; + + var flipDiagonally = (flags & TiledMapTileFlipFlags.FlipDiagonally) != 0; + var flipHorizontally = (flags & TiledMapTileFlipFlags.FlipHorizontally) != 0; + var flipVertically = (flags & TiledMapTileFlipFlags.FlipVertically) != 0; + + if (flipDiagonally) + { + FloatHelper.Swap(ref vertexTopRight.TextureCoordinate.X, ref vertexBottomLeft.TextureCoordinate.X); + FloatHelper.Swap(ref vertexTopRight.TextureCoordinate.Y, ref vertexBottomLeft.TextureCoordinate.Y); + } + + if (flipHorizontally) + { + if (flipDiagonally) + { + FloatHelper.Swap(ref vertexTopLeft.TextureCoordinate.Y, ref vertexTopRight.TextureCoordinate.Y); + FloatHelper.Swap(ref vertexBottomLeft.TextureCoordinate.Y, ref vertexBottomRight.TextureCoordinate.Y); + } + else + { + FloatHelper.Swap(ref vertexTopLeft.TextureCoordinate.X, ref vertexTopRight.TextureCoordinate.X); + FloatHelper.Swap(ref vertexBottomLeft.TextureCoordinate.X, ref vertexBottomRight.TextureCoordinate.X); + } + } + + if (flipVertically) + { + if (flipDiagonally) + { + FloatHelper.Swap(ref vertexTopLeft.TextureCoordinate.X, ref vertexBottomLeft.TextureCoordinate.X); + FloatHelper.Swap(ref vertexTopRight.TextureCoordinate.X, ref vertexBottomRight.TextureCoordinate.X); + } + else + { + FloatHelper.Swap(ref vertexTopLeft.TextureCoordinate.Y, ref vertexBottomLeft.TextureCoordinate.Y); + FloatHelper.Swap(ref vertexTopRight.TextureCoordinate.Y, ref vertexBottomRight.TextureCoordinate.Y); + } + } + + yield return vertexTopLeft; + yield return vertexTopRight; + yield return vertexBottomLeft; + yield return vertexBottomRight; + } + + private static IEnumerable<ushort> CreateTileIndices(int indexOffset) + { + yield return (ushort)(0 + indexOffset); + yield return (ushort)(1 + indexOffset); + yield return (ushort)(2 + indexOffset); + yield return (ushort)(1 + indexOffset); + yield return (ushort)(3 + indexOffset); + yield return (ushort)(2 + indexOffset); + } + } +} diff --git a/Plugins/MonoGame.Extended/source/MonoGame.Extended.Tiled/Renderers/TiledMapModel.cs b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Tiled/Renderers/TiledMapModel.cs new file mode 100644 index 0000000..52e56bc --- /dev/null +++ b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Tiled/Renderers/TiledMapModel.cs @@ -0,0 +1,41 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Linq; + +namespace MonoGame.Extended.Tiled.Renderers +{ + public class TiledMapModel : IDisposable + { + private readonly TiledMap _map; + private readonly Dictionary<TiledMapTileset, List<TiledMapTilesetAnimatedTile>> _animatedTilesByTileset; + + public TiledMapModel(TiledMap map, Dictionary<TiledMapLayer, TiledMapLayerModel[]> layersOfLayerModels) + { + _map = map; + LayersOfLayerModels = layersOfLayerModels; + _animatedTilesByTileset = _map.Tilesets + .ToDictionary(i => i, i => i.Tiles.OfType<TiledMapTilesetAnimatedTile>() + .ToList()); + } + + public void Dispose() + { + foreach (var layerModel in LayersOfLayerModels) + foreach (var model in layerModel.Value) + model.Dispose(); + } + + public ReadOnlyCollection<TiledMapTileset> Tilesets => _map.Tilesets; + public ReadOnlyCollection<TiledMapLayer> Layers => _map.Layers; + + // each layer has many models + public Dictionary<TiledMapLayer, TiledMapLayerModel[]> LayersOfLayerModels { get; } + + public IEnumerable<TiledMapTilesetAnimatedTile> GetAnimatedTiles(int tilesetIndex) + { + var tileset = _map.Tilesets[tilesetIndex]; + return _animatedTilesByTileset[tileset]; + } + } +}
\ No newline at end of file diff --git a/Plugins/MonoGame.Extended/source/MonoGame.Extended.Tiled/Renderers/TiledMapModelBuilder.cs b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Tiled/Renderers/TiledMapModelBuilder.cs new file mode 100644 index 0000000..b96925e --- /dev/null +++ b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Tiled/Renderers/TiledMapModelBuilder.cs @@ -0,0 +1,126 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Microsoft.Xna.Framework.Graphics; + +namespace MonoGame.Extended.Tiled.Renderers +{ + public class TiledMapModelBuilder + { + private readonly GraphicsDevice _graphicsDevice; + + public TiledMapModelBuilder(GraphicsDevice graphicsDevice) + { + _graphicsDevice = graphicsDevice; + } + + private IEnumerable<TiledMapLayerModel> CreateLayerModels(TiledMap map, TiledMapLayer layer) + { + switch(layer) + { + case TiledMapTileLayer tileLayer: + return CreateTileLayerModels(map, tileLayer); + case TiledMapImageLayer imageLayer: + return CreateImageLayerModels(imageLayer); + default: + return new List<TiledMapLayerModel>(); + } + + } + + private IEnumerable<TiledMapLayerModel> CreateImageLayerModels(TiledMapImageLayer imageLayer) + { + var modelBuilder = new TiledMapStaticLayerModelBuilder(); + modelBuilder.AddSprite(imageLayer.Image, imageLayer.Position, imageLayer.Image.Bounds, TiledMapTileFlipFlags.None); + yield return modelBuilder.Build(_graphicsDevice, imageLayer.Image); + } + + private IEnumerable<TiledMapLayerModel> CreateTileLayerModels(TiledMap map, TiledMapTileLayer tileLayer) + { + var layerModels = new List<TiledMapLayerModel>(); + var staticLayerBuilder = new TiledMapStaticLayerModelBuilder(); + var animatedLayerBuilder = new TiledMapAnimatedLayerModelBuilder(); + + foreach (var tileset in map.Tilesets) + { + var firstGlobalIdentifier = map.GetTilesetFirstGlobalIdentifier(tileset); + var lastGlobalIdentifier = tileset.TileCount + firstGlobalIdentifier - 1; + var texture = tileset.Texture; + + foreach (var tile in tileLayer.Tiles.Where(t => firstGlobalIdentifier <= t.GlobalIdentifier && t.GlobalIdentifier <= lastGlobalIdentifier)) + { + var tileGid = tile.GlobalIdentifier; + var localTileIdentifier = tileGid - firstGlobalIdentifier; + var position = GetTilePosition(map, tile); + var sourceRectangle = tileset.GetTileRegion(localTileIdentifier); + var flipFlags = tile.Flags; + + // animated tiles + var tilesetTile = tileset.Tiles.FirstOrDefault(x => x.LocalTileIdentifier == localTileIdentifier); + if (tilesetTile?.Texture is not null) + { + position.Y += map.TileHeight - sourceRectangle.Height; + texture = tilesetTile.Texture; + } + + 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)); + } + else + { + staticLayerBuilder.AddSprite(texture, position, sourceRectangle, flipFlags); + + if (staticLayerBuilder.IsFull) + layerModels.Add(staticLayerBuilder.Build(_graphicsDevice, texture)); + } + } + + if (staticLayerBuilder.IsBuildable) + layerModels.Add(staticLayerBuilder.Build(_graphicsDevice, texture)); + + if (animatedLayerBuilder.IsBuildable) + layerModels.Add(animatedLayerBuilder.Build(_graphicsDevice, texture)); + } + + return layerModels; + } + + public TiledMapModel Build(TiledMap map) + { + var dictionary = new Dictionary<TiledMapLayer, TiledMapLayerModel[]>(); + foreach (var layer in map.Layers) + BuildLayer(map, layer, dictionary); + + return new TiledMapModel(map, dictionary); + } + + private void BuildLayer(TiledMap map, TiledMapLayer layer, Dictionary<TiledMapLayer, TiledMapLayerModel[]> dictionary) + { + if (layer is TiledMapGroupLayer groupLayer) + foreach (var subLayer in groupLayer.Layers) + BuildLayer(map, subLayer, dictionary); + else + dictionary.Add(layer, CreateLayerModels(map, layer).ToArray()); + } + + private static Point2 GetTilePosition(TiledMap map, TiledMapTile mapTile) + { + switch (map.Orientation) + { + case TiledMapOrientation.Orthogonal: + return TiledMapHelper.GetOrthogonalPosition(mapTile.X, mapTile.Y, map.TileWidth, map.TileHeight); + case TiledMapOrientation.Isometric: + return TiledMapHelper.GetIsometricPosition(mapTile.X, mapTile.Y, map.TileWidth, map.TileHeight); + default: + throw new NotSupportedException($"{map.Orientation} Tiled Maps are not yet implemented."); + } + } + } +} diff --git a/Plugins/MonoGame.Extended/source/MonoGame.Extended.Tiled/Renderers/TiledMapRenderer.cs b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Tiled/Renderers/TiledMapRenderer.cs new file mode 100644 index 0000000..66babad --- /dev/null +++ b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Tiled/Renderers/TiledMapRenderer.cs @@ -0,0 +1,191 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Graphics; + +namespace MonoGame.Extended.Tiled.Renderers +{ + public class TiledMapRenderer : IDisposable + { + private readonly TiledMapModelBuilder _mapModelBuilder; + private readonly TiledMapEffect _defaultEffect; + private readonly GraphicsDevice _graphicsDevice; + private TiledMapModel _mapModel; + private Matrix _worldMatrix = Matrix.Identity; + + public TiledMapRenderer(GraphicsDevice graphicsDevice, TiledMap map = null) + { + if (graphicsDevice == null) throw new ArgumentNullException(nameof(graphicsDevice)); + + _graphicsDevice = graphicsDevice; + _defaultEffect = new TiledMapEffect(graphicsDevice); + _mapModelBuilder = new TiledMapModelBuilder(graphicsDevice); + + if(map != null) + LoadMap(map); + } + + public void Dispose() + { + _mapModel?.Dispose(); + _defaultEffect.Dispose(); + } + + public void LoadMap(TiledMap map) + { + _mapModel?.Dispose(); + _mapModel = map != null ? _mapModelBuilder.Build(map) : null; + } + + public void Update(GameTime gameTime) + { + if(_mapModel == null) + return; + + for (var tilesetIndex = 0; tilesetIndex < _mapModel.Tilesets.Count; tilesetIndex++) + { + foreach (var animatedTilesetTile in _mapModel.GetAnimatedTiles(tilesetIndex)) + animatedTilesetTile.Update(gameTime); + } + + foreach(var layer in _mapModel.LayersOfLayerModels) + UpdateAnimatedLayerModels(layer.Value.OfType<TiledMapAnimatedLayerModel>()); + } + + private static unsafe void UpdateAnimatedLayerModels(IEnumerable<TiledMapAnimatedLayerModel> animatedLayerModels) + { + foreach (var animatedModel in animatedLayerModels) + { + // update the texture coordinates for each animated tile + fixed (VertexPositionTexture* fixedVerticesPointer = animatedModel.Vertices) + { + var verticesPointer = fixedVerticesPointer; + for (int i = 0; i < animatedModel.AnimatedTilesetTiles.Length; i++) + { + var currentFrameTextureCoordinates = animatedModel.AnimatedTilesetTiles[i].CurrentAnimationFrame.GetTextureCoordinates(animatedModel.AnimatedTilesetFlipFlags[i]); + + // ReSharper disable ArrangeRedundantParentheses + (*verticesPointer++).TextureCoordinate = currentFrameTextureCoordinates[0]; + (*verticesPointer++).TextureCoordinate = currentFrameTextureCoordinates[1]; + (*verticesPointer++).TextureCoordinate = currentFrameTextureCoordinates[2]; + (*verticesPointer++).TextureCoordinate = currentFrameTextureCoordinates[3]; + // ReSharper restore ArrangeRedundantParentheses + } + } + + // copy (upload) the updated vertices to the GPU's memory + animatedModel.VertexBuffer.SetData(animatedModel.Vertices, 0, animatedModel.Vertices.Length); + } + } + + public void Draw(Matrix? viewMatrix = null, Matrix? projectionMatrix = null, Effect effect = null, float depth = 0.0f) + { + var viewMatrix1 = viewMatrix ?? Matrix.Identity; + var projectionMatrix1 = projectionMatrix ?? Matrix.CreateOrthographicOffCenter(0, _graphicsDevice.Viewport.Width, _graphicsDevice.Viewport.Height, 0, 0, -1); + + Draw(ref viewMatrix1, ref projectionMatrix1, effect, depth); + } + + public void Draw(ref Matrix viewMatrix, ref Matrix projectionMatrix, Effect effect = null, float depth = 0.0f) + { + if (_mapModel == null) + return; + + for (var index = 0; index < _mapModel.Layers.Count; index++) + Draw(index, ref viewMatrix, ref projectionMatrix, effect, depth); + } + + public void Draw(TiledMapLayer layer, Matrix? viewMatrix = null, Matrix? projectionMatrix = null, Effect effect = null, float depth = 0.0f) + { + var viewMatrix1 = viewMatrix ?? Matrix.Identity; + var projectionMatrix1 = projectionMatrix ?? Matrix.CreateOrthographicOffCenter(0, _graphicsDevice.Viewport.Width, _graphicsDevice.Viewport.Height, 0, 0, -1); + + Draw(layer, ref viewMatrix1, ref projectionMatrix1, effect, depth); + } + + public void Draw(int layerIndex, Matrix? viewMatrix = null, Matrix? projectionMatrix = null, Effect effect = null, float depth = 0.0f) + { + var viewMatrix1 = viewMatrix ?? Matrix.Identity; + var projectionMatrix1 = projectionMatrix ?? Matrix.CreateOrthographicOffCenter(0, _graphicsDevice.Viewport.Width, _graphicsDevice.Viewport.Height, 0, 0, -1); + + Draw(layerIndex, ref viewMatrix1, ref projectionMatrix1, effect, depth); + } + + public void Draw(int layerIndex, ref Matrix viewMatrix, ref Matrix projectionMatrix, Effect effect = null, float depth = 0.0f) + { + var layer = _mapModel.Layers[layerIndex]; + + Draw(layer, ref viewMatrix, ref projectionMatrix, effect, depth); + } + + public void Draw(TiledMapLayer layer, ref Matrix viewMatrix, ref Matrix projectionMatrix, Effect effect = null, float depth = 0.0f) + { + if (_mapModel == null) + return; + + if (!layer.IsVisible) + return; + + if (layer is TiledMapObjectLayer) + return; + + Draw(layer, Vector2.Zero, Vector2.One, ref viewMatrix, ref projectionMatrix, effect, depth); + } + + private void Draw(TiledMapLayer layer, Vector2 parentOffset, Vector2 parentParallaxFactor, ref Matrix viewMatrix, ref Matrix projectionMatrix, Effect effect, float depth) + { + var offset = parentOffset + layer.Offset; + var parallaxFactor = parentParallaxFactor * layer.ParallaxFactor; + + if (layer is TiledMapGroupLayer groupLayer) + { + foreach (var subLayer in groupLayer.Layers) + Draw(subLayer, offset, parallaxFactor, ref viewMatrix, ref projectionMatrix, effect, depth); + } + else + { + _worldMatrix.Translation = new Vector3(offset, depth); + + var effect1 = effect ?? _defaultEffect; + var tiledMapEffect = effect1 as ITiledMapEffect; + if (tiledMapEffect == null) + return; + + // model-to-world transform + tiledMapEffect.World = _worldMatrix; + tiledMapEffect.View = parallaxFactor == Vector2.One ? viewMatrix : IncludeParallax(viewMatrix, parallaxFactor); + tiledMapEffect.Projection = projectionMatrix; + + foreach (var layerModel in _mapModel.LayersOfLayerModels[layer]) + { + // desired alpha + tiledMapEffect.Alpha = layer.Opacity; + + // desired texture + tiledMapEffect.Texture = layerModel.Texture; + + // bind the vertex and index buffer + _graphicsDevice.SetVertexBuffer(layerModel.VertexBuffer); + _graphicsDevice.Indices = layerModel.IndexBuffer; + + // for each pass in our effect + foreach (var pass in effect1.CurrentTechnique.Passes) + { + // apply the pass, effectively choosing which vertex shader and fragment (pixel) shader to use + pass.Apply(); + + // draw the geometry from the vertex buffer / index buffer + _graphicsDevice.DrawIndexedPrimitives(PrimitiveType.TriangleList, 0, 0, layerModel.TriangleCount); + } + } + } + } + + private Matrix IncludeParallax(Matrix viewMatrix, Vector2 parallaxFactor) + { + viewMatrix.Translation *=new Vector3(parallaxFactor, 1f); + return viewMatrix; + } + } +} diff --git a/Plugins/MonoGame.Extended/source/MonoGame.Extended.Tiled/Renderers/TiledMapStaticLayerModel.cs b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Tiled/Renderers/TiledMapStaticLayerModel.cs new file mode 100644 index 0000000..34bf683 --- /dev/null +++ b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Tiled/Renderers/TiledMapStaticLayerModel.cs @@ -0,0 +1,22 @@ +using Microsoft.Xna.Framework.Graphics; + +namespace MonoGame.Extended.Tiled.Renderers +{ + public sealed class TiledMapStaticLayerModel : TiledMapLayerModel + { + public TiledMapStaticLayerModel(GraphicsDevice graphicsDevice, Texture2D texture, VertexPositionTexture[] vertices, ushort[] indices) + : base(graphicsDevice, texture, vertices, indices) + { + } + + protected override VertexBuffer CreateVertexBuffer(GraphicsDevice graphicsDevice, int vertexCount) + { + return new VertexBuffer(graphicsDevice, VertexPositionTexture.VertexDeclaration, vertexCount, BufferUsage.WriteOnly); + } + + protected override IndexBuffer CreateIndexBuffer(GraphicsDevice graphicsDevice, int indexCount) + { + return new IndexBuffer(graphicsDevice, IndexElementSize.SixteenBits, indexCount, BufferUsage.WriteOnly); ; + } + } +}
\ No newline at end of file diff --git a/Plugins/MonoGame.Extended/source/MonoGame.Extended.Tiled/Renderers/TiledMapStaticLayerModelBuilder.cs b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Tiled/Renderers/TiledMapStaticLayerModelBuilder.cs new file mode 100644 index 0000000..8c7d49b --- /dev/null +++ b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Tiled/Renderers/TiledMapStaticLayerModelBuilder.cs @@ -0,0 +1,16 @@ +using Microsoft.Xna.Framework.Graphics; + +namespace MonoGame.Extended.Tiled.Renderers +{ + public class TiledMapStaticLayerModelBuilder : TiledMapLayerModelBuilder<TiledMapStaticLayerModel> + { + protected override void ClearBuffers() + { + } + + protected override TiledMapStaticLayerModel CreateModel(GraphicsDevice graphicsDevice, Texture2D texture) + { + return new TiledMapStaticLayerModel(graphicsDevice, texture, Vertices.ToArray(), Indices.ToArray()); + } + } +}
\ No newline at end of file |