using Microsoft.Xna.Framework; using System; namespace OpenVIII { /// /// /// /// /// public struct HSL { #region Fields /// /// Alpha /// /// Percent public float A; /// /// Hue /// /// Degrees public float H; /// /// Luminosity /// /// Percent public float L; /// /// Saturation /// /// Percent public float S; #endregion Fields #region Constructors public HSL(Color @in) { var cMax = @in.Max() / 255f; var cMin = @in.Min() / 255f; var delta = cMax - cMin; float R = @in.R / 255f, G = @in.G / 255f, B = @in.B / 255f; H = Hue(); var l = L = Luminosity(); S = Saturation(); A = @in.A / 255f; float Hue() { var ret = 0f; if (delta == 0) { } else if (cMax == R) { ret = 60f * (((G - B) / delta) % 6); } else if (cMax == G) { ret = 60f * (((B - R) / delta) + 2); } else if (cMax == B) { ret = 60f * (((R - G) / delta) + 4); } return ret; } float Luminosity() => (cMax + cMin) / 2; float Saturation() => delta == 0 || l == 1 ? 0f : (delta) / (1 - Math.Abs(l * 2 - 1)); } #endregion Constructors #region Methods /// /// HSL to Color /// /// public static implicit operator Color(HSL @in) { var C = (1 - Math.Abs(2 * @in.L - 1)) * @in.S; var H = @in.H / 60f; var X = C * (1 - Math.Abs(H % 2 - 1)); var m = @in.L - C / 2; var rgb = getRGB(); return new Color() { A = (byte)(@in.A * 255), R = (byte)Math.Round(rgb.X), G = (byte)Math.Round(rgb.Y), B = (byte)Math.Round(rgb.Z), }; Vector3 getPrime() { if (H >= 0) { if (H <= 1) return new Vector3(C, X, 0); else if (H <= 2) return new Vector3(X, C, 0); else if (H <= 3) return new Vector3(0, C, X); else if (H <= 4) return new Vector3(0, X, C); else if (H <= 5) return new Vector3(X, 0, C); else if (H <= 6) return new Vector3(C, 0, X); } return Vector3.Zero; } Vector3 getRGB() { var prime = getPrime(); prime += new Vector3(m); prime *= new Vector3(255); return prime; } } public static implicit operator HSL(Color @in) => new HSL(@in); public override string ToString() => $"{H}° {S * 100}% {L * 100}% {A * 100}%"; #endregion Methods } public static class ColorExt { #region Methods public static HSL HSL(this Color @in) => new HSL(@in); public static byte Max(this Color @in) => (byte)MathHelper.Clamp((MathHelper.Max(MathHelper.Max(@in.R, @in.G), @in.B)), 0, 255); public static byte Min(this Color @in) => (byte)MathHelper.Clamp((MathHelper.Min(MathHelper.Min(@in.R, @in.G), @in.B)), 0, 255); #endregion Methods } }