SpriteShapeEditorTool.cs 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324
  1. using System;
  2. using UnityEngine;
  3. using UnityEngine.U2D;
  4. using UnityEditor;
  5. using UnityEditor.U2D.Path;
  6. using UnityEditor.EditorTools;
  7. using UnityEditor.ShortcutManagement;
  8. using UnityEditor.U2D.Common;
  9. namespace UnityEditor.U2D.SpriteShapeInternal
  10. {
  11. internal class CustomDrawer : IDrawer
  12. {
  13. private IDrawer m_Drawer = new Drawer();
  14. private SpriteShapeController m_SpriteShapeController;
  15. public CustomDrawer(SpriteShapeController spriteShapeController)
  16. {
  17. m_SpriteShapeController = spriteShapeController;
  18. }
  19. private int GetSubDivisionCount()
  20. {
  21. return m_SpriteShapeController.splineDetail;
  22. }
  23. void IDrawer.DrawBezier(Vector3 p1, Vector3 p2, Vector3 p3, Vector3 p4, float width, Color color)
  24. {
  25. Handles.color = color;
  26. Handles.DrawAAPolyLine(null, width, Handles.MakeBezierPoints(p1, p4, p2, p3, GetSubDivisionCount()));
  27. }
  28. void IDrawer.DrawCreatePointPreview(Vector3 position)
  29. {
  30. m_Drawer.DrawCreatePointPreview(position);
  31. }
  32. void IDrawer.DrawLine(Vector3 p1, Vector3 p2, float width, Color color)
  33. {
  34. m_Drawer.DrawLine(p1, p2, width, color);
  35. }
  36. void IDrawer.DrawPoint(Vector3 position)
  37. {
  38. m_Drawer.DrawPoint(position);
  39. }
  40. void IDrawer.DrawPointHovered(Vector3 position)
  41. {
  42. m_Drawer.DrawPointHovered(position);
  43. }
  44. void IDrawer.DrawPointSelected(Vector3 position)
  45. {
  46. m_Drawer.DrawPointSelected(position);
  47. }
  48. void IDrawer.DrawTangent(Vector3 position, Vector3 tangent)
  49. {
  50. m_Drawer.DrawTangent(position, tangent);
  51. }
  52. }
  53. [Serializable]
  54. internal class SpriteShapeData
  55. {
  56. public float height = 1f;
  57. public int spriteIndex;
  58. public int corner = 1;
  59. public int cornerMode = 1;
  60. }
  61. internal class ScriptableSpriteShapeData : ScriptableData<SpriteShapeData> { }
  62. [CanEditMultipleObjects]
  63. [CustomEditor(typeof(ScriptableSpriteShapeData))]
  64. internal class SpriteShapeDataInspector : Editor
  65. {
  66. private static class Contents
  67. {
  68. public static readonly GUIContent heightLabel = new GUIContent("Height", "Height override for control point.");
  69. public static readonly GUIContent spriteIndexLabel = new GUIContent("Sprite Variant", "Index of the sprite variant at this control point");
  70. public static readonly GUIContent invalidSpriteLabel = new GUIContent("No sprite defined");
  71. public static readonly GUIContent cornerLabel = new GUIContent("Corner", "Set if Corner is automatic or disabled.");
  72. public static readonly int[] cornerValues = { 0, 1, 2 };
  73. public static readonly GUIContent[] cornerOptions = { new GUIContent("Disabled"), new GUIContent("Automatic"), new GUIContent("Stretched"), };
  74. }
  75. private SerializedProperty m_Data;
  76. private SerializedProperty m_SpriteIndexProperty;
  77. private SerializedProperty m_HeightProperty;
  78. private SerializedProperty m_CornerProperty;
  79. private SerializedProperty m_CornerModeProperty;
  80. private void OnEnable()
  81. {
  82. m_Data = serializedObject.FindProperty("m_Data");
  83. m_SpriteIndexProperty = m_Data.FindPropertyRelative("spriteIndex");
  84. m_HeightProperty = m_Data.FindPropertyRelative("height");
  85. m_CornerProperty = m_Data.FindPropertyRelative("corner");
  86. m_CornerModeProperty = m_Data.FindPropertyRelative("cornerMode");
  87. }
  88. public override void OnInspectorGUI()
  89. {
  90. serializedObject.Update();
  91. EditorGUI.BeginChangeCheck();
  92. var heightValue = EditorGUILayout.Slider(Contents.heightLabel, m_HeightProperty.floatValue, 0.1f, 4.0f);
  93. if (EditorGUI.EndChangeCheck())
  94. m_HeightProperty.floatValue = heightValue;
  95. EditorGUI.BeginChangeCheck();
  96. var cornerValue = EditorGUILayout.IntPopup(Contents.cornerLabel, m_CornerModeProperty.intValue, Contents.cornerOptions, Contents.cornerValues);
  97. if (EditorGUI.EndChangeCheck())
  98. {
  99. m_CornerModeProperty.intValue = cornerValue;
  100. m_CornerProperty.intValue = cornerValue != 0 ? 1 : 0;
  101. }
  102. serializedObject.ApplyModifiedProperties();
  103. }
  104. }
  105. internal class CustomPath : GenericScriptablePath<SpriteShapeData> { }
  106. [CanEditMultipleObjects]
  107. [CustomEditor(typeof(CustomPath))]
  108. internal class CustomPathInspector : GenericScriptablePathInspector<ScriptableSpriteShapeData, SpriteShapeData> { }
  109. [EditorTool("Edit SpriteShape", typeof(SpriteShapeController))]
  110. internal class SpriteShapeEditorTool : PathEditorTool<CustomPath>
  111. {
  112. private static InternalEditorBridge.ShortcutContext m_ShortcutContext;
  113. public static SpriteShapeEditorTool activeSpriteShapeEditorTool
  114. {
  115. get
  116. {
  117. if (m_ShortcutContext != null)
  118. return m_ShortcutContext.context as SpriteShapeEditorTool;
  119. return null;
  120. }
  121. }
  122. protected override bool GetLinearTangentIsZero(UnityEngine.Object target)
  123. {
  124. return true;
  125. }
  126. protected override IDrawer GetCustomDrawer(UnityEngine.Object target)
  127. {
  128. return new CustomDrawer(target as SpriteShapeController);
  129. }
  130. protected override IShape GetShape(UnityEngine.Object target)
  131. {
  132. return Polygon.empty;
  133. }
  134. protected override void Initialize(CustomPath shapeEditor, SerializedObject serializedObject)
  135. {
  136. var controller = serializedObject.targetObject as SpriteShapeController;
  137. var spline = controller.spline;
  138. shapeEditor.shapeType = ShapeType.Spline;
  139. shapeEditor.isOpenEnded = spline.isOpenEnded;
  140. for (var i = 0; i < spline.GetPointCount(); ++i)
  141. {
  142. var position = spline.GetPosition(i);
  143. shapeEditor.AddPoint(new ControlPoint()
  144. {
  145. position = spline.GetPosition(i),
  146. localLeftTangent = spline.GetLeftTangent(i),
  147. localRightTangent = spline.GetRightTangent(i),
  148. tangentMode = (TangentMode)spline.GetTangentMode(i)
  149. });
  150. shapeEditor.SetData(i, new SpriteShapeData()
  151. {
  152. spriteIndex = spline.GetSpriteIndex(i),
  153. height = spline.GetHeight(i),
  154. cornerMode = (int)spline.GetCornerMode(i),
  155. corner = spline.GetCorner(i) ? 1 : 0,
  156. });
  157. }
  158. shapeEditor.UpdateTangentsFromMode();
  159. }
  160. protected override void SetShape(CustomPath shapeEditor, SerializedObject serializedObject)
  161. {
  162. serializedObject.Update();
  163. var controller = serializedObject.targetObject as SpriteShapeController;
  164. var splineProp = serializedObject.FindProperty("m_Spline");
  165. var controlPointsProp = splineProp.FindPropertyRelative("m_ControlPoints");
  166. splineProp.FindPropertyRelative("m_IsOpenEnded").boolValue = shapeEditor.isOpenEnded;
  167. controlPointsProp.arraySize = shapeEditor.pointCount;
  168. for (var i = 0; i < shapeEditor.pointCount; ++i)
  169. {
  170. var elementProp = controlPointsProp.GetArrayElementAtIndex(i);
  171. var point = shapeEditor.GetPoint(i);
  172. var data = shapeEditor.GetData(i);
  173. elementProp.FindPropertyRelative("position").vector3Value = point.position;
  174. elementProp.FindPropertyRelative("leftTangent").vector3Value = point.localLeftTangent;
  175. elementProp.FindPropertyRelative("rightTangent").vector3Value = point.localRightTangent;
  176. elementProp.FindPropertyRelative("mode").enumValueIndex = (int)point.tangentMode;
  177. elementProp.FindPropertyRelative("height").floatValue = data.height;
  178. elementProp.FindPropertyRelative("spriteIndex").intValue = data.spriteIndex;
  179. elementProp.FindPropertyRelative("corner").intValue = data.corner;
  180. elementProp.FindPropertyRelative("m_CornerMode").intValue = data.cornerMode;
  181. }
  182. serializedObject.ApplyModifiedProperties();
  183. }
  184. protected override void OnActivate()
  185. {
  186. RegisterShortcuts();
  187. }
  188. protected override void OnDeactivate()
  189. {
  190. UnregisterShortcuts();
  191. }
  192. private void CycleSpriteIndex()
  193. {
  194. foreach(var target in targets)
  195. {
  196. var spriteShapeController = target as SpriteShapeController;
  197. var shapeEditor = GetPath(target);
  198. Editor cachedEditor = null;
  199. Editor.CreateCachedEditor(spriteShapeController, typeof(SpriteShapeControllerEditor), ref cachedEditor);
  200. if (spriteShapeController == null || spriteShapeController.spriteShape == null || shapeEditor.selection.Count == 0 || cachedEditor == null || shapeEditor.selection.Count > 1)
  201. continue;
  202. var spriteShape = spriteShapeController.spriteShape;
  203. var scEditor = cachedEditor as SpriteShapeControllerEditor;
  204. var selected = shapeEditor.selection.elements[0];
  205. if (shapeEditor.selection.Contains(selected))
  206. {
  207. shapeEditor.undoObject.RegisterUndo("Cycle Variant");
  208. var data = shapeEditor.GetData(selected);
  209. var angleRangeIndex = scEditor.GetAngleRange(selected);
  210. if (angleRangeIndex != -1)
  211. {
  212. var angleRange = spriteShape.angleRanges[angleRangeIndex];
  213. if (angleRange.sprites.Count > 0)
  214. data.spriteIndex = (data.spriteIndex + 1) % angleRange.sprites.Count;
  215. shapeEditor.SetData(selected, data);
  216. }
  217. SetPath(target);
  218. }
  219. }
  220. }
  221. private static float SlopeAngle(Vector2 start, Vector2 end)
  222. {
  223. var dir = start - end;
  224. dir.Normalize();
  225. var dvup = new Vector2(0, 1f);
  226. var dvrt = new Vector2(1f, 0);
  227. var dr = Vector2.Dot(dir, dvrt);
  228. var du = Vector2.Dot(dir, dvup);
  229. var cu = Mathf.Acos(du);
  230. var sn = dr >= 0 ? 1.0f : -1.0f;
  231. var an = cu * Mathf.Rad2Deg * sn;
  232. // Adjust angles when direction is parallel to Up Axis.
  233. an = (du != 1f) ? an : 0;
  234. an = (du != -1f) ? an : -180f;
  235. return an;
  236. }
  237. private void RegisterShortcuts()
  238. {
  239. m_ShortcutContext = new InternalEditorBridge.ShortcutContext()
  240. {
  241. isActive = () => GUIUtility.hotControl == 0,
  242. context = this
  243. };
  244. InternalEditorBridge.RegisterShortcutContext(m_ShortcutContext);
  245. }
  246. private void UnregisterShortcuts()
  247. {
  248. InternalEditorBridge.UnregisterShortcutContext(m_ShortcutContext);
  249. }
  250. [Shortcut("SpriteShape Editing/Cycle Tangent Mode", typeof(InternalEditorBridge.ShortcutContext), KeyCode.M)]
  251. private static void ShortcutCycleTangentMode(ShortcutArguments args)
  252. {
  253. if (args.context == m_ShortcutContext)
  254. (m_ShortcutContext.context as SpriteShapeEditorTool).CycleTangentMode();
  255. }
  256. [Shortcut("SpriteShape Editing/Cycle Variant", typeof(InternalEditorBridge.ShortcutContext), KeyCode.N)]
  257. private static void ShortcutCycleSpriteIndex(ShortcutArguments args)
  258. {
  259. if (args.context == m_ShortcutContext)
  260. (m_ShortcutContext.context as SpriteShapeEditorTool).CycleSpriteIndex();
  261. }
  262. [Shortcut("SpriteShape Editing/Mirror Tangent", typeof(InternalEditorBridge.ShortcutContext), KeyCode.B)]
  263. private static void ShortcutCycleMirrorTangent(ShortcutArguments args)
  264. {
  265. if (args.context == m_ShortcutContext)
  266. (m_ShortcutContext.context as SpriteShapeEditorTool).MirrorTangent();
  267. }
  268. }
  269. }