From baf27bc4cddb95cf9d4eca578c5cccf35a8a160b Mon Sep 17 00:00:00 2001 From: Paul Chote Date: Fri, 16 May 2014 23:23:05 +1200 Subject: [PATCH] Use CellLayers for shroud. --- OpenRA.Game/Traits/World/Shroud.cs | 55 ++++++------ OpenRA.Mods.RA/ShroudRenderer.cs | 137 ++++++++++++++--------------- 2 files changed, 91 insertions(+), 101 deletions(-) diff --git a/OpenRA.Game/Traits/World/Shroud.cs b/OpenRA.Game/Traits/World/Shroud.cs index c4804e535e..2efb5bf226 100644 --- a/OpenRA.Game/Traits/World/Shroud.cs +++ b/OpenRA.Game/Traits/World/Shroud.cs @@ -27,9 +27,9 @@ namespace OpenRA.Traits Actor self; Map map; - int[,] visibleCount; - int[,] generatedShroudCount; - bool[,] explored; + CellLayer visibleCount; + CellLayer generatedShroudCount; + CellLayer explored; readonly Lazy fogVisibilities; @@ -47,9 +47,9 @@ namespace OpenRA.Traits this.self = self; map = self.World.Map; - visibleCount = new int[map.MapSize.X, map.MapSize.Y]; - generatedShroudCount = new int[map.MapSize.X, map.MapSize.Y]; - explored = new bool[map.MapSize.X, map.MapSize.Y]; + visibleCount = new CellLayer(map); + generatedShroudCount = new CellLayer(map); + explored = new CellLayer(map); self.World.ActorAdded += AddVisibility; self.World.ActorRemoved += RemoveVisibility; @@ -104,8 +104,8 @@ namespace OpenRA.Traits // Update visibility foreach (var c in visible) { - visibleCount[c.X, c.Y]++; - explored[c.X, c.Y] = true; + visibleCount[c]++; + explored[c] = true; } if (visibility.ContainsKey(a)) @@ -122,7 +122,7 @@ namespace OpenRA.Traits return; foreach (var c in visible) - visibleCount[c.X, c.Y]--; + visibleCount[c]--; visibility.Remove(a); Invalidate(); @@ -147,7 +147,7 @@ namespace OpenRA.Traits var shrouded = GetVisOrigins(a).SelectMany(o => FindVisibleTiles(a.World, o, cs.Range)) .Distinct().ToArray(); foreach (var c in shrouded) - generatedShroudCount[c.X, c.Y]++; + generatedShroudCount[c]++; if (generation.ContainsKey(a)) throw new InvalidOperationException("Attempting to add duplicate shroud generation"); @@ -163,7 +163,7 @@ namespace OpenRA.Traits return; foreach (var c in shrouded) - generatedShroudCount[c.X, c.Y]--; + generatedShroudCount[c]--; generation.Remove(a); Invalidate(); @@ -203,7 +203,7 @@ namespace OpenRA.Traits public void Explore(World world, CPos center, WRange range) { foreach (var q in FindVisibleTiles(world, center, range)) - explored[q.X, q.Y] = true; + explored[q] = true; var r = (range.Range + 1023) / 1024; var box = new Rectangle(center.X - r, center.Y - r, 2 * r + 1, 2 * r + 1); @@ -214,19 +214,17 @@ namespace OpenRA.Traits public void Explore(Shroud s) { - for (var i = map.Bounds.Left; i < map.Bounds.Right; i++) - for (var j = map.Bounds.Top; j < map.Bounds.Bottom; j++) - if (s.explored[i,j] == true) - explored[i, j] = true; + foreach (var cell in map.Cells) + if (s.explored[cell]) + explored[cell] = true; ExploredBounds = Rectangle.Union(ExploredBounds, s.ExploredBounds); + Invalidate(); } public void ExploreAll(World world) { - for (var i = map.Bounds.Left; i < map.Bounds.Right; i++) - for (var j = map.Bounds.Top; j < map.Bounds.Bottom; j++) - explored[i, j] = true; + explored.Clear(true); ExploredBounds = world.Map.Bounds; @@ -235,23 +233,21 @@ namespace OpenRA.Traits public void ResetExploration() { - for (var i = map.Bounds.Left; i < map.Bounds.Right; i++) - for (var j = map.Bounds.Top; j < map.Bounds.Bottom; j++) - explored[i, j] = visibleCount[i, j] > 0; + foreach (var cell in map.Cells) + explored[cell] = visibleCount[cell] > 0; Invalidate(); } - public bool IsExplored(CPos xy) { return IsExplored(xy.X, xy.Y); } - public bool IsExplored(int x, int y) + public bool IsExplored(CPos cell) { - if (!map.IsInMap(x, y)) + if (!map.IsInMap(cell)) return false; if (Disabled || !self.World.LobbyInfo.GlobalSettings.Shroud) return true; - return explored[x, y] && (generatedShroudCount[x, y] == 0 || visibleCount[x, y] > 0); + return explored[cell] && (generatedShroudCount[cell] == 0 || visibleCount[cell] > 0); } public bool IsExplored(Actor a) @@ -259,16 +255,15 @@ namespace OpenRA.Traits return GetVisOrigins(a).Any(o => IsExplored(o)); } - public bool IsVisible(CPos xy) { return IsVisible(xy.X, xy.Y); } - public bool IsVisible(int x, int y) + public bool IsVisible(CPos cell) { - if (!map.IsInMap(x, y)) + if (!map.IsInMap(cell)) return false; if (Disabled || !self.World.LobbyInfo.GlobalSettings.Fog) return true; - return visibleCount[x, y] > 0; + return visibleCount[cell] > 0; } // Actors are hidden under shroud, but not under fog by default diff --git a/OpenRA.Mods.RA/ShroudRenderer.cs b/OpenRA.Mods.RA/ShroudRenderer.cs index d7ac87c25f..433a229b7e 100644 --- a/OpenRA.Mods.RA/ShroudRenderer.cs +++ b/OpenRA.Mods.RA/ShroudRenderer.cs @@ -10,6 +10,7 @@ using System.Drawing; using System.Linq; +using OpenRA; using OpenRA.Graphics; using OpenRA.Traits; @@ -35,36 +36,41 @@ namespace OpenRA.Mods.RA public class ShroudRenderer : IRenderShroud, IWorldLoaded { - struct ShroudTile + class ShroudTile { - public CPos Position; - public float2 ScreenPosition; - public int Variant; + public readonly CPos Position; + public readonly float2 ScreenPosition; + public readonly int Variant; public Sprite Fog; public Sprite Shroud; + + public ShroudTile(CPos position, float2 screenPosition, int variant) + { + Position = position; + ScreenPosition = screenPosition; + Variant = variant; + } } + ShroudRendererInfo info; Sprite[] sprites; Sprite unexploredTile; int[] spriteMap; - ShroudTile[] tiles; - int tileStride, variantStride; + CellLayer tiles; + int variantStride; int shroudHash; PaletteReference fogPalette, shroudPalette; - Rectangle bounds; - bool useExtendedIndex; + Map map; public ShroudRenderer(World world, ShroudRendererInfo info) { - var map = world.Map; - bounds = map.Bounds; - useExtendedIndex = info.UseExtendedIndex; + this.info = info; + map = world.Map; - tiles = new ShroudTile[map.MapSize.X * map.MapSize.Y]; - tileStride = map.MapSize.X; + tiles = new CellLayer(map); // Force update on first render shroudHash = -1; @@ -80,14 +86,10 @@ namespace OpenRA.Mods.RA } // Mapping of shrouded directions -> sprite index - spriteMap = new int[useExtendedIndex ? 256 : 16]; + spriteMap = new int[info.UseExtendedIndex ? 256 : 16]; for (var i = 0; i < info.Index.Length; i++) spriteMap[info.Index[i]] = i; - // Set individual tile variants to reduce tiling - for (var i = 0; i < tiles.Length; i++) - tiles[i].Variant = Game.CosmeticRandom.Next(info.Variants.Length); - // Synthesize unexplored tile if it isn't defined if (!info.Index.Contains(0)) { @@ -102,21 +104,21 @@ namespace OpenRA.Mods.RA static int FoggedEdges(Shroud s, CPos p, bool useExtendedIndex) { - if (!s.IsVisible(p.X, p.Y)) + if (!s.IsVisible(p)) return 15; // If a side is shrouded then we also count the corners var u = 0; - if (!s.IsVisible(p.X, p.Y - 1)) u |= 0x13; - if (!s.IsVisible(p.X + 1, p.Y)) u |= 0x26; - if (!s.IsVisible(p.X, p.Y + 1)) u |= 0x4C; - if (!s.IsVisible(p.X - 1, p.Y)) u |= 0x89; + if (!s.IsVisible(p + new CVec(0, -1))) u |= 0x13; + if (!s.IsVisible(p + new CVec(1, 0))) u |= 0x26; + if (!s.IsVisible(p + new CVec(0, 1))) u |= 0x4C; + if (!s.IsVisible(p + new CVec(-1, 0))) u |= 0x89; var uside = u & 0x0F; - if (!s.IsVisible(p.X - 1, p.Y - 1)) u |= 0x01; - if (!s.IsVisible(p.X + 1, p.Y - 1)) u |= 0x02; - if (!s.IsVisible(p.X + 1, p.Y + 1)) u |= 0x04; - if (!s.IsVisible(p.X - 1, p.Y + 1)) u |= 0x08; + if (!s.IsVisible(p + new CVec(-1, -1))) u |= 0x01; + if (!s.IsVisible(p + new CVec(1, -1))) u |= 0x02; + if (!s.IsVisible(p + new CVec(1, 1))) u |= 0x04; + if (!s.IsVisible(p + new CVec(-1, 1))) u |= 0x08; // RA provides a set of frames for tiles with shrouded // corners but unshrouded edges. We want to detect this @@ -129,21 +131,21 @@ namespace OpenRA.Mods.RA static int ShroudedEdges(Shroud s, CPos p, bool useExtendedIndex) { - if (!s.IsExplored(p.X, p.Y)) + if (!s.IsExplored(p)) return 15; // If a side is shrouded then we also count the corners var u = 0; - if (!s.IsExplored(p.X, p.Y - 1)) u |= 0x13; - if (!s.IsExplored(p.X + 1, p.Y)) u |= 0x26; - if (!s.IsExplored(p.X, p.Y + 1)) u |= 0x4C; - if (!s.IsExplored(p.X - 1, p.Y)) u |= 0x89; + if (!s.IsExplored(p + new CVec(0, -1))) u |= 0x13; + if (!s.IsExplored(p + new CVec(1, 0))) u |= 0x26; + if (!s.IsExplored(p + new CVec(0, 1))) u |= 0x4C; + if (!s.IsExplored(p + new CVec(-1, 0))) u |= 0x89; var uside = u & 0x0F; - if (!s.IsExplored(p.X - 1, p.Y - 1)) u |= 0x01; - if (!s.IsExplored(p.X + 1, p.Y - 1)) u |= 0x02; - if (!s.IsExplored(p.X + 1, p.Y + 1)) u |= 0x04; - if (!s.IsExplored(p.X - 1, p.Y + 1)) u |= 0x08; + if (!s.IsExplored(p + new CVec(-1, -1))) u |= 0x01; + if (!s.IsExplored(p + new CVec(1, -1))) u |= 0x02; + if (!s.IsExplored(p + new CVec(1, 1))) u |= 0x04; + if (!s.IsExplored(p + new CVec(-1, 1))) u |= 0x08; // RA provides a set of frames for tiles with shrouded // corners but unshrouded edges. We want to detect this @@ -173,15 +175,12 @@ namespace OpenRA.Mods.RA public void WorldLoaded(World w, WorldRenderer wr) { - // Cache the tile positions to avoid unnecessary calculations - for (var i = bounds.Left; i < bounds.Right; i++) + // Initialize tile cache + foreach (var cell in map.Cells) { - for (var j = bounds.Top; j < bounds.Bottom; j++) - { - var k = j * tileStride + i; - tiles[k].Position = new CPos(i, j); - tiles[k].ScreenPosition = wr.ScreenPosition(tiles[k].Position.CenterPosition); - } + var screen = wr.ScreenPosition(cell.CenterPosition); + var variant = Game.CosmeticRandom.Next(info.Variants.Length); + tiles[cell] = new ShroudTile(cell, screen, variant); } fogPalette = wr.Palette("fog"); @@ -209,22 +208,25 @@ namespace OpenRA.Mods.RA if (shroud == null) { // Players with no shroud see the whole map so we only need to set the edges - for (var k = 0; k < tiles.Length; k++) + foreach (var cell in map.Cells) { - var shrouded = ObserverShroudedEdges(tiles[k].Position, bounds, useExtendedIndex); - tiles[k].Shroud = GetTile(shrouded, tiles[k].Variant); - tiles[k].Fog = GetTile(shrouded, tiles[k].Variant); + var t = tiles[cell]; + var shrouded = ObserverShroudedEdges(t.Position, map.Bounds, info.UseExtendedIndex); + + t.Shroud = GetTile(shrouded, t.Variant); + t.Fog = GetTile(shrouded, t.Variant); } } else { - for (var k = 0; k < tiles.Length; k++) + foreach (var cell in map.Cells) { - var shrouded = ShroudedEdges(shroud, tiles[k].Position, useExtendedIndex); - var fogged = FoggedEdges(shroud, tiles[k].Position, useExtendedIndex); + var t = tiles[cell]; + var shrouded = ShroudedEdges(shroud, t.Position, info.UseExtendedIndex); + var fogged = FoggedEdges(shroud, t.Position, info.UseExtendedIndex); - tiles[k].Shroud = GetTile(shrouded, tiles[k].Variant); - tiles[k].Fog = GetTile(fogged, tiles[k].Variant); + t.Shroud = GetTile(shrouded, t.Variant); + t.Fog = GetTile(fogged, t.Variant); } } } @@ -233,27 +235,20 @@ namespace OpenRA.Mods.RA { Update(shroud); - var clip = wr.Viewport.CellBounds; - var width = clip.Width; - for (var j = clip.Top; j < clip.Bottom; j++) + foreach (var cell in wr.Viewport.VisibleCells) { - var start = j * tileStride + clip.Left; - for (var k = 0; k < width; k++) + var t = tiles[cell]; + + if (t.Shroud != null) { - var s = tiles[start + k].Shroud; - var f = tiles[start + k].Fog; + var pos = t.ScreenPosition - 0.5f * t.Shroud.size; + Game.Renderer.WorldSpriteRenderer.DrawSprite(t.Shroud, pos, shroudPalette); + } - if (s != null) - { - var pos = tiles[start + k].ScreenPosition - 0.5f * s.size; - Game.Renderer.WorldSpriteRenderer.DrawSprite(s, pos, shroudPalette); - } - - if (f != null) - { - var pos = tiles[start + k].ScreenPosition - 0.5f * f.size; - Game.Renderer.WorldSpriteRenderer.DrawSprite(f, pos, fogPalette); - } + if (t.Fog != null) + { + var pos = t.ScreenPosition - 0.5f * t.Fog.size; + Game.Renderer.WorldSpriteRenderer.DrawSprite(t.Fog, pos, fogPalette); } } }