A game about forced loneliness, made by TACStudios
at master 425 lines 17 kB view raw
1using System; 2using UnityEngine; 3using UnityEvent = UnityEngine.Event; 4 5namespace UnityEditor.U2D.Sprites 6{ 7 internal class SpriteUtilityWindow : EditorWindow 8 { 9 protected class Styles 10 { 11 public readonly GUIStyle dragdot = "U2D.dragDot"; 12 public readonly GUIStyle dragdotDimmed = "U2D.dragDotDimmed"; 13 public readonly GUIStyle dragdotactive = "U2D.dragDotActive"; 14 public readonly GUIStyle createRect = "U2D.createRect"; 15 public readonly GUIStyle preToolbar = "preToolbar"; 16 public readonly GUIStyle preButton = "preButton"; 17 public readonly GUIStyle preLabel = "preLabel"; 18 public readonly GUIStyle preSlider = "preSlider"; 19 public readonly GUIStyle preSliderThumb = "preSliderThumb"; 20 public readonly GUIStyle preBackground = "preBackground"; 21 public readonly GUIStyle pivotdotactive = "U2D.pivotDotActive"; 22 public readonly GUIStyle pivotdot = "U2D.pivotDot"; 23 24 public readonly GUIStyle dragBorderdot = new GUIStyle(); 25 public readonly GUIStyle dragBorderDotActive = new GUIStyle(); 26 27 public readonly GUIStyle toolbar; 28 public readonly GUIContent alphaIcon; 29 public readonly GUIContent RGBIcon; 30 public readonly GUIStyle notice; 31 32 public readonly GUIContent smallMip; 33 public readonly GUIContent largeMip; 34 35 public Styles() 36 { 37 toolbar = new GUIStyle(EditorStyles.inspectorBig); 38 toolbar.margin.top = 0; 39 toolbar.margin.bottom = 0; 40 alphaIcon = EditorGUIUtility.IconContent("PreTextureAlpha"); 41 RGBIcon = EditorGUIUtility.IconContent("PreTextureRGB"); 42 preToolbar.border.top = 0; 43 createRect.border = new RectOffset(3, 3, 3, 3); 44 45 notice = new GUIStyle(GUI.skin.label); 46 notice.alignment = TextAnchor.MiddleCenter; 47 notice.normal.textColor = Color.yellow; 48 49 dragBorderdot.fixedHeight = 5f; 50 dragBorderdot.fixedWidth = 5f; 51 dragBorderdot.normal.background = EditorGUIUtility.whiteTexture; 52 53 dragBorderDotActive.fixedHeight = dragBorderdot.fixedHeight; 54 dragBorderDotActive.fixedWidth = dragBorderdot.fixedWidth; 55 dragBorderDotActive.normal.background = EditorGUIUtility.whiteTexture; 56 57 smallMip = EditorGUIUtility.IconContent("PreTextureMipMapLow"); 58 largeMip = EditorGUIUtility.IconContent("PreTextureMipMapHigh"); 59 } 60 } 61 62 protected void InitStyles() 63 { 64 if (m_Styles == null) 65 m_Styles = new Styles(); 66 } 67 68 protected Styles m_Styles; 69 70 protected const float k_BorderMargin = 10f; 71 protected const float k_ScrollbarMargin = 16f; 72 protected const float k_InspectorWindowMargin = 8f; 73 protected const float k_InspectorWidth = 330f; 74 protected const float k_MinZoomPercentage = 0.9f; 75 protected const float k_MaxZoom = 50f; 76 protected const float k_WheelZoomSpeed = 0.03f; 77 protected const float k_MouseZoomSpeed = 0.005f; 78 protected const float k_ToolbarHeight = 17f; 79 80 protected ITexture2D m_Texture; 81 protected ITexture2D m_TextureAlphaOverride; 82 Rect m_TextureViewRect; 83 protected Rect m_TextureRect; 84 85 [SerializeField] 86 protected bool m_ShowAlpha = false; 87 [SerializeField] 88 protected float m_MipLevel = 0; 89 [SerializeField] 90 protected float m_Zoom = -1f; 91 [SerializeField] 92 protected Vector2 m_ScrollPosition = new Vector2(); 93 94 public float zoomLevel 95 { 96 get { return m_Zoom; } 97 set { m_Zoom = Mathf.Clamp(value, GetMinZoom(), k_MaxZoom); } 98 } 99 100 internal Rect textureViewRect 101 { 102 get => m_TextureViewRect; 103 set 104 { 105 m_TextureViewRect = value; 106 zoomLevel = m_Zoom; // update zoom level 107 } 108 } 109 110 public Vector2 scrollPosition 111 { 112 get { return m_ScrollPosition; } 113 set 114 { 115 if (m_Zoom < 0) 116 m_Zoom = GetMinZoom(); 117 118 m_ScrollPosition.x = Mathf.Clamp(value.x, maxScrollRect.xMin, maxScrollRect.xMax); 119 m_ScrollPosition.y = Mathf.Clamp(value.y, maxScrollRect.yMin, maxScrollRect.yMax); 120 } 121 } 122 123 public bool showAlpha 124 { 125 get { return m_ShowAlpha; } 126 set { m_ShowAlpha = value; } 127 } 128 129 public float mipLevel 130 { 131 get { return m_MipLevel; } 132 set 133 { 134 var mipCount = 1; 135 if (m_Texture != null) 136 mipCount = Mathf.Max(mipCount, TextureUtil.GetMipmapCount(m_Texture)); 137 m_MipLevel = Mathf.Clamp(value, 0, mipCount - 1); 138 } 139 } 140 141 protected float GetMinZoom() 142 { 143 if (m_Texture == null) 144 return 1.0f; 145 // Case 654327: Add k_MaxZoom size to min check to ensure that min zoom is smaller than max zoom 146 return Mathf.Min(m_TextureViewRect.width / m_Texture.width, m_TextureViewRect.height / m_Texture.height, k_MaxZoom) * k_MinZoomPercentage; 147 } 148 149 protected void HandleZoom() 150 { 151 bool zoomMode = UnityEvent.current.alt && UnityEvent.current.button == 1; 152 if (zoomMode) 153 { 154 EditorGUIUtility.AddCursorRect(m_TextureViewRect, MouseCursor.Zoom); 155 } 156 157 if ( 158 ((UnityEvent.current.type == EventType.MouseUp || UnityEvent.current.type == EventType.MouseDown) && zoomMode) || 159 ((UnityEvent.current.type == EventType.KeyUp || UnityEvent.current.type == EventType.KeyDown) && UnityEvent.current.keyCode == KeyCode.LeftAlt) 160 ) 161 { 162 Repaint(); 163 } 164 165 if (UnityEvent.current.type == EventType.ScrollWheel || (UnityEvent.current.type == EventType.MouseDrag && UnityEvent.current.alt && UnityEvent.current.button == 1)) 166 { 167 float zoomMultiplier = 1f - UnityEvent.current.delta.y * (UnityEvent.current.type == EventType.ScrollWheel ? k_WheelZoomSpeed : -k_MouseZoomSpeed); 168 169 // Clamp zoom 170 float wantedZoom = m_Zoom * zoomMultiplier; 171 172 float currentZoom = Mathf.Clamp(wantedZoom, GetMinZoom(), k_MaxZoom); 173 174 if (currentZoom != m_Zoom) 175 { 176 m_Zoom = currentZoom; 177 178 // We need to fix zoomMultiplier if we clamped wantedZoom != currentZoom 179 if (wantedZoom != currentZoom) 180 zoomMultiplier /= wantedZoom / currentZoom; 181 182 Vector3 textureHalfSize = new Vector2(m_Texture.width, m_Texture.height) * 0.5f; 183 Vector3 mousePositionWorld = Handles.inverseMatrix.MultiplyPoint3x4(UnityEvent.current.mousePosition + m_ScrollPosition); 184 Vector3 delta = (mousePositionWorld - textureHalfSize) * (zoomMultiplier - 1f); 185 186 m_ScrollPosition += (Vector2)Handles.matrix.MultiplyVector(delta); 187 188 UnityEvent.current.Use(); 189 } 190 } 191 } 192 193 protected void HandlePanning() 194 { 195 // You can pan by holding ALT and using left button or NOT holding ALT and using right button. ALT + right is reserved for zooming. 196 bool panMode = (!UnityEvent.current.alt && UnityEvent.current.button > 0 || UnityEvent.current.alt && UnityEvent.current.button <= 0); 197 if (panMode && GUIUtility.hotControl == 0) 198 { 199 EditorGUIUtility.AddCursorRect(m_TextureViewRect, MouseCursor.Pan); 200 201 if (UnityEvent.current.type == EventType.MouseDrag) 202 { 203 m_ScrollPosition -= UnityEvent.current.delta; 204 UnityEvent.current.Use(); 205 } 206 } 207 208 //We need to repaint when entering or exiting the pan mode, so the mouse cursor gets refreshed. 209 if ( 210 ((UnityEvent.current.type == EventType.MouseUp || UnityEvent.current.type == EventType.MouseDown) && panMode) || 211 (UnityEvent.current.type == EventType.KeyUp || UnityEvent.current.type == EventType.KeyDown) && UnityEvent.current.keyCode == KeyCode.LeftAlt 212 ) 213 { 214 Repaint(); 215 } 216 } 217 218 // Bounding values for scrollbars. Changes with zoom, because we want min/max scroll to stop at texture edges. 219 protected Rect maxScrollRect 220 { 221 get 222 { 223 float halfWidth = m_Texture.width * .5f * m_Zoom; 224 float halfHeight = m_Texture.height * .5f * m_Zoom; 225 return new Rect(-halfWidth, -halfHeight, m_TextureViewRect.width + halfWidth * 2f, m_TextureViewRect.height + halfHeight * 2f); 226 } 227 } 228 229 // Max rect in texture space that can ever be visible 230 protected Rect maxRect 231 { 232 get 233 { 234 float marginW = m_TextureViewRect.width * .5f / GetMinZoom(); 235 float marginH = m_TextureViewRect.height * .5f / GetMinZoom(); 236 float left = -marginW; 237 float top = -marginH; 238 float width = m_Texture.width + marginW * 2f; 239 float height = m_Texture.height + marginH * 2f; 240 return new Rect(left, top, width, height); 241 } 242 } 243 244 protected void DrawTexturespaceBackground() 245 { 246 float size = Mathf.Max(maxRect.width, maxRect.height); 247 Vector2 offset = new Vector2(maxRect.xMin, maxRect.yMin); 248 249 float halfSize = size * .5f; 250 float alpha = EditorGUIUtility.isProSkin ? 0.15f : 0.08f; 251 float gridSize = 8f; 252 253 SpriteEditorUtility.BeginLines(new Color(0f, 0f, 0f, alpha)); 254 for (float v = 0; v <= size; v += gridSize) 255 SpriteEditorUtility.DrawLine(new Vector2(-halfSize + v, halfSize + v) + offset, new Vector2(halfSize + v, -halfSize + v) + offset); 256 SpriteEditorUtility.EndLines(); 257 } 258 259 private float Log2(float x) 260 { 261 return (float)(System.Math.Log(x) / System.Math.Log(2)); 262 } 263 264 protected void DrawTexture() 265 { 266 float mipLevel = Mathf.Min(m_MipLevel, TextureUtil.GetMipmapCount(m_Texture) - 1); 267 268 if (m_ShowAlpha) 269 { 270 // check if we have a valid alpha texture 271 if (m_TextureAlphaOverride != null) 272 EditorGUI.DrawTextureTransparent(m_TextureRect, m_TextureAlphaOverride, ScaleMode.StretchToFill, 0, mipLevel); 273 // else use the original texture and display its alpha 274 else 275 EditorGUI.DrawTextureAlpha(m_TextureRect, m_Texture, ScaleMode.StretchToFill, 0, mipLevel); 276 } 277 else 278 EditorGUI.DrawTextureTransparent(m_TextureRect, m_Texture, ScaleMode.StretchToFill, 0, mipLevel); 279 } 280 281 protected void DrawScreenspaceBackground() 282 { 283 if (UnityEvent.current.type == EventType.Repaint) 284 m_Styles.preBackground.Draw(m_TextureViewRect, false, false, false, false); 285 } 286 287 protected void HandleScrollbars() 288 { 289 Rect horizontalScrollBarPosition = new Rect(m_TextureViewRect.xMin, m_TextureViewRect.yMax, m_TextureViewRect.width, k_ScrollbarMargin); 290 m_ScrollPosition.x = GUI.HorizontalScrollbar(horizontalScrollBarPosition, m_ScrollPosition.x, m_TextureViewRect.width, maxScrollRect.xMin, maxScrollRect.xMax); 291 292 Rect verticalScrollBarPosition = new Rect(m_TextureViewRect.xMax, m_TextureViewRect.yMin, k_ScrollbarMargin, m_TextureViewRect.height); 293 m_ScrollPosition.y = GUI.VerticalScrollbar(verticalScrollBarPosition, m_ScrollPosition.y, m_TextureViewRect.height, maxScrollRect.yMin, maxScrollRect.yMax); 294 } 295 296 protected void SetupHandlesMatrix() 297 { 298 // Offset from top left to center in view space 299 Vector3 handlesPos = new Vector3(m_TextureRect.x, m_TextureRect.yMax, 0f); 300 // We flip Y-scale because Unity texture space is bottom-up 301 Vector3 handlesScale = new Vector3(zoomLevel, -zoomLevel, 1f); 302 303 // Handle matrix is for converting between view and texture space coordinates, without taking account the scroll position. 304 // Scroll position is added separately so we can use it with GUIClip. 305 Handles.matrix = Matrix4x4.TRS(handlesPos, Quaternion.identity, handlesScale); 306 } 307 308 protected Rect DoAlphaZoomToolbarGUI(Rect area) 309 { 310 int mipCount = 1; 311 if (m_Texture != null) 312 mipCount = Mathf.Max(mipCount, TextureUtil.GetMipmapCount(m_Texture)); 313 314 Rect drawArea = new Rect(area.width, 0, 0, area.height); 315 using (new EditorGUI.DisabledScope(mipCount == 1)) 316 { 317 drawArea.width = m_Styles.largeMip.image.width; 318 drawArea.x -= drawArea.width; 319 GUI.Box(drawArea, m_Styles.largeMip, m_Styles.preLabel); 320 321 drawArea.width = EditorGUI.kSliderMinW; 322 drawArea.x -= drawArea.width; 323 m_MipLevel = Mathf.Round(GUI.HorizontalSlider(drawArea, m_MipLevel, mipCount - 1, 0, m_Styles.preSlider, m_Styles.preSliderThumb)); 324 325 drawArea.width = m_Styles.smallMip.image.width; 326 drawArea.x -= drawArea.width; 327 GUI.Box(drawArea, m_Styles.smallMip, m_Styles.preLabel); 328 } 329 330 drawArea.width = EditorGUI.kSliderMinW; 331 drawArea.x -= drawArea.width; 332 zoomLevel = GUI.HorizontalSlider(drawArea, zoomLevel, GetMinZoom(), k_MaxZoom, m_Styles.preSlider, m_Styles.preSliderThumb); 333 334 drawArea.width = EditorGUI.kObjectFieldMiniThumbnailWidth; 335 drawArea.x -= drawArea.width + EditorGUI.kSpacing; 336 m_ShowAlpha = GUI.Toggle(drawArea, m_ShowAlpha, m_ShowAlpha ? m_Styles.alphaIcon : m_Styles.RGBIcon, "toolbarButton"); 337 338 // Returns the area that is not used 339 return new Rect(area.x, area.y, drawArea.x, area.height); 340 } 341 342 protected void DoTextureGUI() 343 { 344 if (m_Texture == null) 345 return; 346 347 // zoom startup init 348 if (m_Zoom < 0f) 349 m_Zoom = GetMinZoom(); 350 351 // Texture rect in view space 352 m_TextureRect = new Rect( 353 m_TextureViewRect.width / 2f - (m_Texture.width * m_Zoom / 2f), 354 m_TextureViewRect.height / 2f - (m_Texture.height * m_Zoom / 2f), 355 (m_Texture.width * m_Zoom), 356 (m_Texture.height * m_Zoom) 357 ); 358 359 HandleScrollbars(); 360 SetupHandlesMatrix(); 361 DrawScreenspaceBackground(); 362 363 GUIClip.Push(m_TextureViewRect, -m_ScrollPosition, Vector2.zero, false); 364 365 if (UnityEvent.current.type == EventType.Repaint) 366 { 367 DrawTexturespaceBackground(); 368 DrawTexture(); 369 DrawGizmos(); 370 } 371 372 DoTextureGUIExtras(); 373 374 GUIClip.Pop(); 375 376 // Handle this after DoTextureGUIExtras in case user wants any event that is handled by Zoom or Panning 377 HandleZoom(); 378 HandlePanning(); 379 } 380 381 protected virtual void DoTextureGUIExtras() 382 { 383 } 384 385 protected virtual void DrawGizmos() 386 { 387 } 388 389 protected void SetNewTexture(Texture2D texture) 390 { 391 if (texture != m_Texture) 392 { 393 m_Texture = new Texture2DWrapper(texture); 394 m_Zoom = -1; 395 m_TextureAlphaOverride = null; 396 } 397 } 398 399 protected void SetAlphaTextureOverride(Texture2D alphaTexture) 400 { 401 if (alphaTexture != m_TextureAlphaOverride) 402 { 403 m_TextureAlphaOverride = new Texture2DWrapper(alphaTexture); 404 m_Zoom = -1; 405 } 406 } 407 408 internal override void OnResized() 409 { 410 if (m_Texture != null && UnityEvent.current != null) 411 HandleZoom(); 412 base.OnResized(); 413 } 414 415 internal static void DrawToolBarWidget(ref Rect drawRect, ref Rect toolbarRect, Action<Rect> drawAction) 416 { 417 toolbarRect.width -= drawRect.width; 418 if (toolbarRect.width < 0) 419 drawRect.width += toolbarRect.width; 420 421 if (drawRect.width > 0) 422 drawAction(drawRect); 423 } 424 } // class 425}