Merge pull request #5406 from RoosterDragon/palette-efficiency

Changed HardwarePalette.ApplyModifiers to be more efficient.
This commit is contained in:
Paul Chote
2014-06-28 16:11:43 +12:00
36 changed files with 327 additions and 256 deletions

View File

@@ -153,11 +153,11 @@ namespace OpenRA.Editor
tileset = Program.Rules.TileSets[map.Tileset];
tilesetRenderer = new TileSetRenderer(tileset, modData.Manifest.TileSize);
var shadowIndex = new int[] { 3, 4 };
var palette = new Palette(GlobalFileSystem.Open(tileset.Palette), shadowIndex);
var palette = new ImmutablePalette(GlobalFileSystem.Open(tileset.Palette), shadowIndex);
// required for desert terrain in RA
var playerPalette = tileset.PlayerPalette ?? tileset.Palette;
var shadowedPalette = new Palette(GlobalFileSystem.Open(playerPalette), shadowIndex);
var shadowedPalette = new ImmutablePalette(GlobalFileSystem.Open(playerPalette), shadowIndex);
surface1.Bind(map, tileset, tilesetRenderer, palette, shadowedPalette);

View File

@@ -20,7 +20,7 @@ namespace OpenRA.Editor
{
static class RenderUtils
{
static Bitmap RenderShp(ISpriteSource shp, Palette p)
static Bitmap RenderShp(ISpriteSource shp, IPalette p)
{
var frame = shp.Frames.First();
@@ -45,7 +45,7 @@ namespace OpenRA.Editor
return bitmap;
}
public static ActorTemplate RenderActor(ActorInfo info, TileSet tileset, Palette p)
public static ActorTemplate RenderActor(ActorInfo info, TileSet tileset, IPalette p)
{
var image = RenderSprites.GetImage(info);
@@ -76,7 +76,7 @@ namespace OpenRA.Editor
}
}
public static ResourceTemplate RenderResourceType(ResourceTypeInfo info, string[] exts, Palette p)
public static ResourceTemplate RenderResourceType(ResourceTypeInfo info, string[] exts, IPalette p)
{
var image = info.EditorSprite;
using (var s = GlobalFileSystem.OpenWithExts(image, exts))

View File

@@ -45,8 +45,8 @@ namespace OpenRA.Editor
public Map Map { get; private set; }
public TileSet TileSet { get; private set; }
public TileSetRenderer TileSetRenderer { get; private set; }
public Palette Palette { get; private set; }
public Palette PlayerPalette { get; private set; }
public IPalette Palette { get; private set; }
public IPalette PlayerPalette { get; private set; }
public int2 Offset;
public int2 GetOffset() { return Offset; }
@@ -81,7 +81,7 @@ namespace OpenRA.Editor
public Keys GetModifiers() { return ModifierKeys; }
public void Bind(Map m, TileSet ts, TileSetRenderer tsr, Palette p, Palette pp)
public void Bind(Map m, TileSet ts, TileSetRenderer tsr, IPalette p, IPalette pp)
{
Map = m;
TileSet = ts;
@@ -381,7 +381,7 @@ namespace OpenRA.Editor
var pr = Map.Players[name];
var pcpi = Program.Rules.Actors["player"].Traits.Get<PlayerColorPaletteInfo>();
var remap = new PlayerColorRemap(pcpi.RemapIndex, pr.Color, pcpi.Ramp);
return new Palette(PlayerPalette, remap).AsSystemPalette();
return new ImmutablePalette(PlayerPalette, remap).AsSystemPalette();
}
Cache<string, ColorPalette> playerPalettes;

View File

@@ -82,7 +82,7 @@ namespace OpenRA.Editor
templates.Add(t.Key, LoadTemplate(t.Value.Image, tileset.Extensions, sourceCache, t.Value.Frames));
}
public Bitmap RenderTemplate(ushort id, Palette p)
public Bitmap RenderTemplate(ushort id, IPalette p)
{
var template = TileSet.Templates[id];
var templateData = templates[id];

View File

@@ -41,7 +41,7 @@ namespace OpenRA.Graphics
palette = new HardwarePalette();
foreach (var p in nodesDict["Palettes"].Nodes)
palette.AddPalette(p.Key, new Palette(GlobalFileSystem.Open(p.Value.Value), shadowIndex), false);
palette.AddPalette(p.Key, new ImmutablePalette(GlobalFileSystem.Open(p.Value.Value), shadowIndex), false);
var spriteLoader = new SpriteLoader(new string[0], new SheetBuilder(SheetType.Indexed));
foreach (var s in nodesDict["Cursors"].Nodes)
@@ -53,9 +53,6 @@ namespace OpenRA.Graphics
PaletteReference CreatePaletteReference(string name)
{
var pal = palette.GetPalette(name);
if (pal == null)
throw new InvalidOperationException("Palette `{0}` does not exist".F(name));
return new PaletteReference(name, palette.GetPaletteIndex(name), pal);
}

View File

@@ -1,6 +1,6 @@
#region Copyright & License Information
/*
* Copyright 2007-2011 The OpenRA Developers (see AUTHORS)
* Copyright 2007-2014 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,
@@ -10,7 +10,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
using OpenRA.Traits;
namespace OpenRA.Graphics
@@ -18,70 +17,101 @@ namespace OpenRA.Graphics
public class HardwarePalette
{
public const int MaxPalettes = 256;
int allocated = 0;
public ITexture Texture { get; private set; }
Dictionary<string, Palette> palettes;
Dictionary<string, int> indices;
Dictionary<string, bool> allowsMods;
readonly Dictionary<string, ImmutablePalette> palettes = new Dictionary<string, ImmutablePalette>();
readonly Dictionary<string, MutablePalette> modifiablePalettes = new Dictionary<string, MutablePalette>();
readonly IReadOnlyDictionary<string, MutablePalette> readOnlyModifiablePalettes;
readonly Dictionary<string, int> indices = new Dictionary<string, int>();
readonly uint[,] buffer = new uint[Palette.Size, MaxPalettes];
public HardwarePalette()
{
palettes = new Dictionary<string, Palette>();
indices = new Dictionary<string, int>();
allowsMods = new Dictionary<string, bool>();
Texture = Game.Renderer.Device.CreateTexture();
readOnlyModifiablePalettes = modifiablePalettes.AsReadOnly();
}
public Palette GetPalette(string name)
public IPalette GetPalette(string name)
{
Palette ret;
if (!palettes.TryGetValue(name,out ret))
throw new InvalidOperationException("Palette `{0}` does not exist".F(name));
return ret;
MutablePalette mutable;
if (modifiablePalettes.TryGetValue(name, out mutable))
return mutable.AsReadOnly();
ImmutablePalette immutable;
if (palettes.TryGetValue(name, out immutable))
return immutable;
throw new InvalidOperationException("Palette `{0}` does not exist".F(name));
}
public int GetPaletteIndex(string name)
{
int ret;
if (!indices.TryGetValue(name,out ret))
if (!indices.TryGetValue(name, out ret))
throw new InvalidOperationException("Palette `{0}` does not exist".F(name));
return ret;
}
public void AddPalette(string name, Palette p, bool allowModifiers)
public void AddPalette(string name, ImmutablePalette p, bool allowModifiers)
{
if (palettes.Count >= MaxPalettes)
throw new InvalidOperationException("Limit of {0} palettes reached. Cannot add {1}.".F(MaxPalettes, name));
if (palettes.ContainsKey(name))
throw new InvalidOperationException("Palette {0} has already been defined".F(name));
int index = palettes.Count;
indices.Add(name, index);
palettes.Add(name, p);
indices.Add(name, allocated++);
allowsMods.Add(name, allowModifiers);
if (allowModifiers)
modifiablePalettes.Add(name, new MutablePalette(p));
else
CopyPaletteToBuffer(index, p);
}
uint[,] data = new uint[MaxPalettes, 256];
public void ApplyModifiers(IEnumerable<IPaletteModifier> paletteMods)
public void ReplacePalette(string name, IPalette p)
{
var copy = palettes.ToDictionary(p => p.Key, p => new Palette(p.Value));
var modifiable = copy.Where(p => allowsMods[p.Key]).ToDictionary(p => p.Key, p => p.Value);
foreach (var mod in paletteMods)
mod.AdjustPalette(modifiable);
foreach (var pal in copy)
{
var j = indices[pal.Key];
var c = pal.Value.Values;
for (var i = 0; i < 256; i++)
data[j,i] = c[i];
}
Texture.SetData(data);
if (modifiablePalettes.ContainsKey(name))
CopyPaletteToBuffer(indices[name], modifiablePalettes[name] = new MutablePalette(p));
else if (palettes.ContainsKey(name))
CopyPaletteToBuffer(indices[name], palettes[name] = new ImmutablePalette(p));
else
throw new InvalidOperationException("Palette `{0}` does not exist".F(name));
Texture.SetData(buffer);
}
public void Initialize()
{
ApplyModifiers(new IPaletteModifier[] {});
CopyModifiablePalettesToBuffer();
Texture.SetData(buffer);
}
void CopyPaletteToBuffer(int index, IPalette p)
{
for (var i = 0; i < Palette.Size; i++)
buffer[i, index] = p[i];
}
void CopyModifiablePalettesToBuffer()
{
foreach (var kvp in modifiablePalettes)
CopyPaletteToBuffer(indices[kvp.Key], kvp.Value);
}
public void ApplyModifiers(IEnumerable<IPaletteModifier> paletteMods)
{
foreach (var mod in paletteMods)
mod.AdjustPalette(readOnlyModifiablePalettes);
// Update our texture with the changes.
CopyModifiablePalettesToBuffer();
Texture.SetData(buffer);
// Reset modified palettes back to their original colors, ready for next time.
foreach (var kvp in modifiablePalettes)
{
var originalPalette = palettes[kvp.Key];
var modifiedPalette = kvp.Value;
for (var i = 0; i < Palette.Size; i++)
modifiedPalette[i] = originalPalette[i];
}
}
}
}

View File

@@ -1,6 +1,6 @@
#region Copyright & License Information
/*
* Copyright 2007-2012 The OpenRA Developers (see AUTHORS)
* Copyright 2007-2014 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,
@@ -8,94 +8,35 @@
*/
#endregion
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Reflection;
using System.Runtime.InteropServices;
namespace OpenRA.Graphics
{
public class Palette
public interface IPalette { uint this[int index] { get; } }
public interface IPaletteRemap { Color GetRemappedColor(Color original, int index); }
public static class Palette
{
public static Palette Load(string filename, int[] remap)
public const int Size = 256;
public static Color GetColor(this IPalette palette, int index)
{
using (var s = File.OpenRead(filename))
return new Palette(s, remap);
return Color.FromArgb((int)palette[index]);
}
uint[] colors;
public Color GetColor(int index)
{
return Color.FromArgb((int)colors[index]);
}
public void SetColor(int index, Color color)
{
colors[index] = (uint)color.ToArgb();
}
public void SetColor(int index, uint color)
{
colors[index] = (uint)color;
}
public uint[] Values
{
get { return colors; }
}
public void ApplyRemap(IPaletteRemap r)
{
for (var i = 0; i < 256; i++)
colors[i] = (uint)r.GetRemappedColor(Color.FromArgb((int)colors[i]), i).ToArgb();
}
public Palette(Stream s, int[] remapShadow)
{
colors = new uint[256];
using (var reader = new BinaryReader(s))
{
for (var i = 0; i < 256; i++)
{
var r = (byte)(reader.ReadByte() << 2);
var g = (byte)(reader.ReadByte() << 2);
var b = (byte)(reader.ReadByte() << 2);
colors[i] = (uint)((255 << 24) | (r << 16) | (g << 8) | b);
}
}
colors[0] = 0; // convert black background to transparency
foreach (var i in remapShadow)
colors[i] = 140u << 24;
}
public Palette(Palette p, IPaletteRemap r)
{
colors = (uint[])p.colors.Clone();
ApplyRemap(r);
}
public Palette(Palette p)
{
colors = (uint[])p.colors.Clone();
}
public Palette(uint[] data)
{
if (data.Length != 256)
throw new InvalidDataException("Attempting to create palette with incorrect array size");
colors = (uint[])data.Clone();
}
public ColorPalette AsSystemPalette()
public static ColorPalette AsSystemPalette(this IPalette palette)
{
ColorPalette pal;
using (var b = new Bitmap(1, 1, PixelFormat.Format8bppIndexed))
pal = b.Palette;
for (var i = 0; i < 256; i++)
pal.Entries[i] = GetColor(i);
for (var i = 0; i < Size; i++)
pal.Entries[i] = palette.GetColor(i);
// hack around a mono bug -- the palette flags get set wrong.
if (Platform.CurrentPlatform != PlatformType.Windows)
@@ -105,22 +46,116 @@ namespace OpenRA.Graphics
return pal;
}
public Bitmap AsBitmap()
public static Bitmap AsBitmap(this IPalette palette)
{
var b = new Bitmap(256, 1, PixelFormat.Format32bppArgb);
var b = new Bitmap(Size, 1, PixelFormat.Format32bppArgb);
var data = b.LockBits(new Rectangle(0, 0, b.Width, b.Height),
ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb);
unsafe
{
var c = (uint*)data.Scan0;
for (var x = 0; x < 256; x++)
*(c + x) = colors[x];
}
var temp = new uint[Palette.Size];
for (int i = 0; i < temp.Length; i++)
temp[i] = palette[i];
Marshal.Copy((int[])(object)temp, 0, data.Scan0, Size);
b.UnlockBits(data);
return b;
}
public static IPalette AsReadOnly(this IPalette palette)
{
if (palette is ImmutablePalette)
return palette;
return new ReadOnlyPalette(palette);
}
class ReadOnlyPalette : IPalette
{
IPalette palette;
public ReadOnlyPalette(IPalette palette) { this.palette = palette; }
public uint this[int index] { get { return palette[index]; } }
}
}
public interface IPaletteRemap { Color GetRemappedColor(Color original, int index); }
public class ImmutablePalette : IPalette
{
readonly uint[] colors = new uint[Palette.Size];
public uint this[int index]
{
get { return colors[index]; }
}
public ImmutablePalette(string filename, int[] remap)
{
using (var s = File.OpenRead(filename))
LoadFromStream(s, remap);
}
public ImmutablePalette(Stream s, int[] remapShadow)
{
LoadFromStream(s, remapShadow);
}
void LoadFromStream(Stream s, int[] remapShadow)
{
using (var reader = new BinaryReader(s))
for (var i = 0; i < Palette.Size; i++)
{
var r = (byte)(reader.ReadByte() << 2);
var g = (byte)(reader.ReadByte() << 2);
var b = (byte)(reader.ReadByte() << 2);
colors[i] = (uint)((255 << 24) | (r << 16) | (g << 8) | b);
}
colors[0] = 0; // Convert black background to transparency.
foreach (var i in remapShadow)
colors[i] = 140u << 24;
}
public ImmutablePalette(IPalette p, IPaletteRemap r)
: this(p)
{
for (var i = 0; i < Palette.Size; i++)
colors[i] = (uint)r.GetRemappedColor(this.GetColor(i), i).ToArgb();
}
public ImmutablePalette(IPalette p)
{
for (int i = 0; i < Palette.Size; i++)
colors[i] = p[i];
}
public ImmutablePalette(IEnumerable<uint> sourceColors)
{
var i = 0;
foreach (var sourceColor in sourceColors)
colors[i++] = sourceColor;
}
}
public class MutablePalette : IPalette
{
readonly uint[] colors = new uint[Palette.Size];
public uint this[int index]
{
get { return colors[index]; }
set { colors[index] = value; }
}
public MutablePalette(IPalette p)
{
for (int i = 0; i < Palette.Size; i++)
this[i] = p[i];
}
public void SetColor(int index, Color color)
{
colors[index] = (uint)color.ToArgb();
}
public void ApplyRemap(IPaletteRemap r)
{
for (var i = 0; i < Palette.Size; i++)
colors[i] = (uint)r.GetRemappedColor(this.GetColor(i), i).ToArgb();
}
}
}

View File

@@ -96,7 +96,7 @@ namespace OpenRA.Graphics
return bitmap;
}
public Bitmap AsBitmap(TextureChannel channel, Palette pal)
public Bitmap AsBitmap(TextureChannel channel, IPalette pal)
{
var d = Data;
var dataStride = 4 * Size.Width;
@@ -115,7 +115,7 @@ namespace OpenRA.Graphics
for (var x = 0; x < Size.Width; x++)
{
var paletteIndex = d[dataRowIndex + 4 * x];
colors[bdRowIndex + x] = pal.Values[paletteIndex];
colors[bdRowIndex + x] = pal[paletteIndex];
}
}
}

