This commit is contained in:
2021-06-13 10:28:03 +02:00
parent eb70603c85
commit df2d24cbd3
7487 changed files with 943244 additions and 0 deletions

View File

@@ -0,0 +1,360 @@
using UnityEngine;
using UnityEvent = UnityEngine.Event;
namespace UnityEditor.U2D.Sprites
{
internal static class SpriteEditorHandles
{
private static Vector2 s_CurrentMousePosition;
private static Vector2 s_DragStartScreenPosition;
private static Vector2 s_DragScreenOffset;
static internal Vector2 PointSlider(Vector2 pos, MouseCursor cursor, GUIStyle dragDot, GUIStyle dragDotActive)
{
int id = GUIUtility.GetControlID("Slider1D".GetHashCode(), FocusType.Keyboard);
Vector2 screenVal = Handles.matrix.MultiplyPoint(pos);
Rect handleScreenPos = new Rect(
screenVal.x - dragDot.fixedWidth * .5f,
screenVal.y - dragDot.fixedHeight * .5f,
dragDot.fixedWidth,
dragDot.fixedHeight
);
var evt = UnityEvent.current;
switch (evt.GetTypeForControl(id))
{
case EventType.Repaint:
if (GUIUtility.hotControl == id)
dragDotActive.Draw(handleScreenPos, GUIContent.none, id);
else
dragDot.Draw(handleScreenPos, GUIContent.none, id);
break;
}
return ScaleSlider(pos, cursor, handleScreenPos);
}
static internal Vector2 ScaleSlider(Vector2 pos, MouseCursor cursor, Rect cursorRect)
{
int id = GUIUtility.GetControlID("Slider1D".GetHashCode(), FocusType.Keyboard);
return ScaleSlider(id, pos, cursor, cursorRect);
}
static private Vector2 ScaleSlider(int id, Vector2 pos, MouseCursor cursor, Rect cursorRect)
{
Vector2 screenVal = Handles.matrix.MultiplyPoint(pos);
var evt = UnityEvent.current;
switch (evt.GetTypeForControl(id))
{
case EventType.MouseDown:
// am I closest to the thingy?
if (evt.button == 0 &&
cursorRect.Contains(UnityEvent.current.mousePosition) &&
!evt.alt)
{
GUIUtility.hotControl = GUIUtility.keyboardControl = id; // Grab mouse focus
s_CurrentMousePosition = evt.mousePosition;
s_DragStartScreenPosition = evt.mousePosition;
s_DragScreenOffset = s_CurrentMousePosition - screenVal;
evt.Use();
EditorGUIUtility.SetWantsMouseJumping(1);
}
break;
case EventType.MouseDrag:
if (GUIUtility.hotControl == id)
{
s_CurrentMousePosition += evt.delta;
Vector2 oldPos = pos;
pos = Handles.inverseMatrix.MultiplyPoint(s_CurrentMousePosition);
if (!Mathf.Approximately((oldPos - pos).magnitude, 0f))
GUI.changed = true;
evt.Use();
}
break;
case EventType.MouseUp:
if (GUIUtility.hotControl == id && (evt.button == 0 || evt.button == 2))
{
GUIUtility.hotControl = 0;
evt.Use();
EditorGUIUtility.SetWantsMouseJumping(0);
}
break;
case EventType.KeyDown:
if (GUIUtility.hotControl == id)
{
if (evt.keyCode == KeyCode.Escape)
{
pos = Handles.inverseMatrix.MultiplyPoint(s_DragStartScreenPosition - s_DragScreenOffset);
GUIUtility.hotControl = 0;
GUI.changed = true;
evt.Use();
}
}
break;
case EventType.Repaint:
if (GUIUtility.hotControl == 0 || GUIUtility.hotControl == id)
EditorGUIUtility.AddCursorRect(cursorRect, cursor, id);
break;
}
return pos;
}
static internal Vector2 PivotSlider(Rect sprite, Vector2 pos, GUIStyle pivotDot, GUIStyle pivotDotActive)
{
int id = GUIUtility.GetControlID("Slider1D".GetHashCode(), FocusType.Keyboard);
// Convert from normalized space to texture space
pos = new Vector2(sprite.xMin + sprite.width * pos.x, sprite.yMin + sprite.height * pos.y);
Vector2 screenVal = Handles.matrix.MultiplyPoint(pos);
Rect handleScreenPos = new Rect(
screenVal.x - pivotDot.fixedWidth * .5f,
screenVal.y - pivotDot.fixedHeight * .5f,
pivotDotActive.fixedWidth,
pivotDotActive.fixedHeight
);
var evt = UnityEvent.current;
switch (evt.GetTypeForControl(id))
{
case EventType.MouseDown:
// am I closest to the thingy?
if (evt.button == 0 && handleScreenPos.Contains(UnityEvent.current.mousePosition) && !evt.alt)
{
GUIUtility.hotControl = GUIUtility.keyboardControl = id; // Grab mouse focus
s_CurrentMousePosition = evt.mousePosition;
s_DragStartScreenPosition = evt.mousePosition;
Vector2 rectScreenCenter = Handles.matrix.MultiplyPoint(pos);
s_DragScreenOffset = s_CurrentMousePosition - rectScreenCenter;
evt.Use();
EditorGUIUtility.SetWantsMouseJumping(1);
}
break;
case EventType.MouseDrag:
if (GUIUtility.hotControl == id)
{
s_CurrentMousePosition += evt.delta;
Vector2 oldPos = pos;
Vector3 scrPos = Handles.inverseMatrix.MultiplyPoint(s_CurrentMousePosition - s_DragScreenOffset);
pos = new Vector2(scrPos.x, scrPos.y);
if (!Mathf.Approximately((oldPos - pos).magnitude, 0f))
GUI.changed = true;
evt.Use();
}
break;
case EventType.MouseUp:
if (GUIUtility.hotControl == id && (evt.button == 0 || evt.button == 2))
{
GUIUtility.hotControl = 0;
evt.Use();
EditorGUIUtility.SetWantsMouseJumping(0);
}
break;
case EventType.KeyDown:
if (GUIUtility.hotControl == id)
{
if (evt.keyCode == KeyCode.Escape)
{
pos = Handles.inverseMatrix.MultiplyPoint(s_DragStartScreenPosition - s_DragScreenOffset);
GUIUtility.hotControl = 0;
GUI.changed = true;
evt.Use();
}
}
break;
case EventType.Repaint:
EditorGUIUtility.AddCursorRect(handleScreenPos, MouseCursor.Arrow, id);
if (GUIUtility.hotControl == id)
pivotDotActive.Draw(handleScreenPos, GUIContent.none, id);
else
pivotDot.Draw(handleScreenPos, GUIContent.none, id);
break;
}
// Convert from texture space back to normalized space
pos = new Vector2((pos.x - sprite.xMin) / sprite.width, (pos.y - sprite.yMin) / sprite.height);
return pos;
}
static internal Rect SliderRect(Rect pos)
{
int id = GUIUtility.GetControlID("SliderRect".GetHashCode(), FocusType.Keyboard);
var evt = UnityEvent.current;
// SpriteEditorWindow is telling us we got selected and so we fake a mousedown on our Repaint event to get "one-click dragging" going on
if (SpriteEditorWindow.s_OneClickDragStarted && evt.type == EventType.Repaint)
{
HandleSliderRectMouseDown(id, evt, pos);
SpriteEditorWindow.s_OneClickDragStarted = false;
}
switch (evt.GetTypeForControl(id))
{
case EventType.MouseDown:
// am I closest to the thingy?
if (evt.button == 0 && pos.Contains(Handles.inverseMatrix.MultiplyPoint(UnityEvent.current.mousePosition)) && !evt.alt)
{
HandleSliderRectMouseDown(id, evt, pos);
evt.Use();
}
break;
case EventType.MouseDrag:
if (GUIUtility.hotControl == id)
{
s_CurrentMousePosition += evt.delta;
Vector2 oldCenter = pos.center;
pos.center = Handles.inverseMatrix.MultiplyPoint(s_CurrentMousePosition - s_DragScreenOffset);
if (!Mathf.Approximately((oldCenter - pos.center).magnitude, 0f))
GUI.changed = true;
evt.Use();
}
break;
case EventType.MouseUp:
if (GUIUtility.hotControl == id && (evt.button == 0 || evt.button == 2))
{
GUIUtility.hotControl = 0;
evt.Use();
EditorGUIUtility.SetWantsMouseJumping(0);
}
break;
case EventType.KeyDown:
if (GUIUtility.hotControl == id)
{
if (evt.keyCode == KeyCode.Escape)
{
pos.center = Handles.inverseMatrix.MultiplyPoint(s_DragStartScreenPosition - s_DragScreenOffset);
GUIUtility.hotControl = 0;
GUI.changed = true;
evt.Use();
}
}
break;
case EventType.Repaint:
Vector2 topleft = Handles.inverseMatrix.MultiplyPoint(new Vector2(pos.xMin, pos.yMin));
Vector2 bottomright = Handles.inverseMatrix.MultiplyPoint(new Vector2(pos.xMax, pos.yMax));
EditorGUIUtility.AddCursorRect(new Rect(topleft.x, topleft.y, bottomright.x - topleft.x, bottomright.y - topleft.y), MouseCursor.Arrow, id);
break;
}
return pos;
}
static internal void HandleSliderRectMouseDown(int id, UnityEvent evt, Rect pos)
{
GUIUtility.hotControl = GUIUtility.keyboardControl = id; // Grab mouse focus
s_CurrentMousePosition = evt.mousePosition;
s_DragStartScreenPosition = evt.mousePosition;
Vector2 rectScreenCenter = Handles.matrix.MultiplyPoint(pos.center);
s_DragScreenOffset = s_CurrentMousePosition - rectScreenCenter;
EditorGUIUtility.SetWantsMouseJumping(1);
}
static int s_RectSelectionID = GUIUtility.GetPermanentControlID();
static internal Rect RectCreator(Rect textureArea, GUIStyle rectStyle)
{
var evt = UnityEvent.current;
Vector2 mousePos = evt.mousePosition;
int id = s_RectSelectionID;
Rect result = new Rect();
switch (evt.GetTypeForControl(id))
{
case EventType.MouseDown:
if (evt.button == 0)
{
GUIUtility.hotControl = id;
// Make sure that the starting position is clamped to inside texture area
s_DragStartScreenPosition = Handles.inverseMatrix.MultiplyPoint(mousePos);
s_DragStartScreenPosition.x = Mathf.Min(Mathf.Max(s_DragStartScreenPosition.x, textureArea.xMin), textureArea.xMax);
s_DragStartScreenPosition.y = Mathf.Min(Mathf.Max(s_DragStartScreenPosition.y, textureArea.yMin), textureArea.yMax);
evt.Use();
}
break;
case EventType.MouseDrag:
if (GUIUtility.hotControl == id)
{
evt.Use();
}
break;
case EventType.Repaint:
{
var startDragPoint = Handles.matrix.MultiplyPoint(s_DragStartScreenPosition);
if (GUIUtility.hotControl == id && ValidRect(startDragPoint, mousePos))
{
// TODO: use rectstyle
//rectStyle.Draw (GetCurrentRect (true, textureWidth, textureHeight, s_DragStartScreenPosition, s_CurrentMousePosition), GUIContent.none, false, false, false, false);
SpriteEditorUtility.BeginLines(Color.green * 1.5f);
SpriteEditorUtility.DrawBox(GetCurrentRect(false, textureArea, startDragPoint, mousePos));
SpriteEditorUtility.EndLines();
}
}
break;
case EventType.MouseUp:
if (GUIUtility.hotControl == id && evt.button == 0)
{
var startDragPoint = Handles.matrix.MultiplyPoint(s_DragStartScreenPosition);
if (ValidRect(startDragPoint, mousePos))
{
result = GetCurrentRect(false, textureArea, startDragPoint, mousePos);
GUI.changed = true;
evt.Use();
}
GUIUtility.hotControl = 0;
}
break;
case EventType.KeyDown:
if (GUIUtility.hotControl == id)
{
if (evt.keyCode == KeyCode.Escape)
{
GUIUtility.hotControl = 0;
GUI.changed = true;
evt.Use();
}
}
break;
}
return result;
}
static internal Rect RectCreator(float textureWidth, float textureHeight, GUIStyle rectStyle)
{
return RectCreator(new Rect(0, 0, textureWidth, textureHeight), rectStyle);
}
static private bool ValidRect(Vector2 startPoint, Vector2 endPoint)
{
return Mathf.Abs((endPoint - startPoint).x) > 5f && Mathf.Abs((endPoint - startPoint).y) > 5f;
}
static private Rect GetCurrentRect(bool screenSpace, Rect clampArea, Vector2 startPoint, Vector2 endPoint)
{
Rect r = EditorGUIExt.FromToRect(Handles.inverseMatrix.MultiplyPoint(startPoint), Handles.inverseMatrix.MultiplyPoint(endPoint));
r = SpriteEditorUtility.ClampedRect(SpriteEditorUtility.RoundToInt(r), clampArea, false);
if (screenSpace)
{
Vector2 topleft = Handles.matrix.MultiplyPoint(new Vector2(r.xMin, r.yMin));
Vector2 bottomright = Handles.matrix.MultiplyPoint(new Vector2(r.xMax, r.yMax));
r = new Rect(topleft.x, topleft.y, bottomright.x - topleft.x, bottomright.y - topleft.y);
}
return r;
}
}
}

