diff --git a/MLEM.Extended/MLEM.Extended.csproj b/MLEM.Extended/MLEM.Extended.csproj
index de09dc9..39eb0b8 100644
--- a/MLEM.Extended/MLEM.Extended.csproj
+++ b/MLEM.Extended/MLEM.Extended.csproj
@@ -17,6 +17,9 @@
all
+
+ all
+
all
diff --git a/MLEM.Extended/Tiled/IndividualTiledMapRenderer.cs b/MLEM.Extended/Tiled/IndividualTiledMapRenderer.cs
new file mode 100644
index 0000000..ee83f62
--- /dev/null
+++ b/MLEM.Extended/Tiled/IndividualTiledMapRenderer.cs
@@ -0,0 +1,93 @@
+using System;
+using Microsoft.Xna.Framework;
+using Microsoft.Xna.Framework.Graphics;
+using MLEM.Extensions;
+using MonoGame.Extended;
+using MonoGame.Extended.Tiled;
+
+namespace MLEM.Extended.Tiled {
+ public class IndividualTiledMapRenderer {
+
+ private TiledMap map;
+ private TileDrawInfo[,,] drawInfos;
+ public GetDepth DepthFunction = (tile, layer, layerIndex, position) => 0;
+
+ public IndividualTiledMapRenderer(TiledMap map = null) {
+ if (map != null)
+ this.SetMap(map);
+ }
+
+ public void SetMap(TiledMap map) {
+ if (this.map == map)
+ return;
+ this.map = map;
+
+ this.drawInfos = new TileDrawInfo[map.TileLayers.Count, map.Width, map.Height];
+ for (var i = 0; i < map.TileLayers.Count; i++) {
+ var layer = map.TileLayers[i];
+ for (var x = 0; x < map.Width; x++) {
+ for (var y = 0; y < map.Height; y++) {
+ var tile = layer.GetTile((ushort) x, (ushort) y);
+ if (tile.IsBlank)
+ continue;
+ var tileset = tile.GetTileset(map);
+ var source = tileset.GetTileRegion(tile.GetLocalIdentifier(tileset, map));
+ this.drawInfos[i, x, y] = new TileDrawInfo(this, tile, layer, i, tileset, new Point(x, y), source);
+ }
+ }
+ }
+ }
+
+ public void Draw(SpriteBatch batch, RectangleF? frustum = null) {
+ for (var i = 0; i < this.map.TileLayers.Count; i++) {
+ this.DrawLayer(batch, i, frustum);
+ }
+ }
+
+ public void DrawLayer(SpriteBatch batch, int layerIndex, RectangleF? frustum = null) {
+ var frust = frustum ?? new RectangleF(0, 0, float.MaxValue, float.MaxValue);
+ var minX = Math.Max(0, frust.Left / this.map.TileWidth).Floor();
+ var minY = Math.Max(0, frust.Top / this.map.TileHeight).Floor();
+ var maxX = Math.Min(this.map.Width, frust.Right / this.map.TileWidth).Ceil();
+ var maxY = Math.Min(this.map.Height, frust.Bottom / this.map.TileHeight).Ceil();
+ for (var x = minX; x < maxX; x++) {
+ for (var y = minY; y < maxY; y++) {
+ var info = this.drawInfos[layerIndex, x, y];
+ if (info != null)
+ info.Draw(batch);
+ }
+ }
+ }
+
+ public delegate float GetDepth(TiledMapTile tile, TiledMapTileLayer layer, int layerIndex, Point position);
+
+ private class TileDrawInfo {
+
+ private readonly IndividualTiledMapRenderer renderer;
+ private readonly TiledMapTile tile;
+ private readonly TiledMapTileLayer layer;
+ private readonly int layerIndex;
+ private readonly TiledMapTileset tileset;
+ private readonly Point position;
+ private readonly Rectangle source;
+
+ public TileDrawInfo(IndividualTiledMapRenderer renderer, TiledMapTile tile, TiledMapTileLayer layer, int layerIndex, TiledMapTileset tileset, Point position, Rectangle source) {
+ this.renderer = renderer;
+ this.tile = tile;
+ this.layer = layer;
+ this.layerIndex = layerIndex;
+ this.tileset = tileset;
+ this.position = position;
+ this.source = source;
+ }
+
+ public void Draw(SpriteBatch batch) {
+ var drawPos = new Vector2(this.position.X * this.renderer.map.TileWidth, this.position.Y * this.renderer.map.TileHeight);
+ var depth = this.renderer.DepthFunction(this.tile, this.layer, this.layerIndex, this.position);
+ batch.Draw(this.tileset.Texture, drawPos, this.source, Color.White, 0, Vector2.Zero, 1, SpriteEffects.None, depth);
+ }
+
+ }
+
+ }
+}
\ No newline at end of file
diff --git a/MLEM.Extended/Tiled/TiledExtensions.cs b/MLEM.Extended/Tiled/TiledExtensions.cs
new file mode 100644
index 0000000..dbb5dae
--- /dev/null
+++ b/MLEM.Extended/Tiled/TiledExtensions.cs
@@ -0,0 +1,62 @@
+using System.Linq;
+using Microsoft.Xna.Framework;
+using MonoGame.Extended;
+using MonoGame.Extended.Tiled;
+
+namespace MLEM.Extended.Tiled {
+ public static class TiledExtensions {
+
+ public static string Get(this TiledMapProperties properties, string key) {
+ properties.TryGetValue(key, out var val);
+ return val;
+ }
+
+ public static bool GetBool(this TiledMapProperties properties, string key) {
+ bool.TryParse(properties.Get(key), out var val);
+ return val;
+ }
+
+ public static Color GetColor(this TiledMapProperties properties, string key) {
+ return ColorHelper.FromHex(properties.Get(key));
+ }
+
+ public static float GetFloat(this TiledMapProperties properties, string key) {
+ float.TryParse(properties.Get(key), out var val);
+ return val;
+ }
+
+ public static int GetInt(this TiledMapProperties properties, string key) {
+ int.TryParse(properties.Get(key), out var val);
+ return val;
+ }
+
+ public static TiledMapTileset GetTileset(this TiledMapTile tile, TiledMap map) {
+ return map.GetTilesetByTileGlobalIdentifier(tile.GlobalIdentifier);
+ }
+
+ public static int GetLocalIdentifier(this TiledMapTile tile, TiledMapTileset tileset, TiledMap map) {
+ return tile.GlobalIdentifier - map.GetTilesetFirstGlobalIdentifier(tileset);
+ }
+
+ public static TiledMapTilesetTile GetTilesetTile(this TiledMapTileset tileset, TiledMapTile tile, TiledMap map) {
+ var localId = tile.GetLocalIdentifier(tileset, map);
+ return tileset.Tiles.FirstOrDefault(t => t.LocalTileIdentifier == localId);
+ }
+
+ public static TiledMapTilesetTile GetTilesetTile(this TiledMapTile tile, TiledMap map) {
+ var tileset = tile.GetTileset(map);
+ return tileset.GetTilesetTile(tile, map);
+ }
+
+ public static TiledMapTile GetTile(this TiledMap map, string layerName, int x, int y) {
+ var layer = map.GetLayer(layerName);
+ return layer != null ? layer.GetTile((ushort) x, (ushort) y) : new TiledMapTile(0, (ushort) x, (ushort) y);
+ }
+
+ public static RectangleF GetArea(this TiledMapObject obj, TiledMap map, Vector2 position) {
+ var tileSize = new Vector2(map.TileWidth, map.TileHeight);
+ return new RectangleF(obj.Position / tileSize + position, new Size2(obj.Size.Width, obj.Size.Height) / tileSize);
+ }
+
+ }
+}
\ No newline at end of file