View File

@@ -1,6 +1,6 @@
#region Copyright & License Information
/*
* Copyright 2007-2011 The OpenRA Developers (see AUTHORS)
* Copyright 2007-2014 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,
@@ -12,7 +12,6 @@ using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using OpenRA.Primitives;
using OpenRA.Traits;
namespace OpenRA.Graphics
@@ -21,8 +20,8 @@ namespace OpenRA.Graphics
{
public readonly string Name;
public readonly int Index;
public readonly Palette Palette;
public PaletteReference(string name, int index, Palette palette)
public IPalette Palette { get; internal set; }
public PaletteReference(string name, int index, IPalette palette)
{
Name = name;
Index = index;
@@ -36,10 +35,10 @@ namespace OpenRA.Graphics
public readonly Theater Theater;
public Viewport Viewport { get; private set; }
internal readonly TerrainRenderer terrainRenderer;
internal readonly HardwarePalette palette;
internal Cache<string, PaletteReference> palettes;
Lazy<DeveloperMode> devTrait;
readonly TerrainRenderer terrainRenderer;
readonly HardwarePalette palette;
readonly Dictionary<string, PaletteReference> palettes;
readonly Lazy<DeveloperMode> devTrait;
internal WorldRenderer(World world)
{
@@ -47,9 +46,9 @@ namespace OpenRA.Graphics
Viewport = new Viewport(this, world.Map);
palette = new HardwarePalette();
palettes = new Cache<string, PaletteReference>(CreatePaletteReference);
foreach (var pal in world.traitDict.ActorsWithTrait<IPalette>())
pal.Trait.InitPalette(this);
palettes = new Dictionary<string, PaletteReference>();
foreach (var pal in world.traitDict.ActorsWithTrait<ILoadsPalettes>())
pal.Trait.LoadPalettes(this);
palette.Initialize();
@@ -62,14 +61,13 @@ namespace OpenRA.Graphics
PaletteReference CreatePaletteReference(string name)
{
var pal = palette.GetPalette(name);
if (pal == null)
throw new InvalidOperationException("Palette `{0}` does not exist".F(name));
return new PaletteReference(name, palette.GetPaletteIndex(name), pal);
}
public PaletteReference Palette(string name) { return palettes[name]; }
public void AddPalette(string name, Palette pal, bool allowModifiers) { palette.AddPalette(name, pal, allowModifiers); }
public PaletteReference Palette(string name) { return palettes.GetOrAdd(name, CreatePaletteReference); }
public void AddPalette(string name, ImmutablePalette pal) { palette.AddPalette(name, pal, false); }
public void AddPalette(string name, ImmutablePalette pal, bool allowModifiers) { palette.AddPalette(name, pal, allowModifiers); }
public void ReplacePalette(string name, IPalette pal) { palette.ReplacePalette(name, pal); palettes[name].Palette = pal; }
List<IRenderable> GenerateRenderables()
{

View File

@@ -32,6 +32,14 @@ namespace OpenRA
bool TryGetValue(TKey key, out TValue value);
}
public static class ReadOnlyDictionary
{
public static IReadOnlyDictionary<TKey, TValue> AsReadOnly<TKey, TValue>(this IDictionary<TKey, TValue> dict)
{
return dict as IReadOnlyDictionary<TKey, TValue> ?? new ReadOnlyDictionary<TKey, TValue>(dict);
}
}
/// <summary>
/// A minimal read only dictionary for .NET 4 implemented as a wrapper
/// around an IDictionary.

View File

@@ -31,7 +31,7 @@ namespace OpenRA.Traits
public object Create(ActorInitializer init) { return new FixedColorPalette(this); }
}
public class FixedColorPalette : IPalette
public class FixedColorPalette : ILoadsPalettes
{
readonly FixedColorPaletteInfo info;
@@ -40,10 +40,10 @@ namespace OpenRA.Traits
this.info = info;
}
public void InitPalette(WorldRenderer wr)
public void LoadPalettes(WorldRenderer wr)
{
var remap = new PlayerColorRemap(info.RemapIndex, info.Color, info.Ramp);
wr.AddPalette(info.Name, new Palette(wr.Palette(info.Base).Palette, remap), info.AllowModifiers);
wr.AddPalette(info.Name, new ImmutablePalette(wr.Palette(info.Base).Palette, remap), info.AllowModifiers);
}
}
}

View File

@@ -29,7 +29,7 @@ namespace OpenRA.Traits
public object Create(ActorInitializer init) { return new PlayerColorPalette(init.self.Owner, this); }
}
public class PlayerColorPalette : IPalette
public class PlayerColorPalette : ILoadsPalettes
{
readonly Player owner;
readonly PlayerColorPaletteInfo info;
@@ -40,10 +40,10 @@ namespace OpenRA.Traits
this.info = info;
}
public void InitPalette(WorldRenderer wr)
public void LoadPalettes(WorldRenderer wr)
{
var remap = new PlayerColorRemap(info.RemapIndex, owner.Color, info.Ramp);
wr.AddPalette(info.BaseName + owner.InternalName, new Palette(wr.Palette(info.BasePalette).Palette, remap), info.AllowModifiers);
wr.AddPalette(info.BaseName + owner.InternalName, new ImmutablePalette(wr.Palette(info.BasePalette).Palette, remap), info.AllowModifiers);
}
}
}

View File

@@ -9,6 +9,7 @@
#endregion
using System.Drawing;
using System.Linq;
using OpenRA.Graphics;
namespace OpenRA.Traits
@@ -22,7 +23,7 @@ namespace OpenRA.Traits
public object Create(ActorInitializer init) { return new PlayerHighlightPalette(init.self.Owner, this); }
}
public class PlayerHighlightPalette : IPalette
public class PlayerHighlightPalette : ILoadsPalettes
{
readonly Player owner;
readonly PlayerHighlightPaletteInfo info;
@@ -33,10 +34,10 @@ namespace OpenRA.Traits
this.info = info;
}
public void InitPalette(WorldRenderer wr)
public void LoadPalettes(WorldRenderer wr)
{
var argb = (uint)Color.FromArgb(128, owner.Color.RGB).ToArgb();
wr.AddPalette(info.BaseName + owner.InternalName, new Palette(Exts.MakeArray(256, i => i == 0 ? 0 : argb)), false);
wr.AddPalette(info.BaseName + owner.InternalName, new ImmutablePalette(Enumerable.Range(0, Palette.Size).Select(i => i == 0 ? 0 : argb)));
}
}
}

View File

@@ -150,8 +150,8 @@ namespace OpenRA.Traits
public interface IDamageModifier { float GetDamageModifier(Actor attacker, WarheadInfo warhead); }
public interface ISpeedModifier { decimal GetSpeedModifier(); }
public interface IFirepowerModifier { float GetFirepowerModifier(); }
public interface IPalette { void InitPalette(WorldRenderer wr); }
public interface IPaletteModifier { void AdjustPalette(Dictionary<string, Palette> b); }
public interface ILoadsPalettes { void LoadPalettes(WorldRenderer wr); }
public interface IPaletteModifier { void AdjustPalette(IReadOnlyDictionary<string, MutablePalette> b); }
public interface IPips { IEnumerable<PipType> GetPips(Actor self); }
public interface ITags { IEnumerable<TagType> GetTags(); }
public interface ISelectionBar { float GetValue(); Color GetColor(); }

View File

@@ -29,19 +29,19 @@ namespace OpenRA.Mods.RA
public object Create(ActorInitializer init) { return new FogPaletteFromR8(this); }
}
class FogPaletteFromR8 : IPalette
class FogPaletteFromR8 : ILoadsPalettes
{
readonly FogPaletteFromR8Info info;
public FogPaletteFromR8(FogPaletteFromR8Info info) { this.info = info; }
public void InitPalette(WorldRenderer wr)
public void LoadPalettes(WorldRenderer wr)
{
var colors = new uint[256];
var colors = new uint[Palette.Size];
using (var s = GlobalFileSystem.Open(info.Filename))
{
s.Seek(info.Offset, SeekOrigin.Begin);
for (var i = 0; i < 256; i++)
for (var i = 0; i < Palette.Size; i++)
{
var packed = s.ReadUInt16();
@@ -53,7 +53,7 @@ namespace OpenRA.Mods.RA
}
}
wr.AddPalette(info.Name, new Palette(colors), info.AllowModifiers);
wr.AddPalette(info.Name, new ImmutablePalette(colors), info.AllowModifiers);
}
}
}

View File

@@ -29,19 +29,19 @@ namespace OpenRA.Mods.RA
public object Create(ActorInitializer init) { return new PaletteFromR8(this); }
}
class PaletteFromR8 : IPalette
class PaletteFromR8 : ILoadsPalettes
{
readonly PaletteFromR8Info info;
public PaletteFromR8(PaletteFromR8Info info) { this.info = info; }
public void InitPalette(WorldRenderer wr)
public void LoadPalettes(WorldRenderer wr)
{
var colors = new uint[256];
var colors = new uint[Palette.Size];
using (var s = GlobalFileSystem.Open(info.Filename))
{
s.Seek(info.Offset, SeekOrigin.Begin);
for (var i = 0; i < 256; i++)
for (var i = 0; i < Palette.Size; i++)
{
var packed = s.ReadUInt16();
colors[i] = (uint)((255 << 24) | ((packed & 0xF800) << 8) | ((packed & 0x7E0) << 5) | ((packed & 0x1f) << 3));
@@ -51,7 +51,7 @@ namespace OpenRA.Mods.RA
}
}
wr.AddPalette(info.Name, new Palette(colors), info.AllowModifiers);
wr.AddPalette(info.Name, new ImmutablePalette(colors), info.AllowModifiers);
}
}
}

View File

@@ -35,15 +35,15 @@ namespace OpenRA.Mods.D2k
public object Create(ActorInitializer init) { return new PaletteFromScaledPalette(this); }
}
class PaletteFromScaledPalette : IPalette
class PaletteFromScaledPalette : ILoadsPalettes
{
readonly PaletteFromScaledPaletteInfo info;
public PaletteFromScaledPalette(PaletteFromScaledPaletteInfo info) { this.info = info; }
public void InitPalette(WorldRenderer wr)
public void LoadPalettes(WorldRenderer wr)
{
var remap = new ScaledPaletteRemap(info.Scale, info.Offset);
wr.AddPalette(info.Name, new Palette(wr.Palette(info.BasePalette).Palette, remap), info.AllowModifiers);
wr.AddPalette(info.Name, new ImmutablePalette(wr.Palette(info.BasePalette).Palette, remap), info.AllowModifiers);
}
}

View File

@@ -33,16 +33,16 @@ namespace OpenRA.Mods.RA
remainingFrames--;
}
public void AdjustPalette(Dictionary<string,Palette> palettes)
public void AdjustPalette(IReadOnlyDictionary<string, MutablePalette> palettes)
{
if (remainingFrames == 0)
return;
var frac = (float)remainingFrames / chronoEffectLength;
foreach (var pal in palettes)
{
for (var x = 0; x < 256; x++)
for (var x = 0; x < Palette.Size; x++)
{
var orig = pal.Value.GetColor(x);
var lum = (int)(255 * orig.GetBrightness());

View File

@@ -15,7 +15,7 @@ using OpenRA.Traits;
namespace OpenRA.Mods.RA
{
public class CloakPaletteEffectInfo : TraitInfo<CloakPaletteEffect> {}
public class CloakPaletteEffectInfo : TraitInfo<CloakPaletteEffect> { }
public class CloakPaletteEffect : IPaletteModifier, ITick
{
@@ -29,23 +29,22 @@ namespace OpenRA.Mods.RA
Color.FromArgb(178, 205, 250, 220),
};
public void AdjustPalette(Dictionary<string, Palette> b)
public void AdjustPalette(IReadOnlyDictionary<string, MutablePalette> b)
{
var i = (int)t;
var p = b[paletteName];
for (var j = 0; j < colors.Length; j++ )
for (var j = 0; j < colors.Length; j++)
{
var k = (i+j) % 16 + 0xb0;
p.SetColor(k, colors[j]);
var k = (i + j) % 16 + 0xb0;
p.SetColor(k, colors[j]);
}
}
public void Tick (Actor self)
public void Tick(Actor self)
{
t += 0.25f;
if (t >= 256) t = 0;
}
}
}

View File

@@ -18,7 +18,7 @@ namespace OpenRA.Mods.RA
[Desc("Palette effect used for blinking \"animations\" on actors.")]
class LightPaletteRotatorInfo : ITraitInfo
{
public readonly string[] ExcludePalettes = {};
public readonly string[] ExcludePalettes = { };
public object Create(ActorInitializer init) { return new LightPaletteRotator(this); }
}
@@ -38,7 +38,7 @@ namespace OpenRA.Mods.RA
this.info = info;
}
public void AdjustPalette(Dictionary<string,Palette> palettes)
public void AdjustPalette(IReadOnlyDictionary<string, MutablePalette> palettes)
{
foreach (var pal in palettes)
{
@@ -49,7 +49,7 @@ namespace OpenRA.Mods.RA
if (rotate > 9)
rotate = 18 - rotate;
pal.Value.SetColor(0x67, pal.Value.GetColor(230+rotate));
pal.Value.SetColor(0x67, pal.Value.GetColor(230 + rotate));
}
}
}

View File

@@ -66,24 +66,24 @@ namespace OpenRA.Mods.RA
}
}
public void AdjustPalette(Dictionary<string, Palette> palettes)
public void AdjustPalette(IReadOnlyDictionary<string, MutablePalette> palettes)
{
if (to == EffectType.None && remainingFrames == 0)
return;
foreach (var pal in palettes)
foreach (var pal in palettes.Values)
{
for (var x = 0; x < 256; x++)
for (var x = 0; x < Palette.Size; x++)
{
var orig = pal.Value.GetColor(x);
var orig = pal.GetColor(x);
var t = ColorForEffect(to, orig);
if (remainingFrames == 0)
pal.Value.SetColor(x, t);
pal.SetColor(x, t);
else
{
var f = ColorForEffect(from, orig);
pal.Value.SetColor(x, Exts.ColorLerp((float)remainingFrames / Info.FadeLength, t, f));
pal.SetColor(x, Exts.ColorLerp((float)remainingFrames / Info.FadeLength, t, f));
}
}
}

View File

@@ -33,7 +33,7 @@ namespace OpenRA.Mods.RA
remainingFrames--;
}
public void AdjustPalette(Dictionary<string,Palette> palettes)
public void AdjustPalette(IReadOnlyDictionary<string, MutablePalette> palettes)
{
if (remainingFrames == 0)
return;
@@ -42,11 +42,11 @@ namespace OpenRA.Mods.RA
foreach (var pal in palettes)
{
for (var x = 0; x < 256; x++)
for (var x = 0; x < Palette.Size; x++)
{
var orig = pal.Value.GetColor(x);
var white = Color.FromArgb(orig.A, 255, 255, 255);
pal.Value.SetColor(x, Exts.ColorLerp(frac,orig,white));
pal.Value.SetColor(x, Exts.ColorLerp(frac, orig, white));
}
}
}

View File

@@ -26,7 +26,7 @@ namespace OpenRA.Mods.RA
public object Create(ActorInitializer init) { return new PaletteFromCurrentTileset(init.world, this); }
}
class PaletteFromCurrentTileset : IPalette
class PaletteFromCurrentTileset : ILoadsPalettes
{
readonly World world;
readonly PaletteFromCurrentTilesetInfo info;
@@ -37,9 +37,9 @@ namespace OpenRA.Mods.RA
this.info = info;
}
public void InitPalette(WorldRenderer wr)
public void LoadPalettes(WorldRenderer wr)
{
wr.AddPalette(info.Name, new Palette(GlobalFileSystem.Open(world.TileSet.Palette), info.ShadowIndex), info.AllowModifiers);
wr.AddPalette(info.Name, new ImmutablePalette(GlobalFileSystem.Open(world.TileSet.Palette), info.ShadowIndex), info.AllowModifiers);
}
}
}

View File

@@ -29,7 +29,7 @@ namespace OpenRA.Mods.RA
public object Create(ActorInitializer init) { return new PaletteFromFile(init.world, this); }
}
class PaletteFromFile : IPalette
class PaletteFromFile : ILoadsPalettes
{
readonly World world;
readonly PaletteFromFileInfo info;
@@ -39,10 +39,10 @@ namespace OpenRA.Mods.RA
this.info = info;
}
public void InitPalette(WorldRenderer wr)
public void LoadPalettes(WorldRenderer wr)
{
if (info.Tileset == null || info.Tileset.ToLowerInvariant() == world.Map.Tileset.ToLowerInvariant())
wr.AddPalette(info.Name, new Palette(GlobalFileSystem.Open(info.Filename), info.ShadowIndex), info.AllowModifiers);
wr.AddPalette(info.Name, new ImmutablePalette(GlobalFileSystem.Open(info.Filename), info.ShadowIndex), info.AllowModifiers);
}
public string Filename

View File

@@ -8,6 +8,7 @@
*/
#endregion
using System.Linq;
using OpenRA.Graphics;
using OpenRA.Traits;
@@ -33,7 +34,7 @@ namespace OpenRA.Mods.RA
public object Create(ActorInitializer init) { return new PaletteFromRGBA(init.world, this); }
}
class PaletteFromRGBA : IPalette
class PaletteFromRGBA : ILoadsPalettes
{
readonly World world;
readonly PaletteFromRGBAInfo info;
@@ -43,14 +44,14 @@ namespace OpenRA.Mods.RA
this.info = info;
}
public void InitPalette(WorldRenderer wr)
public void LoadPalettes(WorldRenderer wr)
{
// Enable palette only for a specific tileset
if (info.Tileset != null && info.Tileset.ToLowerInvariant() != world.Map.Tileset.ToLowerInvariant())
return;
var c = (uint)((info.A << 24) | (info.R << 16) | (info.G << 8) | info.B);
wr.AddPalette(info.Name, new Palette(Exts.MakeArray(256, i => (i == 0) ? 0 : c)), info.AllowModifiers);
wr.AddPalette(info.Name, new ImmutablePalette(Enumerable.Range(0, Palette.Size).Select(i => (i == 0) ? 0 : c)), info.AllowModifiers);
}
}
}

