]> git.smokeofanarchy.ru Git - space-station-14.git/commitdiff
Fix ColorExtensions math (#41717)
authorPieter-Jan Briers <pieterjan.briers+git@gmail.com>
Mon, 15 Dec 2025 02:07:32 +0000 (03:07 +0100)
committerGitHub <noreply@github.com>
Mon, 15 Dec 2025 02:07:32 +0000 (03:07 +0100)
All of this was doing sRGB -> OkLAB conversions without linearizing the sRGB first, so it was broken. I could have sworn I pointed this out in review but I guess that got lost.

Also, add a gamut clipping step since we have out-of-gamut colors and I don't want random negative values causing weird nightmare bugs somewhere. Shouldn't change anything in regular rendering.

Content.Client/Stylesheets/Colorspace/ColorExtensions.cs

index 1a191992b1e5ced21b5cf4bfb57173b8fb6e013b..6af9308bbc3367da4918172a8791edc56e3a4008 100644 (file)
@@ -14,10 +14,10 @@ public static class ColorExtensions
     {
         DebugTools.Assert(lightness is >= 0.0f and <= 1.0f);
 
-        var oklab = Color.ToLab(c);
+        var oklab = c.LabFromSrgb();
         oklab.X = lightness;
 
-        return Color.FromLab(oklab);
+        return oklab.LabToSrgb();
     }
 
     /// <summary>
@@ -25,10 +25,10 @@ public static class ColorExtensions
     /// </summary>
     public static Color NudgeLightness(this Color c, float lightnessShift)
     {
-        var oklab = Color.ToLab(c);
+        var oklab = c.LabFromSrgb();
         oklab.X = Math.Clamp(oklab.X + lightnessShift, 0, 1);
 
-        return Color.FromLab(oklab);
+        return oklab.LabToSrgb();
     }
 
     /// <summary>
@@ -39,12 +39,12 @@ public static class ColorExtensions
     /// </remarks>
     public static Color NudgeChroma(this Color c, float chromaShift)
     {
-        var oklab = Color.ToLab(c);
+        var oklab = c.LabFromSrgb();
         var oklch = Color.ToLch(oklab);
 
         oklch.Y = Math.Clamp(oklch.Y + chromaShift, 0, 1);
 
-        return Color.FromLab(Color.FromLch(oklch));
+        return Color.FromLch(oklch).LabToSrgb();
     }
 
     /// <summary>
@@ -54,10 +54,43 @@ public static class ColorExtensions
     {
         DebugTools.Assert(factor is >= 0.0f and <= 1.0f);
 
-        var okFrom = Color.ToLab(from);
-        var okTo = Color.ToLab(to);
+        var okFrom = from.LabFromSrgb();
+        var okTo = to.LabFromSrgb();
 
         var blended = Vector4.Lerp(okFrom, okTo, factor);
-        return Color.FromLab(blended);
+        return blended.LabToSrgb();
+    }
+
+    /// <summary>
+    /// Converts a nonlinear sRGB ("normal") color to OkLAB.
+    /// </summary>
+    public static Vector4 LabFromSrgb(this Color from)
+    {
+        return Color.ToLab(Color.FromSrgb(from));
+    }
+
+    /// <summary>
+    /// Converts OkLAB to a nonlinear sRGB ("normal") color.
+    /// </summary>
+    public static Color LabToSrgb(this Vector4 from)
+    {
+        return Color.ToSrgb(Color.FromLab(from).SimpleClipGamut());
+    }
+
+    /// <summary>
+    /// Clips the gamut of the color so that all color channels are in the range 0 -> 1.
+    /// </summary>
+    /// <remarks>
+    /// This uses no clever perceptual techniques, it literally just clamps the individual channels.
+    /// </remarks>
+    public static Color SimpleClipGamut(this Color from)
+    {
+        return new Color
+        {
+            R = Math.Clamp(from.R, 0, 1),
+            G = Math.Clamp(from.G, 0, 1),
+            B = Math.Clamp(from.B, 0, 1),
+            A = from.A,
+        };
     }
 }