Merge pull request #7291 from RoosterDragon/dynamic-palette-sizing

Implement dynamic hardware palette sizing.
This commit is contained in:
Paul Chote
2015-01-13 17:41:15 +13:00
7 changed files with 42 additions and 32 deletions

View File

@@ -16,14 +16,13 @@ namespace OpenRA.Graphics
{ {
public sealed class HardwarePalette : IDisposable public sealed class HardwarePalette : IDisposable
{ {
public const int MaxPalettes = 256;
public ITexture Texture { get; private set; } public ITexture Texture { get; private set; }
public int Height { get; private set; }
readonly Dictionary<string, ImmutablePalette> palettes = new Dictionary<string, ImmutablePalette>(); readonly Dictionary<string, ImmutablePalette> palettes = new Dictionary<string, ImmutablePalette>();
readonly Dictionary<string, MutablePalette> modifiablePalettes = new Dictionary<string, MutablePalette>(); readonly Dictionary<string, MutablePalette> modifiablePalettes = new Dictionary<string, MutablePalette>();
readonly IReadOnlyDictionary<string, MutablePalette> readOnlyModifiablePalettes; readonly IReadOnlyDictionary<string, MutablePalette> readOnlyModifiablePalettes;
readonly Dictionary<string, int> indices = new Dictionary<string, int>(); readonly Dictionary<string, int> indices = new Dictionary<string, int>();
readonly uint[,] buffer = new uint[MaxPalettes, Palette.Size]; byte[] buffer = new byte[0];
public HardwarePalette() public HardwarePalette()
{ {
@@ -52,14 +51,19 @@ namespace OpenRA.Graphics
public void AddPalette(string name, ImmutablePalette 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)) if (palettes.ContainsKey(name))
throw new InvalidOperationException("Palette {0} has already been defined".F(name)); throw new InvalidOperationException("Palette {0} has already been defined".F(name));
int index = palettes.Count; int index = palettes.Count;
indices.Add(name, index); indices.Add(name, index);
palettes.Add(name, p); palettes.Add(name, p);
if (palettes.Count > Height)
{
Height = Exts.NextPowerOf2(palettes.Count);
Array.Resize(ref buffer, Height * Palette.Size * 4);
}
if (allowModifiers) if (allowModifiers)
modifiablePalettes.Add(name, new MutablePalette(p)); modifiablePalettes.Add(name, new MutablePalette(p));
else else
@@ -74,13 +78,13 @@ namespace OpenRA.Graphics
CopyPaletteToBuffer(indices[name], palettes[name] = new ImmutablePalette(p)); CopyPaletteToBuffer(indices[name], palettes[name] = new ImmutablePalette(p));
else else
throw new InvalidOperationException("Palette `{0}` does not exist".F(name)); throw new InvalidOperationException("Palette `{0}` does not exist".F(name));
Texture.SetData(buffer); CopyBufferToTexture();
} }
public void Initialize() public void Initialize()
{ {
CopyModifiablePalettesToBuffer(); CopyModifiablePalettesToBuffer();
Texture.SetData(buffer); CopyBufferToTexture();
} }
void CopyPaletteToBuffer(int index, IPalette p) void CopyPaletteToBuffer(int index, IPalette p)
@@ -94,6 +98,11 @@ namespace OpenRA.Graphics
CopyPaletteToBuffer(indices[kvp.Key], kvp.Value); CopyPaletteToBuffer(indices[kvp.Key], kvp.Value);
} }
void CopyBufferToTexture()
{
Texture.SetData(buffer, Palette.Size, Height);
}
public void ApplyModifiers(IEnumerable<IPaletteModifier> paletteMods) public void ApplyModifiers(IEnumerable<IPaletteModifier> paletteMods)
{ {
foreach (var mod in paletteMods) foreach (var mod in paletteMods)
@@ -101,7 +110,7 @@ namespace OpenRA.Graphics
// Update our texture with the changes. // Update our texture with the changes.
CopyModifiablePalettesToBuffer(); CopyModifiablePalettesToBuffer();
Texture.SetData(buffer); CopyBufferToTexture();
// Reset modified palettes back to their original colors, ready for next time. // Reset modified palettes back to their original colors, ready for next time.
foreach (var kvp in modifiablePalettes) foreach (var kvp in modifiablePalettes)

View File

@@ -57,7 +57,7 @@ namespace OpenRA.Graphics
PaletteReference CreatePaletteReference(string name) PaletteReference CreatePaletteReference(string name)
{ {
var pal = palette.GetPalette(name); var pal = palette.GetPalette(name);
return new PaletteReference(name, palette.GetPaletteIndex(name), pal); return new PaletteReference(name, palette.GetPaletteIndex(name), pal, palette);
} }
string cursorName; string cursorName;

View File

@@ -51,15 +51,15 @@ namespace OpenRA.Graphics
public void DrawSprite(Sprite s, float2 location, PaletteReference pal) public void DrawSprite(Sprite s, float2 location, PaletteReference pal)
{ {
DrawSprite(s, location, pal.Index, s.Size); DrawSprite(s, location, pal.TextureIndex, s.Size);
} }
public void DrawSprite(Sprite s, float2 location, PaletteReference pal, float2 size) public void DrawSprite(Sprite s, float2 location, PaletteReference pal, float2 size)
{ {
DrawSprite(s, location, pal.Index, size); DrawSprite(s, location, pal.TextureIndex, size);
} }
void DrawSprite(Sprite s, float2 location, int paletteIndex, float2 size) void DrawSprite(Sprite s, float2 location, float paletteTextureIndex, float2 size)
{ {
renderer.CurrentBatchRenderer = this; renderer.CurrentBatchRenderer = this;
@@ -74,7 +74,7 @@ namespace OpenRA.Graphics
currentBlend = s.BlendMode; currentBlend = s.BlendMode;
currentSheet = s.Sheet; currentSheet = s.Sheet;
Util.FastCreateQuad(vertices, location + s.FractionalOffset * size, s, paletteIndex, nv, size); Util.FastCreateQuad(vertices, location + s.FractionalOffset * size, s, paletteTextureIndex, nv, size);
nv += 4; nv += 4;
} }

View File

@@ -24,7 +24,7 @@ namespace OpenRA.Graphics
this.world = world; this.world = world;
this.map = world.Map; this.map = world.Map;
var terrainPalette = wr.Palette("terrain").Index; var terrainPalette = wr.Palette("terrain").TextureIndex;
var vertices = new Vertex[4 * map.Bounds.Height * map.Bounds.Width]; var vertices = new Vertex[4 * map.Bounds.Height * map.Bounds.Width];
var nv = 0; var nv = 0;

View File

@@ -21,23 +21,22 @@ namespace OpenRA.Graphics
static readonly int[] ChannelMasks = { 2, 1, 0, 3 }; static readonly int[] ChannelMasks = { 2, 1, 0, 3 };
static readonly float[] ChannelSelect = { 0.75f, 0.25f, -0.25f, -0.75f }; static readonly float[] ChannelSelect = { 0.75f, 0.25f, -0.25f, -0.75f };
public static void FastCreateQuad(Vertex[] vertices, float2 o, Sprite r, int palette, int nv, float2 size) public static void FastCreateQuad(Vertex[] vertices, float2 o, Sprite r, float paletteTextureIndex, int nv, float2 size)
{ {
var b = new float2(o.X + size.X, o.Y); var b = new float2(o.X + size.X, o.Y);
var c = new float2(o.X + size.X, o.Y + size.Y); var c = new float2(o.X + size.X, o.Y + size.Y);
var d = new float2(o.X, o.Y + size.Y); var d = new float2(o.X, o.Y + size.Y);
FastCreateQuad(vertices, o, b, c, d, r, palette, nv); FastCreateQuad(vertices, o, b, c, d, r, paletteTextureIndex, nv);
} }
public static void FastCreateQuad(Vertex[] vertices, float2 a, float2 b, float2 c, float2 d, Sprite r, int palette, int nv) public static void FastCreateQuad(Vertex[] vertices, float2 a, float2 b, float2 c, float2 d, Sprite r, float paletteTextureIndex, int nv)
{ {
var attribP = palette / (float)HardwarePalette.MaxPalettes;
var attribC = ChannelSelect[(int)r.Channel]; var attribC = ChannelSelect[(int)r.Channel];
vertices[nv] = new Vertex(a, r.Left, r.Top, attribP, attribC); vertices[nv] = new Vertex(a, r.Left, r.Top, paletteTextureIndex, attribC);
vertices[nv + 1] = new Vertex(b, r.Right, r.Top, attribP, attribC); vertices[nv + 1] = new Vertex(b, r.Right, r.Top, paletteTextureIndex, attribC);
vertices[nv + 2] = new Vertex(c, r.Right, r.Bottom, attribP, attribC); vertices[nv + 2] = new Vertex(c, r.Right, r.Bottom, paletteTextureIndex, attribC);
vertices[nv + 3] = new Vertex(d, r.Left, r.Bottom, attribP, attribC); vertices[nv + 3] = new Vertex(d, r.Left, r.Bottom, paletteTextureIndex, attribC);
} }
public static void FastCopyIntoChannel(Sprite dest, byte[] src) { FastCopyIntoChannel(dest, 0, src); } public static void FastCopyIntoChannel(Sprite dest, byte[] src) { FastCopyIntoChannel(dest, 0, src); }

View File

@@ -203,11 +203,11 @@ namespace OpenRA.Graphics
var lightDirection = ExtractRotationVector(Util.MatrixMultiply(Util.MatrixInverse(t), lightTransform)); var lightDirection = ExtractRotationVector(Util.MatrixMultiply(Util.MatrixInverse(t), lightTransform));
Render(rd, Util.MatrixMultiply(transform, t), lightDirection, Render(rd, Util.MatrixMultiply(transform, t), lightDirection,
lightAmbientColor, lightDiffuseColor, color.Index, normals.Index); lightAmbientColor, lightDiffuseColor, color.TextureMidIndex, normals.TextureMidIndex);
// Disable shadow normals by forcing zero diffuse and identity ambient light // Disable shadow normals by forcing zero diffuse and identity ambient light
Render(rd, Util.MatrixMultiply(shadow, t), lightDirection, Render(rd, Util.MatrixMultiply(shadow, t), lightDirection,
ShadowAmbient, ShadowDiffuse, shadowPalette.Index, normals.Index); ShadowAmbient, ShadowDiffuse, shadowPalette.TextureMidIndex, normals.TextureMidIndex);
} }
} }
})); }));
@@ -254,12 +254,10 @@ namespace OpenRA.Graphics
VoxelRenderData renderData, VoxelRenderData renderData,
float[] t, float[] lightDirection, float[] t, float[] lightDirection,
float[] ambientLight, float[] diffuseLight, float[] ambientLight, float[] diffuseLight,
int colorPalette, int normalsPalette) float colorPaletteTextureMidIndex, float normalsPaletteTextureMidIndex)
{ {
shader.SetTexture("DiffuseTexture", renderData.Sheet.GetTexture()); shader.SetTexture("DiffuseTexture", renderData.Sheet.GetTexture());
shader.SetVec("PaletteRows", shader.SetVec("PaletteRows", colorPaletteTextureMidIndex, normalsPaletteTextureMidIndex);
(colorPalette + 0.5f) / HardwarePalette.MaxPalettes,
(normalsPalette + 0.5f) / HardwarePalette.MaxPalettes);
shader.SetMatrix("TransformMatrix", t); shader.SetMatrix("TransformMatrix", t);
shader.SetVec("LightDirection", lightDirection, 4); shader.SetVec("LightDirection", lightDirection, 4);
shader.SetVec("AmbientLight", ambientLight, 3); shader.SetVec("AmbientLight", ambientLight, 3);

View File

@@ -19,13 +19,17 @@ namespace OpenRA.Graphics
public class PaletteReference public class PaletteReference
{ {
public readonly string Name; public readonly string Name;
public readonly int Index;
public IPalette Palette { get; internal set; } public IPalette Palette { get; internal set; }
public PaletteReference(string name, int index, IPalette palette) readonly float index;
readonly HardwarePalette hardwarePalette;
public float TextureIndex { get { return index / hardwarePalette.Height; } }
public float TextureMidIndex { get { return (index + 0.5f) / hardwarePalette.Height; } }
public PaletteReference(string name, int index, IPalette palette, HardwarePalette hardwarePalette)
{ {
Name = name; Name = name;
Index = index;
Palette = palette; Palette = palette;
this.index = index;
this.hardwarePalette = hardwarePalette;
} }
} }
@@ -62,7 +66,7 @@ namespace OpenRA.Graphics
PaletteReference CreatePaletteReference(string name) PaletteReference CreatePaletteReference(string name)
{ {
var pal = palette.GetPalette(name); var pal = palette.GetPalette(name);
return new PaletteReference(name, palette.GetPaletteIndex(name), pal); return new PaletteReference(name, palette.GetPaletteIndex(name), pal, palette);
} }
public PaletteReference Palette(string name) { return palettes.GetOrAdd(name, CreatePaletteReference); } public PaletteReference Palette(string name) { return palettes.GetOrAdd(name, CreatePaletteReference); }