View File

@@ -26,7 +26,7 @@ namespace OpenRA.Mods.RA
public object Create(ActorInitializer init) { return new PlayerPaletteFromCurrentTileset(init.world, this); }
}
class PlayerPaletteFromCurrentTileset : IPalette
class PlayerPaletteFromCurrentTileset : ILoadsPalettes
{
readonly World world;
readonly PlayerPaletteFromCurrentTilesetInfo info;
@@ -37,10 +37,10 @@ namespace OpenRA.Mods.RA
this.info = info;
}
public void InitPalette(WorldRenderer wr)
public void LoadPalettes(WorldRenderer wr)
{
var filename = world.TileSet.PlayerPalette ?? world.TileSet.Palette;
wr.AddPalette(info.Name, new Palette(GlobalFileSystem.Open(filename), info.ShadowIndex), info.AllowModifiers);
wr.AddPalette(info.Name, new ImmutablePalette(GlobalFileSystem.Open(filename), info.ShadowIndex), info.AllowModifiers);
}
}
}

View File

@@ -9,6 +9,7 @@
#endregion
using System.Drawing;
using System.Linq;
using OpenRA.Graphics;
using OpenRA.Traits;
@@ -26,16 +27,16 @@ namespace OpenRA.Mods.RA
public object Create(ActorInitializer init) { return new ShroudPalette(this); }
}
class ShroudPalette : IPalette
class ShroudPalette : ILoadsPalettes
{
readonly ShroudPaletteInfo info;
public ShroudPalette(ShroudPaletteInfo info) { this.info = info; }
public void InitPalette(WorldRenderer wr)
public void LoadPalettes(WorldRenderer wr)
{
var c = info.Fog ? Fog : Shroud;
wr.AddPalette(info.Name, new Palette(Exts.MakeArray(256, i => (uint)c[i % 8].ToArgb())), false);
wr.AddPalette(info.Name, new ImmutablePalette(Enumerable.Range(0, Palette.Size).Select(i => (uint)c[i % 8].ToArgb())));
}
static Color[] Fog = new[] {

View File

@@ -22,7 +22,7 @@ namespace OpenRA.Mods.RA
public object Create(ActorInitializer init) { return new VoxelNormalsPalette(this); }
}
public class VoxelNormalsPalette : IPalette
public class VoxelNormalsPalette : ILoadsPalettes
{
readonly VoxelNormalsPaletteInfo info;
@@ -31,7 +31,7 @@ namespace OpenRA.Mods.RA
this.info = info;
}
public void InitPalette(WorldRenderer wr)
public void LoadPalettes(WorldRenderer wr)
{
// Rotate vectors to expected orientation
// Voxel coordinates are x=forward, y=right, z=up
@@ -40,7 +40,7 @@ namespace OpenRA.Mods.RA
// Map normals into color range
// Introduces a maximum error of ~0.5%
var data = new uint[256];
var data = new uint[Palette.Size];
for (var i = 0; i < n.Length / 3; i++)
{
data[i] = 0xFF000000;
@@ -51,7 +51,7 @@ namespace OpenRA.Mods.RA
}
}
wr.AddPalette(info.Name, new Palette(data), false);
wr.AddPalette(info.Name, new ImmutablePalette(data));
}
// Normal vector tables from http://www.sleipnirstuff.com/forum/viewtopic.php?t=8048

