From 74254e6cdb524ba45bc1f48ebadeb32e5b369e2d Mon Sep 17 00:00:00 2001 From: Ellpeck Date: Mon, 29 Jul 2024 20:46:40 +0200 Subject: [PATCH] Added ColorExtensions.ToHsv and ColorHelper.FromHsv --- CHANGELOG.md | 2 +- MLEM/Graphics/ColorExtensions.cs | 72 ++++++++++++++++++++++++++++++++ Sandbox/GameImpl.cs | 26 ++++++------ 3 files changed, 86 insertions(+), 14 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index dd86673..a171a49 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,7 +18,7 @@ Jump to version: ### MLEM Additions -- Added ColorExtensions.ToHsl and ColorHelper.FromHsl +- Added ColorExtensions.ToHsl and ColorHelper.FromHsl as well as ColorExtensions.ToHsv and ColorHelper.FromHsv ## 7.0.0 diff --git a/MLEM/Graphics/ColorExtensions.cs b/MLEM/Graphics/ColorExtensions.cs index 897fbb8..bbd569c 100644 --- a/MLEM/Graphics/ColorExtensions.cs +++ b/MLEM/Graphics/ColorExtensions.cs @@ -91,6 +91,38 @@ namespace MLEM.Graphics { return (h, s, l); } + /// + /// Converts the given into HSV representation and returns the result as a value tuple with values between 0 and 1. + /// + /// This code is adapted from https://gist.github.com/mjackson/5311256. + /// The color to convert. + /// The resulting HSV color as a value tuple containing H, S and V, each between 0 and 1. + public static (float H, float S, float V) ToHsv(this Color color) { + var r = color.R / 255F; + var g = color.G / 255F; + var b = color.B / 255F; + + var max = Math.Max(Math.Max(r, g), b); + var min = Math.Min(Math.Min(r, g), b); + var d = max - min; + float h, s = max == 0 ? 0 : d / max, v = max; + + if (max == min) { + h = 0; // achromatic + } else { + if (r == max) { + h = (g - b) / d + (g < b ? 6 : 0); + } else if (g == max) { + h = (b - r) / d + 2; + } else { + h = (r - g) / d + 4; + } + h /= 6; + } + + return (h, s, v); + } + } /// @@ -184,6 +216,46 @@ namespace MLEM.Graphics { return new Color(r, g, b); } + /// + ///Converts the given HSV color to an RGB and returns the result. + /// + /// This code is adapted from https://gist.github.com/mjackson/5311256. + /// The HSV color to convert, as a value tuple that contains H, S and V values, each between 0 and 1. + /// The resulting RGB color. + public static Color FromHsv((float H, float S, float V) color) { + return ColorHelper.FromHsv(color.H, color.S, color.V); + } + + /// + ///Converts the given HSV values to an RGB and returns the result. + /// + /// This code is adapted from https://gist.github.com/mjackson/5311256. + /// The H component of the HSV color, between 0 and 1. + /// The S component of the HSV color, between 0 and 1. + /// The V component of the HSV color, between 0 and 1. + /// The resulting RGB color. + public static Color FromHsv(float h, float s, float v) { + var i = (int) (h * 6); + var f = h * 6 - i; + var p = v * (1 - s); + var q = v * (1 - f * s); + var t = v * (1 - (1 - f) * s); + switch (i % 6) { + case 0: + return new Color(v, t, p); + case 1: + return new Color(q, v, p); + case 2: + return new Color(p, v, t); + case 3: + return new Color(p, q, v); + case 4: + return new Color(t, p, v); + default: // 5 + return new Color(v, p, q); + } + } + private static float HueToRgb(float p, float q, float t) { if (t < 0) t += 1; diff --git a/Sandbox/GameImpl.cs b/Sandbox/GameImpl.cs index 3a2711f..0431ac3 100644 --- a/Sandbox/GameImpl.cs +++ b/Sandbox/GameImpl.cs @@ -398,27 +398,27 @@ public class GameImpl : MlemGame { Console.WriteLine("Buttons: " + string.Join(", ", GenericInput.AllButtons)); Console.WriteLine("Inputs: " + string.Join(", ", GenericInput.AllInputs));*/ - var hsl = new Panel(Anchor.Center, new Vector2(100), true); - var color = Color.Pink.ToHsl(); - hsl.AddChild(new Paragraph(Anchor.AutoLeft, 1, "H")); - hsl.AddChild(new Slider(Anchor.AutoLeft, new Vector2(1, 10), 5, 1) { + var hsv = new Panel(Anchor.Center, new Vector2(100), true); + var color = Color.Pink.ToHsv(); + hsv.AddChild(new Paragraph(Anchor.AutoLeft, 1, "H")); + hsv.AddChild(new Slider(Anchor.AutoLeft, new Vector2(1, 10), 5, 1) { CurrentValue = color.H, OnValueChanged = (_, v) => color.H = v }); - hsl.AddChild(new Paragraph(Anchor.AutoLeft, 1, "S")); - hsl.AddChild(new Slider(Anchor.AutoLeft, new Vector2(1, 10), 5, 1) { + hsv.AddChild(new Paragraph(Anchor.AutoLeft, 1, "S")); + hsv.AddChild(new Slider(Anchor.AutoLeft, new Vector2(1, 10), 5, 1) { CurrentValue = color.S, OnValueChanged = (_, v) => color.S = v }); - hsl.AddChild(new Paragraph(Anchor.AutoLeft, 1, "L")); - hsl.AddChild(new Slider(Anchor.AutoLeft, new Vector2(1, 10), 5, 1) { - CurrentValue = color.L, - OnValueChanged = (_, v) => color.L = v + hsv.AddChild(new Paragraph(Anchor.AutoLeft, 1, "V")); + hsv.AddChild(new Slider(Anchor.AutoLeft, new Vector2(1, 10), 5, 1) { + CurrentValue = color.V, + OnValueChanged = (_, v) => color.V = v }); - hsl.AddChild(new Group(Anchor.AutoLeft, new Vector2(1, 40), false) { - OnDrawn = (e, _, batch, _, _) => batch.Draw(batch.GetBlankTexture(), e.DisplayArea, ColorHelper.FromHsl(color)) + hsv.AddChild(new Group(Anchor.AutoLeft, new Vector2(1, 40), false) { + OnDrawn = (e, _, batch, _, _) => batch.Draw(batch.GetBlankTexture(), e.DisplayArea, ColorHelper.FromHsv(color)) }); - this.UiSystem.Add("HSL", hsl); + this.UiSystem.Add("HSV", hsv); } protected override void DoUpdate(GameTime gameTime) {