Files
OpenRA/OpenRA.Game/Graphics/HardwarePalette.cs
RoosterDragon 53f06ba093 Implement dynamic hardware palette sizing.
The HardwarePalette will now grow its palette buffer and texture in power-of-2 increments. This avoids it having to allocate memory for a full 256x256 texture up front. In practice the default mods use 22 or 23 palettes so a 32x256 texture is used. This means both the buffer and texture save neatly on memory. Additionally, HardwarePalette.ApplyModifiers sees a nice speedup as it has to transfer a much smaller amount of memory from the buffer to the texture.

To facilitate this change, the MaxPalettes constant is no more. Instead the PaletteReference deals with the calculation of the index and this is passed into the appropriate methods.
2015-01-07 22:41:51 +00:00

130 lines
3.7 KiB
C#

#region Copyright & License Information
/*
* 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,
* see COPYING.
*/
#endregion
using System;
using System.Collections.Generic;
using OpenRA.Traits;
namespace OpenRA.Graphics
{
public sealed class HardwarePalette : IDisposable
{
public ITexture Texture { get; private set; }
public int Height { get; private set; }
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>();
byte[] buffer = new byte[0];
public HardwarePalette()
{
Texture = Game.Renderer.Device.CreateTexture();
readOnlyModifiablePalettes = modifiablePalettes.AsReadOnly();
}
public IPalette GetPalette(string name)
{
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))
throw new InvalidOperationException("Palette `{0}` does not exist".F(name));
return ret;
}
public void AddPalette(string name, ImmutablePalette p, bool allowModifiers)
{
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);
if (palettes.Count > Height)
{
Height = Exts.NextPowerOf2(palettes.Count);
Array.Resize(ref buffer, Height * Palette.Size * 4);
}
if (allowModifiers)
modifiablePalettes.Add(name, new MutablePalette(p));
else
CopyPaletteToBuffer(index, p);
}
public void ReplacePalette(string name, IPalette p)
{
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));
CopyBufferToTexture();
}
public void Initialize()
{
CopyModifiablePalettesToBuffer();
CopyBufferToTexture();
}
void CopyPaletteToBuffer(int index, IPalette p)
{
p.CopyToArray(buffer, index * Palette.Size);
}
void CopyModifiablePalettesToBuffer()
{
foreach (var kvp in modifiablePalettes)
CopyPaletteToBuffer(indices[kvp.Key], kvp.Value);
}
void CopyBufferToTexture()
{
Texture.SetData(buffer, Palette.Size, Height);
}
public void ApplyModifiers(IEnumerable<IPaletteModifier> paletteMods)
{
foreach (var mod in paletteMods)
mod.AdjustPalette(readOnlyModifiablePalettes);
// Update our texture with the changes.
CopyModifiablePalettesToBuffer();
CopyBufferToTexture();
// 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;
modifiedPalette.SetFromPalette(originalPalette);
}
}
public void Dispose()
{
Texture.Dispose();
}
}
}