#undef DEBUG #if DEBUG #define DEV_MODE #endif using UnityEngine; using System.Collections.Generic; using System.Linq; using System; using Unity.Collections.LowLevel.Unsafe; using System.Buffers; #if UNITY_EDITOR using UnityEditor; #endif namespace DCFApixels { using IN = System.Runtime.CompilerServices.MethodImplAttribute; public static unsafe partial class DebugX { #region Utils Methods private static string GetGenericTypeName_Internal(Type type, int maxDepth, bool isFull) { #if (DEBUG && !DISABLE_DEBUG) || !REFLECTION_DISABLED //в дебажных утилитах REFLECTION_DISABLED только в релизном билде работает string typeName = isFull ? type.FullName : type.Name; if (!type.IsGenericType || maxDepth == 0) { return typeName; } int genericInfoIndex = typeName.LastIndexOf('`'); if (genericInfoIndex > 0) { typeName = typeName.Remove(genericInfoIndex); } string genericParams = ""; Type[] typeParameters = type.GetGenericArguments(); for (int i = 0; i < typeParameters.Length; ++i) { //чтобы строка не была слишком длинной, используются сокращенные имена для типов аргументов string paramTypeName = GetGenericTypeName_Internal(typeParameters[i], maxDepth - 1, false); genericParams += (i == 0 ? paramTypeName : $", {paramTypeName}"); } return $"{typeName}<{genericParams}>"; #else Debug.LogWarning($"Reflection is not available, the {nameof(GetGenericTypeName_Internal)} method does not work."); return isFull ? type.FullName : type.Name; #endif } [IN(LINE)] public static float FastMagnitude(Vector3 v) { return FastSqrt(v.x * v.x + v.y * v.y + v.z * v.z); } [IN(LINE)] private static unsafe float FastSqrt(float number) { long i; float x2, y; const float threehalfs = 1.5F; x2 = number * 0.5F; y = number; i = *(long*)&y; // evil floating point bit level hacking i = 0x5f3759df - (i >> 1); // what the fuck? y = *(float*)&i; y = y * (threehalfs - (x2 * y * y)); // 1st iteration //y = y * ( threehalfs - ( x2 * y * y ) ); // 2nd iteration, this can be removed return 1 / y; } [IN(LINE)] private static int NextPow2(int v) { v--; v |= v >> 1; v |= v >> 2; v |= v >> 4; v |= v >> 8; v |= v >> 16; return ++v; } private static Color[] _setColorBuffer = new Color[64]; [IN(LINE)] static void AddColorsToMesh(Mesh mesh, Color color) { int vertexCount = mesh.vertexCount; if (_setColorBuffer.Length < vertexCount) { _setColorBuffer = new Color[NextPow2(vertexCount)]; } for (int i = 0; i < mesh.vertexCount; i++) { _setColorBuffer[i] = color; } mesh.SetColors(_setColorBuffer, 0, vertexCount); } [IN(LINE)] private static bool IsGizmosRender() { bool result = true; #if UNITY_EDITOR result = Handles.ShouldRenderGizmos(); #endif return result; } #endregion #region private StructList private interface IStructListElement { void OnSwap(ref T element); } private struct StructList { internal Array _items; internal int _count; internal readonly bool _isUseArrayPool; private StructList(Array items, int count, bool isUseArrayPool) { _items = items; _count = count; _isUseArrayPool = isUseArrayPool; } public static StructList ConvertFrom(StructList list) { return new StructList(list._items, list._count, list._isUseArrayPool); } } [System.Diagnostics.DebuggerDisplay("Count: {Count}")] private struct StructList : IDisposable { //private struct Dummy : IStructListElement //{ // public void OnSwap(ref T element) { } //} //private static IStructListElement _internal = default(T) as IStructListElement ?? default(Dummy); internal T[] _items; internal int _count; internal readonly bool _isUseArrayPool; private static readonly bool _isUnmanaged = UnsafeUtility.IsUnmanaged(); public bool IsCreated { [IN(LINE)] get { return _items != null; } } public int Count { [IN(LINE)] get { return _count; } } public int Capacity { [IN(LINE)] get { return _items.Length; } set { UpSize(value); } } public T this[int index] { [IN(LINE)] get { #if DEV_MODE if (index < 0 || index >= _count) { new ArgumentOutOfRangeException(); } #endif return _items[index]; } [IN(LINE)] set { #if DEV_MODE if (index < 0 || index >= _count) { new ArgumentOutOfRangeException(); } #endif _items[index] = value; } } [IN(LINE)] public StructList(int minCapacity, bool useArrayPool = false) { minCapacity = NextPow2(minCapacity); if (useArrayPool) { _items = ArrayPool.Shared.Rent(minCapacity); } else { _items = new T[minCapacity]; } _count = 0; _isUseArrayPool = useArrayPool; } private StructList(StructList list) { _items = (T[])list._items; _count = list._count; _isUseArrayPool = list._isUseArrayPool; } [IN(LINE)] public void Add(T item) { UpSize(_count + 1); //_internal.OnSwap(ref item); _items[_count++] = item; } [IN(LINE)] public void AddRange(ReadOnlySpan items) { UpSize(_count + items.Length); for (int i = 0; i < items.Length; i++) { //_internal.OnSwap(ref item); _items[_count++] = items[i]; } } public void UpSize(int newMinSize) { if (newMinSize <= _items.Length) { return; } newMinSize = NextPow2(newMinSize); if (newMinSize <= _items.Length) { return; } if (_isUseArrayPool) { var newItems = ArrayPool.Shared.Rent(newMinSize); for (int i = 0, iMax = _count; i < iMax; i++) { newItems[i] = _items[i]; } ArrayPool.Shared.Return(_items, !_isUnmanaged); _items = newItems; } else { Array.Resize(ref _items, newMinSize); } } [IN(LINE)] public int IndexOf(T item) { return Array.IndexOf(_items, item, 0, _count); } [IN(LINE)] public void SwapAt(int idnex1, int idnex2) { T tmp = _items[idnex1]; _items[idnex1] = _items[idnex2]; _items[idnex2] = tmp; //_internal.OnSwap(ref _items[idnex1]); //_internal.OnSwap(ref _items[idnex2]); } [IN(LINE)] public void FastRemoveAt(int index) { #if DEV_MODE if (index < 0 || index >= _count) { new ArgumentOutOfRangeException(); } #endif _items[index] = _items[--_count]; //_internal.OnSwap(ref _items[index]); } [IN(LINE)] public void RemoveAt(int index) { #if DEV_MODE if (index < 0 || index >= _count) { new ArgumentOutOfRangeException(); } #endif _items[index] = _items[--_count]; //_internal.OnSwap(ref _items[index]); _items[_count] = default; } [IN(LINE)] public void RemoveAtWithOrder(int index) { #if DEV_MODE if (index < 0 || index >= _count) { new ArgumentOutOfRangeException(); } #endif for (int i = index; i < _count; i++) { _items[i] = _items[i + 1]; //_internal.OnSwap(ref _items[i]); } } [IN(LINE)] public bool Remove(T item) { int index = IndexOf(item); if (index >= 0) { RemoveAt(index); return true; } return false; } [IN(LINE)] public bool RemoveWithOrder(T item) { int index = IndexOf(item); if (index >= 0) { RemoveAtWithOrder(index); return true; } return false; } [IN(LINE)] public void FastClear() { _count = 0; } [IN(LINE)] public void Clear() { for (int i = 0; i < _count; i++) { _items[i] = default; } _count = 0; } [IN(LINE)] public ReadOnlySpan.Enumerator GetEnumerator() { return new ReadOnlySpan(_items, 0, _count).GetEnumerator(); } [IN(LINE)] public Span AsSpan() { return new Span(_items, 0, _count); } [IN(LINE)] public ReadOnlySpan AsReadOnlySpan() { return new ReadOnlySpan(_items, 0, _count); } [IN(LINE)] public IEnumerable ToEnumerable() { return _items.Take(_count); } [IN(LINE)] private static int NextPow2(int v) { v--; v |= v >> 1; v |= v >> 2; v |= v >> 4; v |= v >> 8; v |= v >> 16; return ++v; } public void Dispose() { if (_isUseArrayPool) { ArrayPool.Shared.Return(_items); } _items = null; _count = 0; } public static implicit operator StructList(StructList a) => StructList.ConvertFrom(a); public static explicit operator StructList(StructList a) => new StructList(a); } #endregion #region private PinnedArray private static class DummyArray { private readonly static T[] _array = new T[2]; public static T[] Get() { return _array; } } private readonly struct PinnedArray : IDisposable where T : unmanaged { public readonly T[] Array; public readonly T* Ptr; public readonly ulong Handle; public PinnedArray(T[] array, T* ptr, ulong handle) { Array = array; Ptr = ptr; Handle = handle; } public static PinnedArray Pin(T[] array) { return new PinnedArray(array, (T*)UnsafeUtility.PinGCArrayAndGetDataAddress(array, out ulong handle), handle); } public void Dispose() { if (Ptr != null) { UnsafeUtility.ReleaseGCObject(Handle); } } public PinnedArray As() where U : unmanaged { T[] array = Array; U[] newArray = UnsafeUtility.As(ref array); return new PinnedArray(newArray, (U*)Ptr, Handle); } } #endregion } }