summaryrefslogtreecommitdiff
path: root/Plugins/MonoGame.Extended/source/MonoGame.Extended.Tiled/Renderers/TiledMapModelBuilder.cs
blob: b96925e330971ad099cc9cf0ee29d088a5017cba (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
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.");
            }
        }
    }
}