diff --git a/src/Debug/Attributes/DebugColorAttribute.cs b/src/Debug/Attributes/DebugColorAttribute.cs index fe603dc..5ec68dd 100644 --- a/src/Debug/Attributes/DebugColorAttribute.cs +++ b/src/Debug/Attributes/DebugColorAttribute.cs @@ -6,89 +6,99 @@ namespace DCFApixels.DragonECS [AttributeUsage(AttributeTargets.Struct | AttributeTargets.Class, Inherited = false, AllowMultiple = false)] public sealed class DebugColorAttribute : Attribute { - private Color color; + public readonly DebugColor color; public byte r => color.r; public byte g => color.g; public byte b => color.b; - public DebugColorAttribute(byte r, byte g, byte b) => color = new Color(r, g, b); - public DebugColorAttribute(DebugColor color) => this.color = new Color((int)color); - - [StructLayout(LayoutKind.Explicit, Pack = 1, Size = 4)] - internal readonly struct Color - { - [FieldOffset(0)] public readonly int full; - [FieldOffset(3)] public readonly byte r; - [FieldOffset(2)] public readonly byte g; - [FieldOffset(1)] public readonly byte b; - public Color(byte r, byte g, byte b) : this() - { - this.r = r; - this.g = g; - this.b = b; - } - public Color(int full) : this() => this.full = full; - public (byte, byte, byte) ToTuple() => (r, g, b); - - public Color UpContrastColor() - { - 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 Color((byte)((r - minChannel) * factor), (byte)((g - minChannel) * factor), (byte)((b - minChannel) * factor)); - } - - public static Color operator /(Color a, float b) - { - return new Color((byte)(a.r / b), (byte)(a.g / b), (byte)(a.b / b)); - } - } + public DebugColorAttribute(byte r, byte g, byte b) => color = new DebugColor(r, g, b, 255); + public DebugColorAttribute(int colorCode) => color = new DebugColor(colorCode, true); } - public enum DebugColor + [StructLayout(LayoutKind.Explicit, Pack = 1, Size = 4)] + public readonly struct DebugColor { - /// Red. RGB is (255, 0, 0) - Red = (255 << 24) + (000 << 16) + (000 << 8), - /// Green. RGB is (0, 255, 0) - Green = (000 << 24) + (255 << 16) + (000 << 8), - /// Blue. RGB is (0, 0, 255) - Blue = (000 << 24) + (000 << 16) + (255 << 8), + public static readonly DebugColor BlackColor = new DebugColor(Black); + /// color code Red. RGB is (255, 0, 0) + public const int Red = (255 << 24) | (000 << 16) | (000 << 8) | 255; + /// color code Green. RGB is (0, 255, 0) + public const int Green = (000 << 24) | (255 << 16) | (000 << 8) | 255; + /// color code Blue. RGB is (0, 0, 255) + public const int Blue = (000 << 24) | (000 << 16) | (255 << 8) | 255; - /// Yellow. RGB is (255, 255, 0) - Yellow = (255 << 24) + (255 << 16) + (000 << 8), - /// Cyan. RGB is (0, 255, 255) - Cyan = (000 << 24) + (255 << 16) + (255 << 8), - /// Magenta. RGB is (255, 0, 255) - Magenta = (255 << 24) + (000 << 16) + (255 << 8), + /// color code Yellow. RGB is (255, 255, 0) + public const int Yellow = (255 << 24) | (255 << 16) | (000 << 8) | 255; + /// color code Cyan. RGB is (0, 255, 255) + public const int Cyan = (000 << 24) | (255 << 16) | (255 << 8) | 255; + /// color code Magenta. RGB is (255, 0, 255) + public const int Magenta = (255 << 24) | (000 << 16) | (255 << 8) | 255; - /// Yellow. RGB is (255, 165, 0) - Orange = (255 << 24) + (165 << 16) + (000 << 8), - /// Yellow. RGB is (255, 69, 0) - OrangeRed = (255 << 24) + (69 << 16) + (000 << 8), - /// Lime. RGB is (125, 255, 0) - Lime = (125 << 24) + (255 << 16) + (000 << 8), - /// Lime. RGB is (127, 255, 212) - Aquamarine = (127 << 24) + (255 << 16) + (212 << 8), - /// Lime. RGB is (218, 165, 32) - Goldenrod = (218 << 24) + (165 << 16) + (32 << 8), - /// Yellow. RGB is (255, 105, 180) - DeepPink = (255 << 24) + (105 << 16) + (180 << 8), - /// Yellow. RGB is (220, 20, 60) - Crimson = (220 << 24) + (20 << 16) + (60 << 8), - /// Yellow. RGB is (138, 43, 226) - BlueViolet = (138 << 24) + (43 << 16) + (226 << 8), - /// Yellow. RGB is (255, 3, 62) - AmericanRose = (255 << 24) + (3 << 16) + (62 << 8), + /// color code Orange. RGB is (255, 165, 0) + public const int Orange = (255 << 24) | (165 << 16) | (000 << 8) | 255; + /// color code OrangeRed. RGB is (255, 69, 0) + public const int OrangeRed = (255 << 24) | (69 << 16) | (000 << 8) | 255; + /// color code Lime. RGB is (125, 255, 0) + public const int Lime = (125 << 24) | (255 << 16) | (000 << 8) | 255; + /// color code Aquamarine. RGB is (127, 255, 212) + public const int Aquamarine = (127 << 24) | (255 << 16) | (212 << 8) | 255; + /// color code Goldenrod. RGB is (218, 165, 32) + public const int Goldenrod = (218 << 24) | (165 << 16) | (32 << 8) | 255; + /// color code DeepPink. RGB is (255, 105, 180) + public const int DeepPink = (255 << 24) | (105 << 16) | (180 << 8) | 255; + /// color code Crimson. RGB is (220, 20, 60) + public const int Crimson = (220 << 24) | (20 << 16) | (60 << 8) | 255; + /// color code BlueViolet. RGB is (138, 43, 226) + public const int BlueViolet = (138 << 24) | (43 << 16) | (226 << 8) | 255; + /// color code AmericanRose. RGB is (255, 3, 62) + public const int AmericanRose = (255 << 24) | (3 << 16) | (62 << 8) | 255; - /// Grey/Gray. RGB is (127, 127, 127) - Gray = (127 << 24) + (127 << 16) + (127 << 8), - /// Grey/Gray. RGB is (127, 127, 127) - Grey = Gray, - /// Grey/Gray. RGB is (192, 192, 192) - Silver = (192 << 24) + (192 << 16) + (192 << 8), - /// White. RGB is (255, 255, 255) - White = -1, - /// Black. RGB is (0, 0, 0) - Black = 0, + /// color code Grey/Gray. RGB is (127, 127, 127) + public const int Gray = (127 << 24) | (127 << 16) | (127 << 8) | 255; + /// color code Grey/Gray. RGB is (127, 127, 127) + public const int Grey = Gray; + /// color code Silver. RGB is (192, 192, 192) + public const int Silver = (192 << 24) | (192 << 16) | (192 << 8) | 255; + /// color code White. RGB is (255, 255, 255) + public const int White = -1; + /// color code Black. RGB is (0, 0, 0) + public const int Black = 0; + + + [FieldOffset(0)] public readonly int colorCode; + [FieldOffset(3)] public readonly byte r; + [FieldOffset(2)] public readonly byte g; + [FieldOffset(1)] public readonly byte b; + [FieldOffset(0)] public readonly byte a; + public DebugColor(byte r, byte g, byte b) : this() + { + this.r = r; + this.g = g; + this.b = b; + a = 255; + } + public DebugColor(byte r, byte g, byte b, byte a) : this() + { + this.r = r; + this.g = g; + this.b = b; + this.a = a; + } + public DebugColor(int colorCode) : this() => this.colorCode = colorCode; + public DebugColor(int colorCode, bool withoutAlpha) : this() => this.colorCode = withoutAlpha ? colorCode | 255 : colorCode; + public (byte, byte, byte) ToTupleRGB() => (r, g, b); + public (byte, byte, byte, byte) ToTupleRGBA() => (r, g, b, a); + + public DebugColor UpContrastColor() + { + 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 DebugColor((byte)((r - minChannel) * factor), (byte)((g - minChannel) * factor), (byte)((b - minChannel) * factor)); + } + public static DebugColor operator /(DebugColor a, float b) + { + return new DebugColor((byte)(a.r / b), (byte)(a.g / b), (byte)(a.b / b)); + } + //public static explicit operator DebugColor(int colorCode) => new DebugColor(colorCode); } } \ No newline at end of file diff --git a/src/Debug/Attributes/DebugGroupAttribute.cs b/src/Debug/Attributes/DebugGroupAttribute.cs new file mode 100644 index 0000000..e0c7567 --- /dev/null +++ b/src/Debug/Attributes/DebugGroupAttribute.cs @@ -0,0 +1,33 @@ +using System; +using System.Text.RegularExpressions; + +namespace DCFApixels.DragonECS +{ + [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct, Inherited = false, AllowMultiple = false)] + public sealed class DebugGroupAttribute : Attribute + { + public static readonly DebugGroupAttribute Empty = new DebugGroupAttribute(""); + public readonly string name; + public readonly string rootCategory; + public DebugGroupAttribute(string name) + { + name = Regex.Replace(name, @"^[/|\\]+|[/|\\]+$", ""); + rootCategory = Regex.Match(name, @"^(.*?)[/\\]").Groups[1].Value; + this.name = name; + } + public string[] SplitCategories() + { + return Regex.Split(name, @"[/|\\]"); + } + public DebugGroup GetData() => new DebugGroup(this); + } + public readonly struct DebugGroup + { + public static readonly DebugGroup Empty = new DebugGroup(DebugGroupAttribute.Empty); + private readonly DebugGroupAttribute _source; + public string Name => _source.name; + public string RootCategory => _source.rootCategory; + public DebugGroup(DebugGroupAttribute source) => _source = source; + public string[] SplitCategories() => _source.SplitCategories(); + } +} diff --git a/src/Debug/Attributes/DebugGroupAttribute.cs.meta b/src/Debug/Attributes/DebugGroupAttribute.cs.meta new file mode 100644 index 0000000..594d6fb --- /dev/null +++ b/src/Debug/Attributes/DebugGroupAttribute.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: c447392c75f8b4a42a2e5c3eb49e5b82 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/src/Debug/EcsDebugUtility.cs b/src/Debug/EcsDebugUtility.cs index 7985286..803c9b6 100644 --- a/src/Debug/EcsDebugUtility.cs +++ b/src/Debug/EcsDebugUtility.cs @@ -72,6 +72,22 @@ namespace DCFApixels.DragonECS } #endregion + #region GetGroup + public static DebugGroup GetGroup() => GetGroup(typeof(T)); + public static DebugGroup GetGroup(Type type) => type.TryGetCustomAttribute(out DebugGroupAttribute atr) ? atr.GetData() : DebugGroup.Empty; + public static bool TryGetGroup(out DebugGroup text) => TryGetGroup(typeof(T), out text); + public static bool TryGetGroup(Type type, out DebugGroup group) + { + if (type.TryGetCustomAttribute(out DebugGroupAttribute atr)) + { + group = atr.GetData(); + return true; + } + group = DebugGroup.Empty; + return false; + } + #endregion + #region GetDescription public static string GetDescription() => GetDescription(typeof(T)); public static string GetDescription(Type type) => type.TryGetCustomAttribute(out DebugDescriptionAttribute atr) ? atr.description : string.Empty; @@ -94,7 +110,7 @@ namespace DCFApixels.DragonECS private class WordColor { public int wordsCount; - public DebugColorAttribute.Color color; + public DebugColor color; } private class NameColor { @@ -107,7 +123,7 @@ namespace DCFApixels.DragonECS { color = new WordColor(); _words.Add(word, color); - color.color = new DebugColorAttribute.Color((byte)random.Next(), (byte)random.Next(), (byte)random.Next()).UpContrastColor() / 2; + color.color = new DebugColor((byte)random.Next(), (byte)random.Next(), (byte)random.Next()).UpContrastColor() / 2; } color.wordsCount++; colors.Add(color); @@ -122,7 +138,7 @@ namespace DCFApixels.DragonECS } return result; } - public DebugColorAttribute.Color CalcColor() + public DebugColor CalcColor() { float r = 0, g = 0, b = 0; int totalWordsCount = CalcTotalWordsColor(); @@ -134,11 +150,11 @@ namespace DCFApixels.DragonECS g += m * color.color.g; b += m * color.color.b; } - return new DebugColorAttribute.Color((byte)r, (byte)g, (byte)b); + return new DebugColor((byte)r, (byte)g, (byte)b); } } private static Dictionary _names = new Dictionary(); - private static DebugColorAttribute.Color CalcNameColorFor(Type type) + private static DebugColor CalcNameColorFor(Type type) { Type targetType = type.IsGenericType ? type.GetGenericTypeDefinition() : type; if (!_names.TryGetValue(targetType, out NameColor nameColor)) @@ -169,27 +185,27 @@ namespace DCFApixels.DragonECS return words; } - public static (byte, byte, byte) GetColorRGB() => GetColorRGB(typeof(T)); - public static (byte, byte, byte) GetColorRGB(Type type) + public static DebugColor GetColor() => GetColor(typeof(T)); + public static DebugColor GetColor(Type type) { var atr = type.GetCustomAttribute(); - return atr != null ? (atr.r, atr.g, atr.b) + return atr != null ? atr.color #if DEBUG //optimization for release build - : CalcNameColorFor(type).ToTuple(); -#else - : ((byte)0, (byte)0, (byte)0); + : CalcNameColorFor(type); +#else + : DebugColor.BlackColor; #endif } - public static bool TryGetColorRGB(out (byte, byte, byte) color) => TryGetColorRGB(typeof(T), out color); - public static bool TryGetColorRGB(Type type, out (byte, byte, byte) color) + public static bool TryGetColor(out DebugColor color) => TryGetColor(typeof(T), out color); + public static bool TryGetColor(Type type, out DebugColor color) { var atr = type.GetCustomAttribute(); if (atr != null) { - color = (atr.r, atr.g, atr.b); + color = atr.color; return true; } - color = ((byte)0, (byte)0, (byte)0); + color = DebugColor.BlackColor; return false; } #endregion @@ -199,6 +215,20 @@ namespace DCFApixels.DragonECS public static bool IsHidden(Type type) => type.TryGetCustomAttribute(out DebugHideAttribute _); #endregion + #region GenerateTypeDebugData + public static TypeDebugData GenerateTypeDebugData() => GenerateTypeDebugData(typeof(T)); + public static TypeDebugData GenerateTypeDebugData(Type type) + { + return new TypeDebugData( + type, + GetName(type), + GetGroup(type), + GetColor(type), + GetDescription(type), + IsHidden(type)); + } + #endregion + #region ReflectionExtensions internal static bool TryGetCustomAttribute(this Type self, out T attribute) where T : Attribute { @@ -212,4 +242,24 @@ namespace DCFApixels.DragonECS } #endregion } + + [Serializable] + public sealed class TypeDebugData + { + public readonly Type type; + public readonly string name; + public readonly DebugGroup group; + public readonly DebugColor color; + public readonly string description; + public readonly bool isHidden; + public TypeDebugData(Type type, string name, DebugGroup group, DebugColor color, string description, bool isHidden) + { + this.type = type; + this.name = name; + this.group = group; + this.color = color; + this.description = description; + this.isHidden = isHidden; + } + } } diff --git a/src/Utils/EcsTypeCode.cs b/src/Utils/EcsTypeCode.cs index 77d26f2..b18b4af 100644 --- a/src/Utils/EcsTypeCode.cs +++ b/src/Utils/EcsTypeCode.cs @@ -21,7 +21,7 @@ namespace DCFApixels.DragonECS public static int Count => _codes.Count; internal static class Cache { - public static readonly int code = EcsTypeCode.GetCode(typeof(T)); + public static readonly int code = GetCode(typeof(T)); } } }