View File

@@ -18,7 +18,7 @@ namespace OpenRA.Mods.RA
[Desc("Palette effect used for sprinkle \"animations\" on terrain tiles.")]
class WaterPaletteRotationInfo : ITraitInfo
{
public readonly string[] ExcludePalettes = {};
public readonly string[] ExcludePalettes = { };
public object Create(ActorInitializer init) { return new WaterPaletteRotation(init.world, this); }
}
@@ -38,23 +38,26 @@ namespace OpenRA.Mods.RA
public void Tick(Actor self) { t += .25f; }
static uint[] temp = new uint[7]; /* allocating this on the fly actually hurts our profile */
uint[] temp = new uint[7]; /* allocating this on the fly actually hurts our profile */
public void AdjustPalette(Dictionary<string,Palette> palettes)
public void AdjustPalette(IReadOnlyDictionary<string, MutablePalette> palettes)
{
foreach (var pal in palettes)
var rotate = (int)t % 7;
if (rotate == 0)
return;
foreach (var kvp in palettes)
{
if (info.ExcludePalettes.Contains(pal.Key))
if (info.ExcludePalettes.Contains(kvp.Key))
continue;
var colors = pal.Value.Values;
var rotate = (int)t % 7;
var palette = kvp.Value;
for (var i = 0; i < 7; i++)
temp[(rotate + i) % 7] = colors[world.TileSet.WaterPaletteRotationBase + i];
temp[(rotate + i) % 7] = palette[world.TileSet.WaterPaletteRotationBase + i];
for (var i = 0; i < 7; i++)
pal.Value.SetColor(world.TileSet.WaterPaletteRotationBase + i, temp[i]);
palette[world.TileSet.WaterPaletteRotationBase + i] = temp[i];
}
}
}

