1051 lines
		
	
	
		
			39 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
			
		
		
	
	
			1051 lines
		
	
	
		
			39 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
| using UnityEngine;
 | |
| using System.Collections.Generic;
 | |
| using System;
 | |
| using System.Linq;
 | |
| using Unity.Collections;
 | |
| using UnityEditor.U2D.Sprites.SpriteEditorTool;
 | |
| using UnityEngine.U2D;
 | |
| using UnityEngine.UIElements;
 | |
| using Object = UnityEngine.Object;
 | |
| 
 | |
| namespace UnityEditor.U2D.Sprites
 | |
| {
 | |
|     // We need this so that undo/redo works
 | |
|     [Serializable]
 | |
|     internal class SpriteOutline
 | |
|     {
 | |
|         [SerializeField]
 | |
|         public List<Vector2> m_Path = new List<Vector2>();
 | |
| 
 | |
|         public void Add(Vector2 point)
 | |
|         {
 | |
|             m_Path.Add(point);
 | |
|         }
 | |
| 
 | |
|         public void Insert(int index, Vector2 point)
 | |
|         {
 | |
|             m_Path.Insert(index, point);
 | |
|         }
 | |
| 
 | |
|         public void RemoveAt(int index)
 | |
|         {
 | |
|             m_Path.RemoveAt(index);
 | |
|         }
 | |
| 
 | |
|         public Vector2 this[int index]
 | |
|         {
 | |
|             get { return m_Path[index]; }
 | |
|             set { m_Path[index] = value; }
 | |
|         }
 | |
| 
 | |
|         public int Count
 | |
|         {
 | |
|             get { return m_Path.Count; }
 | |
|         }
 | |
| 
 | |
|         public void AddRange(IEnumerable<Vector2> addRange)
 | |
|         {
 | |
|             m_Path.AddRange(addRange);
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     // Collection of outlines for a single Sprite
 | |
|     [Serializable]
 | |
|     internal class SpriteOutlineList
 | |
|     {
 | |
|         [SerializeField]
 | |
|         List<SpriteOutline> m_SpriteOutlines;
 | |
|         [SerializeField]
 | |
|         float m_TessellationDetail = 0;
 | |
| 
 | |
|         public List<SpriteOutline> spriteOutlines { get { return m_SpriteOutlines; } set { m_SpriteOutlines = value; } }
 | |
|         public GUID spriteID { get; private set; }
 | |
| 
 | |
|         public float tessellationDetail
 | |
|         {
 | |
|             get { return m_TessellationDetail; }
 | |
|             set
 | |
|             {
 | |
|                 m_TessellationDetail = value;
 | |
|                 m_TessellationDetail = Mathf.Min(1, m_TessellationDetail);
 | |
|                 m_TessellationDetail = Mathf.Max(0, m_TessellationDetail);
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         public SpriteOutlineList(GUID guid)
 | |
|         {
 | |
|             this.spriteID = guid;
 | |
|             m_SpriteOutlines = new List<SpriteOutline>();
 | |
|         }
 | |
| 
 | |
|         public SpriteOutlineList(GUID guid, List<Vector2[]> list)
 | |
|         {
 | |
|             this.spriteID = guid;
 | |
| 
 | |
|             m_SpriteOutlines = new List<SpriteOutline>(list.Count);
 | |
|             for (int i = 0; i < list.Count; ++i)
 | |
|             {
 | |
|                 var newList = new SpriteOutline();
 | |
|                 newList.m_Path.AddRange(list[i]);
 | |
|                 m_SpriteOutlines.Add(newList);
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         public SpriteOutlineList(GUID guid, List<SpriteOutline> list)
 | |
|         {
 | |
|             this.spriteID = guid;
 | |
| 
 | |
|             m_SpriteOutlines = list;
 | |
|         }
 | |
| 
 | |
|         public List<Vector2[]> ToListVector()
 | |
|         {
 | |
|             var value = new List<Vector2[]>(m_SpriteOutlines.Count);
 | |
|             foreach (var s in m_SpriteOutlines)
 | |
|             {
 | |
|                 value.Add(s.m_Path.ToArray());
 | |
|             }
 | |
|             return value;
 | |
|         }
 | |
| 
 | |
|         public List<Vector2[]> ToListVectorCapped(Rect rect)
 | |
|         {
 | |
|             var value = ToListVector();
 | |
|             rect.center = Vector2.zero;
 | |
|             foreach (var path in value)
 | |
|             {
 | |
|                 for (int i = 0; i < path.Length; ++i)
 | |
|                 {
 | |
|                     var point = path[i];
 | |
|                     path[i] = SpriteOutlineModule.CapPointToRect(point, rect);
 | |
|                 }
 | |
|             }
 | |
|             return value;
 | |
|         }
 | |
| 
 | |
|         public SpriteOutline this[int index]
 | |
|         {
 | |
|             get { return IsValidIndex(index) ? m_SpriteOutlines[index] : null; }
 | |
|             set
 | |
|             {
 | |
|                 if (IsValidIndex(index))
 | |
|                     m_SpriteOutlines[index] = value;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         public static implicit operator List<SpriteOutline>(SpriteOutlineList list)
 | |
|         {
 | |
|             return list != null ? list.m_SpriteOutlines : null;
 | |
|         }
 | |
| 
 | |
|         public int Count { get { return m_SpriteOutlines.Count; } }
 | |
| 
 | |
|         bool IsValidIndex(int index)
 | |
|         {
 | |
|             return index >= 0 && index < Count;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     // Collection of Sprites' outlines
 | |
|     internal class SpriteOutlineModel : ScriptableObject
 | |
|     {
 | |
|         [SerializeField]
 | |
|         List<SpriteOutlineList> m_SpriteOutlineList = new List<SpriteOutlineList>();
 | |
| 
 | |
|         private SpriteOutlineModel()
 | |
|         {}
 | |
| 
 | |
|         public SpriteOutlineList this[int index]
 | |
|         {
 | |
|             get { return IsValidIndex(index) ? m_SpriteOutlineList[index] : null; }
 | |
|             set
 | |
|             {
 | |
|                 if (IsValidIndex(index))
 | |
|                     m_SpriteOutlineList[index] = value;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         public SpriteOutlineList this[GUID guid]
 | |
|         {
 | |
|             get { return m_SpriteOutlineList.FirstOrDefault(x => x.spriteID == guid); }
 | |
|             set
 | |
|             {
 | |
|                 var index = m_SpriteOutlineList.FindIndex(x => x.spriteID == guid);
 | |
|                 if (index != -1)
 | |
|                     m_SpriteOutlineList[index] = value;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         public void AddListVector2(GUID guid, List<Vector2[]> outline)
 | |
|         {
 | |
|             m_SpriteOutlineList.Add(new SpriteOutlineList(guid, outline));
 | |
|         }
 | |
| 
 | |
|         public int Count { get { return m_SpriteOutlineList.Count; } }
 | |
| 
 | |
|         bool IsValidIndex(int index)
 | |
|         {
 | |
|             return index >= 0 && index < Count;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     [RequireSpriteDataProvider(typeof(ISpriteOutlineDataProvider), typeof(ITextureDataProvider))]
 | |
|     internal class SpriteOutlineModule : SpriteEditorModuleBase
 | |
|     {
 | |
|         class Styles
 | |
|         {
 | |
|             public GUIContent generatingOutlineDialogTitle = EditorGUIUtility.TrTextContent("Outline");
 | |
|             public GUIContent generatingOutlineDialogContent = EditorGUIUtility.TrTextContent("Generating outline {0}/{1}");
 | |
|             public Color spriteBorderColor = new Color(0.25f, 0.5f, 1f, 0.75f);
 | |
|         }
 | |
| 
 | |
|         protected SpriteRect m_Selected;
 | |
| 
 | |
|         private const float k_HandleSize = 5f;
 | |
|         private readonly string k_DeleteCommandName = EventCommandNames.Delete;
 | |
|         private readonly string k_SoftDeleteCommandName = EventCommandNames.SoftDelete;
 | |
| 
 | |
|         private ShapeEditor[] m_ShapeEditors;
 | |
|         private bool m_RequestRepaint;
 | |
|         private Matrix4x4 m_HandleMatrix;
 | |
|         private Vector2 m_MousePosition;
 | |
|         private ShapeEditorRectSelectionTool m_ShapeSelectionUI;
 | |
|         private bool m_WasRectSelecting = false;
 | |
|         private Rect? m_SelectionRect;
 | |
|         private ITexture2D m_OutlineTexture;
 | |
|         private Styles m_Styles;
 | |
|         protected SpriteOutlineModel m_Outline;
 | |
|         protected ITextureDataProvider m_TextureDataProvider;
 | |
|         protected SpriteOutlineToolOverlayPanel m_SpriteOutlineToolElement;
 | |
| 
 | |
|         [SerializeReference]
 | |
|         private static SpriteOutlineList s_CopyOutline = null;
 | |
| 
 | |
|         public SpriteOutlineModule(ISpriteEditor sem, IEventSystem es, IUndoSystem us, IAssetDatabase ad, IGUIUtility gu, IShapeEditorFactory sef, ITexture2D outlineTexture)
 | |
|         {
 | |
|             spriteEditorWindow = sem;
 | |
|             undoSystem = us;
 | |
|             eventSystem = es;
 | |
|             assetDatabase = ad;
 | |
|             guiUtility = gu;
 | |
|             shapeEditorFactory = sef;
 | |
|             m_OutlineTexture = outlineTexture;
 | |
| 
 | |
|             m_ShapeSelectionUI = new ShapeEditorRectSelectionTool(gu);
 | |
| 
 | |
|             m_ShapeSelectionUI.RectSelect += RectSelect;
 | |
|             m_ShapeSelectionUI.ClearSelection += ClearSelection;
 | |
|         }
 | |
| 
 | |
|         public override string moduleName
 | |
|         {
 | |
|             get { return "Custom Outline"; }
 | |
|         }
 | |
| 
 | |
|         public override bool ApplyRevert(bool apply)
 | |
|         {
 | |
|             if (m_Outline != null)
 | |
|             {
 | |
|                 if (apply)
 | |
|                 {
 | |
|                     var outlineDataProvider = spriteEditorWindow.GetDataProvider<ISpriteOutlineDataProvider>();
 | |
|                     for (int i = 0; i < m_Outline.Count; ++i)
 | |
|                     {
 | |
|                         outlineDataProvider.SetOutlines(m_Outline[i].spriteID, m_Outline[i].ToListVector());
 | |
|                         outlineDataProvider.SetTessellationDetail(m_Outline[i].spriteID, m_Outline[i].tessellationDetail);
 | |
|                     }
 | |
|                 }
 | |
| 
 | |
|                 Object.DestroyImmediate(m_Outline);
 | |
|                 m_Outline = null;
 | |
|             }
 | |
| 
 | |
|             return true;
 | |
|         }
 | |
| 
 | |
|         private Styles styles
 | |
|         {
 | |
|             get
 | |
|             {
 | |
|                 if (m_Styles == null)
 | |
|                     m_Styles = new Styles();
 | |
|                 return m_Styles;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         protected virtual List<SpriteOutline> selectedShapeOutline
 | |
|         {
 | |
|             get
 | |
|             {
 | |
|                 return m_Outline[m_Selected.spriteID].spriteOutlines;
 | |
|             }
 | |
|             set
 | |
|             {
 | |
|                 m_Outline[m_Selected.spriteID].spriteOutlines = value;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         protected virtual string alterateLabelText => L10n.Tr("From Physics Shape");
 | |
| 
 | |
|         private bool shapeEditorDirty
 | |
|         {
 | |
|             get; set;
 | |
|         }
 | |
| 
 | |
|         private bool editingDisabled
 | |
|         {
 | |
|             get { return spriteEditorWindow.editingDisabled; }
 | |
|         }
 | |
| 
 | |
|         private ISpriteEditor spriteEditorWindow
 | |
|         {
 | |
|             get; set;
 | |
|         }
 | |
| 
 | |
|         private IUndoSystem undoSystem
 | |
|         {
 | |
|             get; set;
 | |
|         }
 | |
| 
 | |
|         private IEventSystem eventSystem
 | |
|         {
 | |
|             get; set;
 | |
|         }
 | |
| 
 | |
|         private IAssetDatabase assetDatabase
 | |
|         {
 | |
|             get; set;
 | |
|         }
 | |
| 
 | |
|         private IGUIUtility guiUtility
 | |
|         {
 | |
|             get; set;
 | |
|         }
 | |
| 
 | |
|         private IShapeEditorFactory shapeEditorFactory
 | |
|         {
 | |
|             get; set;
 | |
|         }
 | |
| 
 | |
|         private void RectSelect(Rect r, ShapeEditor.SelectionType selectionType)
 | |
|         {
 | |
|             var localRect = EditorGUIExt.FromToRect(ScreenToLocal(r.min), ScreenToLocal(r.max));
 | |
|             m_SelectionRect = localRect;
 | |
|         }
 | |
| 
 | |
|         private void ClearSelection()
 | |
|         {
 | |
|             m_RequestRepaint = true;
 | |
|         }
 | |
| 
 | |
|         protected virtual void LoadOutline()
 | |
|         {
 | |
|             m_Outline = ScriptableObject.CreateInstance<SpriteOutlineModel>();
 | |
|             m_Outline.hideFlags = HideFlags.HideAndDontSave;
 | |
|             var spriteDataProvider = spriteEditorWindow.GetDataProvider<ISpriteEditorDataProvider>();
 | |
|             var outlineDataProvider = spriteEditorWindow.GetDataProvider<ISpriteOutlineDataProvider>();
 | |
|             foreach (var rect in spriteDataProvider.GetSpriteRects())
 | |
|             {
 | |
|                 var outlines = outlineDataProvider.GetOutlines(rect.spriteID);
 | |
|                 m_Outline.AddListVector2(rect.spriteID, outlines);
 | |
|                 m_Outline[m_Outline.Count - 1].tessellationDetail = outlineDataProvider.GetTessellationDetail(rect.spriteID);
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         protected virtual List<Vector2[]> GetAlternateOutlines(GUID spriteID)
 | |
|         {
 | |
|             var alternateOutlineProvider = spriteEditorWindow.GetDataProvider<ISpritePhysicsOutlineDataProvider>();
 | |
|             return alternateOutlineProvider.GetOutlines(spriteID);
 | |
|         }
 | |
| 
 | |
|         public override void OnModuleActivate()
 | |
|         {
 | |
|             m_TextureDataProvider = spriteEditorWindow.GetDataProvider<ITextureDataProvider>();
 | |
|             LoadOutline();
 | |
|             GenerateOutlineIfNotExist();
 | |
|             undoSystem.RegisterUndoCallback(UndoRedoPerformed);
 | |
|             shapeEditorDirty = true;
 | |
|             SetupShapeEditor();
 | |
|             spriteEditorWindow.enableMouseMoveEvent = true;
 | |
|             AddMainUI(spriteEditorWindow.GetMainVisualContainer());
 | |
|         }
 | |
| 
 | |
|         void GenerateOutlineIfNotExist()
 | |
|         {
 | |
|             var rectCache = spriteEditorWindow.GetDataProvider<ISpriteEditorDataProvider>().GetSpriteRects();
 | |
|             if (rectCache != null)
 | |
|             {
 | |
|                 bool needApply = false;
 | |
|                 for (int i = 0; i < rectCache.Length; ++i)
 | |
|                 {
 | |
|                     var rect = rectCache[i];
 | |
|                     if (!HasShapeOutline(rect))
 | |
|                     {
 | |
|                         EditorUtility.DisplayProgressBar(styles.generatingOutlineDialogTitle.text,
 | |
|                             string.Format(styles.generatingOutlineDialogContent.text, i + 1 , rectCache.Length),
 | |
|                             (float)(i) / rectCache.Length);
 | |
| 
 | |
|                         SetupShapeEditorOutline(rect);
 | |
|                         needApply = true;
 | |
|                     }
 | |
|                 }
 | |
|                 if (needApply)
 | |
|                 {
 | |
|                     EditorUtility.ClearProgressBar();
 | |
|                     spriteEditorWindow.ApplyOrRevertModification(true);
 | |
|                     LoadOutline();
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         public override void OnModuleDeactivate()
 | |
|         {
 | |
|             undoSystem.UnregisterUndoCallback(UndoRedoPerformed);
 | |
|             CleanupShapeEditors();
 | |
|             m_Selected = null;
 | |
|             spriteEditorWindow.enableMouseMoveEvent = false;
 | |
|             if (m_Outline != null)
 | |
|             {
 | |
|                 undoSystem.ClearUndo(m_Outline);
 | |
|                 Object.DestroyImmediate(m_Outline);
 | |
|                 m_Outline = null;
 | |
|             }
 | |
|             RemoveMainUI(spriteEditorWindow.GetMainVisualContainer());
 | |
|         }
 | |
| 
 | |
|         public override void DoMainGUI()
 | |
|         {
 | |
|             IEvent evt = eventSystem.current;
 | |
| 
 | |
|             m_RequestRepaint = false;
 | |
|             m_HandleMatrix = Handles.matrix;
 | |
| 
 | |
|             m_MousePosition = Handles.inverseMatrix.MultiplyPoint(eventSystem.current.mousePosition);
 | |
|             if (m_Selected == null || !m_Selected.rect.Contains(m_MousePosition) && !IsMouseOverOutlinePoints() && evt.shift == false)
 | |
|                 spriteEditorWindow.HandleSpriteSelection();
 | |
| 
 | |
|             HandleCreateNewOutline();
 | |
| 
 | |
|             m_WasRectSelecting = m_ShapeSelectionUI.isSelecting;
 | |
| 
 | |
|             UpdateShapeEditors();
 | |
| 
 | |
|             m_ShapeSelectionUI.OnGUI();
 | |
| 
 | |
|             DrawGizmos();
 | |
| 
 | |
|             if (m_RequestRepaint || evt.type == EventType.MouseMove)
 | |
|                 spriteEditorWindow.RequestRepaint();
 | |
|         }
 | |
| 
 | |
|         protected virtual int alphaTolerance
 | |
|         {
 | |
|             get => SpriteOutlineModulePreference.alphaTolerance;
 | |
|             set => SpriteOutlineModulePreference.alphaTolerance = value;
 | |
|         }
 | |
| 
 | |
|         internal SpriteOutlineList selectedOutline => m_Outline[m_Selected.spriteID];
 | |
| 
 | |
|         public override void DoToolbarGUI(Rect drawArea)
 | |
|         {}
 | |
| 
 | |
|         public override void DoPostGUI()
 | |
|         {}
 | |
| 
 | |
|         public override bool CanBeActivated()
 | |
|         {
 | |
|             return SpriteFrameModule.GetSpriteImportMode(spriteEditorWindow.GetDataProvider<ISpriteEditorDataProvider>()) != SpriteImportMode.None;
 | |
|         }
 | |
| 
 | |
|         private void RecordUndo()
 | |
|         {
 | |
|             undoSystem.RegisterCompleteObjectUndo(m_Outline, "Outline changed");
 | |
|         }
 | |
| 
 | |
|         public void CreateNewOutline(Rect rectOutline)
 | |
|         {
 | |
|             Rect rect = m_Selected.rect;
 | |
|             if (rect.Contains(rectOutline.min) && rect.Contains(rectOutline.max))
 | |
|             {
 | |
|                 RecordUndo();
 | |
|                 SpriteOutline so = new SpriteOutline();
 | |
|                 Vector2 outlineOffset = new Vector2(0.5f * rect.width + rect.x, 0.5f * rect.height + rect.y);
 | |
|                 Rect selectionRect = new Rect(rectOutline);
 | |
|                 selectionRect.min = SnapPoint(rectOutline.min);
 | |
|                 selectionRect.max = SnapPoint(rectOutline.max);
 | |
|                 so.Add(CapPointToRect(new Vector2(selectionRect.xMin, selectionRect.yMin), rect) - outlineOffset);
 | |
|                 so.Add(CapPointToRect(new Vector2(selectionRect.xMax, selectionRect.yMin), rect) - outlineOffset);
 | |
|                 so.Add(CapPointToRect(new Vector2(selectionRect.xMax, selectionRect.yMax), rect) - outlineOffset);
 | |
|                 so.Add(CapPointToRect(new Vector2(selectionRect.xMin, selectionRect.yMax), rect) - outlineOffset);
 | |
|                 selectedShapeOutline.Add(so);
 | |
|                 spriteEditorWindow.SetDataModified();
 | |
|                 shapeEditorDirty = true;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         private void HandleCreateNewOutline()
 | |
|         {
 | |
|             if (m_WasRectSelecting && m_ShapeSelectionUI.isSelecting == false && m_SelectionRect != null && m_Selected != null)
 | |
|             {
 | |
|                 bool createNewOutline = true;
 | |
|                 foreach (var se in m_ShapeEditors)
 | |
|                 {
 | |
|                     if (se.selectedPoints.Count != 0)
 | |
|                     {
 | |
|                         createNewOutline = false;
 | |
|                         break;
 | |
|                     }
 | |
|                 }
 | |
| 
 | |
|                 if (createNewOutline)
 | |
|                     CreateNewOutline(m_SelectionRect.Value);
 | |
|             }
 | |
|             m_SelectionRect = null;
 | |
|         }
 | |
| 
 | |
|         public void UpdateShapeEditors()
 | |
|         {
 | |
|             SetupShapeEditor();
 | |
| 
 | |
|             if (m_Selected != null)
 | |
|             {
 | |
|                 IEvent currentEvent = eventSystem.current;
 | |
|                 var wantsDelete = currentEvent.type == EventType.ExecuteCommand && (currentEvent.commandName == k_SoftDeleteCommandName || currentEvent.commandName == k_DeleteCommandName);
 | |
| 
 | |
|                 for (int i = 0; i < m_ShapeEditors.Length; ++i)
 | |
|                 {
 | |
|                     if (m_ShapeEditors[i].GetPointsCount() == 0)
 | |
|                         continue;
 | |
| 
 | |
|                     m_ShapeEditors[i].inEditMode = true;
 | |
|                     m_ShapeEditors[i].OnGUI();
 | |
|                     if (shapeEditorDirty)
 | |
|                         break;
 | |
|                 }
 | |
| 
 | |
|                 if (wantsDelete)
 | |
|                 {
 | |
|                     // remove outline which have lesser than 3 points
 | |
|                     for (int i = selectedShapeOutline.Count - 1; i >= 0; --i)
 | |
|                     {
 | |
|                         if (selectedShapeOutline[i].Count < 3)
 | |
|                         {
 | |
|                             selectedShapeOutline.RemoveAt(i);
 | |
|                             shapeEditorDirty = true;
 | |
|                         }
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         private bool IsMouseOverOutlinePoints()
 | |
|         {
 | |
|             if (m_Selected == null)
 | |
|                 return false;
 | |
|             Vector2 outlineOffset = new Vector2(0.5f * m_Selected.rect.width + m_Selected.rect.x, 0.5f * m_Selected.rect.height + m_Selected.rect.y);
 | |
|             float handleSize = GetHandleSize();
 | |
|             Rect r = new Rect(0, 0, handleSize * 2, handleSize * 2);
 | |
|             for (int i = 0; i < selectedShapeOutline.Count; ++i)
 | |
|             {
 | |
|                 var outline = selectedShapeOutline[i];
 | |
|                 for (int j = 0; j < outline.Count; ++j)
 | |
|                 {
 | |
|                     r.center = outline[j] + outlineOffset;
 | |
|                     if (r.Contains(m_MousePosition))
 | |
|                         return true;
 | |
|                 }
 | |
|             }
 | |
|             return false;
 | |
|         }
 | |
| 
 | |
|         private float GetHandleSize()
 | |
|         {
 | |
|             return k_HandleSize / m_HandleMatrix.m00;
 | |
|         }
 | |
| 
 | |
|         private void CleanupShapeEditors()
 | |
|         {
 | |
|             if (m_ShapeEditors != null)
 | |
|             {
 | |
|                 for (int i = 0; i < m_ShapeEditors.Length; ++i)
 | |
|                 {
 | |
|                     for (int j = 0; j < m_ShapeEditors.Length; ++j)
 | |
|                     {
 | |
|                         if (i != j)
 | |
|                             m_ShapeEditors[j].UnregisterFromShapeEditor(m_ShapeEditors[i]);
 | |
|                     }
 | |
|                     m_ShapeEditors[i].OnDisable();
 | |
|                 }
 | |
|             }
 | |
|             m_ShapeEditors = null;
 | |
|         }
 | |
| 
 | |
|         public void SetupShapeEditor()
 | |
|         {
 | |
|             if (shapeEditorDirty || m_Selected != spriteEditorWindow.selectedSpriteRect)
 | |
|             {
 | |
|                 m_Selected = spriteEditorWindow.selectedSpriteRect;
 | |
|                 CleanupShapeEditors();
 | |
| 
 | |
|                 if (m_Selected != null)
 | |
|                 {
 | |
|                     if (!HasShapeOutline(m_Selected))
 | |
|                         SetupShapeEditorOutline(m_Selected);
 | |
|                     m_ShapeEditors = new ShapeEditor[selectedShapeOutline.Count];
 | |
| 
 | |
|                     for (int i = 0; i < selectedShapeOutline.Count; ++i)
 | |
|                     {
 | |
|                         int outlineIndex = i;
 | |
|                         m_ShapeEditors[i] = shapeEditorFactory.CreateShapeEditor();
 | |
|                         m_ShapeEditors[i].SetRectSelectionTool(m_ShapeSelectionUI);
 | |
|                         m_ShapeEditors[i].LocalToWorldMatrix = () => m_HandleMatrix;
 | |
|                         m_ShapeEditors[i].LocalToScreen = (point) => Handles.matrix.MultiplyPoint(point);
 | |
|                         m_ShapeEditors[i].ScreenToLocal = ScreenToLocal;
 | |
|                         m_ShapeEditors[i].RecordUndo = RecordUndo;
 | |
|                         m_ShapeEditors[i].GetHandleSize = GetHandleSize;
 | |
|                         m_ShapeEditors[i].lineTexture = m_OutlineTexture;
 | |
|                         m_ShapeEditors[i].Snap = SnapPoint;
 | |
|                         m_ShapeEditors[i].GetPointPosition = (index) => GetPointPosition(outlineIndex, index);
 | |
|                         m_ShapeEditors[i].SetPointPosition = (index, position) => SetPointPosition(outlineIndex, index, position);
 | |
|                         m_ShapeEditors[i].InsertPointAt = (index, position) => InsertPointAt(outlineIndex, index, position);
 | |
|                         m_ShapeEditors[i].RemovePointAt = (index) => RemovePointAt(outlineIndex, index);
 | |
|                         m_ShapeEditors[i].GetPointsCount = () => GetPointsCount(outlineIndex);
 | |
|                     }
 | |
|                     for (int i = 0; i < selectedShapeOutline.Count; ++i)
 | |
|                     {
 | |
|                         for (int j = 0; j < selectedShapeOutline.Count; ++j)
 | |
|                         {
 | |
|                             if (i != j)
 | |
|                                 m_ShapeEditors[j].RegisterToShapeEditor(m_ShapeEditors[i]);
 | |
|                         }
 | |
|                     }
 | |
|                 }
 | |
|                 else
 | |
|                 {
 | |
|                     m_ShapeEditors = new ShapeEditor[0];
 | |
|                 }
 | |
|             }
 | |
|             shapeEditorDirty = false;
 | |
|         }
 | |
| 
 | |
|         protected virtual bool HasShapeOutline(SpriteRect spriteRect)
 | |
|         {
 | |
|             var outline = m_Outline[spriteRect.spriteID] != null ? m_Outline[spriteRect.spriteID].spriteOutlines : null;
 | |
|             return outline != null;
 | |
|         }
 | |
| 
 | |
|         private void AddMainUI(VisualElement mainView)
 | |
|         {
 | |
|             m_SpriteOutlineToolElement = SpriteOutlineToolOverlayPanel.GenerateFromUXML(alterateLabelText);
 | |
|             m_SpriteOutlineToolElement.AddStyleSheetPath("Packages/com.unity.2d.sprite/Editor/UI/SpriteEditor/SpriteEditor.uss");
 | |
|             m_SpriteOutlineToolElement.AddToClassList("moduleWindow");
 | |
|             m_SpriteOutlineToolElement.AddToClassList("bottomRightFloating");
 | |
|             mainView.Add(m_SpriteOutlineToolElement);
 | |
|             m_SpriteOutlineToolElement.onGenerateOutline += OnGenerateOutline;
 | |
|             m_SpriteOutlineToolElement.onCopy += Copy;
 | |
|             m_SpriteOutlineToolElement.onPaste += Paste;
 | |
|             m_SpriteOutlineToolElement.onPasteAll += PasteAll;
 | |
|             m_SpriteOutlineToolElement.onPasteAlternate += PasteFromAlternate;
 | |
|             m_SpriteOutlineToolElement.onPasteAlternateAll += PasteAllFromAlternate;
 | |
|             m_SpriteOutlineToolElement.onAlphaToleranceChanged += OnAlphaToleranceChanged;
 | |
|             m_SpriteOutlineToolElement.onOutlineDetailChanged += OnOutlineDetailChanged;
 | |
|             mainView.RegisterCallback<SpriteSelectionChangeEvent>(SpriteSelectionChange);
 | |
|             SetupUIPanel();
 | |
|         }
 | |
| 
 | |
|         private void RemoveMainUI(VisualElement mainView)
 | |
|         {
 | |
|             if (m_SpriteOutlineToolElement != null)
 | |
|             {
 | |
|                 if (mainView.Contains(m_SpriteOutlineToolElement))
 | |
|                     mainView.Remove(m_SpriteOutlineToolElement);
 | |
|                 mainView.UnregisterCallback<SpriteSelectionChangeEvent>(SpriteSelectionChange);
 | |
|                 m_SpriteOutlineToolElement.onGenerateOutline -= OnGenerateOutline;
 | |
|                 m_SpriteOutlineToolElement.onCopy -= Copy;
 | |
|                 m_SpriteOutlineToolElement.onPaste -= Paste;
 | |
|                 m_SpriteOutlineToolElement.onPasteAll -= PasteAll;
 | |
|                 m_SpriteOutlineToolElement.onPasteAlternate -= PasteFromAlternate;
 | |
|                 m_SpriteOutlineToolElement.onPasteAlternateAll -= PasteAllFromAlternate;
 | |
|                 m_SpriteOutlineToolElement.onAlphaToleranceChanged -= OnAlphaToleranceChanged;
 | |
|                 m_SpriteOutlineToolElement.onOutlineDetailChanged -= OnOutlineDetailChanged;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         void SetupUIPanel()
 | |
|         {
 | |
|             m_Selected = spriteEditorWindow.selectedSpriteRect;
 | |
|             m_SpriteOutlineToolElement.SetPanelMode(m_Selected != null);
 | |
|             if (m_Selected != null)
 | |
|             {
 | |
|                 m_SpriteOutlineToolElement.outlineDetail = m_Outline[m_Selected.spriteID].tessellationDetail;
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 m_SpriteOutlineToolElement.outlineDetail = 0;
 | |
|             }
 | |
| 
 | |
|             m_SpriteOutlineToolElement.alphaTolerance = alphaTolerance;
 | |
|         }
 | |
| 
 | |
|         void OnAlphaToleranceChanged(int value)
 | |
|         {
 | |
|             alphaTolerance = value;
 | |
|         }
 | |
| 
 | |
|         internal void OnOutlineDetailChanged(float value)
 | |
|         {
 | |
|             if(m_Selected != null)
 | |
|                 m_Outline[m_Selected.spriteID].tessellationDetail = value;
 | |
|         }
 | |
| 
 | |
|         void OnGenerateOutline(bool forceGenerate)
 | |
|         {
 | |
|             RecordUndo();
 | |
|             if (m_Selected != null)
 | |
|             {
 | |
|                 selectedShapeOutline.Clear();
 | |
|                 SetupShapeEditorOutline(m_Selected);
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 var rectCache = spriteEditorWindow.GetDataProvider<ISpriteEditorDataProvider>().GetSpriteRects();
 | |
|                 if (rectCache != null)
 | |
|                 {
 | |
|                     bool showedProgressBar = false;
 | |
|                     for (int i = 0; i < rectCache.Length; ++i)
 | |
|                     {
 | |
|                         var rect = rectCache[i];
 | |
|                         var outline = m_Outline[rect.spriteID] != null ? m_Outline[rect.spriteID].spriteOutlines : null;
 | |
|                         if (forceGenerate || outline == null || outline.Count == 0)
 | |
|                         {
 | |
|                             EditorUtility.DisplayProgressBar(styles.generatingOutlineDialogTitle.text,
 | |
|                                 string.Format(styles.generatingOutlineDialogContent.text, i + 1, rectCache.Length),
 | |
|                                 (float)(i) / rectCache.Length);
 | |
|                             showedProgressBar = true;
 | |
|                             m_Outline[rect.spriteID].tessellationDetail = m_SpriteOutlineToolElement.outlineDetail;
 | |
|                             SetupShapeEditorOutline(rect);
 | |
|                         }
 | |
|                     }
 | |
|                     if(showedProgressBar)
 | |
|                         EditorUtility.ClearProgressBar();
 | |
|                 }
 | |
|             }
 | |
|             spriteEditorWindow.SetDataModified();
 | |
|             shapeEditorDirty = true;
 | |
|         }
 | |
| 
 | |
|         void SpriteSelectionChange(SpriteSelectionChangeEvent evt)
 | |
|         {
 | |
|             var spriteRect = spriteEditorWindow.selectedSpriteRect;
 | |
|             m_SpriteOutlineToolElement.SetPanelMode(spriteRect != null);
 | |
|             if (spriteRect != null)
 | |
|             {
 | |
|                 var data = m_Outline[spriteRect.spriteID];
 | |
|                 if(data != null)
 | |
|                     m_SpriteOutlineToolElement.outlineDetail = m_Outline[spriteRect.spriteID].tessellationDetail;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         protected virtual void SetupShapeEditorOutline(SpriteRect spriteRect)
 | |
|         {
 | |
|             var outline = m_Outline[spriteRect.spriteID];
 | |
|             var outlines = GenerateSpriteRectOutline(spriteRect.rect,
 | |
|                 Math.Abs(outline.tessellationDetail - (-1f)) < Mathf.Epsilon ? 0 : outline.tessellationDetail,
 | |
|                 (byte)(alphaTolerance), m_TextureDataProvider, m_SpriteOutlineToolElement.optimizeOutline);
 | |
|             if (outlines.Count == 0)
 | |
|             {
 | |
|                 Vector2 halfSize = spriteRect.rect.size * 0.5f;
 | |
|                 outlines = new List<SpriteOutline>()
 | |
|                 {
 | |
|                     new SpriteOutline()
 | |
|                     {
 | |
|                         m_Path = new List<Vector2>()
 | |
|                         {
 | |
|                             new Vector2(-halfSize.x, -halfSize.y),
 | |
|                             new Vector2(-halfSize.x, halfSize.y),
 | |
|                             new Vector2(halfSize.x, halfSize.y),
 | |
|                             new Vector2(halfSize.x, -halfSize.y),
 | |
|                         }
 | |
|                     }
 | |
|                 };
 | |
|             }
 | |
|             m_Outline[spriteRect.spriteID].spriteOutlines = outlines;
 | |
|         }
 | |
| 
 | |
|         public Vector3 SnapPoint(Vector3 position)
 | |
|         {
 | |
|             if (m_SpriteOutlineToolElement.snapOn)
 | |
|             {
 | |
|                 position.x = Mathf.RoundToInt(position.x);
 | |
|                 position.y = Mathf.RoundToInt(position.y);
 | |
|             }
 | |
|             return position;
 | |
|         }
 | |
| 
 | |
|         public Vector3 GetPointPosition(int outlineIndex, int pointIndex)
 | |
|         {
 | |
|             if (outlineIndex >= 0 && outlineIndex < selectedShapeOutline.Count)
 | |
|             {
 | |
|                 var outline = selectedShapeOutline[outlineIndex];
 | |
|                 if (pointIndex >= 0 && pointIndex < outline.Count)
 | |
|                 {
 | |
|                     return ConvertSpriteRectSpaceToTextureSpace(outline[pointIndex]);
 | |
|                 }
 | |
|             }
 | |
|             return new Vector3(float.NaN, float.NaN, float.NaN);
 | |
|         }
 | |
| 
 | |
|         public void SetPointPosition(int outlineIndex, int pointIndex, Vector3 position)
 | |
|         {
 | |
|             selectedShapeOutline[outlineIndex][pointIndex] = ConvertTextureSpaceToSpriteRectSpace(CapPointToRect(position, m_Selected.rect));
 | |
|             spriteEditorWindow.SetDataModified();
 | |
|         }
 | |
| 
 | |
|         public void InsertPointAt(int outlineIndex, int pointIndex, Vector3 position)
 | |
|         {
 | |
|             selectedShapeOutline[outlineIndex].Insert(pointIndex, ConvertTextureSpaceToSpriteRectSpace(CapPointToRect(position, m_Selected.rect)));
 | |
|             spriteEditorWindow.SetDataModified();
 | |
|         }
 | |
| 
 | |
|         public void RemovePointAt(int outlineIndex, int i)
 | |
|         {
 | |
|             selectedShapeOutline[outlineIndex].RemoveAt(i);
 | |
|             spriteEditorWindow.SetDataModified();
 | |
|         }
 | |
| 
 | |
|         public int GetPointsCount(int outlineIndex)
 | |
|         {
 | |
|             return selectedShapeOutline[outlineIndex].Count;
 | |
|         }
 | |
| 
 | |
|         private Vector2 ConvertSpriteRectSpaceToTextureSpace(Vector2 value)
 | |
|         {
 | |
|             Vector2 outlineOffset = new Vector2(0.5f * m_Selected.rect.width + m_Selected.rect.x, 0.5f * m_Selected.rect.height + m_Selected.rect.y);
 | |
|             value += outlineOffset;
 | |
|             return value;
 | |
|         }
 | |
| 
 | |
|         private Vector2 ConvertTextureSpaceToSpriteRectSpace(Vector2 value)
 | |
|         {
 | |
|             Vector2 outlineOffset = new Vector2(0.5f * m_Selected.rect.width + m_Selected.rect.x, 0.5f * m_Selected.rect.height + m_Selected.rect.y);
 | |
|             value -= outlineOffset;
 | |
|             return value;
 | |
|         }
 | |
| 
 | |
|         private Vector3 ScreenToLocal(Vector2 point)
 | |
|         {
 | |
|             return Handles.inverseMatrix.MultiplyPoint(point);
 | |
|         }
 | |
| 
 | |
|         private void UndoRedoPerformed()
 | |
|         {
 | |
|             shapeEditorDirty = true;
 | |
|         }
 | |
| 
 | |
|         private void DrawGizmos()
 | |
|         {
 | |
|             if (eventSystem.current.type == EventType.Repaint)
 | |
|             {
 | |
|                 var selected = spriteEditorWindow.selectedSpriteRect;
 | |
|                 if (selected != null)
 | |
|                 {
 | |
|                     SpriteEditorUtility.BeginLines(styles.spriteBorderColor);
 | |
|                     SpriteEditorUtility.DrawBox(selected.rect);
 | |
|                     SpriteEditorUtility.EndLines();
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         protected static List<SpriteOutline> GenerateSpriteRectOutline(Rect rect, float detail, byte alphaTolerance, ITextureDataProvider textureProvider, bool useClipper)
 | |
|         {
 | |
|             List<SpriteOutline> outline = new List<SpriteOutline>();
 | |
|             var texture = textureProvider.GetReadableTexture2D();
 | |
|             if (texture != null)
 | |
|             {
 | |
|                 Vector2[][] paths;
 | |
| 
 | |
|                 // we might have a texture that is capped because of max size or NPOT.
 | |
|                 // in that case, we need to convert values from capped space to actual texture space and back.
 | |
|                 int actualWidth = 0, actualHeight = 0;
 | |
|                 int cappedWidth, cappedHeight;
 | |
|                 textureProvider.GetTextureActualWidthAndHeight(out actualWidth, out actualHeight);
 | |
|                 cappedWidth = texture.width;
 | |
|                 cappedHeight = texture.height;
 | |
| 
 | |
|                 Vector2 scale = new Vector2(cappedWidth / (float)actualWidth, cappedHeight / (float)actualHeight);
 | |
|                 Rect spriteRect = rect;
 | |
|                 spriteRect.xMin *= scale.x;
 | |
|                 spriteRect.xMax *= scale.x;
 | |
|                 spriteRect.yMin *= scale.y;
 | |
|                 spriteRect.yMax *= scale.y;
 | |
| 
 | |
|                 UnityEditor.Sprites.SpriteUtility.GenerateOutline(texture, spriteRect, detail, alphaTolerance, true, out paths);
 | |
|                 if (useClipper)
 | |
|                 {
 | |
|                         Clipper2D.Solution clipperSolution = new Clipper2D.Solution();
 | |
|                         var pathSize = new NativeArray<int>(paths.Length, Allocator.Temp);
 | |
|                         var pathArguments = new NativeArray<Clipper2D.PathArguments>(paths.Length, Allocator.Temp);
 | |
|                         var totalPoints = 0;
 | |
|                         for (int j = 0; j < paths.Length; ++j)
 | |
|                         {
 | |
|                             pathSize[j] = paths[j].Length;
 | |
|                             totalPoints += paths[j].Length;
 | |
|                             pathArguments[j] = new Clipper2D.PathArguments(Clipper2D.PolyType.ptSubject, true);
 | |
|                         }
 | |
|                         var pathPoints= new NativeArray<Vector2>(totalPoints, Allocator.Temp);
 | |
|                         int pathPointsCounter = 0;
 | |
|                         for (int j = 0; j < paths.Length; ++j)
 | |
|                         {
 | |
|                             NativeArray<Vector2>.Copy(paths[j], 0, pathPoints, pathPointsCounter, paths[j].Length);
 | |
|                             pathPointsCounter += paths[j].Length;
 | |
|                         }
 | |
|                         var executeArgument = new Clipper2D.ExecuteArguments()
 | |
|                         {
 | |
|                             initOption = Clipper2D.InitOptions.ioStrictlySimple,
 | |
|                             clipType = Clipper2D.ClipType.ctUnion,
 | |
|                             subjFillType = Clipper2D.PolyFillType.pftPositive,
 | |
|                             clipFillType = Clipper2D.PolyFillType.pftPositive
 | |
|                         };
 | |
|                         Clipper2D.Execute(ref clipperSolution, pathPoints, pathSize, pathArguments, executeArgument, Allocator.Temp);
 | |
|                         paths = new Vector2[clipperSolution.pathSizes.Length][];
 | |
|                         pathPointsCounter = 0;
 | |
|                         for (int i = 0; i < paths.Length; ++i)
 | |
|                         {
 | |
|                             paths[i] = new Vector2[clipperSolution.pathSizes[i]];
 | |
|                             NativeArray<Vector2>.Copy(clipperSolution.points, pathPointsCounter, paths[i], 0, paths[i].Length);
 | |
|                             pathPointsCounter += paths[i].Length;
 | |
|                         }
 | |
|                         pathSize.Dispose();
 | |
|                         pathArguments.Dispose();
 | |
|                         pathPoints.Dispose();
 | |
|                         clipperSolution.Dispose();
 | |
|                 }
 | |
| 
 | |
|                 Rect capRect = new Rect();
 | |
|                 capRect.size = rect.size;
 | |
|                 capRect.center = Vector2.zero;
 | |
|                 for (int j = 0; j < paths.Length; ++j)
 | |
|                 {
 | |
|                     SpriteOutline points = new SpriteOutline();
 | |
|                     foreach (Vector2 v in paths[j])
 | |
|                         points.Add(CapPointToRect(new Vector2(v.x / scale.x, v.y / scale.y), capRect));
 | |
| 
 | |
|                     outline.Add(points);
 | |
|                 }
 | |
|             }
 | |
|             return outline;
 | |
|         }
 | |
| 
 | |
|         public void Copy()
 | |
|         {
 | |
|             if (m_Selected == null || !HasShapeOutline(m_Selected))
 | |
|                 return;
 | |
| 
 | |
|             s_CopyOutline = new SpriteOutlineList(m_Selected.spriteID, m_Outline[m_Selected.spriteID].ToListVectorCapped(m_Selected.rect));
 | |
|         }
 | |
| 
 | |
|         private void ReplaceOutline(GUID spriteID, List<Vector2[]> newOutline)
 | |
|         {
 | |
|             var oldOutline = m_Outline[spriteID];
 | |
|             m_Outline[spriteID] = new SpriteOutlineList(spriteID, newOutline);
 | |
|             if (oldOutline != null)
 | |
|                 m_Outline[spriteID].tessellationDetail = oldOutline.tessellationDetail;
 | |
|         }
 | |
| 
 | |
| 
 | |
|         public void Paste()
 | |
|         {
 | |
|             if (m_Selected == null || s_CopyOutline == null)
 | |
|                 return;
 | |
| 
 | |
|             RecordUndo();
 | |
|             ReplaceOutline(m_Selected.spriteID, s_CopyOutline.ToListVectorCapped(m_Selected.rect));
 | |
|             spriteEditorWindow.SetDataModified();
 | |
|             shapeEditorDirty = true;
 | |
|         }
 | |
| 
 | |
|         public void PasteAll()
 | |
|         {
 | |
|             if (s_CopyOutline == null)
 | |
|                 return;
 | |
| 
 | |
|             RecordUndo();
 | |
|             var rectCache = spriteEditorWindow.GetDataProvider<ISpriteEditorDataProvider>().GetSpriteRects();
 | |
|             if (rectCache != null)
 | |
|             {
 | |
|                 foreach (var spriteRect in rectCache)
 | |
|                 {
 | |
|                     var outlines = s_CopyOutline.ToListVectorCapped(spriteRect.rect);
 | |
|                     ReplaceOutline(spriteRect.spriteID, outlines);
 | |
|                 }
 | |
|             }
 | |
|             spriteEditorWindow.SetDataModified();
 | |
|             shapeEditorDirty = true;
 | |
|         }
 | |
| 
 | |
|         public void PasteFromAlternate()
 | |
|         {
 | |
|             if (m_Selected == null)
 | |
|                 return;
 | |
| 
 | |
|             var alternateOutline = GetAlternateOutlines(m_Selected.spriteID);
 | |
| 
 | |
|             RecordUndo();
 | |
|             ReplaceOutline(m_Selected.spriteID, alternateOutline);
 | |
|             spriteEditorWindow.SetDataModified();
 | |
|             shapeEditorDirty = true;
 | |
|         }
 | |
| 
 | |
|         public void PasteAllFromAlternate()
 | |
|         {
 | |
|             RecordUndo();
 | |
|             var rectCache = spriteEditorWindow.GetDataProvider<ISpriteEditorDataProvider>().GetSpriteRects();
 | |
|             if (rectCache != null)
 | |
|             {
 | |
|                 foreach (var spriteRect in rectCache)
 | |
|                 {
 | |
|                     var alternateOutline = GetAlternateOutlines(spriteRect.spriteID);
 | |
|                     ReplaceOutline(spriteRect.spriteID, alternateOutline);
 | |
|                 }
 | |
|             }
 | |
|             spriteEditorWindow.SetDataModified();
 | |
|             shapeEditorDirty = true;
 | |
|         }
 | |
| 
 | |
|         internal static Vector2 CapPointToRect(Vector2 so, Rect r)
 | |
|         {
 | |
|             so.x = Mathf.Min(r.xMax, so.x);
 | |
|             so.x = Mathf.Max(r.xMin, so.x);
 | |
|             so.y = Mathf.Min(r.yMax, so.y);
 | |
|             so.y = Mathf.Max(r.yMin, so.y);
 | |
|             return so;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     internal class SpriteOutlineModulePreference
 | |
|     {
 | |
|         public const string kSettingsUniqueKey = "UnityEditor.U2D.Sprites/SpriteOutlineModule";
 | |
|         public const string kUseClipper = kSettingsUniqueKey + "kUseClipper";
 | |
|         public const string kAlphaTolerance = kSettingsUniqueKey + "kAlphaTolerance";
 | |
|         public const string kPhysicsAlphaTolerance = kSettingsUniqueKey + "kPhysicsAlphaTolerance";
 | |
| 
 | |
|         public static bool useClipper
 | |
|         {
 | |
|             get { return EditorPrefs.GetBool(kUseClipper, true); }
 | |
|             set { EditorPrefs.SetBool(kUseClipper, value); }
 | |
|         }
 | |
| 
 | |
|         public static int alphaTolerance
 | |
|         {
 | |
|             get { return EditorPrefs.GetInt(kAlphaTolerance, 0); }
 | |
|             set { EditorPrefs.SetInt(kAlphaTolerance, value); }
 | |
|         }
 | |
| 
 | |
|         public static int physicsAlphaTolerance
 | |
|         {
 | |
|             get { return EditorPrefs.GetInt(kPhysicsAlphaTolerance, 200); }
 | |
|             set { EditorPrefs.SetInt(kPhysicsAlphaTolerance, value); }
 | |
|         }
 | |
|     }
 | |
| }
 |