No Description
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

SpriteShapeEditorTool.cs 14KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392
  1. using System;
  2. using UnityEngine;
  3. using UnityEngine.U2D;
  4. using UnityEditor;
  5. using UnityEditor.U2D.Common.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, Color color)
  29. {
  30. m_Drawer.DrawCreatePointPreview(position, color);
  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, Color color)
  37. {
  38. m_Drawer.DrawPoint(position, color);
  39. }
  40. void IDrawer.DrawPointHovered(Vector3 position, Color color)
  41. {
  42. m_Drawer.DrawPointHovered(position, color);
  43. }
  44. void IDrawer.DrawPointSelected(Vector3 position, Color color)
  45. {
  46. m_Drawer.DrawPointSelected(position, color);
  47. }
  48. void IDrawer.DrawTangent(Vector3 position, Vector3 tangent, Color color)
  49. {
  50. m_Drawer.DrawTangent(position, tangent, color);
  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 cornerLabel = new GUIContent("Corner", "Set if Corner is automatic or disabled.");
  70. public static readonly int[] cornerValues = { 0, 1, 2 };
  71. public static readonly GUIContent[] cornerOptions = { new GUIContent("Disabled"), new GUIContent("Automatic"), new GUIContent("Stretched"), };
  72. }
  73. private SerializedProperty m_Data;
  74. private SerializedProperty m_HeightProperty;
  75. private SerializedProperty m_CornerProperty;
  76. private SerializedProperty m_CornerModeProperty;
  77. private void OnEnable()
  78. {
  79. m_Data = serializedObject.FindProperty("m_Data");
  80. m_HeightProperty = m_Data.FindPropertyRelative("height");
  81. m_CornerProperty = m_Data.FindPropertyRelative("corner");
  82. m_CornerModeProperty = m_Data.FindPropertyRelative("cornerMode");
  83. }
  84. internal void OnHeightChanged(UnityEngine.Object[] targets, float height)
  85. {
  86. foreach (var t in targets)
  87. {
  88. var shapeData = t as ScriptableSpriteShapeData;
  89. var path = SpriteShapeEditorTool.activeSpriteShapeEditorTool.GetPath(shapeData.owner);
  90. if (path.selection.Count == 0)
  91. continue;
  92. path.undoObject.RegisterUndo("Set Height");
  93. for (var i = 0; i < path.pointCount; ++i)
  94. {
  95. if (!path.selection.Contains(i))
  96. continue;
  97. var data = path.data[i] as SpriteShapeData;
  98. data.height = height;
  99. }
  100. SpriteShapeEditorTool.activeSpriteShapeEditorTool.SetPath(shapeData.owner);
  101. }
  102. }
  103. internal void OnCornerModeChanged(UnityEngine.Object[] targets, int cornerValue)
  104. {
  105. foreach (var t in targets)
  106. {
  107. var shapeData = t as ScriptableSpriteShapeData;
  108. var path = SpriteShapeEditorTool.activeSpriteShapeEditorTool.GetPath(shapeData.owner);
  109. if (path.selection.Count == 0)
  110. continue;
  111. path.undoObject.RegisterUndo("Set Corner Mode");
  112. for (var i = 0; i < path.pointCount; ++i)
  113. {
  114. if (!path.selection.Contains(i))
  115. continue;
  116. var data = path.data[i] as SpriteShapeData;
  117. data.cornerMode = cornerValue;
  118. data.corner = cornerValue != 0 ? 1 : 0;
  119. }
  120. SpriteShapeEditorTool.activeSpriteShapeEditorTool.SetPath(shapeData.owner);
  121. }
  122. }
  123. public override void OnInspectorGUI()
  124. {
  125. var scriptableSpriteShapeData = target as ScriptableSpriteShapeData;
  126. if (!scriptableSpriteShapeData)
  127. return;
  128. serializedObject.Update();
  129. EditorGUI.BeginChangeCheck();
  130. var heightValue = EditorGUILayout.Slider(Contents.heightLabel, m_HeightProperty.floatValue, 0.1f, 4.0f);
  131. if (EditorGUI.EndChangeCheck())
  132. {
  133. m_HeightProperty.floatValue = heightValue;
  134. if (serializedObject.isEditingMultipleObjects)
  135. OnHeightChanged(targets, heightValue);
  136. }
  137. EditorGUI.BeginChangeCheck();
  138. var cornerValue = EditorGUILayout.IntPopup(Contents.cornerLabel, m_CornerModeProperty.intValue, Contents.cornerOptions, Contents.cornerValues);
  139. if (EditorGUI.EndChangeCheck())
  140. {
  141. m_CornerModeProperty.intValue = cornerValue;
  142. m_CornerProperty.intValue = cornerValue != 0 ? 1 : 0;
  143. if (serializedObject.isEditingMultipleObjects)
  144. OnCornerModeChanged(targets, cornerValue);
  145. }
  146. serializedObject.ApplyModifiedProperties();
  147. }
  148. }
  149. internal class CustomPath : GenericScriptablePath<SpriteShapeData> { }
  150. [CanEditMultipleObjects]
  151. [CustomEditor(typeof(CustomPath))]
  152. internal class CustomPathInspector : GenericScriptablePathInspector<ScriptableSpriteShapeData, SpriteShapeData> { }
  153. [EditorTool("Edit SpriteShape", typeof(SpriteShapeController))]
  154. internal class SpriteShapeEditorTool : PathEditorTool<CustomPath>
  155. {
  156. private static InternalEditorBridge.ShortcutContext m_ShortcutContext;
  157. public static SpriteShapeEditorTool activeSpriteShapeEditorTool
  158. {
  159. get
  160. {
  161. if (m_ShortcutContext != null)
  162. return m_ShortcutContext.context as SpriteShapeEditorTool;
  163. return null;
  164. }
  165. }
  166. protected override bool GetLinearTangentIsZero(UnityEngine.Object target)
  167. {
  168. return true;
  169. }
  170. protected override IDrawer GetCustomDrawer(UnityEngine.Object target)
  171. {
  172. return new CustomDrawer(target as SpriteShapeController);
  173. }
  174. protected override IShape GetShape(UnityEngine.Object target)
  175. {
  176. return Polygon.empty;
  177. }
  178. protected override void Initialize(CustomPath shapeEditor, SerializedObject serializedObject)
  179. {
  180. var controller = serializedObject.targetObject as SpriteShapeController;
  181. var spline = controller.spline;
  182. shapeEditor.shapeType = ShapeType.Spline;
  183. shapeEditor.isOpenEnded = spline.isOpenEnded;
  184. for (var i = 0; i < spline.GetPointCount(); ++i)
  185. {
  186. var position = spline.GetPosition(i);
  187. shapeEditor.AddPoint(new ControlPoint()
  188. {
  189. position = spline.GetPosition(i),
  190. localLeftTangent = spline.GetLeftTangent(i),
  191. localRightTangent = spline.GetRightTangent(i),
  192. tangentMode = (TangentMode)spline.GetTangentMode(i)
  193. });
  194. shapeEditor.SetData(i, new SpriteShapeData()
  195. {
  196. spriteIndex = spline.GetSpriteIndex(i),
  197. height = spline.GetHeight(i),
  198. cornerMode = (int)spline.GetCornerMode(i),
  199. corner = spline.GetCorner(i) ? 1 : 0,
  200. });
  201. }
  202. shapeEditor.UpdateTangentsFromMode();
  203. }
  204. protected override void SetShape(CustomPath shapeEditor, SerializedObject serializedObject)
  205. {
  206. serializedObject.Update();
  207. var controller = serializedObject.targetObject as SpriteShapeController;
  208. var splineProp = serializedObject.FindProperty("m_Spline");
  209. var controlPointsProp = splineProp.FindPropertyRelative("m_ControlPoints");
  210. splineProp.FindPropertyRelative("m_IsOpenEnded").boolValue = shapeEditor.isOpenEnded;
  211. controlPointsProp.arraySize = shapeEditor.pointCount;
  212. for (var i = 0; i < shapeEditor.pointCount; ++i)
  213. {
  214. var elementProp = controlPointsProp.GetArrayElementAtIndex(i);
  215. var point = shapeEditor.GetPoint(i);
  216. var data = shapeEditor.GetData(i);
  217. elementProp.FindPropertyRelative("position").vector3Value = point.position;
  218. elementProp.FindPropertyRelative("leftTangent").vector3Value = point.localLeftTangent;
  219. elementProp.FindPropertyRelative("rightTangent").vector3Value = point.localRightTangent;
  220. elementProp.FindPropertyRelative("mode").enumValueIndex = (int)point.tangentMode;
  221. elementProp.FindPropertyRelative("height").floatValue = data.height;
  222. elementProp.FindPropertyRelative("spriteIndex").intValue = data.spriteIndex;
  223. elementProp.FindPropertyRelative("corner").intValue = data.corner;
  224. elementProp.FindPropertyRelative("m_CornerMode").intValue = data.cornerMode;
  225. }
  226. serializedObject.ApplyModifiedProperties();
  227. }
  228. protected override void OnActivate()
  229. {
  230. }
  231. protected override void OnDeactivate()
  232. {
  233. }
  234. private void CycleSpriteIndex()
  235. {
  236. foreach(var target in targets)
  237. {
  238. var spriteShapeController = target as SpriteShapeController;
  239. var shapeEditor = GetPath(target);
  240. Editor cachedEditor = null;
  241. Editor.CreateCachedEditor(spriteShapeController, typeof(SpriteShapeControllerEditor), ref cachedEditor);
  242. if (spriteShapeController == null || spriteShapeController.spriteShape == null || shapeEditor.selection.Count == 0 || cachedEditor == null || shapeEditor.selection.Count > 1)
  243. continue;
  244. var spriteShape = spriteShapeController.spriteShape;
  245. var scEditor = cachedEditor as SpriteShapeControllerEditor;
  246. var selected = shapeEditor.selection.elements[0];
  247. if (shapeEditor.selection.Contains(selected))
  248. {
  249. shapeEditor.undoObject.RegisterUndo("Cycle Variant");
  250. var data = shapeEditor.GetData(selected);
  251. var angleRangeIndex = scEditor.GetAngleRange(selected);
  252. if (angleRangeIndex != -1)
  253. {
  254. var angleRange = spriteShape.angleRanges[angleRangeIndex];
  255. if (angleRange.sprites.Count > 0)
  256. data.spriteIndex = (data.spriteIndex + 1) % angleRange.sprites.Count;
  257. shapeEditor.SetData(selected, data);
  258. }
  259. SetPath(target);
  260. }
  261. }
  262. }
  263. private static float SlopeAngle(Vector2 start, Vector2 end)
  264. {
  265. var dir = start - end;
  266. dir.Normalize();
  267. var dvup = new Vector2(0, 1f);
  268. var dvrt = new Vector2(1f, 0);
  269. var dr = Vector2.Dot(dir, dvrt);
  270. var du = Vector2.Dot(dir, dvup);
  271. var cu = Mathf.Acos(du);
  272. var sn = dr >= 0 ? 1.0f : -1.0f;
  273. var an = cu * Mathf.Rad2Deg * sn;
  274. // Adjust angles when direction is parallel to Up Axis.
  275. an = (du != 1f) ? an : 0;
  276. an = (du != -1f) ? an : -180f;
  277. return an;
  278. }
  279. private void RegisterShortcuts()
  280. {
  281. m_ShortcutContext = new InternalEditorBridge.ShortcutContext()
  282. {
  283. isActive = () => GUIUtility.hotControl == 0,
  284. context = this
  285. };
  286. InternalEditorBridge.RegisterShortcutContext(m_ShortcutContext);
  287. }
  288. private void UnregisterShortcuts()
  289. {
  290. InternalEditorBridge.UnregisterShortcutContext(m_ShortcutContext);
  291. m_ShortcutContext = null;
  292. }
  293. public override void OnActivated()
  294. {
  295. RegisterShortcuts();
  296. }
  297. public override void OnWillBeDeactivated()
  298. {
  299. UnregisterShortcuts();
  300. }
  301. [Shortcut("SpriteShape Editing/Cycle Tangent Mode", typeof(InternalEditorBridge.ShortcutContext), KeyCode.M)]
  302. private static void ShortcutCycleTangentMode(ShortcutArguments args)
  303. {
  304. if (args.context == m_ShortcutContext)
  305. (m_ShortcutContext.context as SpriteShapeEditorTool).CycleTangentMode();
  306. }
  307. [Shortcut("SpriteShape Editing/Cycle Variant", typeof(InternalEditorBridge.ShortcutContext), KeyCode.N)]
  308. private static void ShortcutCycleSpriteIndex(ShortcutArguments args)
  309. {
  310. if (args.context == m_ShortcutContext)
  311. (m_ShortcutContext.context as SpriteShapeEditorTool).CycleSpriteIndex();
  312. }
  313. [Shortcut("SpriteShape Editing/Mirror Tangent", typeof(InternalEditorBridge.ShortcutContext), KeyCode.B)]
  314. private static void ShortcutCycleMirrorTangent(ShortcutArguments args)
  315. {
  316. if (args.context == m_ShortcutContext)
  317. (m_ShortcutContext.context as SpriteShapeEditorTool).MirrorTangent();
  318. }
  319. }
  320. }