View File

@@ -0,0 +1,514 @@
using UnityEngine;
using System;
using System.Collections.Generic;
using UnityEvent = UnityEngine.Event;
namespace UnityEditor.U2D.Sprites
{
[Serializable]
internal class SpriteEditorMenuSetting : ScriptableObject
{
public enum SlicingType
{
Automatic = 0,
GridByCellSize = 1,
GridByCellCount = 2,
IsometricGrid = 3
}
[SerializeField]
public Vector2 gridCellCount = new Vector2(1, 1);
[SerializeField]
public Vector2 gridSpriteSize = new Vector2(64, 64);
[SerializeField]
public Vector2 gridSpriteOffset = new Vector2(0, 0);
[SerializeField]
public Vector2 gridSpritePadding = new Vector2(0, 0);
[SerializeField]
public Vector2 pivot = Vector2.zero;
[SerializeField]
public int autoSlicingMethod = (int)SpriteFrameModule.AutoSlicingMethod.DeleteAll;
[SerializeField]
public int spriteAlignment;
[SerializeField]
public SlicingType slicingType;
[SerializeField]
public bool keepEmptyRects;
[SerializeField]
public bool isAlternate;
}
internal class SpriteEditorMenu : EditorWindow
{
private static Styles s_Styles;
private static long s_LastClosedTime;
private static SpriteEditorMenuSetting s_Setting;
private ITextureDataProvider m_TextureDataProvider;
private SpriteFrameModule m_SpriteFrameModule;
private List<Rect> m_PotentialRects;
private class Styles
{
public GUIStyle background = "grey_border";
public GUIStyle notice;
public Styles()
{
notice = new GUIStyle(GUI.skin.label);
notice.alignment = TextAnchor.MiddleCenter;
notice.wordWrap = true;
}
public readonly GUIContent[] spriteAlignmentOptions =
{
EditorGUIUtility.TrTextContent("Center"),
EditorGUIUtility.TrTextContent("Top Left"),
EditorGUIUtility.TrTextContent("Top"),
EditorGUIUtility.TrTextContent("Top Right"),
EditorGUIUtility.TrTextContent("Left"),
EditorGUIUtility.TrTextContent("Right"),
EditorGUIUtility.TrTextContent("Bottom Left"),
EditorGUIUtility.TrTextContent("Bottom"),
EditorGUIUtility.TrTextContent("Bottom Right"),
EditorGUIUtility.TrTextContent("Custom")
};
public readonly GUIContent[] slicingMethodOptions =
{
EditorGUIUtility.TrTextContent("Delete Existing", "Delete all existing sprite assets before the slicing operation"),
EditorGUIUtility.TrTextContent("Smart", "Try to match existing sprite rects to sliced rects from the slicing operation"),
EditorGUIUtility.TrTextContent("Safe", "Keep existing sprite rects intact")
};
public readonly GUIContent methodLabel = EditorGUIUtility.TrTextContent("Method");
public readonly GUIContent pivotLabel = EditorGUIUtility.TrTextContent("Pivot");
public readonly GUIContent typeLabel = EditorGUIUtility.TrTextContent("Type");
public readonly GUIContent sliceButtonLabel = EditorGUIUtility.TrTextContent("Slice");
public readonly GUIContent columnAndRowLabel = EditorGUIUtility.TrTextContent("Column & Row");
public readonly GUIContent columnLabel = EditorGUIUtility.TextContent("C");
public readonly GUIContent rowLabel = EditorGUIUtility.TextContent("R");
public readonly GUIContent pixelSizeLabel = EditorGUIUtility.TrTextContent("Pixel Size");
public readonly GUIContent xLabel = EditorGUIUtility.TextContent("X");
public readonly GUIContent yLabel = EditorGUIUtility.TextContent("Y");
public readonly GUIContent offsetLabel = EditorGUIUtility.TrTextContent("Offset");
public readonly GUIContent paddingLabel = EditorGUIUtility.TrTextContent("Padding");
public readonly GUIContent automaticSlicingHintLabel = EditorGUIUtility.TrTextContent("To obtain more accurate slicing results, manual slicing is recommended!");
public readonly GUIContent customPivotLabel = EditorGUIUtility.TrTextContent("Custom Pivot");
public readonly GUIContent keepEmptyRectsLabel = EditorGUIUtility.TrTextContent("Keep Empty Rects");
public readonly GUIContent isAlternateLabel = EditorGUIUtility.TrTextContent("Is Alternate");
}
internal List<Rect> GetPotentialRects()
{
if (m_PotentialRects == null)
m_PotentialRects = new List<Rect>();
m_PotentialRects.Clear();
switch (s_Setting.slicingType)
{
case SpriteEditorMenuSetting.SlicingType.Automatic:
// Do not show rects for Automatic
break;
case SpriteEditorMenuSetting.SlicingType.GridByCellCount:
DetermineGridCellSizeWithCellCount(out var cellSize);
m_PotentialRects.AddRange(m_SpriteFrameModule.GetGridRects(cellSize
, s_Setting.gridSpriteOffset
, s_Setting.gridSpritePadding
, true));
break;
case SpriteEditorMenuSetting.SlicingType.GridByCellSize:
m_PotentialRects.AddRange(m_SpriteFrameModule.GetGridRects(s_Setting.gridSpriteSize
, s_Setting.gridSpriteOffset
, s_Setting.gridSpritePadding
, true));
break;
case SpriteEditorMenuSetting.SlicingType.IsometricGrid:
m_PotentialRects.AddRange(m_SpriteFrameModule.GetIsometricRects(s_Setting.gridSpriteSize
, s_Setting.gridSpriteOffset
, s_Setting.isAlternate
, true));
break;
}
return m_PotentialRects;
}
private void Init(Rect buttonRect, SpriteFrameModule sf, ITextureDataProvider dataProvider)
{
// Create for once if setting was not created before.
if (s_Setting == null)
s_Setting = CreateInstance<SpriteEditorMenuSetting>();
m_SpriteFrameModule = sf;
m_TextureDataProvider = dataProvider;
buttonRect = GUIUtility.GUIToScreenRect(buttonRect);
float windowHeight = 195;
var windowSize = new Vector2(300, windowHeight);
ShowAsDropDown(buttonRect, windowSize);
Undo.undoRedoPerformed += UndoRedoPerformed;
RectSettingsDirty();
}
private void UndoRedoPerformed()
{
Repaint();
}
void OnEnable()
{
AssemblyReloadEvents.beforeAssemblyReload += Close;
}
private void OnDisable()
{
AssemblyReloadEvents.beforeAssemblyReload -= Close;
Undo.undoRedoPerformed -= UndoRedoPerformed;
s_LastClosedTime = DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond;
m_SpriteFrameModule.potentialRects = null;
m_SpriteFrameModule.spriteEditor.RequestRepaint();
}
private void RectSettingsDirty()
{
m_SpriteFrameModule.potentialRects = GetPotentialRects();
m_SpriteFrameModule.spriteEditor.RequestRepaint();
}
internal static bool ShowAtPosition(Rect buttonRect, SpriteFrameModule sf, ITextureDataProvider textureProvider)
{
// We could not use realtimeSinceStartUp since it is set to 0 when entering/exitting playmode, we assume an increasing time when comparing time.
long nowMilliSeconds = DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond;
bool justClosed = nowMilliSeconds < s_LastClosedTime + 50;
if (!justClosed)
{
if (UnityEvent.current != null) // Event.current can be null during integration test
UnityEvent.current.Use();
SpriteEditorMenu spriteEditorMenu = CreateInstance<SpriteEditorMenu>();
spriteEditorMenu.Init(buttonRect, sf, textureProvider);
return true;
}
return false;
}
private void OnGUI()
{
if (s_Styles == null)
s_Styles = new Styles();
// Leave some space above the elements
GUILayout.Space(4);
EditorGUIUtility.labelWidth = 124f;
EditorGUIUtility.wideMode = true;
GUI.Label(new Rect(0, 0, position.width, position.height), GUIContent.none, s_Styles.background);
EditorGUI.BeginChangeCheck();
SpriteEditorMenuSetting.SlicingType slicingType = s_Setting.slicingType;
slicingType = (SpriteEditorMenuSetting.SlicingType)EditorGUILayout.EnumPopup(s_Styles.typeLabel, slicingType);
if (EditorGUI.EndChangeCheck())
{
Undo.RegisterCompleteObjectUndo(s_Setting, "Change slicing type");
s_Setting.slicingType = slicingType;
RectSettingsDirty();
}
switch (slicingType)
{
case SpriteEditorMenuSetting.SlicingType.GridByCellSize:
case SpriteEditorMenuSetting.SlicingType.GridByCellCount:
OnGridGUI();
break;
case SpriteEditorMenuSetting.SlicingType.Automatic:
OnAutomaticGUI();
break;
case SpriteEditorMenuSetting.SlicingType.IsometricGrid:
OnIsometricGridGUI();
break;
}
DoPivotGUI();
GUILayout.Space(2f);
EditorGUI.BeginChangeCheck();
int slicingMethod = s_Setting.autoSlicingMethod;
slicingMethod = EditorGUILayout.Popup(s_Styles.methodLabel, slicingMethod, s_Styles.slicingMethodOptions);
if (EditorGUI.EndChangeCheck())
{
Undo.RegisterCompleteObjectUndo(s_Setting, "Change Slicing Method");
s_Setting.autoSlicingMethod = slicingMethod;
}
GUILayout.FlexibleSpace();
GUILayout.BeginHorizontal();
GUILayout.Space(EditorGUIUtility.labelWidth + 4);
if (GUILayout.Button(s_Styles.sliceButtonLabel))
DoSlicing();
GUILayout.EndHorizontal();
}
private void DoSlicing()
{
switch (s_Setting.slicingType)
{
case SpriteEditorMenuSetting.SlicingType.GridByCellCount:
case SpriteEditorMenuSetting.SlicingType.GridByCellSize:
DoGridSlicing();
break;
case SpriteEditorMenuSetting.SlicingType.Automatic:
DoAutomaticSlicing();
break;
case SpriteEditorMenuSetting.SlicingType.IsometricGrid:
DoIsometricGridSlicing();
break;
}
}
private void TwoIntFields(GUIContent label, GUIContent labelX, GUIContent labelY, ref int x, ref int y)
{
float height = EditorGUI.kSingleLineHeight;
Rect rect = GUILayoutUtility.GetRect(EditorGUILayout.kLabelFloatMinW, EditorGUILayout.kLabelFloatMaxW, height, height, EditorStyles.numberField);
Rect labelRect = rect;
labelRect.width = EditorGUIUtility.labelWidth;
labelRect.height = EditorGUI.kSingleLineHeight;
GUI.Label(labelRect, label);
Rect fieldRect = rect;
fieldRect.width -= EditorGUIUtility.labelWidth;
fieldRect.height = EditorGUI.kSingleLineHeight;
fieldRect.x += EditorGUIUtility.labelWidth;
fieldRect.width /= 2;
fieldRect.width -= 2;
EditorGUIUtility.labelWidth = 12;
x = EditorGUI.IntField(fieldRect, labelX, x);
fieldRect.x += fieldRect.width + 3;
y = EditorGUI.IntField(fieldRect, labelY, y);
EditorGUIUtility.labelWidth = labelRect.width;
}
private void OnGridGUI()
{
int width, height;
m_TextureDataProvider.GetTextureActualWidthAndHeight(out width, out height);
var texture = m_TextureDataProvider.GetReadableTexture2D();
int maxWidth = texture != null ? width : 4096;
int maxHeight = texture != null ? height : 4096;
if (s_Setting.slicingType == SpriteEditorMenuSetting.SlicingType.GridByCellCount)
{
int x = (int)s_Setting.gridCellCount.x;
int y = (int)s_Setting.gridCellCount.y;
EditorGUI.BeginChangeCheck();
TwoIntFields(s_Styles.columnAndRowLabel, s_Styles.columnLabel, s_Styles.rowLabel, ref x, ref y);
if (EditorGUI.EndChangeCheck())
{
Undo.RegisterCompleteObjectUndo(s_Setting, "Change column & row");
s_Setting.gridCellCount.x = Mathf.Clamp(x, 1, maxWidth);
s_Setting.gridCellCount.y = Mathf.Clamp(y, 1, maxHeight);
RectSettingsDirty();
}
}
else
{
int x = (int)s_Setting.gridSpriteSize.x;
int y = (int)s_Setting.gridSpriteSize.y;
EditorGUI.BeginChangeCheck();
TwoIntFields(s_Styles.pixelSizeLabel, s_Styles.xLabel, s_Styles.yLabel, ref x, ref y);
if (EditorGUI.EndChangeCheck())
{
Undo.RegisterCompleteObjectUndo(s_Setting, "Change grid size");
s_Setting.gridSpriteSize.x = Mathf.Clamp(x, 1, maxWidth);
s_Setting.gridSpriteSize.y = Mathf.Clamp(y, 1, maxHeight);
RectSettingsDirty();
}
}
{
int x = (int)s_Setting.gridSpriteOffset.x;
int y = (int)s_Setting.gridSpriteOffset.y;
EditorGUI.BeginChangeCheck();
TwoIntFields(s_Styles.offsetLabel, s_Styles.xLabel, s_Styles.yLabel, ref x, ref y);
if (EditorGUI.EndChangeCheck())
{
Undo.RegisterCompleteObjectUndo(s_Setting, "Change grid offset");
s_Setting.gridSpriteOffset.x = Mathf.Clamp(x, 0, maxWidth - s_Setting.gridSpriteSize.x);
s_Setting.gridSpriteOffset.y = Mathf.Clamp(y, 0, maxHeight - s_Setting.gridSpriteSize.y);
RectSettingsDirty();
}
}
{
int x = (int)s_Setting.gridSpritePadding.x;
int y = (int)s_Setting.gridSpritePadding.y;
EditorGUI.BeginChangeCheck();
TwoIntFields(s_Styles.paddingLabel, s_Styles.xLabel, s_Styles.yLabel, ref x, ref y);
if (EditorGUI.EndChangeCheck())
{
Undo.RegisterCompleteObjectUndo(s_Setting, "Change grid padding");
s_Setting.gridSpritePadding.x = Mathf.Clamp(x, 0, maxWidth);
s_Setting.gridSpritePadding.y = Mathf.Clamp(y, 0, maxHeight);
RectSettingsDirty();
}
}
EditorGUI.BeginChangeCheck();
bool keepEmptyRects = s_Setting.keepEmptyRects;
keepEmptyRects = EditorGUILayout.Toggle(s_Styles.keepEmptyRectsLabel, keepEmptyRects);
if (EditorGUI.EndChangeCheck())
{
Undo.RegisterCompleteObjectUndo(s_Setting, "Keep Empty Rects");
s_Setting.keepEmptyRects = keepEmptyRects;
}
}
private void OnAutomaticGUI()
{
float spacing = 38f;
var texture = m_TextureDataProvider.GetReadableTexture2D();
if (texture != null && UnityEditor.TextureUtil.IsCompressedTextureFormat(texture.format))
{
EditorGUILayout.LabelField(s_Styles.automaticSlicingHintLabel, s_Styles.notice);
spacing -= 31f;
}
}
private void OnIsometricGridGUI()
{
int width, height;
m_TextureDataProvider.GetTextureActualWidthAndHeight(out width, out height);
var texture = m_TextureDataProvider.GetReadableTexture2D();
int maxWidth = texture != null ? width : 4096;
int maxHeight = texture != null ? height : 4096;
{
int x = (int)s_Setting.gridSpriteSize.x;
int y = (int)s_Setting.gridSpriteSize.y;
EditorGUI.BeginChangeCheck();
TwoIntFields(s_Styles.pixelSizeLabel, s_Styles.xLabel, s_Styles.yLabel, ref x, ref y);
if (EditorGUI.EndChangeCheck())
{
Undo.RegisterCompleteObjectUndo(s_Setting, "Change grid size");
s_Setting.gridSpriteSize.x = Mathf.Clamp(x, 1, maxWidth);
s_Setting.gridSpriteSize.y = Mathf.Clamp(y, 1, maxHeight);
RectSettingsDirty();
}
}
{
int x = (int)s_Setting.gridSpriteOffset.x;
int y = (int)s_Setting.gridSpriteOffset.y;
EditorGUI.BeginChangeCheck();
TwoIntFields(s_Styles.offsetLabel, s_Styles.xLabel, s_Styles.yLabel, ref x, ref y);
if (EditorGUI.EndChangeCheck())
{
Undo.RegisterCompleteObjectUndo(s_Setting, "Change grid offset");
s_Setting.gridSpriteOffset.x = Mathf.Clamp(x, 0, maxWidth - s_Setting.gridSpriteSize.x);
s_Setting.gridSpriteOffset.y = Mathf.Clamp(y, 0, maxHeight - s_Setting.gridSpriteSize.y);
RectSettingsDirty();
}
}
EditorGUI.BeginChangeCheck();
bool keepEmptyRects = s_Setting.keepEmptyRects;
keepEmptyRects = EditorGUILayout.Toggle(s_Styles.keepEmptyRectsLabel, keepEmptyRects);
if (EditorGUI.EndChangeCheck())
{
Undo.RegisterCompleteObjectUndo(s_Setting, "Keep Empty Rects");
s_Setting.keepEmptyRects = keepEmptyRects;
}
EditorGUI.BeginChangeCheck();
bool isAlternate = s_Setting.isAlternate;
isAlternate = EditorGUILayout.Toggle(s_Styles.isAlternateLabel, isAlternate);
if (EditorGUI.EndChangeCheck())
{
Undo.RegisterCompleteObjectUndo(s_Setting, "Is Alternate");
s_Setting.isAlternate = isAlternate;
RectSettingsDirty();
}
}
private void DoPivotGUI()
{
EditorGUI.BeginChangeCheck();
int alignment = s_Setting.spriteAlignment;
alignment = EditorGUILayout.Popup(s_Styles.pivotLabel, alignment, s_Styles.spriteAlignmentOptions);
if (EditorGUI.EndChangeCheck())
{
Undo.RegisterCompleteObjectUndo(s_Setting, "Change Alignment");
s_Setting.spriteAlignment = alignment;
s_Setting.pivot = SpriteEditorUtility.GetPivotValue((SpriteAlignment)alignment, s_Setting.pivot);
}
Vector2 pivot = s_Setting.pivot;
EditorGUI.BeginChangeCheck();
using (new EditorGUI.DisabledScope(alignment != (int)SpriteAlignment.Custom))
{
pivot = EditorGUILayout.Vector2Field(s_Styles.customPivotLabel, pivot);
}
if (EditorGUI.EndChangeCheck())
{
Undo.RegisterCompleteObjectUndo(s_Setting, "Change custom pivot");
s_Setting.pivot = pivot;
}
}
private void DoAutomaticSlicing()
{
// 4 seems to be a pretty nice min size for a automatic sprite slicing. It used to be exposed to the slicing dialog, but it is actually better workflow to slice&crop manually than find a suitable size number
m_SpriteFrameModule.DoAutomaticSlicing(4, s_Setting.spriteAlignment, s_Setting.pivot, (SpriteFrameModule.AutoSlicingMethod)s_Setting.autoSlicingMethod);
}
private void DoGridSlicing()
{
if (s_Setting.slicingType == SpriteEditorMenuSetting.SlicingType.GridByCellCount)
SetGridCellSizeWithCellCount();
m_SpriteFrameModule.DoGridSlicing(s_Setting.gridSpriteSize, s_Setting.gridSpriteOffset, s_Setting.gridSpritePadding, s_Setting.spriteAlignment, s_Setting.pivot, (SpriteFrameModule.AutoSlicingMethod)s_Setting.autoSlicingMethod, s_Setting.keepEmptyRects);
}
private void DoIsometricGridSlicing()
{
m_SpriteFrameModule.DoIsometricGridSlicing(s_Setting.gridSpriteSize, s_Setting.gridSpriteOffset, s_Setting.spriteAlignment, s_Setting.pivot, (SpriteFrameModule.AutoSlicingMethod)s_Setting.autoSlicingMethod, s_Setting.keepEmptyRects, s_Setting.isAlternate);
}
private void SetGridCellSizeWithCellCount()
{
DetermineGridCellSizeWithCellCount(out var cellSize);
s_Setting.gridSpriteSize = cellSize;
}
private void DetermineGridCellSizeWithCellCount(out Vector2 cellSize)
{
int width, height;
m_TextureDataProvider.GetTextureActualWidthAndHeight(out width, out height);
var texture = m_TextureDataProvider.GetReadableTexture2D();
int maxWidth = texture != null ? width : 4096;
int maxHeight = texture != null ? height : 4096;
cellSize.x = (maxWidth - s_Setting.gridSpriteOffset.x - (s_Setting.gridSpritePadding.x * s_Setting.gridCellCount.x)) / s_Setting.gridCellCount.x;
cellSize.y = (maxHeight - s_Setting.gridSpriteOffset.y - (s_Setting.gridSpritePadding.y * s_Setting.gridCellCount.y)) / s_Setting.gridCellCount.y;
cellSize.x = Mathf.Clamp(cellSize.x, 1, maxWidth);
cellSize.y = Mathf.Clamp(cellSize.y, 1, maxHeight);
}
}
}

