Revert color validator

This commit is contained in:
Gustas
2023-07-03 12:21:26 +03:00
committed by Matthias Mailänder
parent 4cd4e1f8ea
commit 9d8f0634b1
2 changed files with 27 additions and 31 deletions

View File

@@ -11,7 +11,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
using OpenRA.Graphics;
using OpenRA.Mods.Common.Widgets;
using OpenRA.Primitives;
@@ -41,7 +40,7 @@ namespace OpenRA.Mods.Common.Traits
public readonly float[] HsvValueRange = { 0.3f, 0.95f };
[Desc("Perceptual color threshold for determining whether two colors are too similar.")]
public readonly float SimilarityThreshold = 0.314f;
public readonly int SimilarityThreshold = 0x50;
[Desc("List of colors to be displayed in the palette tab.")]
public readonly Color[] PresetColors = Array.Empty<Color>();
@@ -55,7 +54,7 @@ namespace OpenRA.Mods.Common.Traits
"A dictionary of [faction name]: [actor name].")]
public readonly Dictionary<string, string> FactionPreviewActors = new();
public bool TryGetBlockingColor((float R, float G, float B) color, List<(float R, float G, float B)> candidateBlockers, out (float R, float G, float B) closestBlocker)
public bool TryGetBlockingColor(Color color, IEnumerable<Color> candidateBlockers, out Color closestBlocker)
{
var closestDistance = SimilarityThreshold;
closestBlocker = default;
@@ -63,16 +62,23 @@ namespace OpenRA.Mods.Common.Traits
foreach (var candidate in candidateBlockers)
{
// Uses the perceptually based color metric explained by https://www.compuphase.com/cmetric.htm
// Input colors are expected to be in the linear (non-gamma corrected) color space
var rmean = (color.R + candidate.R) / 2.0;
var r = color.R - candidate.R;
var g = color.G - candidate.G;
var b = color.B - candidate.B;
var weightR = 2.0 + rmean;
var weightG = 4.0;
var weightB = 3.0 - rmean;
// HACK: We provide gamma space colors to a linear space metric. This is not ideal, but
// it works much better in gamma space. In linear space the metric is too small for dark colors
// and too large for bright colors. By using gamma we shift the metric to be more uniform.
// This hack doesn't fully fix bright colors, i.e. it still allows for very similar pinks,
// greens and reports colors with slightly different saturations as significantly different.
// TODO: Replace with a model which has image hue remapping in mind.
var rmean = (color.R + candidate.R) >> 1;
var distance = (float)Math.Sqrt(weightR * r * r + weightG * g * g + weightB * b * b);
var rdelta = color.R - candidate.R;
var gdelta = color.G - candidate.G;
var bdelta = color.B - candidate.B;
var weightR = ((512 + rmean) * rdelta * rdelta) >> 8;
var weightG = 4 * gdelta * gdelta;
var weightB = ((767 - rmean) * bdelta * bdelta) >> 8;
var distance = (int)Math.Sqrt(weightR + weightG + weightB);
if (distance < closestDistance)
{
closestBlocker = candidate;
@@ -84,14 +90,6 @@ namespace OpenRA.Mods.Common.Traits
}
Color MakeValid(float hue, float sat, float val, MersenneTwister random, IEnumerable<Color> terrainColors, IEnumerable<Color> playerColors, Action<string> onError)
{
var terrainLinear = terrainColors.Select(c => c.ToLinear()).ToList();
var playerLinear = playerColors.Select(c => c.ToLinear()).ToList();
return MakeValid(hue, sat, val, random, terrainLinear, playerLinear, onError);
}
Color MakeValid(float hue, float sat, float val, MersenneTwister random, List<(float R, float G, float B)> terrainLinear, List<(float R, float G, float B)> playerLinear, Action<string> onError)
{
// Clamp saturation without triggering a warning
// This can only happen due to rounding errors (common) or modified clients (rare)
@@ -103,17 +101,17 @@ namespace OpenRA.Mods.Common.Traits
var stepSign = 0;
for (var i = 0; i < 101; i++)
{
var linear = Color.FromAhsv(hue, sat, val).ToLinear();
if (TryGetBlockingColor(linear, terrainLinear, out var blocker))
var color = Color.FromAhsv(hue, sat, val);
if (TryGetBlockingColor(color, terrainColors, out var blocker))
errorMessage = PlayerColorTerrain;
else if (TryGetBlockingColor(linear, playerLinear, out blocker))
else if (TryGetBlockingColor(color, playerColors, out blocker))
errorMessage = PlayerColorPlayer;
else
{
if (errorMessage != null)
onError?.Invoke(errorMessage);
return Color.FromAhsv(hue, sat, val);
return color;
}
// Pick a direction based on the first blocking color and step in hue
@@ -143,14 +141,10 @@ namespace OpenRA.Mods.Common.Traits
Color IColorPickerManagerInfo.RandomPresetColor(MersenneTwister random, IEnumerable<Color> terrainColors, IEnumerable<Color> playerColors)
{
var terrainLinear = terrainColors.Select(c => c.ToLinear()).ToList();
var playerLinear = playerColors.Select(c => c.ToLinear()).ToList();
foreach (var color in PresetColors.Shuffle(random))
{
// Color may already be taken
var linear = color.ToLinear();
if (!TryGetBlockingColor(linear, terrainLinear, out _) && !TryGetBlockingColor(linear, playerLinear, out _))
if (!TryGetBlockingColor(color, terrainColors, out _) && !TryGetBlockingColor(color, playerColors, out _))
return color;
}
@@ -158,7 +152,7 @@ namespace OpenRA.Mods.Common.Traits
var randomHue = random.NextFloat();
var randomSat = float2.Lerp(HsvSaturationRange[0], HsvSaturationRange[1], random.NextFloat());
var randomVal = float2.Lerp(HsvValueRange[0], HsvValueRange[1], random.NextFloat());
return MakeValid(randomHue, randomSat, randomVal, random, terrainLinear, playerLinear, null);
return MakeValid(randomHue, randomSat, randomVal, random, terrainColors, playerColors, null);
}
Color IColorPickerManagerInfo.MakeValid(Color color, MersenneTwister random, IEnumerable<Color> terrainColors, IEnumerable<Color> playerColors, Action<string> onError)

View File

@@ -19,7 +19,7 @@ namespace OpenRA.Mods.Common.UpdateRules.Rules
public override string Name => "ColorPickerManager's PresetHues, PresetSaturations and V were replaced with PresetColors.";
public override string Description =>
"Each preset color can now have their brightness specified.";
"Each preset color can now have their brightness specified. SimilarityThreshold range was changed.";
public override IEnumerable<string> UpdateActorNode(ModData modData, MiniYamlNode actorNode)
{
@@ -27,6 +27,8 @@ namespace OpenRA.Mods.Common.UpdateRules.Rules
if (manager == null)
yield break;
manager.RemoveNodes("SimilarityThreshold");
var v = manager.LastChildMatching("V")?.NodeValue<float>() ?? 0.95f;
var hues = manager.LastChildMatching("PresetHues")?.NodeValue<float[]>();
var saturations = manager.LastChildMatching("PresetSaturations")?.NodeValue<float[]>();