diff --git a/Robust.Shared.Maths/Color.cs b/Robust.Shared.Maths/Color.cs
index 7174b7e1896..097fcf468a5 100644
--- a/Robust.Shared.Maths/Color.cs
+++ b/Robust.Shared.Maths/Color.cs
@@ -161,19 +161,36 @@ public readonly int ToArgb()
/// A new Color structure containing the converted components.
public static implicit operator Color(System.Drawing.Color color)
{
- return new(color.R, color.G, color.B, color.A);
+ return new Color(color.R, color.G, color.B, color.A);
}
+ ///
+ /// Converts the specified RGBA float tuple into a Color instance.
+ ///
+ /// The tuple to convert.
+ /// The converted Color instance with the tuple's values.
public static implicit operator Color((float r, float g, float b, float a) tuple)
{
- return new(tuple.r, tuple.g, tuple.b, tuple.a);
+ return new Color(tuple.r, tuple.g, tuple.b, tuple.a);
}
+ ///
+ /// Converts the specified RGB float tuple into a Color instance.
+ ///
+ /// The tuple to convert.
+ /// The converted Color instance with the tuple's values.
public static implicit operator Color((float r, float g, float b) tuple)
{
- return new(tuple.r, tuple.g, tuple.b);
+ return new Color(tuple.r, tuple.g, tuple.b);
}
+ ///
+ /// Deconstructs a Color instance into its float RGBA parts.
+ ///
+ /// The Color instance's red value.
+ /// The Color instance's green value.
+ /// The Color instance's blue value.
+ /// The Color instance's alpha value.
public readonly void Deconstruct(out float r, out float g, out float b, out float a)
{
r = R;
@@ -182,6 +199,12 @@ public readonly void Deconstruct(out float r, out float g, out float b, out floa
a = A;
}
+ ///
+ /// Deconstructs a Color instance into its float RGB parts.
+ ///
+ /// The Color instance's red value.
+ /// The Color instance's green value.
+ /// The Color instance's blue value.
public readonly void Deconstruct(out float r, out float g, out float b)
{
r = R;
@@ -203,16 +226,32 @@ public static explicit operator System.Drawing.Color(Color color)
(int) (color.B * byte.MaxValue));
}
- public static Color FromName(string colorname)
+ ///
+ /// Indexes the instance and returns the value.
+ ///
+ /// The key to index the instance with.
+ /// The Color instance returned from indexing the dictionary.
+ public static Color FromName(string colorName)
{
- return DefaultColors[colorname.ToLower()];
+ return DefaultColors[colorName.ToLower()];
}
+ ///
+ /// Tries to output a specific Color instance from the dictionary
+ /// based on a colorName key.
+ ///
+ /// The key to index the with.
+ /// The Color instance value that was associated with the colorName key, if any.
+ /// Whether a Color instance was successfully found with the key.
public static bool TryFromName(string colorName, out Color color)
{
return DefaultColors.TryGetValue(colorName.ToLower(), out color);
}
+ ///
+ /// Gets the dictionary with all color names and their associated values.
+ ///
+ /// The dictionary.
public static IEnumerable> GetAllDefaultColors()
{
return DefaultColors;
@@ -249,11 +288,14 @@ public readonly override string ToString()
return $"{{(R, G, B, A) = ({R}, {G}, {B}, {A})}}";
}
+ ///
+ /// Does not do anything different to ToString().
public readonly string ToString(string? format, IFormatProvider? formatProvider)
{
return ToString();
}
+
public readonly bool TryFormat(
Span destination,
out int charsWritten,
@@ -266,44 +308,84 @@ public readonly bool TryFormat(
$"{{(R, G, B, A) = ({R}, {G}, {B}, {A})}}");
}
+ ///
+ /// Creates a new Color instance with the provided red value.
+ ///
+ /// The new red value to give the Color instance.
+ /// A new Color instance with the provided red value.
public readonly Color WithRed(float newR)
{
- return new(newR, G, B, A);
+ return new Color(newR, G, B, A);
}
+ ///
+ /// Creates a new Color instance with the provided green value.
+ ///
+ /// The new green value to give the Color instance.
+ /// A new Color instance with the provided green value.
public readonly Color WithGreen(float newG)
{
- return new(R, newG, B, A);
+ return new Color(R, newG, B, A);
}
+ ///
+ /// Creates a new Color instance with the provided blue value.
+ ///
+ /// The new blue value to give the Color instance.
+ /// A new Color instance with the provided blue value.
public readonly Color WithBlue(float newB)
{
- return new(R, G, newB, A);
+ return new Color(R, G, newB, A);
}
+ ///
+ /// Creates a new Color instance with the provided alpha value.
+ ///
+ /// The new alpha value to give the Color instance.
+ /// A new Color instance with the provided alpha value.
public readonly Color WithAlpha(float newA)
{
- return new(R, G, B, newA);
+ return new Color(R, G, B, newA);
}
+ ///
+ /// Creates a new Color instance with a new byte-based red value.
+ ///
+ /// The byte to convert into the new red value.
+ /// A new Color instance with the provided red value.
public readonly Color WithRed(byte newR)
{
- return new((float) newR / byte.MaxValue, G, B, A);
+ return new Color((float) newR / byte.MaxValue, G, B, A);
}
+ ///
+ /// Creates a new Color instance with a new byte-based green value.
+ ///
+ /// The byte to convert into the new green value.
+ /// A new Color instance with the provided green value.
public readonly Color WithGreen(byte newG)
{
- return new(R, (float) newG / byte.MaxValue, B, A);
+ return new Color(R, (float) newG / byte.MaxValue, B, A);
}
+ ///
+ /// Creates a new Color instance with a new byte-based blue value.
+ ///
+ /// The byte to convert into the new blue value.
+ /// A new Color instance with the provided blue value.
public readonly Color WithBlue(byte newB)
{
- return new(R, G, (float) newB / byte.MaxValue, A);
+ return new Color(R, G, (float) newB / byte.MaxValue, A);
}
+ ///
+ /// Creates a new Color instance with a new byte-based alpha value.
+ ///
+ /// The byte to convert into the new alpha value.
+ /// A new Color instance with the provided alpha value.
public readonly Color WithAlpha(byte newA)
{
- return new(R, G, B, (float) newA / byte.MaxValue);
+ return new Color(R, G, B, (float) newA / byte.MaxValue);
}
///
@@ -342,27 +424,27 @@ public static Color FromSrgb(Color srgb)
///
/// Returns the converted color value.
///
- /// Color value to convert.
- public static Color ToSrgb(Color rgb)
+ /// Color value to convert.
+ public static Color ToSrgb(Color color)
{
float r, g, b;
- if (rgb.R <= 0.0031308)
- r = 12.92f * rgb.R;
+ if (color.R <= 0.0031308)
+ r = 12.92f * color.R;
else
- r = (1.0f + 0.055f) * MathF.Pow(rgb.R, 1.0f / 2.4f) - 0.055f;
+ r = (1.0f + 0.055f) * MathF.Pow(color.R, 1.0f / 2.4f) - 0.055f;
- if (rgb.G <= 0.0031308)
- g = 12.92f * rgb.G;
+ if (color.G <= 0.0031308)
+ g = 12.92f * color.G;
else
- g = (1.0f + 0.055f) * MathF.Pow(rgb.G, 1.0f / 2.4f) - 0.055f;
+ g = (1.0f + 0.055f) * MathF.Pow(color.G, 1.0f / 2.4f) - 0.055f;
- if (rgb.B <= 0.0031308)
- b = 12.92f * rgb.B;
+ if (color.B <= 0.0031308)
+ b = 12.92f * color.B;
else
- b = (1.0f + 0.055f) * MathF.Pow(rgb.B, 1.0f / 2.4f) - 0.055f;
+ b = (1.0f + 0.055f) * MathF.Pow(color.B, 1.0f / 2.4f) - 0.055f;
- return new Color(r, g, b, rgb.A);
+ return new Color(r, g, b, color.A);
}
///
@@ -445,23 +527,23 @@ public static Color FromHsl(Vector4 hsl)
/// Alpha (a copy of the input's Alpha value).
/// Each has a range of 0.0 to 1.0.
///
- /// Color value to convert.
+ /// Color value to convert.
[SuppressMessage("ReSharper", "CompareOfFloatsByEqualityOperator")]
- public static Vector4 ToHsl(Color rgb)
+ public static Vector4 ToHsl(Color color)
{
- var max = MathF.Max(rgb.R, MathF.Max(rgb.G, rgb.B));
- var min = MathF.Min(rgb.R, MathF.Min(rgb.G, rgb.B));
+ var max = MathF.Max(color.R, MathF.Max(color.G, color.B));
+ var min = MathF.Min(color.R, MathF.Min(color.G, color.B));
var c = max - min;
var h = 0.0f;
if (c != 0)
{
- if (max == rgb.R)
- h = (rgb.G - rgb.B) / c;
- else if (max == rgb.G)
- h = (rgb.B - rgb.R) / c + 2.0f;
- else if (max == rgb.B)
- h = (rgb.R - rgb.G) / c + 4.0f;
+ if (max == color.R)
+ h = (color.G - color.B) / c;
+ else if (max == color.G)
+ h = (color.B - color.R) / c + 2.0f;
+ else if (max == color.B)
+ h = (color.R - color.G) / c + 4.0f;
}
var hue = h / 6.0f;
@@ -474,7 +556,7 @@ public static Vector4 ToHsl(Color rgb)
if (0.0f != lightness && lightness != 1.0f)
saturation = c / (1.0f - MathF.Abs(2.0f * lightness - 1.0f));
- return new Vector4(hue, saturation, lightness, rgb.A);
+ return new Vector4(hue, saturation, lightness, color.A);
}
///
@@ -559,25 +641,25 @@ public static Color FromHsv(Vector4 hsv)
///
/// Color value to convert.
[SuppressMessage("ReSharper", "CompareOfFloatsByEqualityOperator")]
- public static Vector4 ToHsv(Color rgb)
+ public static Vector4 ToHsv(Color color)
{
- var max = MathF.Max(rgb.R, MathF.Max(rgb.G, rgb.B));
- var min = MathF.Min(rgb.R, MathF.Min(rgb.G, rgb.B));
+ var max = MathF.Max(color.R, MathF.Max(color.G, color.B));
+ var min = MathF.Min(color.R, MathF.Min(color.G, color.B));
var c = max - min;
var h = 0.0f;
if (c != 0)
{
- if (max == rgb.R)
+ if (max == color.R)
{
- h = (rgb.G - rgb.B) / c % 6.0f;
+ h = (color.G - color.B) / c % 6.0f;
if (h < 0f)
h += 6.0f;
}
- else if (max == rgb.G)
- h = (rgb.B - rgb.R) / c + 2.0f;
- else if (max == rgb.B)
- h = (rgb.R - rgb.G) / c + 4.0f;
+ else if (max == color.G)
+ h = (color.B - color.R) / c + 2.0f;
+ else if (max == color.B)
+ h = (color.R - color.G) / c + 4.0f;
}
var hue = h * 60.0f / 360.0f;
@@ -586,7 +668,7 @@ public static Vector4 ToHsv(Color rgb)
if (0.0f != max)
saturation = c / max;
- return new Vector4(hue, saturation, max, rgb.A);
+ return new Vector4(hue, saturation, max, color.A);
}
#region Oklab/Oklch
@@ -736,14 +818,14 @@ public static Color FromXyz(Vector4 xyz)
/// element with Alpha (a copy of the input's Alpha value).
/// Each has a range of 0.0 to 1.0.
///
- /// Color value to convert.
+ /// Color value to convert.
/// Uses the CIE XYZ colorspace.
- public static Vector4 ToXyz(Color rgb)
+ public static Vector4 ToXyz(Color color)
{
- var x = (0.49f * rgb.R + 0.31f * rgb.G + 0.20f * rgb.B) / 0.17697f;
- var y = (0.17697f * rgb.R + 0.81240f * rgb.G + 0.01063f * rgb.B) / 0.17697f;
- var z = (0.00f * rgb.R + 0.01f * rgb.G + 0.99f * rgb.B) / 0.17697f;
- return new Vector4(x, y, z, rgb.A);
+ var x = (0.49f * color.R + 0.31f * color.G + 0.20f * color.B) / 0.17697f;
+ var y = (0.17697f * color.R + 0.81240f * color.G + 0.01063f * color.B) / 0.17697f;
+ var z = (0.00f * color.R + 0.01f * color.G + 0.99f * color.B) / 0.17697f;
+ return new Vector4(x, y, z, color.A);
}
///
@@ -777,14 +859,14 @@ public static Color FromYcbcr(Vector4 ycbcr)
/// input's Alpha value).
/// Each has a range of 0.0 to 1.0.
///
- /// Color value to convert.
+ /// Color value to convert.
/// Converts using ITU-R BT.601/CCIR 601 W(r) = 0.299 W(b) = 0.114 U(max) = 0.436 V(max) = 0.615.
- public static Vector4 ToYcbcr(Color rgb)
+ public static Vector4 ToYcbcr(Color color)
{
- var y = 0.299f * rgb.R + 0.587f * rgb.G + 0.114f * rgb.B;
- var u = -0.168736f * rgb.R + -0.331264f * rgb.G + 0.5f * rgb.B;
- var v = 0.5f * rgb.R + -0.418688f * rgb.G + -0.081312f * rgb.B;
- return new Vector4(y, u, v, rgb.A);
+ var y = 0.299f * color.R + 0.587f * color.G + 0.114f * color.B;
+ var u = -0.168736f * color.R + -0.331264f * color.G + 0.5f * color.B;
+ var v = 0.5f * color.R + -0.418688f * color.G + -0.081312f * color.B;
+ return new Vector4(y, u, v, color.A);
}
///
@@ -894,10 +976,19 @@ public static Vector4 ToHcy(Color rgb)
return new Vector4(hue, c, luminance, rgb.A);
}
-
- public static Vector4 ToCmyk(Color rgb)
+ ///
+ /// Converts a Color instance into CMYK color values.
+ ///
+ /// The color instance to convert.
+ ///
+ /// Returns the converted color value.
+ /// The X element is cyan (C), the Y element is magenta (M), the Z element is yellow (Y),
+ /// and the W element is the key (K).
+ /// Each has a range of 0.0 to 1.0.
+ ///
+ public static Vector4 ToCmyk(Color color)
{
- var (r, g, b) = rgb;
+ var (r, g, b) = color;
var k = 1 - MathF.Max(r, MathF.Max(g, b));
var c = (1 - r - k) / (1 - k);
var m = (1 - g - k) / (1 - k);
@@ -906,6 +997,18 @@ public static Vector4 ToCmyk(Color rgb)
return new Vector4(c, m, y, k);
}
+ ///
+ /// Converts CMYK color values into a Color instance.
+ ///
+ ///
+ /// The CMYK color values.
+ /// The X element is cyan (C), the Y element is magenta (M), the Z element is yellow (Y),
+ /// and the W element is the key (K).
+ /// Each has a range of 0.0 to 1.0.
+ ///
+ ///
+ /// The converted color instance.
+ ///
public static Color FromCmyk(Vector4 cmyk)
{
var (c, m, y, k) = cmyk;
@@ -930,62 +1033,107 @@ public static Color FromCmyk(Vector4 cmyk)
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Color InterpolateBetween(Color α, Color β, float λ)
{
- return new(Vector4.Lerp(α.RGBA, β.RGBA, λ));
+ return new Color(Vector4.Lerp(α.RGBA, β.RGBA, λ));
}
- public static Color? TryFromHex(ReadOnlySpan hexColor)
+ ///
+ /// Tries to convert a of characters into a instance.
+ ///
+ /// The to try to convert into a instance.
+ /// The created instance.
+ ///
+ /// Returns if it created a proper instance from the hex code.
+ /// Returns if no instance could be made.
+ ///
+ ///
+ /// must start with a #.
+ /// Works with the following hex code formats:
+ /// #00000000, #000000, #0000, #000
+ ///
+ public static bool TryFromHex(ReadOnlySpan hexColor, out Color color)
{
- if (hexColor.Length <= 0 || hexColor[0] != '#') return null;
+ color = default;
+
+ if (hexColor.Length <= 0 || hexColor[0] != '#') return false;
if (hexColor.Length == 9)
{
- if (!byte.TryParse(hexColor[1..3], NumberStyles.HexNumber, null, out var r)) return null;
- if (!byte.TryParse(hexColor[3..5], NumberStyles.HexNumber, null, out var g)) return null;
- if (!byte.TryParse(hexColor[5..7], NumberStyles.HexNumber, null, out var b)) return null;
- if (!byte.TryParse(hexColor[7..9], NumberStyles.HexNumber, null, out var a)) return null;
- return new Color(r, g, b, a);
+ if (!byte.TryParse(hexColor[1..3], NumberStyles.HexNumber, null, out var r)) return false;
+ if (!byte.TryParse(hexColor[3..5], NumberStyles.HexNumber, null, out var g)) return false;
+ if (!byte.TryParse(hexColor[5..7], NumberStyles.HexNumber, null, out var b)) return false;
+ if (!byte.TryParse(hexColor[7..9], NumberStyles.HexNumber, null, out var a)) return false;
+ color = new Color(r, g, b, a);
+ return true;
}
if (hexColor.Length == 7)
{
- if (!byte.TryParse(hexColor[1..3], NumberStyles.HexNumber, null, out var r)) return null;
- if (!byte.TryParse(hexColor[3..5], NumberStyles.HexNumber, null, out var g)) return null;
- if (!byte.TryParse(hexColor[5..7], NumberStyles.HexNumber, null, out var b)) return null;
- return new Color(r, g, b);
- }
-
- static bool ParseDup(char chr, out byte value)
- {
- Span buf = stackalloc char[2];
- buf[0] = chr;
- buf[1] = chr;
-
- return byte.TryParse(buf, NumberStyles.HexNumber, null, out value);
+ if (!byte.TryParse(hexColor[1..3], NumberStyles.HexNumber, null, out var r)) return false;
+ if (!byte.TryParse(hexColor[3..5], NumberStyles.HexNumber, null, out var g)) return false;
+ if (!byte.TryParse(hexColor[5..7], NumberStyles.HexNumber, null, out var b)) return false;
+ color = new Color(r, g, b);
+ return true;
}
if (hexColor.Length == 5)
{
- if (!ParseDup(hexColor[1], out var rByte)) return null;
- if (!ParseDup(hexColor[2], out var gByte)) return null;
- if (!ParseDup(hexColor[3], out var bByte)) return null;
- if (!ParseDup(hexColor[4], out var aByte)) return null;
+ if (!ParseDup(hexColor[1], out var rByte)) return false;
+ if (!ParseDup(hexColor[2], out var gByte)) return false;
+ if (!ParseDup(hexColor[3], out var bByte)) return false;
+ if (!ParseDup(hexColor[4], out var aByte)) return false;
- return new Color(rByte, gByte, bByte, aByte);
+ color = new Color(rByte, gByte, bByte, aByte);
+ return true;
}
if (hexColor.Length == 4)
{
- if (!ParseDup(hexColor[1], out var rByte)) return null;
- if (!ParseDup(hexColor[2], out var gByte)) return null;
- if (!ParseDup(hexColor[3], out var bByte)) return null;
+ if (!ParseDup(hexColor[1], out var rByte)) return false;
+ if (!ParseDup(hexColor[2], out var gByte)) return false;
+ if (!ParseDup(hexColor[3], out var bByte)) return false;
- return new Color(rByte, gByte, bByte);
+ color = new Color(rByte, gByte, bByte);
+ return true;
}
+ return false;
+ }
+
+ ///
+ /// Tries to convert a of characters into a .
+ ///
+ /// The of characters to convert into a instance.
+ /// A instance if it succeeded, otherwise.
+ ///
+ /// must start with a #.
+ /// Works with the following hex code formats:
+ /// #00000000, #000000, #0000, #000
+ ///
+ private static Color? TryFromHex(ReadOnlySpan hexColor)
+ {
+ if (TryFromHex(hexColor, out var color))
+ return color;
+
return null;
}
+ private static bool ParseDup(char chr, out byte value)
+ {
+ Span buf = stackalloc char[2];
+ buf[0] = chr;
+ buf[1] = chr;
+
+ return byte.TryParse(buf, NumberStyles.HexNumber, null, out value);
+ }
+
+ ///
+ /// Converts a of characters into a instance
+ /// and lets you provide a fallback if it fails.
+ ///
+ /// Tries to
+ ///
+ ///
+ /// If no fallback is provided, throws an
public static Color FromHex(ReadOnlySpan hexColor, Color? fallback = null)
{
- var color = TryFromHex(hexColor);
- if (color.HasValue)
- return color.Value;
+ if (TryFromHex(hexColor, out var color))
+ return color;
if (fallback.HasValue)
return fallback.Value;
throw new ArgumentException($"Invalid color code \"{new string(hexColor)}\" and no fallback provided.", nameof(hexColor));
@@ -993,9 +1141,8 @@ public static Color FromHex(ReadOnlySpan hexColor, Color? fallback = null)
public static Color FromXaml(string name)
{
- var color = TryFromHex(name);
- if (color != null)
- return color.Value;
+ if (TryFromHex(name, out var color))
+ return color;
if (TryFromName(name, out var namedColor))
return namedColor;
@@ -1089,6 +1236,10 @@ public static Color Blend(Color dstColor, Color srcColor, BlendFactor dstFactor,
public static Color operator *(in Color a, in Color b)
=> new(a.RGBA * b.RGBA);
+ ///
+ /// Converts a instance into a hex color .
+ ///
+ /// The hex color code, formatted as #00000000.
public readonly string ToHex()
{
var hexColor = 0;
@@ -1100,6 +1251,8 @@ public readonly string ToHex()
return $"#{hexColor:X8}";
}
+ ///
+ /// The hex color code, formatted as #000000.
public readonly string ToHexNoAlpha()
{
var hexColor = 0;
@@ -2015,22 +2168,30 @@ public enum BlendFactor : byte
private static readonly FrozenDictionary DefaultColorsInverted =
DefaultColors.ToLookup(pair => pair.Value).ToFrozenDictionary(i => i.Key, i => i.First().Key);
+ ///
+ /// Gets the associated color name with this color instance by using an inverted version of .
+ /// Returns if there is no possible name with this color instance.
+ ///
+ /// The associated color name if any, usable with .
public readonly string? Name()
{
return DefaultColorsInverted.GetValueOrDefault(this);
}
+ ///
+ /// Tries to return a instance by first calling , and then
+ /// .
+ ///
+ /// A that could either be a hex color code or a valid default color name.
+ /// The parsed color if it returned true.
+ /// Returns true if a color was returned successfully. Returns false otherwise.
public static bool TryParse(string input, out Color color)
{
if (TryFromName(input, out color))
return true;
- var nullableColor = TryFromHex(input);
- if (nullableColor != null)
- {
- color = nullableColor.Value;
+ if (TryFromHex(input, out color))
return true;
- }
return false;
}
diff --git a/Robust.Shared/Serialization/TypeSerializers/Implementations/ColorSerializer.cs b/Robust.Shared/Serialization/TypeSerializers/Implementations/ColorSerializer.cs
index 816e7115faf..9580ecd548a 100644
--- a/Robust.Shared/Serialization/TypeSerializers/Implementations/ColorSerializer.cs
+++ b/Robust.Shared/Serialization/TypeSerializers/Implementations/ColorSerializer.cs
@@ -30,7 +30,7 @@ public ValidationNode Validate(ISerializationManager serializationManager, Value
IDependencyCollection dependencies,
ISerializationContext? context = null)
{
- return Color.TryFromName(node.Value, out _) || Color.TryFromHex(node.Value) != null
+ return Color.TryFromName(node.Value, out _) || Color.TryFromHex(node.Value, out _)
? new ValidatedValueNode(node)
: new ErrorNode(node, "Failed parsing Color.");
}
diff --git a/Robust.Shared/Utility/FormattedMessage.MarkupParser.cs b/Robust.Shared/Utility/FormattedMessage.MarkupParser.cs
index 61507999405..fb639b3abf7 100644
--- a/Robust.Shared/Utility/FormattedMessage.MarkupParser.cs
+++ b/Robust.Shared/Utility/FormattedMessage.MarkupParser.cs
@@ -272,6 +272,10 @@ private static Color CreateColor(string nameOrHex)
if (Color.TryFromName(nameOrHex, out var nameColor))
return nameColor;
- return Color.TryFromHex(nameOrHex) ?? Color.Black;
+ // ReSharper disable once ConvertIfStatementToReturnStatement
+ if (Color.TryFromHex(nameOrHex, out var hexColor))
+ return hexColor;
+
+ return Color.Black;
}
}