View File

@@ -0,0 +1,179 @@
using UnityEngine;
using UnityEngine.Assertions;
using UnityEvent = UnityEngine.Event;
namespace UnityEditor.U2D.Sprites
{
static internal class SpriteEditorUtility
{
public static Vector2 GetPivotValue(SpriteAlignment alignment, Vector2 customOffset)
{
switch (alignment)
{
case SpriteAlignment.BottomLeft:
return new Vector2(0f, 0f);
case SpriteAlignment.BottomCenter:
return new Vector2(0.5f, 0f);
case SpriteAlignment.BottomRight:
return new Vector2(1f, 0f);
case SpriteAlignment.LeftCenter:
return new Vector2(0f, 0.5f);
case SpriteAlignment.Center:
return new Vector2(0.5f, 0.5f);
case SpriteAlignment.RightCenter:
return new Vector2(1f, 0.5f);
case SpriteAlignment.TopLeft:
return new Vector2(0f, 1f);
case SpriteAlignment.TopCenter:
return new Vector2(0.5f, 1f);
case SpriteAlignment.TopRight:
return new Vector2(1f, 1f);
case SpriteAlignment.Custom:
return customOffset;
}
return Vector2.zero;
}
public static Rect RoundedRect(Rect rect)
{
return new Rect(
Mathf.RoundToInt(rect.xMin),
Mathf.RoundToInt(rect.yMin),
Mathf.RoundToInt(rect.width),
Mathf.RoundToInt(rect.height)
);
}
public static Rect RoundToInt(Rect r)
{
r.xMin = Mathf.RoundToInt(r.xMin);
r.yMin = Mathf.RoundToInt(r.yMin);
r.xMax = Mathf.RoundToInt(r.xMax);
r.yMax = Mathf.RoundToInt(r.yMax);
return r;
}
public static Rect ClampedRect(Rect rect, Rect clamp, bool maintainSize)
{
Rect r = new Rect(rect);
if (maintainSize)
{
Vector2 center = rect.center;
if (center.x + Mathf.Abs(rect.width) * .5f > clamp.xMax)
center.x = clamp.xMax - rect.width * .5f;
if (center.x - Mathf.Abs(rect.width) * .5f < clamp.xMin)
center.x = clamp.xMin + rect.width * .5f;
if (center.y + Mathf.Abs(rect.height) * .5f > clamp.yMax)
center.y = clamp.yMax - rect.height * .5f;
if (center.y - Mathf.Abs(rect.height) * .5f < clamp.yMin)
center.y = clamp.yMin + rect.height * .5f;
r.center = center;
}
else
{
if (r.width > 0f)
{
r.xMin = Mathf.Max(rect.xMin, clamp.xMin);
r.xMax = Mathf.Min(rect.xMax, clamp.xMax);
}
else
{
r.xMin = Mathf.Min(rect.xMin, clamp.xMax);
r.xMax = Mathf.Max(rect.xMax, clamp.xMin);
}
if (r.height > 0f)
{
r.yMin = Mathf.Max(rect.yMin, clamp.yMin);
r.yMax = Mathf.Min(rect.yMax, clamp.yMax);
}
else
{
r.yMin = Mathf.Min(rect.yMin, clamp.yMax);
r.yMax = Mathf.Max(rect.yMax, clamp.yMin);
}
}
r.width = Mathf.Abs(r.width);
r.height = Mathf.Abs(r.height);
return r;
}
public static void DrawBox(Rect position)
{
var points0 = new Vector3(position.xMin, position.yMin, 0f);
var points1 = new Vector3(position.xMax, position.yMin, 0f);
var points2 = new Vector3(position.xMax, position.yMax, 0f);
var points3 = new Vector3(position.xMin, position.yMax, 0f);
DrawLine(points0, points1);
DrawLine(points1, points2);
DrawLine(points2, points3);
DrawLine(points3, points0);
}
public static void DrawLine(Vector3 p1, Vector3 p2)
{
GL.Vertex(p1);
GL.Vertex(p2);
}
public static void BeginLines(Color color)
{
Assert.IsTrue(UnityEvent.current.type == EventType.Repaint);
HandleUtility.ApplyWireMaterial();
GL.PushMatrix();
GL.MultMatrix(Handles.matrix);
GL.Begin(GL.LINES);
GL.Color(color);
}
public static void EndLines()
{
Assert.IsTrue(UnityEvent.current.type == EventType.Repaint);
GL.End();
GL.PopMatrix();
}
public static void FourIntFields(Vector2 rectSize, GUIContent label, GUIContent labelX, GUIContent labelY, GUIContent labelZ, GUIContent labelW, ref int x, ref int y, ref int z, ref int w)
{
Rect rect = GUILayoutUtility.GetRect(rectSize.x, rectSize.y);
Rect labelRect = rect;
labelRect.width = EditorGUIUtility.labelWidth;
labelRect.height = EditorGUI.kSingleLineHeight;
GUI.Label(labelRect, label);
Rect fieldRect = rect;
fieldRect.width -= EditorGUIUtility.labelWidth;
fieldRect.height = EditorGUI.kSingleLineHeight;
fieldRect.x += EditorGUIUtility.labelWidth;
fieldRect.width /= 2;
fieldRect.width -= EditorGUI.kSpacingSubLabel;
float oldLabelWidth = EditorGUIUtility.labelWidth;
EditorGUIUtility.labelWidth = EditorGUI.kMiniLabelW;
GUI.SetNextControlName("FourIntFields_x");
x = EditorGUI.IntField(fieldRect, labelX, x);
fieldRect.x += fieldRect.width + EditorGUI.kSpacing;
GUI.SetNextControlName("FourIntFields_y");
y = EditorGUI.IntField(fieldRect, labelY, y);
fieldRect.y += EditorGUI.kSingleLineHeight + EditorGUI.kVerticalSpacingMultiField;
fieldRect.x -= fieldRect.width + EditorGUI.kSpacing;
GUI.SetNextControlName("FourIntFields_z");
z = EditorGUI.IntField(fieldRect, labelZ, z);
fieldRect.x += fieldRect.width + EditorGUI.kSpacing;
GUI.SetNextControlName("FourIntFields_w");
w = EditorGUI.IntField(fieldRect, labelW, w);
EditorGUIUtility.labelWidth = oldLabelWidth;
}
}
}

