ImagePackerDebugEditor.cs 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using UnityEditor.U2D.Sprites;
  5. using UnityEditorInternal;
  6. using UnityEngine;
  7. using UnityEngine.UIElements;
  8. using Object = UnityEngine.Object;
  9. namespace UnityEditor.U2D.Common
  10. {
  11. internal class ImagePackerDebugEditor : EditorWindow
  12. {
  13. [MenuItem("internal:Window/2D/Common/Image Packer Debug Editor")]
  14. static void Launch()
  15. {
  16. var window = EditorWindow.GetWindow<ImagePackerDebugEditor>();
  17. var pos = window.position;
  18. pos.height = pos.width = 400;
  19. window.position = pos;
  20. window.Show();
  21. }
  22. ReorderableList m_ReorderableList;
  23. ImagePacker.ImagePackRect[] m_PackingRect = null;
  24. List<RectInt> m_PackRects = new List<RectInt>();
  25. RectInt[] m_PackResult = null;
  26. SpriteRect[] m_SpriteRects = null;
  27. Texture2D m_Texture;
  28. int m_TextureActualWidth = 0;
  29. int m_TextureActualHeight = 0;
  30. int m_PackWidth = 0;
  31. int m_PackHeight = 0;
  32. int m_Padding = 0;
  33. Vector2 m_ConfigScroll = Vector2.zero;
  34. float m_Zoom = 1;
  35. IMGUIContainer m_PackArea;
  36. int m_PackStep = -1;
  37. protected const float k_MinZoomPercentage = 0.9f;
  38. protected const float k_WheelZoomSpeed = 0.03f;
  39. protected const float k_MouseZoomSpeed = 0.005f;
  40. void OnEnable()
  41. {
  42. var visualContainer = new VisualElement()
  43. {
  44. name = "Container",
  45. style =
  46. {
  47. flexGrow = 1,
  48. flexDirection = FlexDirection.Row
  49. }
  50. };
  51. this.rootVisualElement.Add(visualContainer);
  52. var imgui = new IMGUIContainer(OnConfigGUI)
  53. {
  54. name = "Config",
  55. style =
  56. {
  57. width = 300
  58. }
  59. };
  60. visualContainer.Add(imgui);
  61. m_PackArea = new IMGUIContainer(OnImagePackerGUI)
  62. {
  63. name = "ImagePacker",
  64. style =
  65. {
  66. flexGrow = 1,
  67. }
  68. };
  69. visualContainer.Add(m_PackArea);
  70. SetupConfigGUI();
  71. }
  72. void SetupConfigGUI()
  73. {
  74. m_ReorderableList = new ReorderableList(m_PackRects, typeof(RectInt), false, false, true, true);
  75. m_ReorderableList.elementHeightCallback = (int index) =>
  76. {
  77. return EditorGUIUtility.singleLineHeight * 2 + 6;
  78. };
  79. m_ReorderableList.drawElementCallback = DrawListElement;
  80. m_ReorderableList.onAddCallback = (list) =>
  81. {
  82. m_PackRects.Add(new RectInt());
  83. };
  84. m_ReorderableList.onRemoveCallback = (list) =>
  85. {
  86. m_PackRects.RemoveAt(list.index);
  87. };
  88. }
  89. void DrawListElement(Rect rect, int index, bool isactive, bool isfocused)
  90. {
  91. var rectInt = m_PackRects[index];
  92. var name = m_SpriteRects == null || index >= m_SpriteRects.Length ? index.ToString() : m_SpriteRects[index].
  93. name;
  94. rectInt.size = EditorGUI.Vector2IntField(rect, name, rectInt.size);
  95. m_PackRects[index] = rectInt;
  96. }
  97. void OnConfigGUI()
  98. {
  99. EditorGUILayout.BeginVertical();
  100. m_ConfigScroll = EditorGUILayout.BeginScrollView(m_ConfigScroll);
  101. m_ReorderableList.DoLayoutList();
  102. EditorGUILayout.EndScrollView();
  103. GUILayout.FlexibleSpace();
  104. m_PackStep = EditorGUILayout.IntSlider("Step", m_PackStep, 0, m_PackRects.Count);
  105. EditorGUI.BeginChangeCheck();
  106. m_Texture = EditorGUILayout.ObjectField(new GUIContent("Texture"), (Object)m_Texture, typeof(Texture2D), false) as Texture2D;
  107. if (EditorGUI.EndChangeCheck())
  108. UpdateSpriteRect();
  109. m_Padding = EditorGUILayout.IntField("Padding", m_Padding);
  110. EditorGUILayout.BeginHorizontal();
  111. if (GUILayout.Button("<<"))
  112. {
  113. m_PackStep = m_PackStep <= 0 ? 0 : m_PackStep - 1;
  114. Pack();
  115. }
  116. if (GUILayout.Button("Pack"))
  117. Pack();
  118. if (GUILayout.Button(">>"))
  119. {
  120. m_PackStep = m_PackStep > m_PackRects.Count ? m_PackRects.Count : m_PackStep + 1;
  121. Pack();
  122. }
  123. if (GUILayout.Button("Clear"))
  124. {
  125. m_PackRects.Clear();
  126. m_Texture = null;
  127. m_PackingRect = null;
  128. m_PackResult = null;
  129. m_SpriteRects = null;
  130. }
  131. EditorGUILayout.EndHorizontal();
  132. EditorGUILayout.EndVertical();
  133. }
  134. void UpdateSpriteRect()
  135. {
  136. var dataProvider = AssetImporter.GetAtPath(AssetDatabase.GetAssetPath(m_Texture)) as ISpriteEditorDataProvider;
  137. if (dataProvider == null)
  138. return;
  139. dataProvider.InitSpriteEditorDataProvider();
  140. dataProvider.GetDataProvider<ITextureDataProvider>().GetTextureActualWidthAndHeight(out m_TextureActualWidth, out m_TextureActualHeight);
  141. m_SpriteRects = dataProvider.GetDataProvider<ISpriteEditorDataProvider>().GetSpriteRects();
  142. m_PackRects.Clear();
  143. m_PackRects.AddRange(m_SpriteRects.Select(x => new RectInt((int)x.rect.x, (int)x.rect.y, (int)x.rect.width, (int)x.rect.height)));
  144. m_PackResult = null;
  145. m_PackStep = m_PackRects.Count;
  146. }
  147. void Pack()
  148. {
  149. int count = m_PackStep > 0 && m_PackStep < m_PackRects.Count ? m_PackStep : m_PackRects.Count;
  150. m_PackingRect = new ImagePacker.ImagePackRect[m_PackRects.Count];
  151. for (int i = 0; i < m_PackRects.Count; ++i)
  152. {
  153. m_PackingRect[i] = new ImagePacker.ImagePackRect()
  154. {
  155. rect = m_PackRects[i],
  156. index = i
  157. };
  158. }
  159. Array.Sort(m_PackingRect);
  160. ImagePacker.Pack(m_PackingRect.Take(count).Select(x => x.rect).ToArray(), m_Padding, out m_PackResult, out m_PackWidth, out m_PackHeight);
  161. }
  162. void DrawLabel(Rect rect, string label)
  163. {
  164. rect.position = Handles.matrix.MultiplyPoint(rect.position);
  165. GUI.Label(rect, label);
  166. }
  167. void OnImagePackerGUI()
  168. {
  169. if (m_PackResult == null)
  170. return;
  171. HandleZoom();
  172. var oldMatrix = Handles.matrix;
  173. SetupHandlesMatrix();
  174. Handles.DrawSolidRectangleWithOutline(new Rect(0, 0, m_PackWidth, m_PackHeight), Color.gray, Color.black);
  175. DrawLabel(new Rect(0, 0, m_PackWidth, m_PackHeight), m_PackWidth + "x" + m_PackHeight);
  176. int index = 0;
  177. foreach (var rect in m_PackResult)
  178. {
  179. Handles.DrawSolidRectangleWithOutline(new Rect(rect.x, rect.y, rect.width, rect.height), Color.white, Color.black);
  180. var rect1 = new Rect(rect.x, rect.y + rect.height * 0.5f, rect.width, EditorGUIUtility.singleLineHeight);
  181. DrawLabel(rect1, m_PackingRect[index].index.ToString());
  182. ++index;
  183. }
  184. index = 0;
  185. if (m_Texture != null && m_SpriteRects != null)
  186. {
  187. var material = new Material(Shader.Find("Sprites/Default"));
  188. material.mainTexture = m_Texture;
  189. material.SetPass(0);
  190. int mouseOverIndex = -1;
  191. GL.PushMatrix();
  192. GL.LoadIdentity();
  193. GL.MultMatrix(GUI.matrix * Handles.matrix);
  194. GL.Begin(GL.QUADS);
  195. for (int i = 0; i < m_PackResult.Length; ++i)
  196. {
  197. index = m_PackingRect[i].index;
  198. if (index >= m_SpriteRects.Length)
  199. continue;
  200. var rect = m_PackResult[i];
  201. GL.TexCoord(new Vector3(m_SpriteRects[index].rect.x / m_TextureActualWidth, m_SpriteRects[index].rect.y / m_TextureActualHeight, 0));
  202. GL.Vertex(new Vector3(rect.x, rect.y, 0));
  203. GL.TexCoord(new Vector3(m_SpriteRects[index].rect.xMax / m_TextureActualWidth, m_SpriteRects[index].rect.y / m_TextureActualHeight, 0));
  204. GL.Vertex(new Vector3(rect.x + rect.width, rect.y, 0));
  205. GL.TexCoord(new Vector3(m_SpriteRects[index].rect.xMax / m_TextureActualWidth, m_SpriteRects[index].rect.yMax / m_TextureActualHeight, 0));
  206. GL.Vertex(new Vector3(rect.x + rect.width, rect.y + rect.height, 0));
  207. GL.TexCoord(new Vector3(m_SpriteRects[index].rect.x / m_TextureActualWidth, m_SpriteRects[index].rect.yMax / m_TextureActualHeight, 0));
  208. GL.Vertex(new Vector3(rect.x, rect.y + rect.height, 0));
  209. var m = Handles.matrix.inverse.MultiplyPoint(Event.current.mousePosition);
  210. if (rect.Contains(new Vector2Int((int)m.x, (int)m.y)))
  211. {
  212. mouseOverIndex = index;
  213. }
  214. ++index;
  215. }
  216. GL.End();
  217. GL.PopMatrix();
  218. if (mouseOverIndex >= 0)
  219. {
  220. var text = new GUIContent(m_SpriteRects[mouseOverIndex].name + " " + index);
  221. var length = EditorStyles.textArea.CalcSize(text);
  222. var rect1 = new Rect(m_PackResult[mouseOverIndex].x, m_PackResult[mouseOverIndex].y + m_PackResult[mouseOverIndex].height * 0.5f, length.x, length.y);
  223. rect1.position = Handles.matrix.MultiplyPoint(rect1.position);
  224. if (Event.current.type == EventType.Repaint)
  225. EditorStyles.textArea.Draw(rect1, text, false, false, false, false);
  226. }
  227. }
  228. Handles.matrix = oldMatrix;
  229. }
  230. void SetupHandlesMatrix()
  231. {
  232. Vector3 handlesPos = new Vector3(0, m_PackHeight * m_Zoom, 0f);
  233. Vector3 handlesScale = new Vector3(m_Zoom, -m_Zoom, 1f);
  234. Handles.matrix = Matrix4x4.TRS(handlesPos, Quaternion.identity, handlesScale);
  235. }
  236. protected void HandleZoom()
  237. {
  238. bool zoomMode = Event.current.alt && Event.current.button == 1;
  239. if (zoomMode)
  240. {
  241. EditorGUIUtility.AddCursorRect(m_PackArea.worldBound, MouseCursor.Zoom);
  242. }
  243. if (
  244. ((Event.current.type == EventType.MouseUp || Event.current.type == EventType.MouseDown) && zoomMode) ||
  245. ((Event.current.type == EventType.KeyUp || Event.current.type == EventType.KeyDown) && Event.current.keyCode == KeyCode.LeftAlt)
  246. )
  247. {
  248. Repaint();
  249. }
  250. if (Event.current.type == EventType.ScrollWheel || (Event.current.type == EventType.MouseDrag && Event.current.alt && Event.current.button == 1))
  251. {
  252. float zoomMultiplier = 1f - Event.current.delta.y * (Event.current.type == EventType.ScrollWheel ? k_WheelZoomSpeed : -k_MouseZoomSpeed);
  253. // Clamp zoom
  254. float wantedZoom = m_Zoom * zoomMultiplier;
  255. float currentZoom = Mathf.Clamp(wantedZoom, GetMinZoom(), 1);
  256. if (currentZoom != m_Zoom)
  257. {
  258. m_Zoom = currentZoom;
  259. Event.current.Use();
  260. }
  261. }
  262. }
  263. protected float GetMinZoom()
  264. {
  265. if (m_Texture == null)
  266. return 1.0f;
  267. return Mathf.Min(m_PackArea.worldBound.width / m_PackWidth, m_PackArea.worldBound.height / m_PackHeight, 0.05f) * k_MinZoomPercentage;
  268. }
  269. }
  270. }