View File

@@ -16,14 +16,14 @@ namespace OpenRA.Mods.RA.Widgets
{
public class ColorPreviewManagerWidget : Widget
{
public readonly string Palette = "colorpicker";
public readonly string PaletteName = "colorpicker";
public readonly int[] RemapIndices = ChromeMetrics.Get<int[]>("ColorPickerRemapIndices");
public readonly float Ramp = 0.05f;
public HSLColor Color;
HSLColor cachedColor;
WorldRenderer worldRenderer;
Palette preview;
IPalette preview;
[ObjectCreator.UseCtor]
public ColorPreviewManagerWidget(WorldRenderer worldRenderer)
@@ -34,17 +34,18 @@ namespace OpenRA.Mods.RA.Widgets
public override void Initialize(WidgetArgs args)
{
base.Initialize(args);
preview = worldRenderer.Palette(Palette).Palette;
preview = worldRenderer.Palette(PaletteName).Palette;
}
public override void Tick()
{
if (cachedColor == Color)
return;
preview.ApplyRemap(new PlayerColorRemap(RemapIndices, Color, Ramp));
cachedColor = Color;
var newPalette = new MutablePalette(preview);
newPalette.ApplyRemap(new PlayerColorRemap(RemapIndices, Color, Ramp));
worldRenderer.ReplacePalette(PaletteName, newPalette);
}
}
}