View File

@@ -0,0 +1,47 @@
using System.Collections;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
namespace UnityEditor.U2D.Sprites
{
internal class SpriteEditorWindowSettings : SettingsProvider
{
public const string kSettingsUniqueKey = "UnityEditor.U2D.Sprites/SpriteEditorWindow";
public const string kShowRevertConfirmation = kSettingsUniqueKey + "RevertConfirmation";
public const string kShowApplyConfirmation = kSettingsUniqueKey + "ApplyConfirmation";
public static readonly GUIContent kShowRevertConfirmationLabel = EditorGUIUtility.TrTextContent("Show Revert Confirmation");
public static readonly GUIContent kShowApplyConfirmationLabel = EditorGUIUtility.TrTextContent("Show Apply Confirmation");
public SpriteEditorWindowSettings() : base("Preferences/2D/Sprite Editor Window", SettingsScope.User)
{
guiHandler = OnGUI;
}
[SettingsProvider]
private static SettingsProvider CreateSettingsProvider()
{
return new SpriteEditorWindowSettings()
{
guiHandler = SettingsGUI
};
}
private static void SettingsGUI(string searchContext)
{
showApplyConfirmation = EditorGUILayout.Toggle(kShowApplyConfirmationLabel, showApplyConfirmation);
showRevertConfirmation = EditorGUILayout.Toggle(kShowRevertConfirmationLabel, showRevertConfirmation);
}
public static bool showRevertConfirmation
{
get { return EditorPrefs.GetBool(kShowRevertConfirmation, false); }
set { EditorPrefs.SetBool(kShowRevertConfirmation, value); }
}
public static bool showApplyConfirmation
{
get { return EditorPrefs.GetBool(kShowApplyConfirmation, false); }
set { EditorPrefs.SetBool(kShowApplyConfirmation, value); }
}
}
}

