Use CellLayers for shroud.

This commit is contained in:
Paul Chote
2014-05-16 23:23:05 +12:00
parent 295af5741f
commit baf27bc4cd
2 changed files with 91 additions and 101 deletions

View File

@@ -27,9 +27,9 @@ namespace OpenRA.Traits
Actor self; Actor self;
Map map; Map map;
int[,] visibleCount; CellLayer<int> visibleCount;
int[,] generatedShroudCount; CellLayer<int> generatedShroudCount;
bool[,] explored; CellLayer<bool> explored;
readonly Lazy<IFogVisibilityModifier[]> fogVisibilities; readonly Lazy<IFogVisibilityModifier[]> fogVisibilities;
@@ -47,9 +47,9 @@ namespace OpenRA.Traits
this.self = self; this.self = self;
map = self.World.Map; map = self.World.Map;
visibleCount = new int[map.MapSize.X, map.MapSize.Y]; visibleCount = new CellLayer<int>(map);
generatedShroudCount = new int[map.MapSize.X, map.MapSize.Y]; generatedShroudCount = new CellLayer<int>(map);
explored = new bool[map.MapSize.X, map.MapSize.Y]; explored = new CellLayer<bool>(map);
self.World.ActorAdded += AddVisibility; self.World.ActorAdded += AddVisibility;
self.World.ActorRemoved += RemoveVisibility; self.World.ActorRemoved += RemoveVisibility;
@@ -104,8 +104,8 @@ namespace OpenRA.Traits
// Update visibility // Update visibility
foreach (var c in visible) foreach (var c in visible)
{ {
visibleCount[c.X, c.Y]++; visibleCount[c]++;
explored[c.X, c.Y] = true; explored[c] = true;
} }
if (visibility.ContainsKey(a)) if (visibility.ContainsKey(a))
@@ -122,7 +122,7 @@ namespace OpenRA.Traits
return; return;
foreach (var c in visible) foreach (var c in visible)
visibleCount[c.X, c.Y]--; visibleCount[c]--;
visibility.Remove(a); visibility.Remove(a);
Invalidate(); Invalidate();
@@ -147,7 +147,7 @@ namespace OpenRA.Traits
var shrouded = GetVisOrigins(a).SelectMany(o => FindVisibleTiles(a.World, o, cs.Range)) var shrouded = GetVisOrigins(a).SelectMany(o => FindVisibleTiles(a.World, o, cs.Range))
.Distinct().ToArray(); .Distinct().ToArray();
foreach (var c in shrouded) foreach (var c in shrouded)
generatedShroudCount[c.X, c.Y]++; generatedShroudCount[c]++;
if (generation.ContainsKey(a)) if (generation.ContainsKey(a))
throw new InvalidOperationException("Attempting to add duplicate shroud generation"); throw new InvalidOperationException("Attempting to add duplicate shroud generation");
@@ -163,7 +163,7 @@ namespace OpenRA.Traits
return; return;
foreach (var c in shrouded) foreach (var c in shrouded)
generatedShroudCount[c.X, c.Y]--; generatedShroudCount[c]--;
generation.Remove(a); generation.Remove(a);
Invalidate(); Invalidate();
@@ -203,7 +203,7 @@ namespace OpenRA.Traits
public void Explore(World world, CPos center, WRange range) public void Explore(World world, CPos center, WRange range)
{ {
foreach (var q in FindVisibleTiles(world, center, 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 r = (range.Range + 1023) / 1024;
var box = new Rectangle(center.X - r, center.Y - r, 2 * r + 1, 2 * r + 1); 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) public void Explore(Shroud s)
{ {
for (var i = map.Bounds.Left; i < map.Bounds.Right; i++) foreach (var cell in map.Cells)
for (var j = map.Bounds.Top; j < map.Bounds.Bottom; j++) if (s.explored[cell])
if (s.explored[i,j] == true) explored[cell] = true;
explored[i, j] = true;
ExploredBounds = Rectangle.Union(ExploredBounds, s.ExploredBounds); ExploredBounds = Rectangle.Union(ExploredBounds, s.ExploredBounds);
Invalidate();
} }
public void ExploreAll(World world) public void ExploreAll(World world)
{ {
for (var i = map.Bounds.Left; i < map.Bounds.Right; i++) explored.Clear(true);
for (var j = map.Bounds.Top; j < map.Bounds.Bottom; j++)
explored[i, j] = true;
ExploredBounds = world.Map.Bounds; ExploredBounds = world.Map.Bounds;
@@ -235,23 +233,21 @@ namespace OpenRA.Traits
public void ResetExploration() public void ResetExploration()
{ {
for (var i = map.Bounds.Left; i < map.Bounds.Right; i++) foreach (var cell in map.Cells)
for (var j = map.Bounds.Top; j < map.Bounds.Bottom; j++) explored[cell] = visibleCount[cell] > 0;
explored[i, j] = visibleCount[i, j] > 0;
Invalidate(); Invalidate();
} }
public bool IsExplored(CPos xy) { return IsExplored(xy.X, xy.Y); } public bool IsExplored(CPos cell)
public bool IsExplored(int x, int y)
{ {
if (!map.IsInMap(x, y)) if (!map.IsInMap(cell))
return false; return false;
if (Disabled || !self.World.LobbyInfo.GlobalSettings.Shroud) if (Disabled || !self.World.LobbyInfo.GlobalSettings.Shroud)
return true; 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) public bool IsExplored(Actor a)
@@ -259,16 +255,15 @@ namespace OpenRA.Traits
return GetVisOrigins(a).Any(o => IsExplored(o)); return GetVisOrigins(a).Any(o => IsExplored(o));
} }
public bool IsVisible(CPos xy) { return IsVisible(xy.X, xy.Y); } public bool IsVisible(CPos cell)
public bool IsVisible(int x, int y)
{ {
if (!map.IsInMap(x, y)) if (!map.IsInMap(cell))
return false; return false;
if (Disabled || !self.World.LobbyInfo.GlobalSettings.Fog) if (Disabled || !self.World.LobbyInfo.GlobalSettings.Fog)
return true; return true;
return visibleCount[x, y] > 0; return visibleCount[cell] > 0;
} }
// Actors are hidden under shroud, but not under fog by default // Actors are hidden under shroud, but not under fog by default

View File

@@ -10,6 +10,7 @@
using System.Drawing; using System.Drawing;
using System.Linq; using System.Linq;
using OpenRA;
using OpenRA.Graphics; using OpenRA.Graphics;
using OpenRA.Traits; using OpenRA.Traits;
@@ -35,36 +36,41 @@ namespace OpenRA.Mods.RA
public class ShroudRenderer : IRenderShroud, IWorldLoaded public class ShroudRenderer : IRenderShroud, IWorldLoaded
{ {
struct ShroudTile class ShroudTile
{ {
public CPos Position; public readonly CPos Position;
public float2 ScreenPosition; public readonly float2 ScreenPosition;
public int Variant; public readonly int Variant;
public Sprite Fog; public Sprite Fog;
public Sprite Shroud; public Sprite Shroud;
public ShroudTile(CPos position, float2 screenPosition, int variant)
{
Position = position;
ScreenPosition = screenPosition;
Variant = variant;
}
} }
ShroudRendererInfo info;
Sprite[] sprites; Sprite[] sprites;
Sprite unexploredTile; Sprite unexploredTile;
int[] spriteMap; int[] spriteMap;
ShroudTile[] tiles; CellLayer<ShroudTile> tiles;
int tileStride, variantStride; int variantStride;
int shroudHash; int shroudHash;
PaletteReference fogPalette, shroudPalette; PaletteReference fogPalette, shroudPalette;
Rectangle bounds; Map map;
bool useExtendedIndex;
public ShroudRenderer(World world, ShroudRendererInfo info) public ShroudRenderer(World world, ShroudRendererInfo info)
{ {
var map = world.Map; this.info = info;
bounds = map.Bounds; map = world.Map;
useExtendedIndex = info.UseExtendedIndex;
tiles = new ShroudTile[map.MapSize.X * map.MapSize.Y]; tiles = new CellLayer<ShroudTile>(map);
tileStride = map.MapSize.X;
// Force update on first render // Force update on first render
shroudHash = -1; shroudHash = -1;
@@ -80,14 +86,10 @@ namespace OpenRA.Mods.RA
} }
// Mapping of shrouded directions -> sprite index // 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++) for (var i = 0; i < info.Index.Length; i++)
spriteMap[info.Index[i]] = 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 // Synthesize unexplored tile if it isn't defined
if (!info.Index.Contains(0)) if (!info.Index.Contains(0))
{ {
@@ -102,21 +104,21 @@ namespace OpenRA.Mods.RA
static int FoggedEdges(Shroud s, CPos p, bool useExtendedIndex) static int FoggedEdges(Shroud s, CPos p, bool useExtendedIndex)
{ {
if (!s.IsVisible(p.X, p.Y)) if (!s.IsVisible(p))
return 15; return 15;
// If a side is shrouded then we also count the corners // If a side is shrouded then we also count the corners
var u = 0; var u = 0;
if (!s.IsVisible(p.X, p.Y - 1)) u |= 0x13; if (!s.IsVisible(p + new CVec(0, -1))) u |= 0x13;
if (!s.IsVisible(p.X + 1, p.Y)) u |= 0x26; if (!s.IsVisible(p + new CVec(1, 0))) u |= 0x26;
if (!s.IsVisible(p.X, p.Y + 1)) u |= 0x4C; if (!s.IsVisible(p + new CVec(0, 1))) u |= 0x4C;
if (!s.IsVisible(p.X - 1, p.Y)) u |= 0x89; if (!s.IsVisible(p + new CVec(-1, 0))) u |= 0x89;
var uside = u & 0x0F; var uside = u & 0x0F;
if (!s.IsVisible(p.X - 1, p.Y - 1)) u |= 0x01; if (!s.IsVisible(p + new CVec(-1, -1))) u |= 0x01;
if (!s.IsVisible(p.X + 1, p.Y - 1)) u |= 0x02; if (!s.IsVisible(p + new CVec(1, -1))) u |= 0x02;
if (!s.IsVisible(p.X + 1, p.Y + 1)) u |= 0x04; if (!s.IsVisible(p + new CVec(1, 1))) u |= 0x04;
if (!s.IsVisible(p.X - 1, p.Y + 1)) u |= 0x08; if (!s.IsVisible(p + new CVec(-1, 1))) u |= 0x08;
// RA provides a set of frames for tiles with shrouded // RA provides a set of frames for tiles with shrouded
// corners but unshrouded edges. We want to detect this // 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) static int ShroudedEdges(Shroud s, CPos p, bool useExtendedIndex)
{ {
if (!s.IsExplored(p.X, p.Y)) if (!s.IsExplored(p))
return 15; return 15;
// If a side is shrouded then we also count the corners // If a side is shrouded then we also count the corners
var u = 0; var u = 0;
if (!s.IsExplored(p.X, p.Y - 1)) u |= 0x13; if (!s.IsExplored(p + new CVec(0, -1))) u |= 0x13;
if (!s.IsExplored(p.X + 1, p.Y)) u |= 0x26; if (!s.IsExplored(p + new CVec(1, 0))) u |= 0x26;
if (!s.IsExplored(p.X, p.Y + 1)) u |= 0x4C; if (!s.IsExplored(p + new CVec(0, 1))) u |= 0x4C;
if (!s.IsExplored(p.X - 1, p.Y)) u |= 0x89; if (!s.IsExplored(p + new CVec(-1, 0))) u |= 0x89;
var uside = u & 0x0F; var uside = u & 0x0F;
if (!s.IsExplored(p.X - 1, p.Y - 1)) u |= 0x01; if (!s.IsExplored(p + new CVec(-1, -1))) u |= 0x01;
if (!s.IsExplored(p.X + 1, p.Y - 1)) u |= 0x02; if (!s.IsExplored(p + new CVec(1, -1))) u |= 0x02;
if (!s.IsExplored(p.X + 1, p.Y + 1)) u |= 0x04; if (!s.IsExplored(p + new CVec(1, 1))) u |= 0x04;
if (!s.IsExplored(p.X - 1, p.Y + 1)) u |= 0x08; if (!s.IsExplored(p + new CVec(-1, 1))) u |= 0x08;
// RA provides a set of frames for tiles with shrouded // RA provides a set of frames for tiles with shrouded
// corners but unshrouded edges. We want to detect this // corners but unshrouded edges. We want to detect this
@@ -173,15 +175,12 @@ namespace OpenRA.Mods.RA
public void WorldLoaded(World w, WorldRenderer wr) public void WorldLoaded(World w, WorldRenderer wr)
{ {
// Cache the tile positions to avoid unnecessary calculations // Initialize tile cache
for (var i = bounds.Left; i < bounds.Right; i++) foreach (var cell in map.Cells)
{ {
for (var j = bounds.Top; j < bounds.Bottom; j++) var screen = wr.ScreenPosition(cell.CenterPosition);
{ var variant = Game.CosmeticRandom.Next(info.Variants.Length);
var k = j * tileStride + i; tiles[cell] = new ShroudTile(cell, screen, variant);
tiles[k].Position = new CPos(i, j);
tiles[k].ScreenPosition = wr.ScreenPosition(tiles[k].Position.CenterPosition);
}
} }
fogPalette = wr.Palette("fog"); fogPalette = wr.Palette("fog");
@@ -209,22 +208,25 @@ namespace OpenRA.Mods.RA
if (shroud == null) if (shroud == null)
{ {
// Players with no shroud see the whole map so we only need to set the edges // 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); var t = tiles[cell];
tiles[k].Shroud = GetTile(shrouded, tiles[k].Variant); var shrouded = ObserverShroudedEdges(t.Position, map.Bounds, info.UseExtendedIndex);
tiles[k].Fog = GetTile(shrouded, tiles[k].Variant);
t.Shroud = GetTile(shrouded, t.Variant);
t.Fog = GetTile(shrouded, t.Variant);
} }
} }
else else
{ {
for (var k = 0; k < tiles.Length; k++) foreach (var cell in map.Cells)
{ {
var shrouded = ShroudedEdges(shroud, tiles[k].Position, useExtendedIndex); var t = tiles[cell];
var fogged = FoggedEdges(shroud, tiles[k].Position, useExtendedIndex); var shrouded = ShroudedEdges(shroud, t.Position, info.UseExtendedIndex);
var fogged = FoggedEdges(shroud, t.Position, info.UseExtendedIndex);
tiles[k].Shroud = GetTile(shrouded, tiles[k].Variant); t.Shroud = GetTile(shrouded, t.Variant);
tiles[k].Fog = GetTile(fogged, tiles[k].Variant); t.Fog = GetTile(fogged, t.Variant);
} }
} }
} }
@@ -233,27 +235,20 @@ namespace OpenRA.Mods.RA
{ {
Update(shroud); Update(shroud);
var clip = wr.Viewport.CellBounds; foreach (var cell in wr.Viewport.VisibleCells)
var width = clip.Width;
for (var j = clip.Top; j < clip.Bottom; j++)
{ {
var start = j * tileStride + clip.Left; var t = tiles[cell];
for (var k = 0; k < width; k++)
if (t.Shroud != null)
{ {
var s = tiles[start + k].Shroud; var pos = t.ScreenPosition - 0.5f * t.Shroud.size;
var f = tiles[start + k].Fog; Game.Renderer.WorldSpriteRenderer.DrawSprite(t.Shroud, pos, shroudPalette);
}
if (s != null) if (t.Fog != null)
{ {
var pos = tiles[start + k].ScreenPosition - 0.5f * s.size; var pos = t.ScreenPosition - 0.5f * t.Fog.size;
Game.Renderer.WorldSpriteRenderer.DrawSprite(s, pos, shroudPalette); Game.Renderer.WorldSpriteRenderer.DrawSprite(t.Fog, pos, fogPalette);
}
if (f != null)
{
var pos = tiles[start + k].ScreenPosition - 0.5f * f.size;
Game.Renderer.WorldSpriteRenderer.DrawSprite(f, pos, fogPalette);
}
} }
} }
} }