View File

@@ -95,7 +95,7 @@ namespace OpenRA.Mods.RA.Widgets.Logic
var colorDropdown = panel.GetOrNull<DropDownButtonWidget>("COLOR");
if (colorDropdown != null)
{
colorDropdown.IsDisabled = () => currentPalette != colorPreview.Palette;
colorDropdown.IsDisabled = () => currentPalette != colorPreview.PaletteName;
colorDropdown.OnMouseDown = _ => ShowColorDropDown(colorDropdown, colorPreview, world);
panel.Get<ColorBlockWidget>("COLORBLOCK").GetColor = () => Game.Settings.Player.Color.RGB;
}

View File

@@ -9,8 +9,7 @@
#endregion
using System;
using System.Drawing;
using OpenRA.FileFormats;
using System.Linq;
using OpenRA.Graphics;
using OpenRA.Traits;
@@ -25,13 +24,13 @@ namespace OpenRA.Mods.TS
public object Create(ActorInitializer init) { return new TSShroudPalette(this); }
}
class TSShroudPalette : IPalette
class TSShroudPalette : ILoadsPalettes
{
readonly TSShroudPaletteInfo info;
public TSShroudPalette(TSShroudPaletteInfo info) { this.info = info; }
public void InitPalette(WorldRenderer wr)
public void LoadPalettes(WorldRenderer wr)
{
Func<int, uint> makeColor = i =>
{
@@ -40,7 +39,7 @@ namespace OpenRA.Mods.TS
return 0;
};
wr.AddPalette(info.Name, new Palette(Exts.MakeArray(256, i => makeColor(i))), false);
wr.AddPalette(info.Name, new ImmutablePalette(Enumerable.Range(0, Palette.Size).Select(i => makeColor(i))));
}
}
}