View File

@@ -0,0 +1,194 @@
using System;
using UnityEngine;
using System.Collections.Generic;
namespace UnityEditor
{
/// <summary>Abstract class that is used by systems to encapsulate Sprite data representation. Currently this is used by Sprite Editor Window.</summary>
[Serializable]
public class SpriteRect
{
[SerializeField]
string m_Name;
[SerializeField]
string m_OriginalName;
[SerializeField]
Vector2 m_Pivot;
[SerializeField]
SpriteAlignment m_Alignment;
[SerializeField]
Vector4 m_Border;
[SerializeField]
Rect m_Rect;
[SerializeField]
string m_SpriteID;
[SerializeField]
internal long m_InternalID;
internal bool m_RegisterInternalID;
GUID m_GUID;
// <summary>The name of the Sprite data.</summary>
public string name
{
get { return m_Name; }
set { m_Name = value; }
}
// <summary>Vector2value representing the pivot for the Sprite data.</summary>
public Vector2 pivot
{
get { return m_Pivot; }
set { m_Pivot = value; }
}
/// <summary>SpriteAlignment that represents the pivot value for the Sprite data.</summary>
public SpriteAlignment alignment
{
get { return m_Alignment; }
set { m_Alignment = value; }
}
/// <summary>Returns a Vector4 that represents the border of the Sprite data.</summary>
public Vector4 border
{
get { return m_Border; }
set { m_Border = value; }
}
// <summary>Rect value that represents the position and size of the Sprite data.</summary>
public Rect rect
{
get { return m_Rect; }
set { m_Rect = value; }
}
internal string originalName
{
get
{
if (m_OriginalName == null)
{
m_OriginalName = name;
}
return m_OriginalName;
}
set { m_OriginalName = value; }
}
// <summary>GUID to uniquely identify the SpriteRect data. This will be populated to Sprite.spriteID to identify the SpriteRect used to generate the Sprite.</summary>
public GUID spriteID
{
get
{
ValidateGUID();
return m_GUID;
}
set
{
m_GUID = value;
m_SpriteID = m_GUID.ToString();
ValidateGUID();
}
}
private void ValidateGUID()
{
if (m_GUID.Empty())
{
// We can't use ISerializationCallbackReceiver because we will hit into Script serialization errors
m_GUID = new GUID(m_SpriteID);
if (m_GUID.Empty())
{
m_GUID = GUID.Generate();
m_SpriteID = m_GUID.ToString();
}
}
}
/// <summary>Helper method to get SpriteRect.spriteID from a SerializedProperty.</summary>
/// <param name="sp">The SerializedProperty to acquire from.</param>
/// <returns>GUID for the SpriteRect.</returns>
public static GUID GetSpriteIDFromSerializedProperty(SerializedProperty sp)
{
return new GUID(sp.FindPropertyRelative("m_SpriteID").stringValue);
}
internal long internalID
{
get
{
return m_InternalID;
}
set
{
m_InternalID = value;
}
}
}
internal class SpriteRectCache : ScriptableObject
{
[SerializeField]
private List<SpriteRect> m_Rects;
public int Count
{
get { return m_Rects != null ? m_Rects.Count : 0; }
}
public SpriteRect RectAt(int i)
{
return i >= Count || i < 0 ? null : m_Rects[i];
}
public void AddRect(SpriteRect r)
{
if (m_Rects != null)
m_Rects.Add(r);
}
public void RemoveRect(SpriteRect r)
{
if (m_Rects != null)
m_Rects.RemoveAll(x => x.spriteID == r.spriteID);
}
public void ClearAll()
{
if (m_Rects != null)
m_Rects.Clear();
}
public int GetIndex(SpriteRect spriteRect)
{
if (m_Rects != null && spriteRect != null)
return m_Rects.FindIndex(p => p.spriteID == spriteRect.spriteID);
return -1;
}
public bool Contains(SpriteRect spriteRect)
{
if (m_Rects != null && spriteRect != null)
return m_Rects.Find(x => x.spriteID == spriteRect.spriteID) != null;
return false;
}
void OnEnable()
{
if (m_Rects == null)
m_Rects = new List<SpriteRect>();
}
}
}

