// Copyright (c) Xenko contributors (https://xenko.com) and Silicon Studio Corp. (https://www.siliconstudio.co.jp) // Distributed under the MIT license. See the LICENSE.md file in the project root for more information. using System; using System.Globalization; using System.Runtime.InteropServices; using System.Runtime.Serialization; namespace math { /// /// Represents a color in the form of Hue, Saturation, Value, Alpha. /// [DataContract( Name = "ColorHSV" )] [StructLayout( LayoutKind.Sequential, Pack = 4 )] public struct ColorHSV : IEquatable, IFormattable { private const string ToStringFormat = "Hue:{0} Saturation:{1} Value:{2} Alpha:{3}"; /// /// The Hue of the color. /// [DataMember( Order = 0 )] public float H; /// /// The Saturation of the color. /// [DataMember( Order = 1 )] public float S; /// /// The Value of the color. /// [DataMember( Order = 2 )] public float V; /// /// The alpha component of the color. /// [DataMember( Order = 3 )] public float A; /// /// Initializes a new instance of the struct. /// /// The h. /// The s. /// The v. /// A. public ColorHSV( float h, float s, float v, float a ) { H = h; S = s; V = v; A = a; } /// /// Converts the color into a three component vector. /// /// A three component vector containing the red, green, and blue components of the color. public Color4 ToColor() { float hdiv = H / 60; int hi = (int)hdiv; float f = hdiv - hi; float p = V * ( 1 - S ); float q = V * ( 1 - ( S * f ) ); float t = V * ( 1 - ( S * ( 1 - f ) ) ); switch( hi ) { case 0: return new Color4( V, t, p, A ); case 1: return new Color4( q, V, p, A ); case 2: return new Color4( p, V, t, A ); case 3: return new Color4( p, q, V, A ); case 4: return new Color4( t, p, V, A ); default: return new Color4( V, p, q, A ); } } /// /// Converts the color into a HSV color. /// /// The color. /// A HSV color public static ColorHSV FromColor( Color4 color ) { float max = Math.Max( color.R, Math.Max( color.G, color.B ) ); float min = Math.Min( color.R, Math.Min( color.G, color.B ) ); float delta = max - min; float h = 0.0f; if( delta > 0.0f ) { if( color.R >= max ) h = ( color.G - color.B ) / delta; else if( color.G >= max ) h = ( color.B - color.R ) / delta + 2.0f; else h = ( color.R - color.G ) / delta + 4.0f; h *= 60.0f; if( h < 0 ) h += 360f; } float s = MathUtil.IsZero( max ) ? 0.0f : delta / max; return new ColorHSV( h, s, max, color.A ); } /// public bool Equals( ColorHSV other ) { return other.H.Equals( H ) && other.S.Equals( S ) && other.V.Equals( V ) && other.A.Equals( A ); } /// public override bool Equals( object obj ) { if( ReferenceEquals( null, obj ) ) return false; if( obj.GetType() != typeof( ColorHSV ) ) return false; return Equals( (ColorHSV)obj ); } /// public override int GetHashCode() { unchecked { int result = H.GetHashCode(); result = ( result * 397 ) ^ S.GetHashCode(); result = ( result * 397 ) ^ V.GetHashCode(); result = ( result * 397 ) ^ A.GetHashCode(); return result; } } /// /// Returns a that represents this instance. /// /// /// A that represents this instance. /// public override string ToString() { return ToString( CultureInfo.CurrentCulture ); } /// /// Returns a that represents this instance. /// /// The format. /// /// A that represents this instance. /// public string ToString( string format ) { return ToString( format, CultureInfo.CurrentCulture ); } /// /// Returns a that represents this instance. /// /// The format provider. /// /// A that represents this instance. /// public string ToString( IFormatProvider formatProvider ) { return string.Format( formatProvider, ToStringFormat, H, S, V, A ); } /// /// Returns a that represents this instance. /// /// The format. /// The format provider. /// /// A that represents this instance. /// public string ToString( string format, IFormatProvider formatProvider ) { if( format == null ) return ToString( formatProvider ); return string.Format( formatProvider, ToStringFormat, H.ToString( format, formatProvider ), S.ToString( format, formatProvider ), V.ToString( format, formatProvider ), A.ToString( format, formatProvider ) ); } } }