View File

@@ -25,7 +25,7 @@ namespace OpenRA.TilesetBuilder
string srcfile;
int size;
public TerrainTypeInfo[] TerrainType;
public Palette TerrainPalette;
public ImmutablePalette TerrainPalette;
public bool PaletteFromImage = true;
public string PaletteFile = "";
public string ImageFile = "";
@@ -60,7 +60,7 @@ namespace OpenRA.TilesetBuilder
if (!PaletteFromImage)
{
TerrainPalette = Palette.Load(PaletteFile, shadowIndex);
TerrainPalette = new ImmutablePalette(PaletteFile, shadowIndex);
rbitmap.Palette = TerrainPalette.AsSystemPalette();
}
@@ -247,8 +247,8 @@ namespace OpenRA.TilesetBuilder
static string ExportPalette(List<Color> p, string file)
{
while (p.Count < 256) p.Add(Color.Black); // pad the palette out with extra blacks
var paletteData = p.Take(256).SelectMany(
while (p.Count < Palette.Size) p.Add(Color.Black); // pad the palette out with extra blacks
var paletteData = p.Take(Palette.Size).SelectMany(
c => new byte[] { (byte)(c.R >> 2), (byte)(c.G >> 2), (byte)(c.B >> 2) }).ToArray();
File.WriteAllBytes(file, paletteData);
return file;

View File

@@ -96,7 +96,7 @@ namespace OpenRA.Utility
shadowIndex[shadowIndex.Length - 3] = 4;
}
var palette = Palette.Load(args[2], shadowIndex);
var palette = new ImmutablePalette(args[2], shadowIndex);
ISpriteSource source;
using (var stream = File.OpenRead(src))
@@ -209,16 +209,14 @@ namespace OpenRA.Utility
= PlayerColorRemap.GetRemapIndex(destRemapIndex, i);
// map everything else to the best match based on channel-wise distance
var srcPalette = Palette.Load(args[1].Split(':')[1], shadowIndex);
var destPalette = Palette.Load(args[2].Split(':')[1], shadowIndex);
var srcPalette = new ImmutablePalette(args[1].Split(':')[1], shadowIndex);
var destPalette = new ImmutablePalette(args[2].Split(':')[1], shadowIndex);
var fullIndexRange = Exts.MakeArray<int>(256, x => x);
for (var i = 0; i < 256; i++)
for (var i = 0; i < Palette.Size; i++)
if (!remap.ContainsKey(i))
remap[i] = fullIndexRange
remap[i] = Enumerable.Range(0, Palette.Size)
.Where(a => !remap.ContainsValue(a))
.MinBy(a => ColorDistance(destPalette.Values[a], srcPalette.Values[i]));
.MinBy(a => ColorDistance(destPalette[a], srcPalette[i]));
var srcImage = ShpReader.Load(args[3]);

View File

@@ -3,6 +3,6 @@ uniform sampler2D DiffuseTexture, Palette;
void main()
{
vec4 x = texture2D(DiffuseTexture, gl_TexCoord[0].st);
vec2 p = vec2( dot(x, gl_TexCoord[1]), gl_TexCoord[0].p );
gl_FragColor = texture2D(Palette,p);
}
vec2 p = vec2(gl_TexCoord[0].p, dot(x, gl_TexCoord[1]));
gl_FragColor = texture2D(Palette, p);
}

View File

@@ -7,11 +7,11 @@ uniform vec3 AmbientLight, DiffuseLight;
void main()
{
vec4 x = texture2D(DiffuseTexture, gl_TexCoord[0].st);
vec4 color = texture2D(Palette, vec2(dot(x, gl_TexCoord[1]), PaletteRows.x));
vec4 color = texture2D(Palette, vec2(PaletteRows.x, dot(x, gl_TexCoord[1])));
if (color.a < 0.01)
discard;
vec4 normal = (2.0*texture2D(Palette, vec2(dot(x, gl_TexCoord[2]), PaletteRows.y)) - 1.0);
vec3 intensity = AmbientLight + DiffuseLight*max(dot(normal, LightDirection), 0.0);
gl_FragColor = vec4(intensity*color.rgb, color.a);
vec4 normal = (2.0 * texture2D(Palette, vec2(PaletteRows.y, dot(x, gl_TexCoord[2]))) - 1.0);
vec3 intensity = AmbientLight + DiffuseLight * max(dot(normal, LightDirection), 0.0);
gl_FragColor = vec4(intensity * color.rgb, color.a);
}