diff --git a/Content.Tests/DMProject/Tests/Builtins/rgb.dm b/Content.Tests/DMProject/Tests/Builtins/rgb.dm
new file mode 100644
index 0000000000..f0eb2f206d
--- /dev/null
+++ b/Content.Tests/DMProject/Tests/Builtins/rgb.dm
@@ -0,0 +1,12 @@
+/proc/RunTest()
+ ASSERT(rgb(255, 255, 255) =="#ffffff")
+ ASSERT(rgb(255, 0, 0) == "#ff0000" )
+ ASSERT(rgb(0, 0, 255) == "#0000ff")
+ ASSERT(rgb(18, 245, 230) == "#12f5e6")
+ ASSERT(rgb(18, 245, 230, 128) == "#12f5e680")
+ ASSERT(rgb(202, 96, 219, space=COLORSPACE_RGB) == "#ca60db")
+ ASSERT(rgb(291.70734, 56.164383, 85.882355, space=COLORSPACE_HSV) == "#ca60db")
+ ASSERT(rgb(291.70734, 63.07692, 61.764706, space=COLORSPACE_HSL) == "#ca60db" )
+
+ ASSERT(rgb(291.70734, 63.07692, 61.764706, 128, COLORSPACE_HSL) == "#ca60db80" )
+ //ASSERT(rgb(291.70734, 68.2215, 55.423534, space=COLORSPACE_HCY) == "#ca60db") // TODO Support HCY
\ No newline at end of file
diff --git a/OpenDream.sln.DotSettings b/OpenDream.sln.DotSettings
index d7ed950d3a..68a026431e 100644
--- a/OpenDream.sln.DotSettings
+++ b/OpenDream.sln.DotSettings
@@ -16,6 +16,9 @@
LHS
RHS
UI
+ RGB
+ HSV
+ HSL
True
True
True
diff --git a/OpenDreamRuntime/Procs/DMOpcodeHandlers.cs b/OpenDreamRuntime/Procs/DMOpcodeHandlers.cs
index 542ac796cf..8e15ccf7bd 100644
--- a/OpenDreamRuntime/Procs/DMOpcodeHandlers.cs
+++ b/OpenDreamRuntime/Procs/DMOpcodeHandlers.cs
@@ -1929,7 +1929,7 @@ public static ProcStatus Rgb(DMProcState state) {
DreamValue color1 = default;
DreamValue color2 = default;
DreamValue color3 = default;
- DreamValue a = default;
+ DreamValue a = DreamValue.Null;
ColorHelpers.ColorSpace space = ColorHelpers.ColorSpace.RGB;
if (arguments.Item1 != null) {
@@ -1974,6 +1974,9 @@ public static ProcStatus Rgb(DMProcState state) {
} else if (name.StartsWith("v", StringComparison.InvariantCultureIgnoreCase) && color3 == default) {
color3 = arg.Value;
space = ColorHelpers.ColorSpace.HSV;
+ } else if (name.StartsWith("l", StringComparison.InvariantCultureIgnoreCase) && color3 == default) {
+ color3 = arg.Value;
+ space = ColorHelpers.ColorSpace.HSL;
} else if (name.StartsWith("a", StringComparison.InvariantCultureIgnoreCase) && a == default)
a = arg.Value;
else if (name == "space" && space == default)
@@ -1994,10 +1997,10 @@ public static ProcStatus Rgb(DMProcState state) {
return ProcStatus.Continue;
}
- int color1Value = (int)color1.UnsafeGetValueAsFloat();
- int color2Value = (int)color2.UnsafeGetValueAsFloat();
- int color3Value = (int)color3.UnsafeGetValueAsFloat();
- byte aValue = (byte)Math.Clamp((int)a.UnsafeGetValueAsFloat(), 0, 255);
+ float color1Value = color1.UnsafeGetValueAsFloat();
+ float color2Value = color2.UnsafeGetValueAsFloat();
+ float color3Value = color3.UnsafeGetValueAsFloat();
+ byte aValue = a.IsNull ? (byte)255 : (byte)Math.Clamp((int)a.UnsafeGetValueAsFloat(), 0, 255);
Color color;
switch (space) {
@@ -2018,15 +2021,23 @@ public static ProcStatus Rgb(DMProcState state) {
color = Color.FromHsv((h, s, v, aValue / 255f));
break;
}
+ case ColorHelpers.ColorSpace.HSL: {
+ float h = Math.Clamp(color1Value, 0, 360) / 360f;
+ float s = Math.Clamp(color2Value, 0, 100) / 100f;
+ float l = Math.Clamp(color3Value, 0, 100) / 100f;
+
+ color = Color.FromHsl((h, s, l, aValue / 255f));
+ break;
+ }
default:
throw new Exception($"Unimplemented color space {space}");
}
// TODO: There is a difference between passing null and not passing a fourth arg at all
if (a.IsNull) {
- state.Push(new DreamValue($"#{color.RByte:X2}{color.GByte:X2}{color.BByte:X2}"));
+ state.Push(new DreamValue($"#{color.RByte:X2}{color.GByte:X2}{color.BByte:X2}".ToLower()));
} else {
- state.Push(new DreamValue($"#{color.RByte:X2}{color.GByte:X2}{color.BByte:X2}{color.AByte:X2}"));
+ state.Push(new DreamValue($"#{color.RByte:X2}{color.GByte:X2}{color.BByte:X2}{color.AByte:X2}".ToLower()));
}
return ProcStatus.Continue;
diff --git a/OpenDreamShared/Dream/ColorHelpers.cs b/OpenDreamShared/Dream/ColorHelpers.cs
index 45f5a2794b..98f5e413eb 100644
--- a/OpenDreamShared/Dream/ColorHelpers.cs
+++ b/OpenDreamShared/Dream/ColorHelpers.cs
@@ -29,7 +29,8 @@ public static class ColorHelpers {
public enum ColorSpace {
RGB = 0,
- HSV = 1
+ HSV = 1,
+ HSL = 2
}
public static bool TryParseColor(string color, out Color colorOut, string defaultAlpha = "ff") {