From 9e805dcd44843ef04ea23ed26d311d3a39daebc0 Mon Sep 17 00:00:00 2001 From: TheOmyNomy Date: Sun, 8 Aug 2021 21:27:32 +1000 Subject: [PATCH 1/5] Fix legacy slider body colour interpolation --- .../Skinning/Legacy/LegacySliderBody.cs | 26 +++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacySliderBody.cs b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacySliderBody.cs index 744ded37c9..9e4b57ca10 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacySliderBody.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacySliderBody.cs @@ -3,7 +3,6 @@ using System; using osu.Framework.Extensions.Color4Extensions; -using osu.Framework.Utils; using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Osu.Skinning.Default; using osuTK.Graphics; @@ -40,7 +39,10 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy Color4 outerColour = AccentColour.Darken(0.1f); Color4 innerColour = lighten(AccentColour, 0.5f); - return Interpolation.ValueAt(position / realGradientPortion, outerColour, innerColour, 0, 1); + // Stable doesn't use linear space / gamma-correct colour interpolation + // for slider bodies, so we can't use Interpolation.ValueAt(). + // Instead, we use a local method that interpolates between the colours directly in sRGB space. + return valueAt(position / realGradientPortion, outerColour, innerColour, 0, 1); } /// @@ -55,6 +57,26 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy Math.Min(1, color.B * (1 + 0.5f * amount) + 1 * amount), color.A); } + + private static Color4 valueAt(double time, Color4 startColour, Color4 endColour, double startTime, double endTime) + { + if (startColour == endColour) + return startColour; + + double current = time - startTime; + double duration = endTime - startTime; + + if (duration == 0 || current == 0) + return startColour; + + float t = (float)Math.Max(0, Math.Min(1, current / duration)); + + return new Color4( + startColour.R + t * (endColour.R - startColour.R), + startColour.G + t * (endColour.G - startColour.G), + startColour.B + t * (endColour.B - startColour.B), + startColour.A + t * (endColour.A - startColour.A)); + } } } } From 140d29d53762b1d0df5e44fdcd125410769ca50b Mon Sep 17 00:00:00 2001 From: TheOmyNomy Date: Sun, 8 Aug 2021 23:54:35 +1000 Subject: [PATCH 2/5] Use helper methods instead of local valueAt() method --- .../Skinning/Legacy/LegacySliderBody.cs | 34 +++++-------------- 1 file changed, 8 insertions(+), 26 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacySliderBody.cs b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacySliderBody.cs index 9e4b57ca10..a8bb69c080 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacySliderBody.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacySliderBody.cs @@ -3,6 +3,7 @@ using System; using osu.Framework.Extensions.Color4Extensions; +using osu.Framework.Utils; using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Osu.Skinning.Default; using osuTK.Graphics; @@ -36,13 +37,14 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy position -= realBorderPortion; - Color4 outerColour = AccentColour.Darken(0.1f); - Color4 innerColour = lighten(AccentColour, 0.5f); + // Stable interpolates slider body colour directly in sRGB space, and because + // Interpolation.ValueAt() uses linear space, we have to counteract applying it + // by calling ToSRGB() on the input colours, and ToLinear() on the resulting colour. - // Stable doesn't use linear space / gamma-correct colour interpolation - // for slider bodies, so we can't use Interpolation.ValueAt(). - // Instead, we use a local method that interpolates between the colours directly in sRGB space. - return valueAt(position / realGradientPortion, outerColour, innerColour, 0, 1); + Color4 outerColour = AccentColour.Darken(0.1f).ToSRGB(); + Color4 innerColour = lighten(AccentColour, 0.5f).ToSRGB(); + + return Interpolation.ValueAt(position / realGradientPortion, outerColour, innerColour, 0, 1).ToLinear(); } /// @@ -57,26 +59,6 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy Math.Min(1, color.B * (1 + 0.5f * amount) + 1 * amount), color.A); } - - private static Color4 valueAt(double time, Color4 startColour, Color4 endColour, double startTime, double endTime) - { - if (startColour == endColour) - return startColour; - - double current = time - startTime; - double duration = endTime - startTime; - - if (duration == 0 || current == 0) - return startColour; - - float t = (float)Math.Max(0, Math.Min(1, current / duration)); - - return new Color4( - startColour.R + t * (endColour.R - startColour.R), - startColour.G + t * (endColour.G - startColour.G), - startColour.B + t * (endColour.B - startColour.B), - startColour.A + t * (endColour.A - startColour.A)); - } } } } From 24accdcab05b99e1b01a8f71d0f41609738d5d3c Mon Sep 17 00:00:00 2001 From: TheOmyNomy Date: Mon, 9 Aug 2021 18:56:47 +1000 Subject: [PATCH 3/5] Add LegacyUtils class with non linear colour interpolation method --- .../Skinning/Legacy/LegacySliderBody.cs | 12 ++-- osu.Game/Utils/LegacyUtils.cs | 65 +++++++++++++++++++ 2 files changed, 69 insertions(+), 8 deletions(-) create mode 100644 osu.Game/Utils/LegacyUtils.cs diff --git a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacySliderBody.cs b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacySliderBody.cs index a8bb69c080..92941665e0 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacySliderBody.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacySliderBody.cs @@ -3,9 +3,9 @@ using System; using osu.Framework.Extensions.Color4Extensions; -using osu.Framework.Utils; using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Osu.Skinning.Default; +using osu.Game.Utils; using osuTK.Graphics; namespace osu.Game.Rulesets.Osu.Skinning.Legacy @@ -37,14 +37,10 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy position -= realBorderPortion; - // Stable interpolates slider body colour directly in sRGB space, and because - // Interpolation.ValueAt() uses linear space, we have to counteract applying it - // by calling ToSRGB() on the input colours, and ToLinear() on the resulting colour. + Color4 outerColour = AccentColour.Darken(0.1f); + Color4 innerColour = lighten(AccentColour, 0.5f); - Color4 outerColour = AccentColour.Darken(0.1f).ToSRGB(); - Color4 innerColour = lighten(AccentColour, 0.5f).ToSRGB(); - - return Interpolation.ValueAt(position / realGradientPortion, outerColour, innerColour, 0, 1).ToLinear(); + return LegacyUtils.InterpolateNonLinear(position / realGradientPortion, outerColour, innerColour, 0, 1); } /// diff --git a/osu.Game/Utils/LegacyUtils.cs b/osu.Game/Utils/LegacyUtils.cs new file mode 100644 index 0000000000..9351125acd --- /dev/null +++ b/osu.Game/Utils/LegacyUtils.cs @@ -0,0 +1,65 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Transforms; +using osuTK.Graphics; + +namespace osu.Game.Utils +{ + public static class LegacyUtils + { + public static Color4 InterpolateNonLinear(double time, Color4 startColour, Color4 endColour, double startTime, double endTime, Easing easing = Easing.None) + => InterpolateNonLinear(time, startColour, endColour, startTime, endTime, new DefaultEasingFunction(easing)); + + public static Colour4 InterpolateNonLinear(double time, Colour4 startColour, Colour4 endColour, double startTime, double endTime, Easing easing = Easing.None) + => InterpolateNonLinear(time, startColour, endColour, startTime, endTime, new DefaultEasingFunction(easing)); + + /// + /// Interpolates between two sRGB s directly in sRGB space. + /// + public static Color4 InterpolateNonLinear(double time, Color4 startColour, Color4 endColour, double startTime, double endTime, TEasing easing) where TEasing : IEasingFunction + { + if (startColour == endColour) + return startColour; + + double current = time - startTime; + double duration = endTime - startTime; + + if (duration == 0 || current == 0) + return startColour; + + float t = Math.Max(0, Math.Min(1, (float)easing.ApplyEasing(current / duration))); + + return new Color4( + startColour.R + t * (endColour.R - startColour.R), + startColour.G + t * (endColour.G - startColour.G), + startColour.B + t * (endColour.B - startColour.B), + startColour.A + t * (endColour.A - startColour.A)); + } + + /// + /// Interpolates between two sRGB s directly in sRGB space. + /// + public static Colour4 InterpolateNonLinear(double time, Colour4 startColour, Colour4 endColour, double startTime, double endTime, in TEasing easing) where TEasing : IEasingFunction + { + if (startColour == endColour) + return startColour; + + double current = time - startTime; + double duration = endTime - startTime; + + if (duration == 0 || current == 0) + return startColour; + + float t = Math.Max(0, Math.Min(1, (float)easing.ApplyEasing(current / duration))); + + return new Colour4( + startColour.R + t * (endColour.R - startColour.R), + startColour.G + t * (endColour.G - startColour.G), + startColour.B + t * (endColour.B - startColour.B), + startColour.A + t * (endColour.A - startColour.A)); + } + } +} From 76e5a40b8ed15dfba6bf5812743a5bbf1f15a542 Mon Sep 17 00:00:00 2001 From: TheOmyNomy Date: Mon, 9 Aug 2021 20:53:02 +1000 Subject: [PATCH 4/5] Remove unnecessary "in" keyword --- osu.Game/Utils/LegacyUtils.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Utils/LegacyUtils.cs b/osu.Game/Utils/LegacyUtils.cs index 9351125acd..64306adf50 100644 --- a/osu.Game/Utils/LegacyUtils.cs +++ b/osu.Game/Utils/LegacyUtils.cs @@ -42,7 +42,7 @@ namespace osu.Game.Utils /// /// Interpolates between two sRGB s directly in sRGB space. /// - public static Colour4 InterpolateNonLinear(double time, Colour4 startColour, Colour4 endColour, double startTime, double endTime, in TEasing easing) where TEasing : IEasingFunction + public static Colour4 InterpolateNonLinear(double time, Colour4 startColour, Colour4 endColour, double startTime, double endTime, TEasing easing) where TEasing : IEasingFunction { if (startColour == endColour) return startColour; From c5b490c4414d64a9dc80353850cad62d707aa85d Mon Sep 17 00:00:00 2001 From: TheOmyNomy Date: Tue, 10 Aug 2021 11:29:31 +1000 Subject: [PATCH 5/5] Use non linear colour interpolation for legacy health display --- osu.Game/Skinning/LegacyHealthDisplay.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/osu.Game/Skinning/LegacyHealthDisplay.cs b/osu.Game/Skinning/LegacyHealthDisplay.cs index 67280e4acd..b1cd1f86c0 100644 --- a/osu.Game/Skinning/LegacyHealthDisplay.cs +++ b/osu.Game/Skinning/LegacyHealthDisplay.cs @@ -11,6 +11,7 @@ using osu.Framework.Graphics.Textures; using osu.Framework.Utils; using osu.Game.Rulesets.Judgements; using osu.Game.Screens.Play.HUD; +using osu.Game.Utils; using osuTK; using osuTK.Graphics; @@ -83,10 +84,10 @@ namespace osu.Game.Skinning private static Color4 getFillColour(double hp) { if (hp < 0.2) - return Interpolation.ValueAt(0.2 - hp, Color4.Black, Color4.Red, 0, 0.2); + return LegacyUtils.InterpolateNonLinear(0.2 - hp, Color4.Black, Color4.Red, 0, 0.2); if (hp < epic_cutoff) - return Interpolation.ValueAt(0.5 - hp, Color4.White, Color4.Black, 0, 0.5); + return LegacyUtils.InterpolateNonLinear(0.5 - hp, Color4.White, Color4.Black, 0, 0.5); return Color4.White; }