Preserve original brightness when remapping player colors.
This commit is contained in:
@@ -18,43 +18,34 @@ namespace OpenRA.Graphics
|
||||
{
|
||||
public class PlayerColorRemap : IPaletteRemap
|
||||
{
|
||||
Dictionary<int, Color> remapColors;
|
||||
readonly int[] remapIndices;
|
||||
readonly float hue;
|
||||
readonly float saturation;
|
||||
|
||||
public static int GetRemapIndex(int[] ramp, int i)
|
||||
public PlayerColorRemap(int[] remapIndices, float hue, float saturation)
|
||||
{
|
||||
return ramp[i];
|
||||
}
|
||||
|
||||
public PlayerColorRemap(int[] ramp, Color c, float rampFraction)
|
||||
{
|
||||
var h = c.GetHue() / 360.0f;
|
||||
var s = c.GetSaturation();
|
||||
var l = c.GetBrightness();
|
||||
|
||||
// Increase luminosity if required to represent the full ramp
|
||||
var rampRange = (byte)((1 - rampFraction) * l);
|
||||
var c1 = Color.FromAhsl(h, s, Math.Max(rampRange, l));
|
||||
var c2 = Color.FromAhsl(h, s, (byte)Math.Max(0, l - rampRange));
|
||||
var baseIndex = ramp[0];
|
||||
var remapRamp = ramp.Select(r => r - ramp[0]);
|
||||
var rampMaxIndex = ramp.Length - 1;
|
||||
|
||||
// reversed remapping
|
||||
if (ramp[0] > ramp[rampMaxIndex])
|
||||
{
|
||||
baseIndex = ramp[rampMaxIndex];
|
||||
for (var i = rampMaxIndex; i > 0; i--)
|
||||
remapRamp = ramp.Select(r => r - ramp[rampMaxIndex]);
|
||||
}
|
||||
|
||||
remapColors = remapRamp.Select((x, i) => (baseIndex + i, Exts.ColorLerp(x / (float)ramp.Length, c1, c2)))
|
||||
.ToDictionary(u => u.Item1, u => u.Item2);
|
||||
this.remapIndices = remapIndices;
|
||||
this.hue = hue;
|
||||
this.saturation = saturation;
|
||||
}
|
||||
|
||||
public Color GetRemappedColor(Color original, int index)
|
||||
{
|
||||
return remapColors.TryGetValue(index, out var c)
|
||||
? c : original;
|
||||
if (!remapIndices.Contains(index))
|
||||
return original;
|
||||
|
||||
// Color remapping is applied in a linear color space, so start
|
||||
// by undoing the pre-multiplied alpha and gamma corrections
|
||||
var (r, g, b) = original.ToLinear();
|
||||
|
||||
// Calculate the brightness (i.e HSV value) of the original colour
|
||||
var value = Math.Max(Math.Max(r, g), b);
|
||||
|
||||
// Construct the new RGB color
|
||||
(r, g, b) = Color.HsvToRgb(hue, saturation, value);
|
||||
|
||||
// Convert linear back to SRGB and pre-multiply by the alpha
|
||||
return Color.FromLinear(original.A, r, g, b);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,9 +29,6 @@ namespace OpenRA.Traits
|
||||
[Desc("Remap these indices to player colors.")]
|
||||
public readonly int[] RemapIndex = { };
|
||||
|
||||
[Desc("Luminosity range to span.")]
|
||||
public readonly float Ramp = 0.05f;
|
||||
|
||||
[Desc("Allow palette modifiers to change the palette.")]
|
||||
public readonly bool AllowModifiers = true;
|
||||
|
||||
@@ -49,7 +46,9 @@ namespace OpenRA.Traits
|
||||
|
||||
public void LoadPlayerPalettes(WorldRenderer wr, string playerName, Color color, bool replaceExisting)
|
||||
{
|
||||
var remap = new PlayerColorRemap(info.RemapIndex, color, info.Ramp);
|
||||
color.ToAhsv(out _, out var h, out var s, out _);
|
||||
|
||||
var remap = new PlayerColorRemap(info.RemapIndex, h, s);
|
||||
var pal = new ImmutablePalette(wr.Palette(info.BasePalette).Palette, remap);
|
||||
wr.AddPalette(info.BaseName + playerName, pal, info.AllowModifiers, replaceExisting);
|
||||
}
|
||||
|
||||
@@ -31,9 +31,6 @@ namespace OpenRA.Traits
|
||||
[Desc("The fixed color to remap.")]
|
||||
public readonly Color Color;
|
||||
|
||||
[Desc("Luminosity range to span.")]
|
||||
public readonly float Ramp = 0.05f;
|
||||
|
||||
[Desc("Allow palette modifiers to change the palette.")]
|
||||
public readonly bool AllowModifiers = true;
|
||||
|
||||
@@ -51,7 +48,9 @@ namespace OpenRA.Traits
|
||||
|
||||
public void LoadPalettes(WorldRenderer wr)
|
||||
{
|
||||
var remap = new PlayerColorRemap(info.RemapIndex, info.Color, info.Ramp);
|
||||
info.Color.ToAhsv(out _, out var h, out var s, out _);
|
||||
|
||||
var remap = new PlayerColorRemap(info.RemapIndex, h, s);
|
||||
wr.AddPalette(info.Name, new ImmutablePalette(wr.Palette(info.Base).Palette, remap), info.AllowModifiers);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,8 +54,7 @@ namespace OpenRA.Mods.Cnc.UtilityCommands
|
||||
|
||||
// the remap range is always 16 entries, but their location and order changes
|
||||
for (var i = 0; i < 16; i++)
|
||||
remap[PlayerColorRemap.GetRemapIndex(srcRemapIndex, i)]
|
||||
= PlayerColorRemap.GetRemapIndex(destRemapIndex, i);
|
||||
remap[srcRemapIndex[i]] = destRemapIndex[i];
|
||||
|
||||
// map everything else to the best match based on channel-wise distance
|
||||
var srcPalette = new ImmutablePalette(args[1].Split(':')[1], new[] { 0 }, shadowIndex);
|
||||
|
||||
@@ -40,16 +40,19 @@ namespace OpenRA.Mods.Common.Traits
|
||||
"A dictionary of [faction name]: [actor name].")]
|
||||
public readonly Dictionary<string, string> FactionPreviewActors = new Dictionary<string, string>();
|
||||
|
||||
[Desc("Remap these indices to player colors.")]
|
||||
public readonly int[] RemapIndices = { };
|
||||
public readonly float Ramp = 0.05f;
|
||||
|
||||
public Color Color { get; private set; }
|
||||
|
||||
public void Update(WorldRenderer worldRenderer, Color color)
|
||||
{
|
||||
Color = color;
|
||||
|
||||
Color.ToAhsv(out _, out var h, out var s, out _);
|
||||
|
||||
var newPalette = new MutablePalette(worldRenderer.Palette(PaletteName).Palette);
|
||||
newPalette.ApplyRemap(new PlayerColorRemap(RemapIndices, Color, Ramp));
|
||||
newPalette.ApplyRemap(new PlayerColorRemap(RemapIndices, h, s));
|
||||
worldRenderer.ReplacePalette(PaletteName, newPalette);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user