using DCFApixels.DragonECS.Core; using DCFApixels.DragonECS.Internal; using System; using System.Runtime.InteropServices; using System.Runtime.Serialization; namespace DCFApixels.DragonECS { public interface IMetaColor { #region Properties byte R { get; } byte G { get; } byte B { get; } byte A { get; } float FloatR { get; } float FloatG { get; } float FloatB { get; } float FloatA { get; } #endregion } [AttributeUsage(AttributeTargets.Struct | AttributeTargets.Class | AttributeTargets.Interface, Inherited = false, AllowMultiple = false)] public sealed class MetaColorAttribute : EcsMetaAttribute, IMetaColor { public readonly MetaColor color; #region Properties public byte R { get { return color.r; } } public byte G { get { return color.g; } } public byte B { get { return color.b; } } public byte A { get { return color.a; } } public float FloatR { get { return R / (float)byte.MaxValue; } } public float FloatG { get { return G / (float)byte.MaxValue; } } public float FloatB { get { return B / (float)byte.MaxValue; } } public float FloatA { get { return A / (float)byte.MaxValue; } } #endregion #region Constructors public MetaColorAttribute(byte r, byte g, byte b) { color = new MetaColor(r, g, b, 255); } public MetaColorAttribute(uint colorCode) { color = new MetaColor(colorCode, true); } #endregion } [Serializable] [DataContract] [StructLayout(LayoutKind.Explicit, Pack = 1, Size = 4)] public readonly struct MetaColor : IMetaColor, IEquatable { #region Consts public static readonly MetaColor BlackColor = new MetaColor(Black); /// color code Red. RGB is (255, 0, 0) public const uint Red = 0x_ff0000_ff; /// color code Green. RGB is (0, 255, 0) public const uint Green = 0x_00ff00_ff; /// color code Blue. RGB is (0, 0, 255) public const uint Blue = 0x_0000ff_ff; /// color code Yellow. RGB is (255, 255, 0) public const uint Yellow = 0x_ffff00_ff; /// color code Cyan. RGB is (0, 255, 255) public const uint Cyan = 0x_00ffff_ff; /// color code Magenta. RGB is (255, 0, 255) public const uint Magenta = 0x_ff00ff_ff; /// color code White. RGB is (255, 255, 255) public const uint White = 0x_ffffff_ff; /// color code Black. RGB is (0, 0, 0) public const uint Black = 0x_000000_ff; /// color code OrangeRed. RGB is (255, 69, 0) public const uint OrangeRed = 0x_ff4500_ff; /// color code Orange. RGB is (255, 165, 0) public const uint Orange = 0x_ffa500_ff; /// color code Purple. RGB is (128, 0, 128) public const uint Purple = 0x_800080_ff; /// color code Pink. RGB is (255, 192, 203) public const uint Pink = 0x_ffc0cb_ff; /// color code Brown. RGB is (165, 42, 42) public const uint Brown = 0x_a52a2a_ff; /// color code Grey/Gray. RGB is (128, 128, 128) public const uint Gray = 0x_808080_ff; /// color code Grey/Gray. RGB is (128, 128, 128) public const uint Grey = Gray; /// color code LightGray. RGB is (211, 211, 211) public const uint LightGray = 0x_d3d3d3_ff; /// color code DarkGray. RGB is (64, 64, 64) public const uint DarkGray = 0x_404040_ff; /// color code Lime. RGB is (125, 255, 0) public const uint Lime = 0x_7dff00_ff; /// color code Teal. RGB is (0, 128, 128) public const uint Teal = 0x_008080_ff; /// color code Olive. RGB is (128, 128, 0) public const uint Olive = 0x_808000_ff; /// color code Navy. RGB is (0, 0, 128) public const uint Navy = 0x_000080_ff; /// color code Maroon. RGB is (128, 0, 0) public const uint Maroon = 0x_800000_ff; /// color code Aquamarine. RGB is (127, 255, 212) public const uint Aquamarine = 0x_7fffd4_ff; /// color code Fuchsia. RGB is (255, 0, 255) public const uint Fuchsia = 0x_ff00ff_ff; /// color code Silver. RGB is (192, 192, 192) public const uint Silver = 0x_c0c0c0_ff; /// color code Gold. RGB is (255, 215, 0) public const uint Gold = 0x_ffd700_ff; /// color code Indigo. RGB is (75, 0, 130) public const uint Indigo = 0x_4b0082_ff; /// color code Violet. RGB is (238, 130, 238) public const uint Violet = 0x_ee82ee_ff; /// color code Coral. RGB is (255, 127, 80) public const uint Coral = 0x_ff7f50_ff; /// color code Salmon. RGB is (250, 128, 114) public const uint Salmon = 0x_fa8072_ff; /// color code Turquoise. RGB is (64, 224, 208) public const uint Turquoise = 0x_40e0d0_ff; /// color code SkyBlue. RGB is (135, 206, 235) public const uint SkyBlue = 0x_87ceeb_ff; /// color code Plum. RGB is (221, 160, 221) public const uint Plum = 0x_dda0dd_ff; /// color code Khaki. RGB is (213, 197, 138) public const uint Khaki = 0x_d5c58a_ff; /// color code Beige. RGB is (237, 232, 208) public const uint Beige = 0x_ede8d0_ff; /// color code Lavender. RGB is (230, 230, 250) public const uint Lavender = 0x_e6e6fa_ff; /// color code Goldenrod. RGB is (218, 165, 32) public const uint Goldenrod = 0x_daa520_ff; /// color code DeepPink. RGB is (255, 105, 180) public const uint DeepPink = 0x_ff69b4_ff; /// color code Crimson. RGB is (220, 20, 60) public const uint Crimson = 0x_dc143c_ff; /// color code BlueViolet. RGB is (138, 43, 226) public const uint BlueViolet = 0x_8a2be2_ff; /// color code AmericanRose. RGB is (255, 3, 62) public const uint AmericanRose = 0x_ff033e_ff; /// color code DragonRose. RGB is (255, 78, 133) public const uint DragonRose = 0x_ff4e85_ff; /// color code DragonCyan. RGB is (0, 255, 156) public const uint DragonCyan = 0x_00ff9c_ff; #endregion [FieldOffset(0), NonSerialized] public readonly uint colorCode; [FieldOffset(3), DataMember] public readonly byte r; [FieldOffset(2), DataMember] public readonly byte g; [FieldOffset(1), DataMember] public readonly byte b; [FieldOffset(0), DataMember] public readonly byte a; #region Properties byte IMetaColor.R { get { return r; } } byte IMetaColor.G { get { return g; } } byte IMetaColor.B { get { return b; } } byte IMetaColor.A { get { return a; } } public float FloatR { get { return r / (float)byte.MaxValue; } } public float FloatG { get { return g / (float)byte.MaxValue; } } public float FloatB { get { return b / (float)byte.MaxValue; } } public float FloatA { get { return a / (float)byte.MaxValue; } } #endregion #region Constructors public MetaColor(byte r, byte g, byte b) : this() { this.r = r; this.g = g; this.b = b; a = 255; } public MetaColor(byte r, byte g, byte b, byte a) : this() { this.r = r; this.g = g; this.b = b; this.a = a; } public MetaColor(uint colorCode) : this() { this.colorCode = colorCode; } public MetaColor(uint colorCode, bool withoutAlpha) : this() { this.colorCode = withoutAlpha ? colorCode | 255 : colorCode; } public MetaColor(string stringCode) : this() { unchecked { const uint MAGIC_CONST = 0xA638_783E; uint colorCode = (uint)stringCode.GetHashCode(); colorCode ^= MAGIC_CONST; colorCode = BitsUtility.NextXorShiftState(colorCode); this.colorCode = (uint)colorCode | 255; this.colorCode = UpContrast().colorCode; } } #endregion #region Deconstructs public void Deconstruct(out byte r, out byte g, out byte b) { r = this.r; g = this.g; b = this.b; } public void Deconstruct(out byte r, out byte g, out byte b, out byte a) { r = this.r; g = this.g; b = this.b; a = this.a; } #endregion #region Methods public MetaColor Desaturate(float t) { byte r = this.r; byte g = this.g; byte b = this.b; //byte gray = (byte)(r * 0.299 + g * 0.587 + b * 0.114); byte gray = (byte)(r * 0.333333 + g * 0.333333 + b * 0.333333); r = (byte)(r + (gray - r) * (1 - t)); g = (byte)(g + (gray - g) * (1 - t)); b = (byte)(b + (gray - b) * (1 - t)); return new MetaColor(r, g, b); } public MetaColor UpContrast() { byte minChannel = Math.Min(Math.Min(r, g), b); byte maxChannel = Math.Max(Math.Max(r, g), b); if (maxChannel == minChannel) { return default; } float factor = 255f / (maxChannel - minChannel); return new MetaColor((byte)((r - minChannel) * factor), (byte)((g - minChannel) * factor), (byte)((b - minChannel) * factor)); } #endregion #region Operators public static implicit operator MetaColor((byte, byte, byte) a) { return new MetaColor(a.Item1, a.Item2, a.Item3); } public static implicit operator MetaColor((byte, byte, byte, byte) a) { return new MetaColor(a.Item1, a.Item2, a.Item3, a.Item4); } public static implicit operator MetaColor(uint a) { return new MetaColor(a); } public static bool operator ==(MetaColor a, MetaColor b) { return a.colorCode == b.colorCode; } public static bool operator !=(MetaColor a, MetaColor b) { return a.colorCode != b.colorCode; } public static MetaColor operator /(MetaColor a, float b) { return new MetaColor( (byte)(a.r / b), (byte)(a.g / b), (byte)(a.b / b)); } public static MetaColor operator /(float b, MetaColor a) { return new MetaColor( (byte)(a.r / b), (byte)(a.g / b), (byte)(a.b / b)); } public static MetaColor operator /(MetaColor a, MetaColor b) { return new MetaColor( (byte)(a.r / b.r), (byte)(a.g / b.g), (byte)(a.b / b.b)); } public static MetaColor operator *(MetaColor a, float b) { return new MetaColor( (byte)(a.r * b), (byte)(a.g * b), (byte)(a.b * b)); } public static MetaColor operator *(float b, MetaColor a) { return new MetaColor( (byte)(a.r * b), (byte)(a.g * b), (byte)(a.b * b)); } public static MetaColor operator *(MetaColor a, MetaColor b) { return new MetaColor( (byte)(a.r * b.r), (byte)(a.g * b.g), (byte)(a.b * b.b)); } public static MetaColor operator +(MetaColor a, byte b) { return new MetaColor( (byte)(a.r + b), (byte)(a.g + b), (byte)(a.b + b)); } public static MetaColor operator +(byte b, MetaColor a) { return new MetaColor( (byte)(a.r + b), (byte)(a.g + b), (byte)(a.b + b)); } public static MetaColor operator +(MetaColor a, MetaColor b) { return new MetaColor( (byte)(a.r + b.r), (byte)(a.g + b.g), (byte)(a.b + b.b)); } public static MetaColor operator -(MetaColor a, byte b) { return new MetaColor( (byte)(a.r - b), (byte)(a.g - b), (byte)(a.b - b)); } public static MetaColor operator -(byte b, MetaColor a) { return new MetaColor( (byte)(a.r - b), (byte)(a.g - b), (byte)(a.b - b)); } public static MetaColor operator -(MetaColor a, MetaColor b) { return new MetaColor( (byte)(a.r - b.r), (byte)(a.g - b.g), (byte)(a.b - b.b)); } #endregion #region Other public override string ToString() { return $"({r}, {g}, {b}, {a})"; } public bool Equals(MetaColor other) { return colorCode == other.colorCode; } public override bool Equals(object obj) { return obj is MetaColor other && Equals(other); } public override int GetHashCode() { return unchecked((int)colorCode); } #endregion } }