Geen omschrijving
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.

BoneGizmo.cs 14KB

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