BoneGizmo.cs 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470
  1. using System.Collections.Generic;
  2. using UnityEngine;
  3. using UnityEngine.U2D;
  4. using UnityEngine.U2D.Animation;
  5. using UnityEngine.U2D.Common;
  6. namespace UnityEditor.U2D.Animation
  7. {
  8. //Make sure Bone Gizmo registers callbacks before anyone else
  9. [InitializeOnLoad]
  10. internal class BoneGizmoInitializer
  11. {
  12. static BoneGizmoInitializer()
  13. {
  14. BoneGizmo.instance.Initialize();
  15. }
  16. }
  17. internal class BoneGizmo : ScriptableSingleton<BoneGizmo>
  18. {
  19. private BoneGizmoController m_BoneGizmoController;
  20. internal BoneGizmoController boneGizmoController { get { return m_BoneGizmoController; } }
  21. internal void Initialize()
  22. {
  23. m_BoneGizmoController = new BoneGizmoController(new SkeletonView(new GUIWrapper()), new UnityEngineUndo(), new BoneGizmoToggle());
  24. RegisterCallbacks();
  25. }
  26. internal void ClearSpriteBoneCache()
  27. {
  28. boneGizmoController.ClearSpriteBoneCache();
  29. }
  30. private void RegisterCallbacks()
  31. {
  32. Selection.selectionChanged += OnSelectionChanged;
  33. SceneView.duringSceneGui += OnSceneGUI;
  34. AssemblyReloadEvents.afterAssemblyReload += OnAfterAssemblyReload;
  35. EditorApplication.playModeStateChanged += PlayModeStateChanged;
  36. }
  37. private void OnSceneGUI(SceneView sceneView)
  38. {
  39. boneGizmoController.OnGUI();
  40. }
  41. private void OnSelectionChanged()
  42. {
  43. boneGizmoController.OnSelectionChanged();
  44. }
  45. private void OnAfterAssemblyReload()
  46. {
  47. boneGizmoController.OnSelectionChanged();
  48. }
  49. private void PlayModeStateChanged(PlayModeStateChange stateChange)
  50. {
  51. if (stateChange == PlayModeStateChange.EnteredPlayMode ||
  52. stateChange == PlayModeStateChange.EnteredEditMode)
  53. boneGizmoController.OnSelectionChanged();
  54. }
  55. }
  56. internal class BoneGizmoController
  57. {
  58. private Dictionary<Sprite, UnityEngine.U2D.SpriteBone[]> m_SpriteBones = new Dictionary<Sprite, UnityEngine.U2D.SpriteBone[]>();
  59. private Dictionary<Transform, Vector2> m_BoneData = new Dictionary<Transform, Vector2>();
  60. private HashSet<SpriteSkin> m_SkinComponents = new HashSet<SpriteSkin>();
  61. private HashSet<Transform> m_CachedBones = new HashSet<Transform>();
  62. private HashSet<Transform> m_SelectionRoots = new HashSet<Transform>();
  63. private ISkeletonView view;
  64. private IUndo m_Undo;
  65. private Tool m_PreviousTool = Tool.None;
  66. private IBoneGizmoToggle m_BoneGizmoToggle;
  67. internal IBoneGizmoToggle boneGizmoToggle { get { return m_BoneGizmoToggle; } set { m_BoneGizmoToggle = value; } }
  68. public Transform hoveredBone
  69. {
  70. get { return GetBone(view.hoveredBoneID); }
  71. }
  72. public Transform hoveredTail
  73. {
  74. get { return GetBone(view.hoveredTailID); }
  75. }
  76. public Transform hoveredBody
  77. {
  78. get { return GetBone(view.hoveredBodyID); }
  79. }
  80. public Transform hoveredJoint
  81. {
  82. get { return GetBone(view.hoveredJointID); }
  83. }
  84. public Transform hotBone
  85. {
  86. get { return GetBone(view.hotBoneID); }
  87. }
  88. private Transform GetBone(int instanceID)
  89. {
  90. return EditorUtility.InstanceIDToObject(instanceID) as Transform;
  91. }
  92. public BoneGizmoController(ISkeletonView view, IUndo undo, IBoneGizmoToggle toggle)
  93. {
  94. this.view = view;
  95. view.mode = SkeletonMode.EditPose;
  96. view.InvalidID = 0;
  97. m_Undo = undo;
  98. m_BoneGizmoToggle = toggle;
  99. }
  100. internal void OnSelectionChanged()
  101. {
  102. m_SelectionRoots.Clear();
  103. foreach (var selectedTransform in Selection.transforms)
  104. {
  105. var prefabRoot = PrefabUtility.GetOutermostPrefabInstanceRoot(selectedTransform.gameObject);
  106. var animator = default(Animator);
  107. if (prefabRoot != null)
  108. m_SelectionRoots.Add(prefabRoot.transform);
  109. else if ((animator = selectedTransform.GetComponentInParent<Animator>()) != null)
  110. m_SelectionRoots.Add(animator.transform);
  111. else
  112. m_SelectionRoots.Add(selectedTransform.root);
  113. }
  114. if (m_PreviousTool == Tool.None && Selection.activeTransform != null && m_BoneData.ContainsKey(Selection.activeTransform))
  115. {
  116. m_PreviousTool = UnityEditor.Tools.current;
  117. UnityEditor.Tools.current = Tool.None;
  118. }
  119. if (m_PreviousTool != Tool.None && (Selection.activeTransform == null || !m_BoneData.ContainsKey(Selection.activeTransform)))
  120. {
  121. if (UnityEditor.Tools.current == Tool.None)
  122. UnityEditor.Tools.current = m_PreviousTool;
  123. m_PreviousTool = Tool.None;
  124. }
  125. FindSkinComponents();
  126. }
  127. internal void OnGUI()
  128. {
  129. m_BoneGizmoToggle.OnGUI();
  130. if (!m_BoneGizmoToggle.enableGizmos)
  131. return;
  132. PrepareBones();
  133. DoBoneGUI();
  134. }
  135. internal void FindSkinComponents()
  136. {
  137. m_SkinComponents.Clear();
  138. foreach (var root in m_SelectionRoots)
  139. {
  140. var components = root.GetComponentsInChildren<SpriteSkin>(false);
  141. foreach (var component in components)
  142. m_SkinComponents.Add(component);
  143. }
  144. SceneView.RepaintAll();
  145. }
  146. internal void ClearSpriteBoneCache()
  147. {
  148. m_SpriteBones.Clear();
  149. }
  150. private void PrepareBones()
  151. {
  152. if (!view.CanLayout())
  153. return;
  154. if (view.IsActionHot(SkeletonAction.None))
  155. m_CachedBones.Clear();
  156. m_BoneData.Clear();
  157. foreach (var skinComponent in m_SkinComponents)
  158. {
  159. if (skinComponent == null)
  160. continue;
  161. PrepareBones(skinComponent);
  162. }
  163. }
  164. private UnityEngine.U2D.SpriteBone[] GetSpriteBones(SpriteSkin spriteSkin)
  165. {
  166. Debug.Assert(spriteSkin.isValid);
  167. var sprite = spriteSkin.spriteRenderer.sprite;
  168. UnityEngine.U2D.SpriteBone[] spriteBones;
  169. if (!m_SpriteBones.TryGetValue(sprite, out spriteBones))
  170. {
  171. spriteBones = sprite.GetBones();
  172. m_SpriteBones[sprite] = sprite.GetBones();
  173. }
  174. return spriteBones;
  175. }
  176. private void PrepareBones(SpriteSkin spriteSkin)
  177. {
  178. Debug.Assert(spriteSkin != null);
  179. Debug.Assert(view.CanLayout());
  180. if (!spriteSkin.isActiveAndEnabled || !spriteSkin.isValid || !spriteSkin.spriteRenderer.enabled)
  181. return;
  182. var sprite = spriteSkin.spriteRenderer.sprite;
  183. var boneTransforms = spriteSkin.boneTransforms;
  184. var spriteBones = GetSpriteBones(spriteSkin);
  185. var alpha = 1f;
  186. if (spriteBones == null)
  187. return;
  188. for (int i = 0; i < boneTransforms.Length; ++i)
  189. {
  190. var boneTransform = boneTransforms[i];
  191. if (boneTransform == null || m_BoneData.ContainsKey(boneTransform))
  192. continue;
  193. var bone = spriteBones[i];
  194. if (view.IsActionHot(SkeletonAction.None))
  195. m_CachedBones.Add(boneTransform);
  196. m_BoneData.Add(boneTransform, new Vector2(bone.length, alpha));
  197. }
  198. }
  199. private void DoBoneGUI()
  200. {
  201. view.BeginLayout();
  202. if (view.CanLayout())
  203. LayoutBones();
  204. view.EndLayout();
  205. HandleSelectBone();
  206. HandleRotateBone();
  207. HandleMoveBone();
  208. DrawBones();
  209. DrawCursors();
  210. }
  211. private void LayoutBones()
  212. {
  213. foreach (var bone in m_CachedBones)
  214. {
  215. if (bone == null)
  216. continue;
  217. Vector2 value;
  218. if (!m_BoneData.TryGetValue(bone, out value))
  219. continue;
  220. var length = value.x;
  221. if (bone != hotBone)
  222. view.LayoutBone(bone.GetInstanceID(), bone.position, bone.position + bone.GetScaledRight() * length, bone.forward, bone.up, bone.right, false);
  223. }
  224. }
  225. private void HandleSelectBone()
  226. {
  227. int instanceID;
  228. bool additive;
  229. if (view.DoSelectBone(out instanceID, out additive))
  230. {
  231. var bone = GetBone(instanceID);
  232. if (!additive)
  233. {
  234. if (!Selection.Contains(bone.gameObject))
  235. Selection.activeTransform = bone;
  236. }
  237. else
  238. {
  239. var objectList = new List<Object>(Selection.objects);
  240. if(objectList.Contains(bone.gameObject))
  241. objectList.Remove(bone.gameObject);
  242. else
  243. objectList.Add(bone.gameObject);
  244. Selection.objects = objectList.ToArray();
  245. }
  246. }
  247. }
  248. private void HandleRotateBone()
  249. {
  250. var pivot = hoveredBone;
  251. if (view.IsActionHot(SkeletonAction.RotateBone))
  252. pivot = hotBone;
  253. if (pivot == null)
  254. return;
  255. FindPivotTransform(pivot, out pivot);
  256. if (pivot == null)
  257. return;
  258. float deltaAngle;
  259. if (view.DoRotateBone(pivot.position, pivot.forward, out deltaAngle))
  260. SetBoneRotation(deltaAngle);
  261. }
  262. private void HandleMoveBone()
  263. {
  264. Vector3 deltaPosition;
  265. if (view.DoMoveBone(out deltaPosition))
  266. SetBonePosition(deltaPosition);
  267. }
  268. private bool FindPivotTransform(Transform transform, out Transform selectedTransform)
  269. {
  270. selectedTransform = transform;
  271. var selectedRoots = Selection.transforms;
  272. foreach(var selectedRoot in selectedRoots)
  273. {
  274. if(transform.IsDescendentOf(selectedRoot))
  275. {
  276. selectedTransform = selectedRoot;
  277. return true;
  278. }
  279. }
  280. return false;
  281. }
  282. private void SetBonePosition(Vector3 deltaPosition)
  283. {
  284. foreach (var selectedTransform in Selection.transforms)
  285. {
  286. if(!m_BoneData.ContainsKey(selectedTransform))
  287. continue;
  288. var boneTransform = selectedTransform;
  289. m_Undo.RecordObject(boneTransform, TextContent.moveBone);
  290. boneTransform.position += deltaPosition;
  291. }
  292. }
  293. private void SetBoneRotation(float deltaAngle)
  294. {
  295. foreach(var selectedGameObject in Selection.gameObjects)
  296. {
  297. if(!m_BoneData.ContainsKey(selectedGameObject.transform))
  298. continue;
  299. var boneTransform = selectedGameObject.transform;
  300. m_Undo.RecordObject(boneTransform, TextContent.rotateBone);
  301. boneTransform.Rotate(boneTransform.forward, deltaAngle, Space.World);
  302. InternalEngineBridge.SetLocalEulerHint(boneTransform);
  303. }
  304. }
  305. private void DrawBones()
  306. {
  307. if (!view.IsRepainting())
  308. return;
  309. var selectedOutlineColor = SelectionOutlineSettings.outlineColor;
  310. var selectedOutlineSize = SelectionOutlineSettings.selectedBoneOutlineSize;
  311. var defaultOutlineColor = Color.black.AlphaMultiplied(0.5f);
  312. //Draw bone outlines
  313. foreach (var boneData in m_BoneData)
  314. {
  315. var bone = boneData.Key;
  316. if (bone == null)
  317. continue;
  318. var value = boneData.Value;
  319. var length = value.x;
  320. var alpha = value.y;
  321. if (alpha == 0f || !bone.gameObject.activeInHierarchy)
  322. continue;
  323. var color = defaultOutlineColor;
  324. var outlineSize = 1.25f;
  325. var isSelected = Selection.Contains(bone.gameObject);
  326. var isHovered = hoveredBody == bone && view.IsActionHot(SkeletonAction.None);
  327. if (isSelected)
  328. {
  329. color = selectedOutlineColor;
  330. outlineSize = selectedOutlineSize * 0.5f + 1f;
  331. }
  332. else if (isHovered)
  333. color = Handles.preselectionColor;
  334. DrawBoneOutline(bone, length, color, outlineSize);
  335. }
  336. //Draw bones
  337. foreach (var boneData in m_BoneData)
  338. {
  339. var bone = boneData.Key;
  340. if (bone == null)
  341. continue;
  342. var value = boneData.Value;
  343. var length = value.x;
  344. var alpha = value.y;
  345. if (alpha == 0f || !bone.gameObject.activeInHierarchy)
  346. continue;
  347. DrawBone(bone, length, Color.white);
  348. }
  349. }
  350. private void DrawBone(Transform bone, float length, Color color)
  351. {
  352. var isSelected = Selection.Contains(bone.gameObject);
  353. var isJointHovered = view.IsActionHot(SkeletonAction.None) && hoveredJoint == bone;
  354. var isTailHovered = view.IsActionHot(SkeletonAction.None) && hoveredTail == bone;
  355. view.DrawBone(bone.position, bone.GetScaledRight(), bone.forward, length, color, false, isSelected, isJointHovered, isTailHovered, bone == hotBone);
  356. }
  357. private void DrawBoneOutline(Transform bone, float length, Color color, float outlineScale)
  358. {
  359. view.DrawBoneOutline(bone.position, bone.GetScaledRight(), bone.forward, length, color, outlineScale);
  360. }
  361. private void DrawCursors()
  362. {
  363. if (!view.IsRepainting())
  364. return;
  365. view.DrawCursors(true);
  366. }
  367. private bool HasParentBone(Transform transform)
  368. {
  369. Debug.Assert(transform != null);
  370. return transform.parent != null && m_BoneData.ContainsKey(transform.parent);
  371. }
  372. }
  373. }