diff --git a/src/Debug/Attributes/DebugColorAttribute.cs b/src/Debug/Attributes/DebugColorAttribute.cs index 4130b30..75b8bc7 100644 --- a/src/Debug/Attributes/DebugColorAttribute.cs +++ b/src/Debug/Attributes/DebugColorAttribute.cs @@ -6,27 +6,43 @@ namespace DCFApixels.DragonECS [AttributeUsage(AttributeTargets.Struct | AttributeTargets.Class, Inherited = false, AllowMultiple = false)] public sealed class DebugColorAttribute : Attribute { - private ColorRecord color; + private Color 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 ColorRecord(r, g, b); - public DebugColorAttribute(DebugColor color) => this.color = new ColorRecord((int)color); + 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)] - private readonly struct ColorRecord + 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 ColorRecord(byte r, byte g, byte b) : this() + public Color(byte r, byte g, byte b) : this() { this.r = r; this.g = g; this.b = b; } - public ColorRecord(int full) : this() => this.full = full; + 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 enum DebugColor diff --git a/src/Debug/EcsDebugUtility.cs b/src/Debug/EcsDebugUtility.cs index e6f6bf3..caacd1a 100644 --- a/src/Debug/EcsDebugUtility.cs +++ b/src/Debug/EcsDebugUtility.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Reflection; namespace DCFApixels.DragonECS @@ -40,6 +41,18 @@ namespace DCFApixels.DragonECS var atr = type.GetCustomAttribute(); return atr != null ? atr.name : GetGenericTypeName(type); } + public static bool TryGetCustomName(out string name) => TryGetCustomName(typeof(T), out name); + public static bool TryGetCustomName(Type type, out string name) + { + var atr = type.GetCustomAttribute(); + if (atr != null) + { + name = atr.name; + return true; + } + name = string.Empty; + return false; + } public static string GetDescription() => GetDescription(typeof(T)); public static string GetDescription(Type type) @@ -47,13 +60,124 @@ namespace DCFApixels.DragonECS var atr = type.GetCustomAttribute(); return atr != null ? atr.description : string.Empty; } + public static bool TryGetDescription(out string text) => TryGetDescription(typeof(T), out text); + public static bool TryGetDescription(Type type, out string text) + { + var atr = type.GetCustomAttribute(); + if (atr != null) + { + text = atr.description; + return true; + } + text = string.Empty; + return false; + } + + #region GetColor + private static Random random = new Random(); + private static Dictionary _words = new Dictionary(); + private class WordColor + { + public int wordsCount; + public DebugColorAttribute.Color color; + } + private class NameColor + { + public List colors = new List(); + public NameColor(IEnumerable nameWords) + { + foreach (var word in nameWords) + { + if(!_words.TryGetValue(word, out WordColor color)) + { + color = new WordColor(); + _words.Add(word, color); + color.color = new DebugColorAttribute.Color((byte)random.Next(), (byte)random.Next(), (byte)random.Next()).UpContrastColor() / 2; + } + color.wordsCount++; + colors.Add(color); + } + } + private int CalcTotalWordsColor() + { + int result = 0; + for (int i = 0, iMax = colors.Count; i < iMax; i++) + { + result += colors[i].wordsCount; + } + return result; + } + public DebugColorAttribute.Color CalcColor() + { + float r = 0, g = 0, b = 0; + int totalWordsCount = CalcTotalWordsColor(); + for (int i = 0, iMax = colors.Count; i < iMax; i++) + { + var color = colors[i]; + float m = (float)color.wordsCount / totalWordsCount; + r += m * color.color.r; + g += m * color.color.g; + b += m * color.color.b; + } + return new DebugColorAttribute.Color((byte)r, (byte)g, (byte)b); + } + } + private static Dictionary _names = new Dictionary(); + private static DebugColorAttribute.Color CalcNameColorFor(Type type) + { + Type targetType = type.IsGenericType ? type.GetGenericTypeDefinition() : type; + if(!_names.TryGetValue(targetType, out NameColor nameColor)) + { + nameColor = new NameColor(SplitString(targetType.Name)); + _names.Add(targetType, nameColor); + } + return nameColor.CalcColor(); + } + public static List SplitString(string s) + { + string subs; + List words = new List(); + int start = 0; + for (int i = 1; i < s.Length; i++) + { + if (char.IsUpper(s[i])) + { + subs = s.Substring(start, i - start); + if (subs.Length > 2 && subs.ToLower() != "system") + words.Add(subs); + start = i; + } + } + subs = s.Substring(start); + if (subs.Length > 2 && subs.ToLower() != "system") + words.Add(subs); + return words; + } public static (byte, byte, byte) GetColorRGB() => GetColorRGB(typeof(T)); public static (byte, byte, byte) GetColorRGB(Type type) { var atr = type.GetCustomAttribute(); - return atr != null ? (atr.r, atr.g, atr.b) : ((byte)255, (byte)255, (byte)255); + return atr != null ? (atr.r, atr.g, atr.b) +#if DEBUG //optimization for release build + : CalcNameColorFor(type).ToTuple(); +#else + : ((byte)0, (byte)0, (byte)0); +#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) + { + var atr = type.GetCustomAttribute(); + if(atr != null) + { + color = (atr.r, atr.g, atr.b); + return true; + } + color = ((byte)0, (byte)0, (byte)0); + return false; + } + #endregion public static bool IsHidden() => IsHidden(typeof(T)); public static bool IsHidden(Type type) diff --git a/src/EcsWorld.cs b/src/EcsWorld.cs index aa183fb..86c1329 100644 --- a/src/EcsWorld.cs +++ b/src/EcsWorld.cs @@ -385,15 +385,11 @@ namespace DCFApixels.DragonECS { list.Clear(); var itemsCount = GetComponentsCount(entityID); - if (itemsCount == 0) - return; for (var i = 0; i < _pools.Length; i++) { if (_pools[i].Has(entityID)) list.Add(_pools[i].GetRaw(entityID)); - if (list.Count >= itemsCount) - break; } } #endregion