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