| using System; | 
| using NUnit.Framework.Constraints; | 
| using UnityEngine; | 
| using System.Collections.Generic; | 
| using Treemap; | 
| using UnityEditor; | 
| using Assets.Editor.Treemap; | 
| using System.Linq; | 
| using UnityEngine.UI; | 
|   | 
| namespace MemoryProfilerWindow | 
| { | 
|     public class TreeMapView | 
|     { | 
|         CrawledMemorySnapshot _unpackedCrawl; | 
|         private ZoomArea _ZoomArea; | 
|         private Dictionary<string, Group> _groups = new Dictionary<string, Group>(); | 
|         private List<Item> _items = new List<Item>(); | 
|         private List<Mesh> _cachedMeshes = new List<Mesh>(); | 
|         private Item _selectedItem; | 
|         private Group _selectedGroup; | 
|         private Item _mouseDownItem; | 
|   | 
|         MemoryProfilerWindow _hostWindow; | 
|   | 
|         private Vector2 mouseTreemapPosition { get { return _ZoomArea.ViewToDrawingTransformPoint(Event.current.mousePosition); } } | 
|   | 
|         public void Setup(MemoryProfilerWindow hostWindow, CrawledMemorySnapshot _unpackedCrawl) | 
|         { | 
|             this._unpackedCrawl = _unpackedCrawl; | 
|             this._hostWindow = hostWindow; | 
|   | 
|             _ZoomArea = new ZoomArea(true) | 
|             { | 
|                 vRangeMin = -110f, | 
|                 vRangeMax = 110f, | 
|                 hRangeMin = -110f, | 
|                 hRangeMax = 110f, | 
|                 hBaseRangeMin = -110f, | 
|                 vBaseRangeMin = -110f, | 
|                 hBaseRangeMax = 110f, | 
|                 vBaseRangeMax = 110f, | 
|                 shownArea = new Rect(-110f, -110f, 220f, 220f) | 
|             }; | 
|             RefreshCaches(); | 
|             RefreshMesh(); | 
|         } | 
|   | 
|         public void Draw() | 
|         { | 
|             if (_hostWindow == null) | 
|                 return; | 
|              | 
|             Rect r = new Rect(0f, 25f, _hostWindow.position.width - _hostWindow._inspector.width, _hostWindow.position.height - 25f); | 
|   | 
|             _ZoomArea.rect = r; | 
|             _ZoomArea.BeginViewGUI(); | 
|   | 
|             GUI.BeginGroup(r); | 
|             Handles.matrix = _ZoomArea.drawingToViewMatrix; | 
|             HandleMouseClick(); | 
|             RenderTreemap(); | 
|             GUI.EndGroup(); | 
|   | 
|             _ZoomArea.EndViewGUI(); | 
|         } | 
|   | 
|         private void OnHoveredGroupChanged() | 
|         { | 
|             RefreshCachedRects(false); | 
|         } | 
|   | 
|         private void HandleMouseClick() | 
|         { | 
|             if ((Event.current.type == EventType.MouseDown || Event.current.type == EventType.MouseUp) && Event.current.button == 0) | 
|             { | 
|                 if (_ZoomArea.drawRect.Contains(Event.current.mousePosition)) | 
|                 { | 
|                     Group group = _groups.Values.FirstOrDefault(i => i._position.Contains(mouseTreemapPosition)); | 
|                     Item item = _items.FirstOrDefault(i => i._position.Contains(mouseTreemapPosition)); | 
|   | 
|                     if (item != null && _selectedGroup == item._group) | 
|                     { | 
|                         switch (Event.current.type) | 
|                         { | 
|                             case EventType.MouseDown: | 
|                                 _mouseDownItem = item; | 
|                                 break; | 
|   | 
|                             case EventType.MouseUp: | 
|                                 if (_mouseDownItem == item) | 
|                                 { | 
|                                     _hostWindow.SelectThing(item._thingInMemory); | 
|                                     Event.current.Use(); | 
|                                 } | 
|                                 break; | 
|                         } | 
|                     } | 
|                     else if (group != null) | 
|                     { | 
|                         switch (Event.current.type) | 
|                         { | 
|                             case EventType.MouseUp: | 
|                                 _hostWindow.SelectGroup(group); | 
|                                 Event.current.Use(); | 
|                                 break; | 
|                         } | 
|                     } | 
|                 } | 
|             } | 
|         } | 
|   | 
|         public void SelectThing(ThingInMemory thing) | 
|         { | 
|             _selectedItem = _items.First(i => i._thingInMemory == thing); | 
|             _selectedGroup = _selectedItem._group; | 
|             RefreshCachedRects(false); | 
|         } | 
|   | 
|         public void SelectGroup(Group group) | 
|         { | 
|             _selectedItem = null; | 
|             _selectedGroup = group; | 
|             RefreshCachedRects(false); | 
|         } | 
|   | 
|         void RefreshCaches() | 
|         { | 
|             _items.Clear(); | 
|             _groups.Clear(); | 
|   | 
|             foreach (ThingInMemory thingInMemory in _unpackedCrawl.allObjects) | 
|             { | 
|                 string groupName = GetGroupName(thingInMemory); | 
|                 if (groupName.Length == 0) | 
|                     continue; | 
|   | 
|                 if (!_groups.ContainsKey(groupName)) | 
|                 { | 
|                     Group newGroup = new Group(); | 
|                     newGroup._name = groupName; | 
|                     newGroup._items = new List<Item>(); | 
|                     _groups.Add(groupName, newGroup); | 
|                 } | 
|   | 
|                 Item item = new Item(thingInMemory, _groups[groupName]); | 
|                 _items.Add(item); | 
|                 _groups[groupName]._items.Add(item); | 
|             } | 
|   | 
|             foreach (Group group in _groups.Values) | 
|             { | 
|                 group._items.Sort(); | 
|             } | 
|   | 
|             _items.Sort(); | 
|             RefreshCachedRects(true); | 
|         } | 
|   | 
|         private void RefreshCachedRects(bool fullRefresh) | 
|         { | 
|             Rect space = new Rect(-100f, -100f, 200f, 200f); | 
|   | 
|             if (fullRefresh) | 
|             { | 
|                 List<Group> groups = _groups.Values.ToList(); | 
|                 groups.Sort(); | 
|                 float[] groupTotalValues = new float[groups.Count]; | 
|                 for (int i = 0; i < groups.Count; i++) | 
|                 { | 
|                     groupTotalValues[i] = groups.ElementAt(i).totalMemorySize; | 
|                 } | 
|   | 
|                 Rect[] groupRects = Utility.GetTreemapRects(groupTotalValues, space); | 
|                 for (int groupIndex = 0; groupIndex < groupRects.Length; groupIndex++) | 
|                 { | 
|                     Group group = groups[groupIndex]; | 
|                     group._position = groupRects[groupIndex]; | 
|                 } | 
|             } | 
|   | 
|             if (_selectedGroup != null) | 
|             { | 
|                 Rect[] rects = Utility.GetTreemapRects(_selectedGroup.memorySizes, _selectedGroup._position); | 
|   | 
|                 for (int i = 0; i < rects.Length; i++) | 
|                 { | 
|                     _selectedGroup._items[i]._position = rects[i]; | 
|                 } | 
|             } | 
|   | 
|             RefreshMesh(); | 
|         } | 
|   | 
|         public void CleanupMeshes () | 
|         { | 
|             if (_cachedMeshes == null) { | 
|                 _cachedMeshes = new List<Mesh> (); | 
|             } | 
|             else { | 
|                 for (int i = 0; i < _cachedMeshes.Count; i++) { | 
|                     UnityEngine.Object.DestroyImmediate (_cachedMeshes [i]); | 
|                 } | 
|                 | 
|                 _cachedMeshes.Clear (); | 
|             } | 
|         } | 
|   | 
|         private void RefreshMesh() | 
|         { | 
|             CleanupMeshes (); | 
|   | 
|             const int maxVerts = 32000; | 
|             Vector3[] vertices = new Vector3[maxVerts]; | 
|             Color[] colors = new Color[maxVerts]; | 
|             int[] triangles = new int[maxVerts * 6 / 4]; | 
|   | 
|             int meshItemIndex = 0; | 
|             int totalItemIndex = 0; | 
|   | 
|             List<ITreemapRenderable> visible = new List<ITreemapRenderable>(); | 
|             foreach (Group group in _groups.Values) | 
|             { | 
|                 if (group != _selectedGroup) | 
|                 { | 
|                     visible.Add(group); | 
|                 } | 
|                 else | 
|                 { | 
|                     foreach (Item item in group._items) | 
|                     { | 
|                         visible.Add(item); | 
|                     } | 
|                 } | 
|             } | 
|   | 
|             foreach (ITreemapRenderable item in visible) | 
|             { | 
|                 int index = meshItemIndex * 4; | 
|                 vertices[index++] = new Vector3(item.GetPosition().xMin, item.GetPosition().yMin, 0f); | 
|                 vertices[index++] = new Vector3(item.GetPosition().xMax, item.GetPosition().yMin, 0f); | 
|                 vertices[index++] = new Vector3(item.GetPosition().xMax, item.GetPosition().yMax, 0f); | 
|                 vertices[index++] = new Vector3(item.GetPosition().xMin, item.GetPosition().yMax, 0f); | 
|   | 
|                 index = meshItemIndex * 4; | 
|                 var color = item.GetColor(); | 
|                 if (item == _selectedItem) | 
|                     color *= 1.5f; | 
|   | 
|                 colors[index++] = color; | 
|                 colors[index++] = color * 0.75f; | 
|                 colors[index++] = color * 0.5f; | 
|                 colors[index++] = color * 0.75f; | 
|   | 
|                 index = meshItemIndex * 6; | 
|                 triangles[index++] = meshItemIndex * 4 + 0; | 
|                 triangles[index++] = meshItemIndex * 4 + 1; | 
|                 triangles[index++] = meshItemIndex * 4 + 3; | 
|                 triangles[index++] = meshItemIndex * 4 + 1; | 
|                 triangles[index++] = meshItemIndex * 4 + 2; | 
|                 triangles[index++] = meshItemIndex * 4 + 3; | 
|   | 
|                 meshItemIndex++; | 
|                 totalItemIndex++; | 
|   | 
|                 if (meshItemIndex >= maxVerts / 4 || totalItemIndex == visible.Count) | 
|                 { | 
|                     Mesh mesh = new Mesh(); | 
|                     mesh.hideFlags = HideFlags.DontSaveInEditor | HideFlags.HideInHierarchy | HideFlags.NotEditable; | 
|                     mesh.vertices = vertices; | 
|                     mesh.triangles = triangles; | 
|                     mesh.colors = colors; | 
|                     _cachedMeshes.Add(mesh); | 
|   | 
|                     vertices = new Vector3[maxVerts]; | 
|                     colors = new Color[maxVerts]; | 
|                     triangles = new int[maxVerts * 6 / 4]; | 
|                     meshItemIndex = 0; | 
|                 } | 
|             } | 
|         } | 
|   | 
|         public void RenderTreemap() | 
|         { | 
|             if (_cachedMeshes == null) | 
|                 return; | 
|   | 
|             Material mat = (Material)EditorGUIUtility.LoadRequired("SceneView/2DHandleLines.mat"); | 
|             mat.SetPass(0); | 
|   | 
|             for (int i = 0; i < _cachedMeshes.Count; i++) | 
|             { | 
|                 Graphics.DrawMeshNow(_cachedMeshes[i], Handles.matrix); | 
|             } | 
|             RenderLabels(); | 
|         } | 
|   | 
|         private void RenderLabels() | 
|         { | 
|             if (_groups == null) | 
|                 return; | 
|   | 
|             GUI.color = Color.black; | 
|   | 
|             foreach (Group group in _groups.Values) | 
|             { | 
|                 if (Utility.IsInside(group._position, _ZoomArea.shownArea)) | 
|                 { | 
|                     if (_selectedItem != null && _selectedItem._group == group) | 
|                     { | 
|                         RenderGroupItems(group); | 
|                     } | 
|                     else | 
|                     { | 
|                         RenderGroupLabel(group); | 
|                     } | 
|                 } | 
|             } | 
|   | 
|             GUI.color = Color.white; | 
|         } | 
|   | 
|         private void RenderGroupLabel(Group group) | 
|         { | 
|             Matrix4x4 mat = _ZoomArea.drawingToViewMatrix; | 
|   | 
|             Vector3 p1 = mat.MultiplyPoint(new Vector3(group._position.xMin, group._position.yMin)); | 
|             Vector3 p2 = mat.MultiplyPoint(new Vector3(group._position.xMax, group._position.yMax)); | 
|   | 
|             if (p2.x - p1.x > 30f) | 
|             { | 
|                 Rect rect = new Rect(p1.x, p2.y, p2.x - p1.x, p1.y - p2.y); | 
|                 GUI.Label(rect, group.GetLabel()); | 
|             } | 
|         } | 
|   | 
|         private void RenderGroupItems(Group group) | 
|         { | 
|             Matrix4x4 mat = _ZoomArea.drawingToViewMatrix; | 
|   | 
|             foreach (Item item in group._items) | 
|             { | 
|                 if (Utility.IsInside(item._position, _ZoomArea.shownArea)) | 
|                 { | 
|                     Vector3 p1 = mat.MultiplyPoint(new Vector3(item._position.xMin, item._position.yMin)); | 
|                     Vector3 p2 = mat.MultiplyPoint(new Vector3(item._position.xMax, item._position.yMax)); | 
|   | 
|                     if (p2.x - p1.x > 30f) | 
|                     { | 
|                         Rect rect = new Rect(p1.x, p2.y, p2.x - p1.x, p1.y - p2.y); | 
|                         string row1 = item._group._name; | 
|                         string row2 = EditorUtility.FormatBytes(item.memorySize); | 
|                         GUI.Label(rect, row1 + "\n" + row2); | 
|                     } | 
|                 } | 
|             } | 
|         } | 
|   | 
|         public string GetGroupName(ThingInMemory thing) | 
|         { | 
|             if (thing is NativeUnityEngineObject) | 
|                 return (thing as NativeUnityEngineObject).className ?? "MissingName"; | 
|             if (thing is ManagedObject) | 
|                 return (thing as ManagedObject).typeDescription.name; | 
|             return thing.GetType().Name; | 
|         } | 
|     } | 
| } |