From c37a691c33bbc0258672278984c2c6abedaaf6b3 Mon Sep 17 00:00:00 2001 From: RoosterDragon Date: Fri, 5 Dec 2014 20:55:18 +0000 Subject: [PATCH] Convert some keys users of CellLayer to index via map-coords for efficiency. --- OpenRA.Game/Graphics/Minimap.cs | 12 ++-- OpenRA.Game/Map/Map.cs | 18 +++-- OpenRA.Game/Orders/UnitOrderGenerator.cs | 4 +- OpenRA.Game/Traits/Player/FrozenActorLayer.cs | 18 +++-- OpenRA.Game/Traits/World/Shroud.cs | 61 ++++++++++------- OpenRA.Game/World.cs | 11 ++-- .../Traits/World/ShroudRenderer.cs | 65 +++++++++++-------- .../Traits/World/TerrainGeometryOverlay.cs | 8 +-- OpenRA.Mods.RA/Move/PathSearch.cs | 4 +- .../Traits/Modifiers/FrozenUnderFog.cs | 19 ++++-- OpenRA.Mods.RA/Traits/World/ResourceLayer.cs | 8 +-- 11 files changed, 140 insertions(+), 88 deletions(-) diff --git a/OpenRA.Game/Graphics/Minimap.cs b/OpenRA.Game/Graphics/Minimap.cs index b8231c0633..62fdcdaacd 100644 --- a/OpenRA.Game/Graphics/Minimap.cs +++ b/OpenRA.Game/Graphics/Minimap.cs @@ -182,13 +182,13 @@ namespace OpenRA.Graphics var stride = bitmapData.Stride / 4; var shroudObscured = world.ShroudObscuresTest(map.Cells); var fogObscured = world.FogObscuresTest(map.Cells); - foreach (var cell in map.Cells) + foreach (var uv in map.Cells.MapCoords) { - var uv = Map.CellToMap(map.TileShape, cell) - offset; - if (shroudObscured(cell)) - colors[uv.Y * stride + uv.X] = shroud; - else if (fogObscured(cell)) - colors[uv.Y * stride + uv.X] = fog; + var bitmapUv = uv - offset; + if (shroudObscured(uv.X, uv.Y)) + colors[bitmapUv.Y * stride + bitmapUv.X] = shroud; + else if (fogObscured(uv.X, uv.Y)) + colors[bitmapUv.Y * stride + bitmapUv.X] = fog; } } diff --git a/OpenRA.Game/Map/Map.cs b/OpenRA.Game/Map/Map.cs index 2118cdafe2..c065d6a657 100644 --- a/OpenRA.Game/Map/Map.cs +++ b/OpenRA.Game/Map/Map.cs @@ -366,8 +366,8 @@ namespace OpenRA Cells = new CellRegion(TileShape, tl, br); CustomTerrain = new CellLayer(this); - foreach (var cell in Cells) - CustomTerrain[cell] = byte.MaxValue; + foreach (var uv in Cells.MapCoords) + CustomTerrain[uv.X, uv.Y] = byte.MaxValue; } public Ruleset PreloadRules() @@ -597,7 +597,12 @@ namespace OpenRA public bool Contains(CPos cell) { var uv = CellToMap(TileShape, cell); - return Bounds.Contains(uv.X, uv.Y); + return Contains(uv.X, uv.Y); + } + + public bool Contains(int u, int v) + { + return Bounds.Contains(u, v); } public WPos CenterOfCell(CPos cell) @@ -795,8 +800,11 @@ namespace OpenRA public byte GetTerrainIndex(CPos cell) { - var custom = CustomTerrain[cell]; - return custom != byte.MaxValue ? custom : cachedTileSet.Value.GetTerrainIndex(MapTiles.Value[cell]); + var uv = Map.CellToMap(TileShape, cell); + var u = uv.X; + var v = uv.Y; + var custom = CustomTerrain[u, v]; + return custom != byte.MaxValue ? custom : cachedTileSet.Value.GetTerrainIndex(MapTiles.Value[u, v]); } public TerrainTypeInfo GetTerrainInfo(CPos cell) diff --git a/OpenRA.Game/Orders/UnitOrderGenerator.cs b/OpenRA.Game/Orders/UnitOrderGenerator.cs index 8ab6d1af0b..aba42f90d3 100644 --- a/OpenRA.Game/Orders/UnitOrderGenerator.cs +++ b/OpenRA.Game/Orders/UnitOrderGenerator.cs @@ -29,7 +29,7 @@ namespace OpenRA.Orders else { var frozen = world.ScreenMap.FrozenActorsAt(world.RenderPlayer, mi) - .Where(a => a.Info.Traits.Contains() && !a.Footprint.All(c => world.ShroudObscures(c))) + .Where(a => a.Info.Traits.Contains() && !a.FootprintInMapCoords.All(uv => world.ShroudObscures(uv.X, uv.Y))) .WithHighestSelectionPriority(); target = frozen != null ? Target.FromFrozenActor(frozen) : Target.FromCell(world, xy); } @@ -74,7 +74,7 @@ namespace OpenRA.Orders else { var frozen = world.ScreenMap.FrozenActorsAt(world.RenderPlayer, mi) - .Where(a => a.Info.Traits.Contains() && !a.Footprint.All(c => world.ShroudObscures(c))) + .Where(a => a.Info.Traits.Contains() && !a.FootprintInMapCoords.All(uv => world.ShroudObscures(uv.X, uv.Y))) .WithHighestSelectionPriority(); target = frozen != null ? Target.FromFrozenActor(frozen) : Target.FromCell(world, xy); } diff --git a/OpenRA.Game/Traits/Player/FrozenActorLayer.cs b/OpenRA.Game/Traits/Player/FrozenActorLayer.cs index bc8bb48193..5a33244f56 100755 --- a/OpenRA.Game/Traits/Player/FrozenActorLayer.cs +++ b/OpenRA.Game/Traits/Player/FrozenActorLayer.cs @@ -23,7 +23,7 @@ namespace OpenRA.Traits public class FrozenActor { - public readonly CPos[] Footprint; + public readonly CPos[] FootprintInMapCoords; public readonly CellRegion FootprintRegion; public readonly WPos CenterPosition; public readonly Rectangle Bounds; @@ -40,10 +40,10 @@ namespace OpenRA.Traits public bool Visible; - public FrozenActor(Actor self, CPos[] footprint, CellRegion footprintRegion) + public FrozenActor(Actor self, CPos[] footprintInMapCoords, CellRegion footprintRegion) { actor = self; - Footprint = footprint; + FootprintInMapCoords = footprintInMapCoords; FootprintRegion = footprintRegion; CenterPosition = self.CenterPosition; @@ -58,7 +58,17 @@ namespace OpenRA.Traits int flashTicks; public void Tick(World world, Shroud shroud) { - Visible = !Footprint.Any(shroud.IsVisibleTest(FootprintRegion)); + // We are doing the following LINQ manually to avoid allocating an extra delegate since this is a hot path. + // Visible = !FootprintInMapCoords.Any(mapCoord => shroud.IsVisibleTest(FootprintRegion)(mapCoord.X, mapCoord.Y)); + var isVisibleTest = shroud.IsVisibleTest(FootprintRegion); + Visible = true; + foreach (var mapCoord in FootprintInMapCoords) + if (isVisibleTest(mapCoord.X, mapCoord.Y)) + { + Visible = false; + break; + } + if (flashTicks > 0) flashTicks--; } diff --git a/OpenRA.Game/Traits/World/Shroud.cs b/OpenRA.Game/Traits/World/Shroud.cs index 6b7037a28b..685063e929 100644 --- a/OpenRA.Game/Traits/World/Shroud.cs +++ b/OpenRA.Game/Traits/World/Shroud.cs @@ -57,12 +57,12 @@ namespace OpenRA.Traits public int Hash { get; private set; } - static readonly Func TruthPredicate = cell => true; - readonly Func shroudEdgeTest; - readonly Func fastExploredTest; - readonly Func slowExploredTest; - readonly Func fastVisibleTest; - readonly Func slowVisibleTest; + static readonly Func TruthPredicate = (u, v) => true; + readonly Func shroudEdgeTest; + readonly Func fastExploredTest; + readonly Func slowExploredTest; + readonly Func fastVisibleTest; + readonly Func slowVisibleTest; public Shroud(Actor self) { @@ -81,7 +81,7 @@ namespace OpenRA.Traits fogVisibilities = Exts.Lazy(() => self.TraitsImplementing().ToArray()); - shroudEdgeTest = cell => map.Contains(cell); + shroudEdgeTest = (u, v) => map.Contains(u, v); fastExploredTest = IsExploredCore; slowExploredTest = IsExplored; fastVisibleTest = IsVisibleCore; @@ -232,49 +232,54 @@ namespace OpenRA.Traits if (map.Bounds != s.map.Bounds) throw new ArgumentException("The map bounds of these shrouds do not match.", "s"); - foreach (var cell in map.Cells) - if (s.explored[cell]) - explored[cell] = true; + foreach (var uv in map.Cells.MapCoords) + if (s.explored[uv.X, uv.Y]) + explored[uv.X, uv.Y] = true; Invalidate(); } public void ExploreAll(World world) { - foreach (var cell in map.Cells) - explored[cell] = true; + foreach (var uv in map.Cells.MapCoords) + explored[uv.X, uv.Y] = true; Invalidate(); } public void ResetExploration() { - foreach (var cell in map.Cells) - explored[cell] = visibleCount[cell] > 0; + foreach (var uv in map.Cells.MapCoords) + explored[uv.X, uv.Y] = visibleCount[uv.X, uv.Y] > 0; Invalidate(); } public bool IsExplored(CPos cell) { - if (!map.Contains(cell)) + var uv = Map.CellToMap(map.TileShape, cell); + return IsExplored(uv.X, uv.Y); + } + + public bool IsExplored(int u, int v) + { + if (!map.Contains(u, v)) return false; if (!ShroudEnabled) return true; - return IsExploredCore(cell); + return IsExploredCore(u, v); } bool ShroudEnabled { get { return !Disabled && self.World.LobbyInfo.GlobalSettings.Shroud; } } - bool IsExploredCore(CPos cell) + bool IsExploredCore(int u, int v) { - var uv = Map.CellToMap(map.TileShape, cell); - return explored[uv.X, uv.Y] && (generatedShroudCount[uv.X, uv.Y] == 0 || visibleCount[uv.X, uv.Y] > 0); + return explored[u, v] && (generatedShroudCount[u, v] == 0 || visibleCount[u, v] > 0); } - public Func IsExploredTest(CellRegion region) + public Func IsExploredTest(CellRegion region) { // If the region to test extends outside the map we must use the slow test that checks the map boundary every time. if (!map.Cells.Contains(region)) @@ -295,23 +300,29 @@ namespace OpenRA.Traits public bool IsVisible(CPos cell) { - if (!map.Contains(cell)) + var uv = Map.CellToMap(map.TileShape, cell); + return IsVisible(uv.X, uv.Y); + } + + bool IsVisible(int u, int v) + { + if (!map.Contains(u, v)) return false; if (!FogEnabled) return true; - return IsVisibleCore(cell); + return IsVisibleCore(u, v); } bool FogEnabled { get { return !Disabled && self.World.LobbyInfo.GlobalSettings.Fog; } } - bool IsVisibleCore(CPos cell) + bool IsVisibleCore(int u, int v) { - return visibleCount[cell] > 0; + return visibleCount[u, v] > 0; } - public Func IsVisibleTest(CellRegion region) + public Func IsVisibleTest(CellRegion region) { // If the region to test extends outside the map we must use the slow test that checks the map boundary every time. if (!map.Cells.Contains(region)) diff --git a/OpenRA.Game/World.cs b/OpenRA.Game/World.cs index 2d3fdf48d7..439fe8d582 100644 --- a/OpenRA.Game/World.cs +++ b/OpenRA.Game/World.cs @@ -24,7 +24,7 @@ namespace OpenRA { public class World { - static readonly Func FalsePredicate = cell => false; + static readonly Func FalsePredicate = (u, v) => false; internal readonly TraitDictionary traitDict = new TraitDictionary(); readonly HashSet actors = new HashSet(); readonly List effects = new List(); @@ -65,23 +65,24 @@ namespace OpenRA public bool FogObscures(CPos p) { return RenderPlayer != null && !RenderPlayer.Shroud.IsVisible(p); } public bool ShroudObscures(Actor a) { return RenderPlayer != null && !RenderPlayer.Shroud.IsExplored(a); } public bool ShroudObscures(CPos p) { return RenderPlayer != null && !RenderPlayer.Shroud.IsExplored(p); } + public bool ShroudObscures(int u, int v) { return RenderPlayer != null && !RenderPlayer.Shroud.IsExplored(u, v); } - public Func FogObscuresTest(CellRegion region) + public Func FogObscuresTest(CellRegion region) { var rp = RenderPlayer; if (rp == null) return FalsePredicate; var predicate = rp.Shroud.IsVisibleTest(region); - return cell => !predicate(cell); + return (u, v) => !predicate(u, v); } - public Func ShroudObscuresTest(CellRegion region) + public Func ShroudObscuresTest(CellRegion region) { var rp = RenderPlayer; if (rp == null) return FalsePredicate; var predicate = rp.Shroud.IsExploredTest(region); - return cell => !predicate(cell); + return (u, v) => !predicate(u, v); } public bool IsReplay diff --git a/OpenRA.Mods.Common/Traits/World/ShroudRenderer.cs b/OpenRA.Mods.Common/Traits/World/ShroudRenderer.cs index c9b2b859c6..41ce83395b 100644 --- a/OpenRA.Mods.Common/Traits/World/ShroudRenderer.cs +++ b/OpenRA.Mods.Common/Traits/World/ShroudRenderer.cs @@ -151,23 +151,30 @@ namespace OpenRA.Mods.Common.Traits notVisibleEdges = info.UseExtendedIndex ? Edges.AllSides : Edges.AllCorners; } - Edges GetEdges(CPos p, Func isVisible) + Edges GetEdges(int u, int v, Func isVisible) { - if (!isVisible(p)) + if (!isVisible(u, v)) return notVisibleEdges; - // If a side is shrouded then we also count the corners - var u = Edges.None; - if (!isVisible(p + new CVec(0, -1))) u |= Edges.Top; - if (!isVisible(p + new CVec(1, 0))) u |= Edges.Right; - if (!isVisible(p + new CVec(0, 1))) u |= Edges.Bottom; - if (!isVisible(p + new CVec(-1, 0))) u |= Edges.Left; + var cell = Map.MapToCell(map.TileShape, new CPos(u, v)); + Func isCellVisible = c => + { + var uv = Map.CellToMap(map.TileShape, c); + return isVisible(uv.X, uv.Y); + }; - var ucorner = u & Edges.AllCorners; - if (!isVisible(p + new CVec(-1, -1))) u |= Edges.TopLeft; - if (!isVisible(p + new CVec(1, -1))) u |= Edges.TopRight; - if (!isVisible(p + new CVec(1, 1))) u |= Edges.BottomRight; - if (!isVisible(p + new CVec(-1, 1))) u |= Edges.BottomLeft; + // If a side is shrouded then we also count the corners + var edge = Edges.None; + if (!isCellVisible(cell + new CVec(0, -1))) edge |= Edges.Top; + if (!isCellVisible(cell + new CVec(1, 0))) edge |= Edges.Right; + if (!isCellVisible(cell + new CVec(0, 1))) edge |= Edges.Bottom; + if (!isCellVisible(cell + new CVec(-1, 0))) edge |= Edges.Left; + + var ucorner = edge & Edges.AllCorners; + if (!isCellVisible(cell + new CVec(-1, -1))) edge |= Edges.TopLeft; + if (!isCellVisible(cell + new CVec(1, -1))) edge |= Edges.TopRight; + if (!isCellVisible(cell + new CVec(1, 1))) edge |= Edges.BottomRight; + if (!isCellVisible(cell + new CVec(-1, 1))) edge |= Edges.BottomLeft; // RA provides a set of frames for tiles with shrouded // corners but unshrouded edges. We want to detect this @@ -175,7 +182,7 @@ namespace OpenRA.Mods.Common.Traits // in other combinations. The XOR turns off the corner // bits that are enabled twice, which gives the behavior // we want here. - return info.UseExtendedIndex ? u ^ ucorner : u & Edges.AllCorners; + return info.UseExtendedIndex ? edge ^ ucorner : edge & Edges.AllCorners; } Edges GetObserverEdges(CPos p) @@ -199,18 +206,20 @@ namespace OpenRA.Mods.Common.Traits { // Initialize tile cache // Adds a 1-cell border around the border to cover any sprites peeking outside the map - foreach (var cell in CellRegion.Expand(w.Map.Cells, 1)) + foreach (var uv in CellRegion.Expand(w.Map.Cells, 1).MapCoords) { - var screen = wr.ScreenPosition(w.Map.CenterOfCell(cell)); + var u = uv.X; + var v = uv.Y; + var screen = wr.ScreenPosition(w.Map.CenterOfCell(Map.MapToCell(map.TileShape, uv))); var variant = (byte)Game.CosmeticRandom.Next(info.ShroudVariants.Length); - tiles[cell] = new ShroudTile(screen, variant); + tiles[u, v] = new ShroudTile(screen, variant); // Set the cells outside the border so they don't need to be touched again - if (!map.Contains(cell)) + if (!map.Contains(u, v)) { - var shroudTile = tiles[cell]; + var shroudTile = tiles[u, v]; shroudTile.Shroud = GetTile(shroudSprites, notVisibleEdges, variant); - tiles[cell] = shroudTile; + tiles[u, v] = shroudTile; } } @@ -252,15 +261,17 @@ namespace OpenRA.Mods.Common.Traits { var visibleUnderShroud = shroud.IsExploredTest(updatedRegion); var visibleUnderFog = shroud.IsVisibleTest(updatedRegion); - foreach (var cell in updatedRegion) + foreach (var uv in updatedRegion.MapCoords) { - var shrouded = GetEdges(cell, visibleUnderShroud); - var fogged = GetEdges(cell, visibleUnderFog); - var shroudTile = tiles[cell]; + var u = uv.X; + var v = uv.Y; + var shrouded = GetEdges(u, v, visibleUnderShroud); + var fogged = GetEdges(u, v, visibleUnderFog); + var shroudTile = tiles[u, v]; var variant = shroudTile.Variant; shroudTile.Shroud = GetTile(shroudSprites, shrouded, variant); shroudTile.Fog = GetTile(fogSprites, fogged, variant); - tiles[cell] = shroudTile; + tiles[u, v] = shroudTile; } } @@ -281,9 +292,9 @@ namespace OpenRA.Mods.Common.Traits { Update(shroud, wr.Viewport.VisibleCells); - foreach (var cell in CellRegion.Expand(wr.Viewport.VisibleCells, 1)) + foreach (var uv in CellRegion.Expand(wr.Viewport.VisibleCells, 1).MapCoords) { - var t = tiles[cell]; + var t = tiles[uv.X, uv.Y]; if (t.Shroud != null) { diff --git a/OpenRA.Mods.Common/Traits/World/TerrainGeometryOverlay.cs b/OpenRA.Mods.Common/Traits/World/TerrainGeometryOverlay.cs index 40fd050966..715024e97d 100644 --- a/OpenRA.Mods.Common/Traits/World/TerrainGeometryOverlay.cs +++ b/OpenRA.Mods.Common/Traits/World/TerrainGeometryOverlay.cs @@ -81,13 +81,13 @@ namespace OpenRA.Mods.Common.Traits var rightDelta = ts == TileShape.Diamond ? new WVec(512, 0, 0) : new WVec(512, 512, 0); var bottomDelta = ts == TileShape.Diamond ? new WVec(0, 512, 0) : new WVec(-512, 512, 0); - foreach (var cell in wr.Viewport.VisibleCells) + foreach (var uv in wr.Viewport.VisibleCells.MapCoords) { var lr = Game.Renderer.WorldLineRenderer; - var pos = wr.world.Map.CenterOfCell(cell); + var pos = wr.world.Map.CenterOfCell(Map.MapToCell(wr.world.Map.TileShape, uv)); - var height = (int)wr.world.Map.MapHeight.Value[cell]; - var tile = wr.world.Map.MapTiles.Value[cell]; + var height = (int)wr.world.Map.MapHeight.Value[uv.X, uv.Y]; + var tile = wr.world.Map.MapTiles.Value[uv.X, uv.Y]; TerrainTileInfo tileInfo = null; diff --git a/OpenRA.Mods.RA/Move/PathSearch.cs b/OpenRA.Mods.RA/Move/PathSearch.cs index 46e04bb103..77acc2366d 100755 --- a/OpenRA.Mods.RA/Move/PathSearch.cs +++ b/OpenRA.Mods.RA/Move/PathSearch.cs @@ -332,8 +332,8 @@ namespace OpenRA.Mods.RA.Move defaultCellInfoLayer.Shape != map.TileShape) { defaultCellInfoLayer = new CellLayer(map); - foreach (var cell in map.Cells) - defaultCellInfoLayer[cell] = new CellInfo(int.MaxValue, cell, false); + foreach (var uv in map.Cells.MapCoords) + defaultCellInfoLayer[uv.X, uv.Y] = new CellInfo(int.MaxValue, Map.MapToCell(map.TileShape, uv), false); } result.CopyValuesFrom(defaultCellInfoLayer); diff --git a/OpenRA.Mods.RA/Traits/Modifiers/FrozenUnderFog.cs b/OpenRA.Mods.RA/Traits/Modifiers/FrozenUnderFog.cs index f9e776f0c1..3526bef279 100644 --- a/OpenRA.Mods.RA/Traits/Modifiers/FrozenUnderFog.cs +++ b/OpenRA.Mods.RA/Traits/Modifiers/FrozenUnderFog.cs @@ -30,7 +30,7 @@ namespace OpenRA.Mods.RA.Traits [Sync] public int VisibilityHash; readonly bool startsRevealed; - readonly CPos[] footprint; + readonly CPos[] footprintInMapsCoords; readonly CellRegion footprintRegion; readonly Lazy tooltip; @@ -45,7 +45,8 @@ namespace OpenRA.Mods.RA.Traits { // Spawned actors (e.g. building husks) shouldn't be revealed startsRevealed = info.StartsRevealed && !init.Contains(); - footprint = FootprintUtils.Tiles(init.self).ToArray(); + var footprint = FootprintUtils.Tiles(init.self).ToList(); + footprintInMapsCoords = footprint.Select(cell => Map.CellToMap(init.world.Map.TileShape, cell)).ToArray(); footprintRegion = CellRegion.BoundingRegion(init.world.Map.TileShape, footprint); tooltip = Exts.Lazy(() => init.self.TraitsImplementing().FirstOrDefault()); tooltip = Exts.Lazy(() => init.self.TraitsImplementing().FirstOrDefault()); @@ -68,7 +69,17 @@ namespace OpenRA.Mods.RA.Traits VisibilityHash = 0; foreach (var p in self.World.Players) { - var isVisible = footprint.Any(p.Shroud.IsVisibleTest(footprintRegion)); + // We are doing the following LINQ manually to avoid allocating an extra delegate since this is a hot path. + // var isVisible = footprintInMapsCoords.Any(mapCoord => p.Shroud.IsVisibleTest(footprintRegion)(mapCoord.X, mapCoord.Y)); + var isVisibleTest = p.Shroud.IsVisibleTest(footprintRegion); + var isVisible = false; + foreach (var mapCoord in footprintInMapsCoords) + if (isVisibleTest(mapCoord.X, mapCoord.Y)) + { + isVisible = true; + break; + } + visible[p] = isVisible; if (isVisible) VisibilityHash += p.ClientIndex; @@ -79,7 +90,7 @@ namespace OpenRA.Mods.RA.Traits foreach (var p in self.World.Players) { visible[p] |= startsRevealed; - p.PlayerActor.Trait().Add(frozen[p] = new FrozenActor(self, footprint, footprintRegion)); + p.PlayerActor.Trait().Add(frozen[p] = new FrozenActor(self, footprintInMapsCoords, footprintRegion)); } initialized = true; diff --git a/OpenRA.Mods.RA/Traits/World/ResourceLayer.cs b/OpenRA.Mods.RA/Traits/World/ResourceLayer.cs index b8891b91b0..88c7aa0183 100644 --- a/OpenRA.Mods.RA/Traits/World/ResourceLayer.cs +++ b/OpenRA.Mods.RA/Traits/World/ResourceLayer.cs @@ -35,14 +35,14 @@ namespace OpenRA.Mods.RA.Traits public void Render(WorldRenderer wr) { var shroudObscured = world.ShroudObscuresTest(wr.Viewport.VisibleCells); - foreach (var cell in wr.Viewport.VisibleCells) + foreach (var uv in wr.Viewport.VisibleCells.MapCoords) { - if (shroudObscured(cell)) + if (shroudObscured(uv.X, uv.Y)) continue; - var c = render[cell]; + var c = render[uv.X, uv.Y]; if (c.Sprite != null) - new SpriteRenderable(c.Sprite, wr.world.Map.CenterOfCell(cell), + new SpriteRenderable(c.Sprite, wr.world.Map.CenterOfCell(Map.MapToCell(world.Map.TileShape, uv)), WVec.Zero, -511, c.Type.Palette, 1f, true).Render(wr); // TODO ZOffset is ignored } }