feat: added HSVA
This commit is contained in:
parent
df06e8d134
commit
f8fbae6130
@ -37,39 +37,9 @@ public readonly struct ColorHSV(float hue, float saturation, float value)
|
||||
public static bool operator ==(ColorHSV left, ColorHSV right) => left.Hue == right.Hue && left.Saturation == right.Saturation && left.Value == right.Value;
|
||||
public static bool operator !=(ColorHSV left, ColorHSV right) => left.Hue != right.Hue || left.Saturation != right.Saturation || left.Value != right.Value;
|
||||
|
||||
public static implicit operator ColorHSV(ColorRGBA rgba) => (ColorRGB)rgba;
|
||||
public static implicit operator ColorHSV(ColorRGB rgb)
|
||||
{
|
||||
float hue;
|
||||
float saturation;
|
||||
float value;
|
||||
|
||||
float rd = rgb.R / 255f;
|
||||
float gd = rgb.G / 255f;
|
||||
float bd = rgb.B / 255f;
|
||||
|
||||
float max = Math.Max(rd, Math.Max(gd, bd));
|
||||
float min = Math.Min(rd, Math.Min(gd, bd));
|
||||
float delta = max - min;
|
||||
|
||||
if (delta.ApproximatelyEquals(0))
|
||||
hue = 0f;
|
||||
else if (max.ApproximatelyEquals(rd))
|
||||
hue = 60f * ((gd - bd) / delta % 6f);
|
||||
else if (max.ApproximatelyEquals(gd))
|
||||
hue = 60f * (((bd - rd) / delta) + 2f);
|
||||
else
|
||||
hue = 60f * (((rd - gd) / delta) + 4f);
|
||||
|
||||
if (hue < 0f)
|
||||
hue += 360f;
|
||||
|
||||
hue /= 360f;
|
||||
saturation = max.ApproximatelyEquals(0f) ? 0f : delta / max;
|
||||
value = max;
|
||||
|
||||
return new(hue, saturation, value);
|
||||
}
|
||||
public static implicit operator ColorHSV(ColorHSVA hsva) => new(hsva.Hue, hsva.Saturation, hsva.Value);
|
||||
public static implicit operator ColorHSV(ColorRGBA rgba) => (ColorHSVA)rgba;
|
||||
public static implicit operator ColorHSV(ColorRGB rgb) => (ColorHSVA)rgb;
|
||||
|
||||
/// <summary>
|
||||
/// Inverts the given <see cref="ColorHSV"/>.
|
||||
|
189
Engine.Core/Primitives/ColorHSVA.cs
Normal file
189
Engine.Core/Primitives/ColorHSVA.cs
Normal file
@ -0,0 +1,189 @@
|
||||
namespace Syntriax.Engine.Core;
|
||||
|
||||
/// <summary>
|
||||
/// Represents an HSV color.
|
||||
/// </summary>
|
||||
/// <param name="hue">Hue of the <see cref="ColorHSVA"/>.</param>
|
||||
/// <param name="saturation">Saturation of the <see cref="ColorHSVA"/>.</param>
|
||||
/// <param name="value">Value of the <see cref="ColorHSVA"/>.</param>
|
||||
/// <param name="alpha">Alpha of the <see cref="ColorHSVA"/>.</param>
|
||||
/// <remarks>
|
||||
/// Initializes a new instance of the <see cref="ColorHSVA"/> struct with the specified values.
|
||||
/// </remarks>
|
||||
[System.Diagnostics.DebuggerDisplay("{ToString(),nq}")]
|
||||
public readonly struct ColorHSVA(float hue, float saturation, float value, float alpha = 1)
|
||||
{
|
||||
/// <summary>
|
||||
/// The Hue value of the <see cref="ColorHSVA"/>.
|
||||
/// </summary>
|
||||
public readonly float Hue = hue.Clamp(0f, 1f);
|
||||
|
||||
/// <summary>
|
||||
/// The Saturation value of the <see cref="ColorHSVA"/>.
|
||||
/// </summary>
|
||||
public readonly float Saturation = saturation.Clamp(0f, 1f);
|
||||
|
||||
/// <summary>
|
||||
/// The Value value of the <see cref="ColorHSVA"/>.
|
||||
/// </summary>
|
||||
public readonly float Value = value.Clamp(0f, 1f);
|
||||
|
||||
/// <summary>
|
||||
/// The Alpha value of the <see cref="ColorHSVA"/>.
|
||||
/// </summary>
|
||||
public readonly float Alpha = alpha;
|
||||
|
||||
public static ColorHSVA operator -(ColorHSVA color) => new(color.Hue.OneMinus(), color.Saturation.OneMinus(), color.Value.OneMinus(), color.Alpha);
|
||||
public static ColorHSVA operator +(ColorHSVA left, ColorHSVA right) => new(left.Hue + right.Hue, left.Saturation + right.Saturation, left.Value + right.Value, left.Alpha + right.Alpha);
|
||||
public static ColorHSVA operator -(ColorHSVA left, ColorHSVA right) => new(left.Hue - right.Hue, left.Saturation - right.Saturation, left.Value - right.Value, left.Alpha - right.Alpha);
|
||||
public static ColorHSVA operator *(ColorHSVA left, ColorHSVA right) => new(left.Hue * right.Hue, left.Saturation * right.Saturation, left.Value * right.Value, left.Alpha * right.Alpha);
|
||||
public static ColorHSVA operator *(ColorHSVA color, float value) => new(color.Hue * value, color.Saturation * value, color.Value * value, color.Alpha * value);
|
||||
public static ColorHSVA operator *(float value, ColorHSVA color) => new(color.Hue * value, color.Saturation * value, color.Value * value, color.Alpha * value);
|
||||
public static ColorHSVA operator /(ColorHSVA color, float value) => new(color.Hue / value, color.Saturation / value, color.Value / value, color.Alpha / value);
|
||||
public static bool operator ==(ColorHSVA left, ColorHSVA right) => left.Hue == right.Hue && left.Saturation == right.Saturation && left.Value == right.Value;
|
||||
public static bool operator !=(ColorHSVA left, ColorHSVA right) => left.Hue != right.Hue || left.Saturation != right.Saturation || left.Value != right.Value;
|
||||
|
||||
public static implicit operator ColorHSVA(ColorHSV hsv) => new(hsv.Hue, hsv.Saturation, hsv.Value, 1f);
|
||||
public static implicit operator ColorHSVA(ColorRGB rgb) => (ColorRGBA)rgb;
|
||||
public static implicit operator ColorHSVA(ColorRGBA rgba)
|
||||
{
|
||||
float hue;
|
||||
float saturation;
|
||||
float value;
|
||||
|
||||
float rd = rgba.R / 255f;
|
||||
float gd = rgba.G / 255f;
|
||||
float bd = rgba.B / 255f;
|
||||
|
||||
float max = Math.Max(rd, Math.Max(gd, bd));
|
||||
float min = Math.Min(rd, Math.Min(gd, bd));
|
||||
float delta = max - min;
|
||||
|
||||
if (delta.ApproximatelyEquals(0))
|
||||
hue = 0f;
|
||||
else if (max.ApproximatelyEquals(rd))
|
||||
hue = 60f * ((gd - bd) / delta % 6f);
|
||||
else if (max.ApproximatelyEquals(gd))
|
||||
hue = 60f * (((bd - rd) / delta) + 2f);
|
||||
else
|
||||
hue = 60f * (((rd - gd) / delta) + 4f);
|
||||
|
||||
if (hue < 0f)
|
||||
hue += 360f;
|
||||
|
||||
hue /= 360f;
|
||||
saturation = max.ApproximatelyEquals(0f) ? 0f : delta / max;
|
||||
value = max;
|
||||
|
||||
return new(hue, saturation, value, rgba.A / 255f);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Inverts the given <see cref="ColorHSVA"/>.
|
||||
/// </summary>
|
||||
/// <param name="color">The <see cref="ColorHSVA"/>.</param>
|
||||
/// <returns>The inverted <see cref="ColorHSVA"/>.</returns>
|
||||
public static ColorHSVA Invert(ColorHSVA color) => -color;
|
||||
|
||||
/// <summary>
|
||||
/// Adds two <see cref="ColorHSVA"/>s.
|
||||
/// </summary>
|
||||
/// <param name="left">The first <see cref="ColorHSVA"/>.</param>
|
||||
/// <param name="right">The second <see cref="ColorHSVA"/>.</param>
|
||||
/// <returns>The sum of the two <see cref="ColorHSVA"/>s.</returns>
|
||||
public static ColorHSVA Add(ColorHSVA left, ColorHSVA right) => left + right;
|
||||
|
||||
/// <summary>
|
||||
/// Subtracts one <see cref="ColorHSVA"/> from another.
|
||||
/// </summary>
|
||||
/// <param name="left">The <see cref="ColorHSVA"/> to subtract from.</param>
|
||||
/// <param name="right">The <see cref="ColorHSVA"/> to subtract.</param>
|
||||
/// <returns>The result of subtracting the second <see cref="ColorHSVA"/> from the first.</returns>
|
||||
public static ColorHSVA Subtract(ColorHSVA left, ColorHSVA right) => left - right;
|
||||
|
||||
/// <summary>
|
||||
/// Multiplies a <see cref="ColorHSVA"/> by a scalar value.
|
||||
/// </summary>
|
||||
/// <param name="color">The <see cref="ColorHSVA"/>.</param>
|
||||
/// <param name="value">The scalar value.</param>
|
||||
/// <returns>The result of multiplying the <see cref="ColorHSVA"/> by the scalar value.</returns>
|
||||
public static ColorHSVA Multiply(ColorHSVA color, float value) => color * value;
|
||||
|
||||
/// <summary>
|
||||
/// Divides a <see cref="ColorHSVA"/> by a scalar value.
|
||||
/// </summary>
|
||||
/// <param name="color">The <see cref="ColorHSVA"/>.</param>
|
||||
/// <param name="value">The scalar value.</param>
|
||||
/// <returns>The result of dividing the <see cref="ColorHSVA"/> by the scalar value.</returns>
|
||||
public static ColorHSVA Divide(ColorHSVA color, float value) => color / value;
|
||||
|
||||
/// <summary>
|
||||
/// Performs linear interpolation between two <see cref="ColorHSVA"/>s.
|
||||
/// </summary>
|
||||
/// <param name="from">The starting <see cref="ColorHSVA"/> (t = 0).</param>
|
||||
/// <param name="to">The ending <see cref="ColorHSVA"/> (t = 1).</param>
|
||||
/// <param name="t">The interpolation parameter.</param>
|
||||
/// <returns>The interpolated <see cref="ColorHSVA"/>.</returns>
|
||||
public static ColorHSVA Lerp(ColorHSVA from, ColorHSVA to, float t)
|
||||
{
|
||||
float hueDiff = to.Hue - from.Hue;
|
||||
float saturationDiff = to.Saturation - from.Saturation;
|
||||
float valueDiff = to.Value - from.Value;
|
||||
float alphaDiff = to.Alpha - from.Alpha;
|
||||
|
||||
return from + new ColorHSVA(hueDiff * t, saturationDiff * t, valueDiff * t, alphaDiff * t);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if two <see cref="ColorHSVA"/>s are approximately equal within a specified epsilon range.
|
||||
/// </summary>
|
||||
/// <param name="left">The first <see cref="ColorHSVA"/>.</param>
|
||||
/// <param name="right">The second <see cref="ColorHSVA"/>.</param>
|
||||
/// <param name="epsilon">The epsilon range.</param>
|
||||
/// <returns><see cref="true"/> if the <see cref="ColorHSVA"/>s are approximately equal; otherwise, <see cref="false"/>.</returns>
|
||||
public static bool ApproximatelyEquals(ColorHSVA left, ColorHSVA right, float epsilon = float.Epsilon)
|
||||
=> left.Hue.ApproximatelyEquals(right.Hue, epsilon) && left.Saturation.ApproximatelyEquals(right.Saturation, epsilon) && left.Value.ApproximatelyEquals(right.Value, epsilon);
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the specified object is equal to the current <see cref="ColorHSVA"/>.
|
||||
/// </summary>
|
||||
/// <param name="obj">The object to compare with the current <see cref="ColorHSVA"/>.</param>
|
||||
/// <returns><see cref="true"/> if the specified object is equal to the current <see cref="ColorHSVA"/>; otherwise, <see cref="false"/>.</returns>
|
||||
public override bool Equals(object? obj) => obj is ColorHSVA colorHSVA && this == colorHSVA;
|
||||
|
||||
/// <summary>
|
||||
/// Generates a hash code for the <see cref="ColorHSVA"/>.
|
||||
/// </summary>
|
||||
/// <returns>A hash code for the <see cref="ColorHSVA"/>.</returns>
|
||||
public override int GetHashCode() => System.HashCode.Combine(Hue, Saturation, Value);
|
||||
|
||||
/// <summary>
|
||||
/// Converts the <see cref="ColorHSVA"/> to its string representation.
|
||||
/// </summary>
|
||||
/// <returns>A string representation of the <see cref="ColorHSVA"/>.</returns>
|
||||
public override string ToString() => $"{nameof(ColorHSVA)}({Hue}, {Saturation}, {Value})";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Provides extension methods for <see cref="ColorHSVA"/> type.
|
||||
/// </summary>
|
||||
public static class ColorHSVAExtensions
|
||||
{
|
||||
/// <inheritdoc cref="ColorHSVA.Add(ColorHSVA, ColorHSVA)" />
|
||||
public static ColorHSVA Add(this ColorHSVA color, ColorHSVA value) => ColorHSVA.Add(color, value);
|
||||
|
||||
/// <inheritdoc cref="ColorHSVA.Subtract(ColorHSVA, ColorHSVA)" />
|
||||
public static ColorHSVA Subtract(this ColorHSVA color, ColorHSVA value) => ColorHSVA.Subtract(color, value);
|
||||
|
||||
/// <inheritdoc cref="ColorHSVA.Multiply(ColorHSVA, ColorHSVA)" />
|
||||
public static ColorHSVA Multiply(this ColorHSVA color, float value) => ColorHSVA.Multiply(color, value);
|
||||
|
||||
/// <inheritdoc cref="ColorHSVA.Divide(ColorHSVA, ColorHSVA)" />
|
||||
public static ColorHSVA Divide(this ColorHSVA color, float value) => ColorHSVA.Divide(color, value);
|
||||
|
||||
/// <inheritdoc cref="ColorHSVA.Lerp(ColorHSVA, ColorHSVA, float)" />
|
||||
public static ColorHSVA Lerp(this ColorHSVA from, ColorHSVA to, float t) => ColorHSVA.Lerp(from, to, t);
|
||||
|
||||
/// <inheritdoc cref="ColorHSVA.ApproximatelyEquals(ColorHSVA, ColorHSVA, float) " />
|
||||
public static bool ApproximatelyEquals(this ColorHSVA left, ColorHSVA right, float epsilon = float.Epsilon) => ColorHSVA.ApproximatelyEquals(left, right, epsilon);
|
||||
}
|
@ -38,30 +38,8 @@ public readonly struct ColorRGB(byte r, byte g, byte b)
|
||||
public static bool operator !=(ColorRGB left, ColorRGB right) => left.R != right.R || left.G != right.G || left.B != right.B;
|
||||
|
||||
public static implicit operator ColorRGB(ColorRGBA rgba) => new(rgba.R, rgba.G, rgba.B);
|
||||
public static implicit operator ColorRGB(ColorHSV hsv)
|
||||
{
|
||||
float hue = hsv.Hue * 360f;
|
||||
float chroma = hsv.Value * hsv.Saturation;
|
||||
float x = chroma * (1f - Math.Abs(hue / 60f % 2f - 1f));
|
||||
float m = hsv.Value - chroma;
|
||||
|
||||
float r1 = 0f;
|
||||
float g1 = 0f;
|
||||
float b1 = 0f;
|
||||
|
||||
if (hue < 60) { r1 = chroma; g1 = x; b1 = 0; }
|
||||
else if (hue < 120) { r1 = x; g1 = chroma; b1 = 0; }
|
||||
else if (hue < 180) { r1 = 0; g1 = chroma; b1 = x; }
|
||||
else if (hue < 240) { r1 = 0; g1 = x; b1 = chroma; }
|
||||
else if (hue < 300) { r1 = x; g1 = 0; b1 = chroma; }
|
||||
else if (hue <= 360) { r1 = chroma; g1 = 0; b1 = x; }
|
||||
|
||||
byte r = (byte)Math.RoundToInt((r1 + m) * 255);
|
||||
byte g = (byte)Math.RoundToInt((g1 + m) * 255);
|
||||
byte b = (byte)Math.RoundToInt((b1 + m) * 255);
|
||||
|
||||
return new(r, g, b);
|
||||
}
|
||||
public static implicit operator ColorRGB(ColorHSVA hsva) => (ColorRGBA)hsva;
|
||||
public static implicit operator ColorRGB(ColorHSV hsv) => (ColorRGBA)hsv;
|
||||
|
||||
/// <summary>
|
||||
/// Inverts the given <see cref="ColorRGB"/>.
|
||||
|
@ -44,7 +44,31 @@ public readonly struct ColorRGBA(byte r, byte g, byte b, byte a = 255)
|
||||
public static bool operator !=(ColorRGBA left, ColorRGBA right) => left.R != right.R || left.G != right.G || left.B != right.B || left.A != right.A;
|
||||
|
||||
public static implicit operator ColorRGBA(ColorRGB rgb) => new(rgb.R, rgb.G, rgb.B, 255);
|
||||
public static implicit operator ColorRGBA(ColorHSV hsv) => (ColorRGB)hsv;
|
||||
public static implicit operator ColorRGBA(ColorHSV hsv) => (ColorHSVA)hsv;
|
||||
public static implicit operator ColorRGBA(ColorHSVA hsva)
|
||||
{
|
||||
float hue = hsva.Hue * 360f;
|
||||
float chroma = hsva.Value * hsva.Saturation;
|
||||
float x = chroma * (1f - Math.Abs(hue / 60f % 2f - 1f));
|
||||
float m = hsva.Value - chroma;
|
||||
|
||||
float r1 = 0f;
|
||||
float g1 = 0f;
|
||||
float b1 = 0f;
|
||||
|
||||
if (hue < 60) { r1 = chroma; g1 = x; b1 = 0; }
|
||||
else if (hue < 120) { r1 = x; g1 = chroma; b1 = 0; }
|
||||
else if (hue < 180) { r1 = 0; g1 = chroma; b1 = x; }
|
||||
else if (hue < 240) { r1 = 0; g1 = x; b1 = chroma; }
|
||||
else if (hue < 300) { r1 = x; g1 = 0; b1 = chroma; }
|
||||
else if (hue <= 360) { r1 = chroma; g1 = 0; b1 = x; }
|
||||
|
||||
byte r = (byte)Math.RoundToInt((r1 + m) * 255);
|
||||
byte g = (byte)Math.RoundToInt((g1 + m) * 255);
|
||||
byte b = (byte)Math.RoundToInt((b1 + m) * 255);
|
||||
|
||||
return new(r, g, b, (byte)(hsva.Alpha * 255));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Inverts the given <see cref="ColorRGBA"/>.
|
||||
|
@ -5,11 +5,14 @@ namespace Syntriax.Engine.Systems.Tween;
|
||||
public static class TweenColorExtensions
|
||||
{
|
||||
public static ITween TweenColor(this ColorRGB initialColorRGB, ITweenManager tweenManager, float duration, ColorRGB targetColorRGB, System.Action<ColorRGB> setMethod)
|
||||
=> tweenManager.StartTween(duration, t => setMethod?.Invoke(initialColorRGB.Lerp(targetColorRGB, t)));
|
||||
=> TweenColor((ColorHSV)initialColorRGB, tweenManager, duration, (ColorHSV)targetColorRGB, color => setMethod?.Invoke(color));
|
||||
|
||||
public static ITween TweenColor(this ColorRGBA initialColorRGBA, ITweenManager tweenManager, float duration, ColorRGBA targetColorRGBA, System.Action<ColorRGBA> setMethod)
|
||||
=> tweenManager.StartTween(duration, t => setMethod?.Invoke(initialColorRGBA.Lerp(targetColorRGBA, t)));
|
||||
=> TweenColor((ColorHSVA)initialColorRGBA, tweenManager, duration, (ColorHSVA)targetColorRGBA, color => setMethod?.Invoke(color));
|
||||
|
||||
public static ITween TweenColor(this ColorHSV initialColorHSV, ITweenManager tweenManager, float duration, ColorHSV targetColorHSV, System.Action<ColorHSV> setMethod)
|
||||
=> tweenManager.StartTween(duration, t => setMethod?.Invoke(initialColorHSV.Lerp(targetColorHSV, t)));
|
||||
|
||||
public static ITween TweenColor(this ColorHSVA initialColorHSVA, ITweenManager tweenManager, float duration, ColorHSVA targetColorHSVA, System.Action<ColorHSVA> setMethod)
|
||||
=> tweenManager.StartTween(duration, t => setMethod?.Invoke(initialColorHSVA.Lerp(targetColorHSVA, t)));
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user