@@ -482,6 +482,7 @@
|
||||
<Compile Include="Widgets\Logic\SettingsLogic.cs" />
|
||||
<Compile Include="AttackBomber.cs" />
|
||||
<Compile Include="Effects\Rank.cs" />
|
||||
<Compile Include="ShroudRenderer.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\OpenRA.FileFormats\OpenRA.FileFormats.csproj">
|
||||
|
||||
@@ -15,8 +15,6 @@ using OpenRA.Traits;
|
||||
|
||||
namespace OpenRA.Mods.RA
|
||||
{
|
||||
public enum ShroudPaletteType { Shroud, Fog, Combined };
|
||||
|
||||
[Desc("Adds the hard-coded shroud palette to the game")]
|
||||
class ShroudPaletteInfo : ITraitInfo
|
||||
{
|
||||
@@ -24,7 +22,7 @@ namespace OpenRA.Mods.RA
|
||||
public readonly string Name = "shroud";
|
||||
|
||||
[Desc("Palette type")]
|
||||
public readonly ShroudPaletteType Type = ShroudPaletteType.Combined;
|
||||
public readonly bool Fog = false;
|
||||
|
||||
public object Create(ActorInitializer init) { return new ShroudPalette(this); }
|
||||
}
|
||||
@@ -37,35 +35,24 @@ namespace OpenRA.Mods.RA
|
||||
|
||||
public void InitPalette(WorldRenderer wr)
|
||||
{
|
||||
var c = info.Type == ShroudPaletteType.Shroud ? Shroud :
|
||||
info.Type == ShroudPaletteType.Fog ? Fog : Combined;
|
||||
|
||||
var c = info.Fog ? Fog : Shroud;
|
||||
wr.AddPalette(info.Name, new Palette(Exts.MakeArray(256, i => (uint)c[i % 8].ToArgb())), false);
|
||||
}
|
||||
|
||||
static Color[] Shroud = new[] {
|
||||
Color.Transparent, Color.Green,
|
||||
Color.Blue, Color.Yellow,
|
||||
Color.Black,
|
||||
Color.FromArgb(128,0,0,0),
|
||||
Color.Transparent,
|
||||
Color.Transparent
|
||||
};
|
||||
|
||||
static Color[] Fog = new[] {
|
||||
Color.Transparent, Color.Green,
|
||||
Color.Blue, Color.Yellow,
|
||||
Color.FromArgb(128,0,0,0),
|
||||
Color.FromArgb(128,0,0,0),
|
||||
Color.FromArgb(128,0,0,0),
|
||||
Color.FromArgb(64,0,0,0)
|
||||
Color.FromArgb(96,0,0,0),
|
||||
Color.FromArgb(64,0,0,0),
|
||||
Color.FromArgb(32,0,0,0)
|
||||
};
|
||||
|
||||
static Color[] Combined = new[] {
|
||||
static Color[] Shroud = new[] {
|
||||
Color.Transparent, Color.Green,
|
||||
Color.Blue, Color.Yellow,
|
||||
Color.Black,
|
||||
Color.FromArgb(192,0,0,0),
|
||||
Color.FromArgb(160,0,0,0),
|
||||
Color.FromArgb(128,0,0,0),
|
||||
Color.FromArgb(64,0,0,0)
|
||||
};
|
||||
|
||||
267
OpenRA.Mods.RA/ShroudRenderer.cs
Normal file
267
OpenRA.Mods.RA/ShroudRenderer.cs
Normal file
@@ -0,0 +1,267 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2013 The OpenRA Developers (see AUTHORS)
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
* see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using OpenRA.FileFormats;
|
||||
using OpenRA.FileFormats.Graphics;
|
||||
using OpenRA.Graphics;
|
||||
using OpenRA.Traits;
|
||||
|
||||
namespace OpenRA.Mods.RA
|
||||
{
|
||||
public class ShroudRendererInfo : ITraitInfo
|
||||
{
|
||||
public string Sequence = "shroud";
|
||||
public string[] Variants = new[] { "shroud" };
|
||||
|
||||
[Desc("Bitfield of shroud directions for each frame. Lower four bits are",
|
||||
"corners clockwise from TL; upper four are edges clockwise from top")]
|
||||
public int[] Index = new[] { 12, 9, 8, 3, 1, 6, 4, 2, 13, 11, 7, 14 };
|
||||
|
||||
[Desc("Use the upper four bits when calculating frame")]
|
||||
public bool UseExtendedIndex = false;
|
||||
|
||||
[Desc("Palette index for synthesized unexplored tile")]
|
||||
public int ShroudColor = 12;
|
||||
public BlendMode ShroudBlend = BlendMode.Alpha;
|
||||
public object Create(ActorInitializer init) { return new ShroudRenderer(init.world, this); }
|
||||
}
|
||||
|
||||
public class ShroudRenderer : IRenderShroud, IWorldLoaded
|
||||
{
|
||||
struct ShroudTile
|
||||
{
|
||||
public CPos Position;
|
||||
public float2 ScreenPosition;
|
||||
public int Variant;
|
||||
|
||||
public Sprite Fog;
|
||||
public Sprite Shroud;
|
||||
}
|
||||
|
||||
Sprite[] sprites;
|
||||
Sprite unexploredTile;
|
||||
int[] spriteMap;
|
||||
|
||||
ShroudTile[] tiles;
|
||||
int tileStride, variantStride;
|
||||
|
||||
int shroudHash;
|
||||
PaletteReference fogPalette, shroudPalette;
|
||||
Rectangle bounds;
|
||||
bool useExtendedIndex;
|
||||
|
||||
public ShroudRenderer(World world, ShroudRendererInfo info)
|
||||
{
|
||||
var map = world.Map;
|
||||
bounds = map.Bounds;
|
||||
useExtendedIndex = info.UseExtendedIndex;
|
||||
|
||||
tiles = new ShroudTile[map.MapSize.X * map.MapSize.Y];
|
||||
tileStride = map.MapSize.X;
|
||||
|
||||
// Force update on first render
|
||||
shroudHash = -1;
|
||||
|
||||
// Load sprite variants
|
||||
sprites = new Sprite[info.Variants.Length * info.Index.Length];
|
||||
variantStride = info.Index.Length;
|
||||
for (var j = 0; j < info.Variants.Length; j++)
|
||||
{
|
||||
var seq = SequenceProvider.GetSequence(info.Sequence, info.Variants[j]);
|
||||
for (var i = 0; i < info.Index.Length; i++)
|
||||
sprites[j * variantStride + i] = seq.GetSprite(i);
|
||||
}
|
||||
|
||||
// Mapping of shrouded directions -> sprite index
|
||||
spriteMap = new int[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))
|
||||
{
|
||||
var size = new Size(Game.modData.Manifest.TileSize, Game.modData.Manifest.TileSize);
|
||||
var data = Exts.MakeArray<byte>(size.Width * size.Height, _ => (byte)info.ShroudColor);
|
||||
var s = Game.modData.SheetBuilder.Add(data, size);
|
||||
unexploredTile = new Sprite(s.sheet, s.bounds, s.offset, s.channel, info.ShroudBlend);
|
||||
}
|
||||
else
|
||||
unexploredTile = sprites[spriteMap[0]];
|
||||
}
|
||||
|
||||
static int FoggedEdges(Shroud s, CPos p, bool useExtendedIndex)
|
||||
{
|
||||
if (!s.IsVisible(p.X, p.Y))
|
||||
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;
|
||||
|
||||
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;
|
||||
|
||||
// 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
|
||||
// we want here.
|
||||
return useExtendedIndex ? u ^ uside : u & 0x0F;
|
||||
}
|
||||
|
||||
static int ShroudedEdges(Shroud s, CPos p, bool useExtendedIndex)
|
||||
{
|
||||
if (!s.IsExplored(p.X, p.Y))
|
||||
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;
|
||||
|
||||
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;
|
||||
|
||||
// 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
|
||||
// we want here.
|
||||
return useExtendedIndex ? u ^ uside : u & 0x0F;
|
||||
}
|
||||
|
||||
static int ObserverShroudedEdges(CPos p, Rectangle bounds, bool useExtendedIndex)
|
||||
{
|
||||
var u = 0;
|
||||
if (p.Y == bounds.Top) u |= 0x13;
|
||||
if (p.X == bounds.Right - 1) u |= 0x26;
|
||||
if (p.Y == bounds.Bottom - 1) u |= 0x4C;
|
||||
if (p.X == bounds.Left) u |= 0x89;
|
||||
|
||||
var uside = u & 0x0F;
|
||||
if (p.X == bounds.Left && p.Y == bounds.Top) u |= 0x01;
|
||||
if (p.X == bounds.Right - 1 && p.Y == bounds.Top) u |= 0x02;
|
||||
if (p.X == bounds.Right - 1 && p.Y == bounds.Bottom - 1) u |= 0x04;
|
||||
if (p.X == bounds.Left && p.Y == bounds.Bottom - 1) u |= 0x08;
|
||||
|
||||
return useExtendedIndex ? u ^ uside : u & 0x0F;
|
||||
}
|
||||
|
||||
public void WorldLoaded(World w, WorldRenderer wr)
|
||||
{
|
||||
// Cache the tile positions to avoid unnecessary calculations
|
||||
for (var i = bounds.Left; i < bounds.Right; i++)
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
if (w.LobbyInfo.GlobalSettings.Fog)
|
||||
fogPalette = wr.Palette("fog");
|
||||
|
||||
shroudPalette = wr.Palette("shroud");
|
||||
}
|
||||
|
||||
Sprite GetTile(int flags, int variant)
|
||||
{
|
||||
if (flags == 0)
|
||||
return null;
|
||||
|
||||
if (flags == 15)
|
||||
return unexploredTile;
|
||||
|
||||
return sprites[variant * variantStride + spriteMap[flags]];
|
||||
}
|
||||
|
||||
void Update(Shroud shroud)
|
||||
{
|
||||
var hash = shroud != null ? shroud.Hash : 0;
|
||||
if (shroudHash == hash)
|
||||
return;
|
||||
|
||||
shroudHash = hash;
|
||||
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++)
|
||||
{
|
||||
var shrouded = ObserverShroudedEdges(tiles[k].Position, bounds, useExtendedIndex);
|
||||
tiles[k].Shroud = GetTile(shrouded, tiles[k].Variant);
|
||||
tiles[k].Fog = GetTile(shrouded, tiles[k].Variant);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (var k = 0; k < tiles.Length; k++)
|
||||
{
|
||||
var shrouded = ShroudedEdges(shroud, tiles[k].Position, useExtendedIndex);
|
||||
var fogged = FoggedEdges(shroud, tiles[k].Position, useExtendedIndex);
|
||||
|
||||
tiles[k].Shroud = GetTile(shrouded, tiles[k].Variant);
|
||||
tiles[k].Fog = GetTile(fogged, tiles[k].Variant);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void RenderShroud(WorldRenderer wr, Shroud shroud)
|
||||
{
|
||||
Update(shroud);
|
||||
|
||||
var clip = wr.Viewport.CellBounds;
|
||||
var width = clip.Width;
|
||||
for (var j = clip.Top; j < clip.Bottom; j++)
|
||||
{
|
||||
var start = j * tileStride + clip.Left;
|
||||
for (var k = 0; k < width; k++)
|
||||
{
|
||||
var s = tiles[start + k].Shroud;
|
||||
var f = tiles[start + k].Fog;
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user