View File

@@ -0,0 +1,430 @@
using System;
using UnityEngine;
using UnityEvent = UnityEngine.Event;
namespace UnityEditor.U2D.Sprites
{
internal class SpriteUtilityWindow : EditorWindow
{
protected class Styles
{
public readonly GUIStyle dragdot = "U2D.dragDot";
public readonly GUIStyle dragdotDimmed = "U2D.dragDotDimmed";
public readonly GUIStyle dragdotactive = "U2D.dragDotActive";
public readonly GUIStyle createRect = "U2D.createRect";
public readonly GUIStyle preToolbar = "preToolbar";
public readonly GUIStyle preButton = "preButton";
public readonly GUIStyle preLabel = "preLabel";
public readonly GUIStyle preSlider = "preSlider";
public readonly GUIStyle preSliderThumb = "preSliderThumb";
public readonly GUIStyle preBackground = "preBackground";
public readonly GUIStyle pivotdotactive = "U2D.pivotDotActive";
public readonly GUIStyle pivotdot = "U2D.pivotDot";
public readonly GUIStyle dragBorderdot = new GUIStyle();
public readonly GUIStyle dragBorderDotActive = new GUIStyle();
public readonly GUIStyle toolbar;
public readonly GUIContent alphaIcon;
public readonly GUIContent RGBIcon;
public readonly GUIStyle notice;
public readonly GUIContent smallMip;
public readonly GUIContent largeMip;
public Styles()
{
toolbar = new GUIStyle(EditorStyles.inspectorBig);
toolbar.margin.top = 0;
toolbar.margin.bottom = 0;
alphaIcon = EditorGUIUtility.IconContent("PreTextureAlpha");
RGBIcon = EditorGUIUtility.IconContent("PreTextureRGB");
preToolbar.border.top = 0;
createRect.border = new RectOffset(3, 3, 3, 3);
notice = new GUIStyle(GUI.skin.label);
notice.alignment = TextAnchor.MiddleCenter;
notice.normal.textColor = Color.yellow;
dragBorderdot.fixedHeight = 5f;
dragBorderdot.fixedWidth = 5f;
dragBorderdot.normal.background = EditorGUIUtility.whiteTexture;
dragBorderDotActive.fixedHeight = dragBorderdot.fixedHeight;
dragBorderDotActive.fixedWidth = dragBorderdot.fixedWidth;
dragBorderDotActive.normal.background = EditorGUIUtility.whiteTexture;
smallMip = EditorGUIUtility.IconContent("PreTextureMipMapLow");
largeMip = EditorGUIUtility.IconContent("PreTextureMipMapHigh");
}
}
protected void InitStyles()
{
if (m_Styles == null)
m_Styles = new Styles();
}
protected Styles m_Styles;
protected const float k_BorderMargin = 10f;
protected const float k_ScrollbarMargin = 16f;
protected const float k_InspectorWindowMargin = 8f;
protected const float k_InspectorWidth = 330f;
protected const float k_MinZoomPercentage = 0.9f;
protected const float k_MaxZoom = 50f;
protected const float k_WheelZoomSpeed = 0.03f;
protected const float k_MouseZoomSpeed = 0.005f;
protected const float k_ToolbarHeight = 17f;
protected ITexture2D m_Texture;
protected ITexture2D m_TextureAlphaOverride;
Rect m_TextureViewRect;
protected Rect m_TextureRect;
[SerializeField]
protected bool m_ShowAlpha = false;
[SerializeField]
protected float m_MipLevel = 0;
[SerializeField]
protected float m_Zoom = -1f;
[SerializeField]
protected Vector2 m_ScrollPosition = new Vector2();
public float zoomLevel
{
get { return m_Zoom; }
set { m_Zoom = Mathf.Clamp(value, GetMinZoom(), k_MaxZoom); }
}
internal Rect textureViewRect
{
get => m_TextureViewRect;
set
{
m_TextureViewRect = value;
zoomLevel = m_Zoom; // update zoom level
}
}
public Vector2 scrollPosition
{
get { return m_ScrollPosition; }
set
{
if (m_Zoom < 0)
m_Zoom = GetMinZoom();
m_ScrollPosition.x = Mathf.Clamp(value.x, maxScrollRect.xMin, maxScrollRect.xMax);
m_ScrollPosition.y = Mathf.Clamp(value.y, maxScrollRect.yMin, maxScrollRect.yMax);
}
}
public bool showAlpha
{
get { return m_ShowAlpha; }
set { m_ShowAlpha = value; }
}
public float mipLevel
{
get { return m_MipLevel; }
set
{
var mipCount = 1;
if (m_Texture != null)
mipCount = Mathf.Max(mipCount, TextureUtil.GetMipmapCount(m_Texture));
m_MipLevel = Mathf.Clamp(value, 0, mipCount - 1);
}
}
protected float GetMinZoom()
{
if (m_Texture == null)
return 1.0f;
// Case 654327: Add k_MaxZoom size to min check to ensure that min zoom is smaller than max zoom
return Mathf.Min(m_TextureViewRect.width / m_Texture.width, m_TextureViewRect.height / m_Texture.height, k_MaxZoom) * k_MinZoomPercentage;
}
protected void HandleZoom()
{
bool zoomMode = UnityEvent.current.alt && UnityEvent.current.button == 1;
if (zoomMode)
{
EditorGUIUtility.AddCursorRect(m_TextureViewRect, MouseCursor.Zoom);
}
if (
((UnityEvent.current.type == EventType.MouseUp || UnityEvent.current.type == EventType.MouseDown) && zoomMode) ||
((UnityEvent.current.type == EventType.KeyUp || UnityEvent.current.type == EventType.KeyDown) && UnityEvent.current.keyCode == KeyCode.LeftAlt)
)
{
Repaint();
}
if (UnityEvent.current.type == EventType.ScrollWheel || (UnityEvent.current.type == EventType.MouseDrag && UnityEvent.current.alt && UnityEvent.current.button == 1))
{
float zoomMultiplier = 1f - UnityEvent.current.delta.y * (UnityEvent.current.type == EventType.ScrollWheel ? k_WheelZoomSpeed : -k_MouseZoomSpeed);
// Clamp zoom
float wantedZoom = m_Zoom * zoomMultiplier;
float currentZoom = Mathf.Clamp(wantedZoom, GetMinZoom(), k_MaxZoom);
if (currentZoom != m_Zoom)
{
m_Zoom = currentZoom;
// We need to fix zoomMultiplier if we clamped wantedZoom != currentZoom
if (wantedZoom != currentZoom)
zoomMultiplier /= wantedZoom / currentZoom;
Vector3 textureHalfSize = new Vector2(m_Texture.width, m_Texture.height) * 0.5f;
Vector3 mousePositionWorld = Handles.inverseMatrix.MultiplyPoint3x4(UnityEvent.current.mousePosition + m_ScrollPosition);
Vector3 delta = (mousePositionWorld - textureHalfSize) * (zoomMultiplier - 1f);
m_ScrollPosition += (Vector2)Handles.matrix.MultiplyVector(delta);
UnityEvent.current.Use();
}
}
}
protected void HandlePanning()
{
// You can pan by holding ALT and using left button or NOT holding ALT and using right button. ALT + right is reserved for zooming.
bool panMode = (!UnityEvent.current.alt && UnityEvent.current.button > 0 || UnityEvent.current.alt && UnityEvent.current.button <= 0);
if (panMode && GUIUtility.hotControl == 0)
{
EditorGUIUtility.AddCursorRect(m_TextureViewRect, MouseCursor.Pan);
if (UnityEvent.current.type == EventType.MouseDrag)
{
m_ScrollPosition -= UnityEvent.current.delta;
UnityEvent.current.Use();
}
}
//We need to repaint when entering or exiting the pan mode, so the mouse cursor gets refreshed.
if (
((UnityEvent.current.type == EventType.MouseUp || UnityEvent.current.type == EventType.MouseDown) && panMode) ||
(UnityEvent.current.type == EventType.KeyUp || UnityEvent.current.type == EventType.KeyDown) && UnityEvent.current.keyCode == KeyCode.LeftAlt
)
{
Repaint();
}
}
// Bounding values for scrollbars. Changes with zoom, because we want min/max scroll to stop at texture edges.
protected Rect maxScrollRect
{
get
{
float halfWidth = m_Texture.width * .5f * m_Zoom;
float halfHeight = m_Texture.height * .5f * m_Zoom;
return new Rect(-halfWidth, -halfHeight, m_TextureViewRect.width + halfWidth * 2f, m_TextureViewRect.height + halfHeight * 2f);
}
}
// Max rect in texture space that can ever be visible
protected Rect maxRect
{
get
{
float marginW = m_TextureViewRect.width * .5f / GetMinZoom();
float marginH = m_TextureViewRect.height * .5f / GetMinZoom();
float left = -marginW;
float top = -marginH;
float width = m_Texture.width + marginW * 2f;
float height = m_Texture.height + marginH * 2f;
return new Rect(left, top, width, height);
}
}
protected void DrawTexturespaceBackground()
{
float size = Mathf.Max(maxRect.width, maxRect.height);
Vector2 offset = new Vector2(maxRect.xMin, maxRect.yMin);
float halfSize = size * .5f;
float alpha = EditorGUIUtility.isProSkin ? 0.15f : 0.08f;
float gridSize = 8f;
SpriteEditorUtility.BeginLines(new Color(0f, 0f, 0f, alpha));
for (float v = 0; v <= size; v += gridSize)
SpriteEditorUtility.DrawLine(new Vector2(-halfSize + v, halfSize + v) + offset, new Vector2(halfSize + v, -halfSize + v) + offset);
SpriteEditorUtility.EndLines();
}
private float Log2(float x)
{
return (float)(System.Math.Log(x) / System.Math.Log(2));
}
protected void DrawTexture()
{
float mipLevel = Mathf.Min(m_MipLevel, TextureUtil.GetMipmapCount(m_Texture) - 1);
FilterMode oldFilter = m_Texture.filterMode;
TextureUtil.SetFilterModeNoDirty(m_Texture, FilterMode.Point);
if (m_ShowAlpha)
{
// check if we have a valid alpha texture
if (m_TextureAlphaOverride != null)
EditorGUI.DrawTextureTransparent(m_TextureRect, m_TextureAlphaOverride, ScaleMode.StretchToFill, 0, mipLevel);
// else use the original texture and display its alpha
else
EditorGUI.DrawTextureAlpha(m_TextureRect, m_Texture, ScaleMode.StretchToFill, 0, mipLevel);
}
else
EditorGUI.DrawTextureTransparent(m_TextureRect, m_Texture, ScaleMode.StretchToFill, 0, mipLevel);
TextureUtil.SetFilterModeNoDirty(m_Texture, oldFilter);
}
protected void DrawScreenspaceBackground()
{
if (UnityEvent.current.type == EventType.Repaint)
m_Styles.preBackground.Draw(m_TextureViewRect, false, false, false, false);
}
protected void HandleScrollbars()
{
Rect horizontalScrollBarPosition = new Rect(m_TextureViewRect.xMin, m_TextureViewRect.yMax, m_TextureViewRect.width, k_ScrollbarMargin);
m_ScrollPosition.x = GUI.HorizontalScrollbar(horizontalScrollBarPosition, m_ScrollPosition.x, m_TextureViewRect.width, maxScrollRect.xMin, maxScrollRect.xMax);
Rect verticalScrollBarPosition = new Rect(m_TextureViewRect.xMax, m_TextureViewRect.yMin, k_ScrollbarMargin, m_TextureViewRect.height);
m_ScrollPosition.y = GUI.VerticalScrollbar(verticalScrollBarPosition, m_ScrollPosition.y, m_TextureViewRect.height, maxScrollRect.yMin, maxScrollRect.yMax);
}
protected void SetupHandlesMatrix()
{
// Offset from top left to center in view space
Vector3 handlesPos = new Vector3(m_TextureRect.x, m_TextureRect.yMax, 0f);
// We flip Y-scale because Unity texture space is bottom-up
Vector3 handlesScale = new Vector3(zoomLevel, -zoomLevel, 1f);
// Handle matrix is for converting between view and texture space coordinates, without taking account the scroll position.
// Scroll position is added separately so we can use it with GUIClip.
Handles.matrix = Matrix4x4.TRS(handlesPos, Quaternion.identity, handlesScale);
}
protected Rect DoAlphaZoomToolbarGUI(Rect area)
{
int mipCount = 1;
if (m_Texture != null)
mipCount = Mathf.Max(mipCount, TextureUtil.GetMipmapCount(m_Texture));
Rect drawArea = new Rect(area.width, 0, 0, area.height);
using (new EditorGUI.DisabledScope(mipCount == 1))
{
drawArea.width = m_Styles.largeMip.image.width;
drawArea.x -= drawArea.width;
GUI.Box(drawArea, m_Styles.largeMip, m_Styles.preLabel);
drawArea.width = EditorGUI.kSliderMinW;
drawArea.x -= drawArea.width;
m_MipLevel = Mathf.Round(GUI.HorizontalSlider(drawArea, m_MipLevel, mipCount - 1, 0, m_Styles.preSlider, m_Styles.preSliderThumb));
drawArea.width = m_Styles.smallMip.image.width;
drawArea.x -= drawArea.width;
GUI.Box(drawArea, m_Styles.smallMip, m_Styles.preLabel);
}
drawArea.width = EditorGUI.kSliderMinW;
drawArea.x -= drawArea.width;
zoomLevel = GUI.HorizontalSlider(drawArea, zoomLevel, GetMinZoom(), k_MaxZoom, m_Styles.preSlider, m_Styles.preSliderThumb);
drawArea.width = EditorGUI.kObjectFieldMiniThumbnailWidth;
drawArea.x -= drawArea.width + EditorGUI.kSpacing;
m_ShowAlpha = GUI.Toggle(drawArea, m_ShowAlpha, m_ShowAlpha ? m_Styles.alphaIcon : m_Styles.RGBIcon, "toolbarButton");
// Returns the area that is not used
return new Rect(area.x, area.y, drawArea.x, area.height);
}
protected void DoTextureGUI()
{
if (m_Texture == null)
return;
// zoom startup init
if (m_Zoom < 0f)
m_Zoom = GetMinZoom();
// Texture rect in view space
m_TextureRect = new Rect(
m_TextureViewRect.width / 2f - (m_Texture.width * m_Zoom / 2f),
m_TextureViewRect.height / 2f - (m_Texture.height * m_Zoom / 2f),
(m_Texture.width * m_Zoom),
(m_Texture.height * m_Zoom)
);
HandleScrollbars();
SetupHandlesMatrix();
DrawScreenspaceBackground();
GUIClip.Push(m_TextureViewRect, -m_ScrollPosition, Vector2.zero, false);
if (UnityEvent.current.type == EventType.Repaint)
{
DrawTexturespaceBackground();
DrawTexture();
DrawGizmos();
}
DoTextureGUIExtras();
GUIClip.Pop();
// Handle this after DoTextureGUIExtras in case user wants any event that is handled by Zoom or Panning
HandleZoom();
HandlePanning();
}
protected virtual void DoTextureGUIExtras()
{
}
protected virtual void DrawGizmos()
{
}
protected void SetNewTexture(Texture2D texture)
{
if (texture != m_Texture)
{
m_Texture = new Texture2DWrapper(texture);
m_Zoom = -1;
m_TextureAlphaOverride = null;
}
}
protected void SetAlphaTextureOverride(Texture2D alphaTexture)
{
if (alphaTexture != m_TextureAlphaOverride)
{
m_TextureAlphaOverride = new Texture2DWrapper(alphaTexture);
m_Zoom = -1;
}
}
internal override void OnResized()
{
if (m_Texture != null && UnityEvent.current != null)
HandleZoom();
base.OnResized();
}
internal static void DrawToolBarWidget(ref Rect drawRect, ref Rect toolbarRect, Action<Rect> drawAction)
{
toolbarRect.width -= drawRect.width;
if (toolbarRect.width < 0)
drawRect.width += toolbarRect.width;
if (drawRect.width > 0)
drawAction(drawRect);
}
} // class
}