Shroud, combine IsVisible and IsExplored into a single function.

This commit is contained in:
Vapre
2021-08-10 23:02:05 +02:00
committed by teinarss
parent cc1f10dd35
commit 6e547469d6
4 changed files with 146 additions and 37 deletions

View File

@@ -81,6 +81,19 @@ namespace OpenRA.Mods.Common.Traits
All = Top | Right | Bottom | Left
}
// Index into neighbors array.
enum Neighbor
{
Top = 0,
Right,
Bottom,
Left,
TopLeft,
TopRight,
BottomRight,
BottomLeft
}
readonly struct TileInfo
{
public readonly float3 ScreenPosition;
@@ -96,17 +109,20 @@ namespace OpenRA.Mods.Common.Traits
readonly ShroudRendererInfo info;
readonly World world;
readonly Map map;
readonly Edges notVisibleEdges;
readonly (Edges, Edges) notVisibleEdgesPair;
readonly byte variantStride;
readonly byte[] edgesToSpriteIndexOffset;
// PERF: Allocate once.
readonly Shroud.CellVisibility[] neighbors = new Shroud.CellVisibility[8];
readonly CellLayer<TileInfo> tileInfos;
readonly CellLayer<bool> cellsDirty;
bool anyCellDirty;
readonly (Sprite Sprite, float Scale, float Alpha)[] fogSprites, shroudSprites;
Shroud shroud;
Func<PPos, bool> visibleUnderShroud, visibleUnderFog;
Func<PPos, Shroud.CellVisibility> cellVisibility;
TerrainSpriteLayer shroudLayer, fogLayer;
PaletteReference shroudPaletteReference, fogPaletteReference;
bool disposed;
@@ -161,16 +177,26 @@ namespace OpenRA.Mods.Common.Traits
}
}
int spriteCount;
if (info.UseExtendedIndex)
{
notVisibleEdgesPair = (Edges.AllSides, Edges.AllSides);
spriteCount = (int)Edges.All;
}
else
{
notVisibleEdgesPair = (Edges.AllCorners, Edges.AllCorners);
spriteCount = (int)Edges.AllCorners;
}
// Mapping of shrouded directions -> sprite index
edgesToSpriteIndexOffset = new byte[(byte)(info.UseExtendedIndex ? Edges.All : Edges.AllCorners) + 1];
edgesToSpriteIndexOffset = new byte[spriteCount + 1];
for (var i = 0; i < info.Index.Length; i++)
edgesToSpriteIndexOffset[info.Index[i]] = (byte)i;
if (info.OverrideFullShroud != null)
edgesToSpriteIndexOffset[info.OverrideShroudIndex] = (byte)(variantStride - 1);
notVisibleEdges = info.UseExtendedIndex ? Edges.AllSides : Edges.AllCorners;
world.RenderPlayerChanged += WorldOnRenderPlayerChanged;
}
@@ -188,11 +214,9 @@ namespace OpenRA.Mods.Common.Traits
// All tiles are visible in the editor
if (w.Type == WorldType.Editor)
visibleUnderShroud = _ => true;
cellVisibility = puv => Shroud.CellVisibility.Visible;
else
visibleUnderShroud = puv => map.Contains(puv);
visibleUnderFog = puv => map.Contains(puv);
cellVisibility = puv => (map.Contains(puv) ? Shroud.CellVisibility.Visible | Shroud.CellVisibility.Explored : Shroud.CellVisibility.Hidden);
var shroudBlend = shroudSprites[0].Sprite.BlendMode;
if (shroudSprites.Any(s => s.Sprite.BlendMode != shroudBlend))
@@ -211,33 +235,61 @@ namespace OpenRA.Mods.Common.Traits
WorldOnRenderPlayerChanged(world.RenderPlayer);
}
Edges GetEdges(PPos puv, Func<PPos, bool> isVisible)
Shroud.CellVisibility[] GetNeighborsVisbility(PPos puv)
{
if (!isVisible(puv))
return notVisibleEdges;
var cell = ((MPos)puv).ToCPos(map);
neighbors[(int)Neighbor.Top] = cellVisibility((PPos)(cell + new CVec(0, -1)).ToMPos(map));
neighbors[(int)Neighbor.Right] = cellVisibility((PPos)(cell + new CVec(1, 0)).ToMPos(map));
neighbors[(int)Neighbor.Bottom] = cellVisibility((PPos)(cell + new CVec(0, 1)).ToMPos(map));
neighbors[(int)Neighbor.Left] = cellVisibility((PPos)(cell + new CVec(-1, 0)).ToMPos(map));
neighbors[(int)Neighbor.TopLeft] = cellVisibility((PPos)(cell + new CVec(-1, -1)).ToMPos(map));
neighbors[(int)Neighbor.TopRight] = cellVisibility((PPos)(cell + new CVec(1, -1)).ToMPos(map));
neighbors[(int)Neighbor.BottomRight] = cellVisibility((PPos)(cell + new CVec(1, 1)).ToMPos(map));
neighbors[(int)Neighbor.BottomLeft] = cellVisibility((PPos)(cell + new CVec(-1, 1)).ToMPos(map));
return neighbors;
}
Edges GetEdges(Shroud.CellVisibility[] neighbors, Shroud.CellVisibility visibleMask)
{
// If a side is shrouded then we also count the corners.
var edge = Edges.None;
if (!isVisible((PPos)(cell + new CVec(0, -1)).ToMPos(map))) edge |= Edges.Top;
if (!isVisible((PPos)(cell + new CVec(1, 0)).ToMPos(map))) edge |= Edges.Right;
if (!isVisible((PPos)(cell + new CVec(0, 1)).ToMPos(map))) edge |= Edges.Bottom;
if (!isVisible((PPos)(cell + new CVec(-1, 0)).ToMPos(map))) edge |= Edges.Left;
var edges = Edges.None;
if ((neighbors[(int)Neighbor.Top] & visibleMask) == 0) edges |= Edges.Top;
if ((neighbors[(int)Neighbor.Right] & visibleMask) == 0) edges |= Edges.Right;
if ((neighbors[(int)Neighbor.Bottom] & visibleMask) == 0) edges |= Edges.Bottom;
if ((neighbors[(int)Neighbor.Left] & visibleMask) == 0) edges |= Edges.Left;
var ucorner = edge & Edges.AllCorners;
if (!isVisible((PPos)(cell + new CVec(-1, -1)).ToMPos(map))) edge |= Edges.TopLeft;
if (!isVisible((PPos)(cell + new CVec(1, -1)).ToMPos(map))) edge |= Edges.TopRight;
if (!isVisible((PPos)(cell + new CVec(1, 1)).ToMPos(map))) edge |= Edges.BottomRight;
if (!isVisible((PPos)(cell + new CVec(-1, 1)).ToMPos(map))) edge |= Edges.BottomLeft;
var ucorner = edges & Edges.AllCorners;
if ((neighbors[(int)Neighbor.TopLeft] & visibleMask) == 0) edges |= Edges.TopLeft;
if ((neighbors[(int)Neighbor.TopRight] & visibleMask) == 0) edges |= Edges.TopRight;
if ((neighbors[(int)Neighbor.BottomRight] & visibleMask) == 0) edges |= Edges.BottomRight;
if ((neighbors[(int)Neighbor.BottomLeft] & visibleMask) == 0) edges |= Edges.BottomLeft;
// RA provides a set of frames for tiles with shrouded
// corners but unshrouded edges. We want to detect this
// situation without breaking the edge -> corner enabling
// in other combinations. The XOR turns off the corner
// bits that are enabled twice, which gives the behavior
// bits that are enabled twice, which gives the sprite offset
// we want here.
return info.UseExtendedIndex ? edge ^ ucorner : edge & Edges.AllCorners;
return info.UseExtendedIndex ? edges ^ ucorner : edges & Edges.AllCorners;
}
(Edges, Edges) GetEdges(PPos puv)
{
var cv = cellVisibility(puv);
// If a cell is covered by shroud, then all neigbhors are covered by shroud and fog.
if (cv == Shroud.CellVisibility.Hidden)
return notVisibleEdgesPair;
var ncv = GetNeighborsVisbility(puv);
// If a cell is covered by fog, then all neigbhors are as well.
var edgesFog = cv.HasFlag(Shroud.CellVisibility.Visible) ? GetEdges(ncv, Shroud.CellVisibility.Visible) : notVisibleEdgesPair.Item2;
var edgesShroud = GetEdges(ncv, Shroud.CellVisibility.Explored | Shroud.CellVisibility.Visible);
return (edgesShroud, edgesFog);
}
void WorldOnRenderPlayerChanged(Player player)
@@ -251,14 +303,13 @@ namespace OpenRA.Mods.Common.Traits
if (newShroud != null)
{
visibleUnderShroud = puv => newShroud.IsExplored(puv);
visibleUnderFog = puv => newShroud.IsVisible(puv);
cellVisibility = puv => newShroud.GetVisibility(puv);
newShroud.OnShroudChanged += UpdateShroudCell;
}
else
{
visibleUnderShroud = puv => map.Contains(puv);
visibleUnderFog = puv => map.Contains(puv);
// Visible under shroud: Explored. Visible under fog: Visible.
cellVisibility = puv => (map.Contains(puv) ? Shroud.CellVisibility.Visible | Shroud.CellVisibility.Explored : Shroud.CellVisibility.Hidden);
}
shroud = newShroud;
@@ -287,12 +338,13 @@ namespace OpenRA.Mods.Common.Traits
cellsDirty[uv] = false;
var tileInfo = tileInfos[uv];
var shroudSprite = GetSprite(shroudSprites, GetEdges(puv, visibleUnderShroud), tileInfo.Variant);
var (edgesShroud, edgesFog) = GetEdges(puv);
var shroudSprite = GetSprite(shroudSprites, edgesShroud, tileInfo.Variant);
var shroudPos = tileInfo.ScreenPosition;
if (shroudSprite.Sprite != null)
shroudPos += shroudSprite.Sprite.Offset - 0.5f * shroudSprite.Sprite.Size;
var fogSprite = GetSprite(fogSprites, GetEdges(puv, visibleUnderFog), tileInfo.Variant);
var fogSprite = GetSprite(fogSprites, edgesFog, tileInfo.Variant);
var fogPos = tileInfo.ScreenPosition;
if (fogSprite.Sprite != null)
fogPos += fogSprite.Sprite.Offset - 0.5f * fogSprite.Sprite.Size;

View File

@@ -22,6 +22,9 @@ namespace OpenRA.Mods.Common.Widgets
{
public sealed class RadarWidget : Widget, IDisposable
{
public readonly int ColorFog = Color.FromArgb(128, Color.Black).ToArgb();
public readonly int ColorShroud = Color.Black.ToArgb();
public string WorldInteractionController = null;
public int AnimationLength = 5;
public string RadarOnlineSound = null;
@@ -240,10 +243,11 @@ namespace OpenRA.Mods.Common.Widgets
void UpdateShroudCell(PPos puv)
{
var color = 0;
if (!currentPlayer.Shroud.IsExplored(puv))
color = Color.Black.ToArgb();
else if (!currentPlayer.Shroud.IsVisible(puv))
color = Color.FromArgb(128, Color.Black).ToArgb();
var cv = currentPlayer.Shroud.GetVisibility(puv);
if (cv == Shroud.CellVisibility.Hidden)
color = ColorShroud;
else if (cv.HasFlag(Shroud.CellVisibility.Visible))
color = ColorFog;
var stride = radarSheet.Size.Width;
unsafe