diff options
Diffstat (limited to 'Plugins/MonoGame.Extended/source/MonoGame.Extended.Tiled/Renderers/TiledMapRenderer.cs')
-rw-r--r-- | Plugins/MonoGame.Extended/source/MonoGame.Extended.Tiled/Renderers/TiledMapRenderer.cs | 191 |
1 files changed, 191 insertions, 0 deletions
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; + } + } +} |