DefaultHandleManager.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263
  1. //********************************** Banshee Engine (www.banshee3d.com) **************************************************//
  2. //**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
  3. using System.Collections.Generic;
  4. using bs;
  5. namespace bs.Editor
  6. {
  7. /** @addtogroup Handles
  8. * @{
  9. */
  10. /// <summary>
  11. /// Manages the default set of built-in handles like move, rotate and scale. Handles switching between the three handle
  12. /// types, as well as switching between coordinate and pivot modes, while tracking and updating active scene object
  13. /// selection. Essentially it detects which handles need to be displayed and where, and then forwards the data
  14. /// to the specific handle for processing.
  15. /// </summary>
  16. internal sealed class DefaultHandleManager : Handle
  17. {
  18. /// <summary>
  19. /// Representation of a scene object currently being modified by a handle.
  20. /// </summary>
  21. private struct HandledObject
  22. {
  23. /// <summary>
  24. /// Creates a new scene object representation by recording the current object transform.
  25. /// </summary>
  26. /// <param name="so">Scene object that is being modified by a handle.</param>
  27. public HandledObject(SceneObject so)
  28. {
  29. this.so = so;
  30. initialPosition = so.LocalPosition;
  31. initialRotation = so.LocalRotation;
  32. initialScale = so.LocalScale;
  33. }
  34. public SceneObject so;
  35. public Vector3 initialPosition;
  36. public Quaternion initialRotation;
  37. public Vector3 initialScale;
  38. }
  39. private SceneViewTool activeHandleType = SceneViewTool.View;
  40. private DefaultHandle activeHandle;
  41. private HandledObject[] activeSelection;
  42. private bool isDragged;
  43. private Vector3 initialHandlePosition;
  44. private Quaternion initialHandleRotation;
  45. /// <inheritdoc/>
  46. protected internal override void PreInput()
  47. {
  48. SceneObject[] selectedSceneObjects = Selection.SceneObjects;
  49. if (selectedSceneObjects.Length == 0)
  50. {
  51. if (activeHandle != null)
  52. {
  53. activeHandle.Destroy();
  54. activeHandle = null;
  55. }
  56. }
  57. else
  58. {
  59. if (activeHandleType != EditorApplication.ActiveSceneTool || activeHandle == null)
  60. {
  61. if (activeHandle != null)
  62. {
  63. activeHandle.Destroy();
  64. activeHandle = null;
  65. }
  66. switch (EditorApplication.ActiveSceneTool)
  67. {
  68. case SceneViewTool.Move:
  69. activeHandle = new MoveHandle();
  70. break;
  71. case SceneViewTool.Rotate:
  72. activeHandle = new RotateHandle();
  73. break;
  74. case SceneViewTool.Scale:
  75. activeHandle = new ScaleHandle();
  76. break;
  77. }
  78. activeHandleType = EditorApplication.ActiveSceneTool;
  79. }
  80. }
  81. if (activeHandle != null)
  82. {
  83. // In case the object moved programmatically, make the handle reflect its current transform
  84. UpdateActiveHandleTransform(selectedSceneObjects);
  85. activeHandle.PreInput();
  86. }
  87. }
  88. /// <inheritdoc/>
  89. protected internal override void PostInput()
  90. {
  91. if (activeHandle != null)
  92. {
  93. if (activeHandle.IsDragged())
  94. {
  95. if (!isDragged)
  96. {
  97. isDragged = true;
  98. SceneObject[] selectedSceneObjects = Selection.SceneObjects;
  99. GameObjectUndo.RecordSceneObjectHeader(selectedSceneObjects);
  100. activeSelection = new HandledObject[selectedSceneObjects.Length];
  101. for (int i = 0; i < selectedSceneObjects.Length; i++)
  102. activeSelection[i] = new HandledObject(selectedSceneObjects[i]);
  103. initialHandlePosition = activeHandle.Position;
  104. initialHandleRotation = activeHandle.Rotation;
  105. }
  106. }
  107. else
  108. {
  109. if (isDragged)
  110. GameObjectUndo.ResolveDiffs();
  111. isDragged = false;
  112. activeSelection = null;
  113. }
  114. activeHandle.PostInput();
  115. if (activeHandle.IsDragged())
  116. {
  117. switch (activeHandleType)
  118. {
  119. case SceneViewTool.Move:
  120. MoveHandle moveHandle = (MoveHandle) activeHandle;
  121. foreach (var selectedObj in activeSelection)
  122. {
  123. SceneObject parentSO = selectedObj.so.Parent;
  124. if (parentSO == null)
  125. selectedObj.so.LocalPosition = selectedObj.initialPosition + moveHandle.Delta;
  126. else
  127. {
  128. Vector3 parentRelativeDelta = parentSO.Rotation.Inverse.Rotate(moveHandle.Delta);
  129. selectedObj.so.LocalPosition = selectedObj.initialPosition + parentRelativeDelta;
  130. }
  131. }
  132. break;
  133. case SceneViewTool.Rotate:
  134. {
  135. RotateHandle rotateHandle = (RotateHandle) activeHandle;
  136. // Make sure we transform relative to the handle position
  137. SceneObject temporarySO = new SceneObject("Temp");
  138. temporarySO.Position = initialHandlePosition;
  139. temporarySO.LocalRotation = initialHandleRotation;
  140. SceneObject[] originalParents = new SceneObject[activeSelection.Length];
  141. for (int i = 0; i < activeSelection.Length; i++)
  142. {
  143. originalParents[i] = activeSelection[i].so.Parent;
  144. activeSelection[i].so.LocalPosition = activeSelection[i].initialPosition;
  145. activeSelection[i].so.LocalRotation = activeSelection[i].initialRotation;
  146. activeSelection[i].so.Parent = temporarySO;
  147. }
  148. temporarySO.LocalRotation *= rotateHandle.Delta;
  149. for (int i = 0; i < activeSelection.Length; i++)
  150. activeSelection[i].so.Parent = originalParents[i];
  151. temporarySO.Destroy();
  152. }
  153. break;
  154. case SceneViewTool.Scale:
  155. {
  156. ScaleHandle scaleHandle = (ScaleHandle) activeHandle;
  157. // Make sure we transform relative to the handle position
  158. SceneObject temporarySO = new SceneObject("Temp");
  159. temporarySO.Position = activeHandle.Position;
  160. SceneObject[] originalParents = new SceneObject[activeSelection.Length];
  161. for (int i = 0; i < activeSelection.Length; i++)
  162. {
  163. originalParents[i] = activeSelection[i].so.Parent;
  164. activeSelection[i].so.LocalPosition = activeSelection[i].initialPosition;
  165. activeSelection[i].so.LocalRotation = activeSelection[i].initialRotation;
  166. activeSelection[i].so.LocalScale = activeSelection[i].initialScale;
  167. activeSelection[i].so.Parent = temporarySO;
  168. }
  169. temporarySO.LocalScale += scaleHandle.Delta;
  170. for (int i = 0; i < activeSelection.Length; i++)
  171. activeSelection[i].so.Parent = originalParents[i];
  172. temporarySO.Destroy();
  173. }
  174. break;
  175. }
  176. SceneObject[] selectedSceneObjects = new SceneObject[activeSelection.Length];
  177. for (int i = 0; i < activeSelection.Length; i++)
  178. selectedSceneObjects[i] = activeSelection[i].so;
  179. // Make sure to update handle positions for the drawing method (otherwise they lag one frame)
  180. UpdateActiveHandleTransform(selectedSceneObjects);
  181. EditorApplication.SetSceneDirty();
  182. }
  183. }
  184. else
  185. {
  186. isDragged = false;
  187. activeSelection = null;
  188. }
  189. }
  190. /// <inheritdoc/>
  191. protected internal override void Draw()
  192. {
  193. if (activeHandle != null)
  194. activeHandle.Draw();
  195. }
  196. /// <summary>
  197. /// Updates active handle position/rotation based on the currently selected object(s).
  198. /// </summary>
  199. private void UpdateActiveHandleTransform(SceneObject[] selectedSceneObjects)
  200. {
  201. if (activeHandle == null)
  202. return;
  203. Quaternion rotation;
  204. if (EditorApplication.ActiveCoordinateMode == HandleCoordinateMode.World)
  205. rotation = Quaternion.Identity;
  206. else
  207. rotation = selectedSceneObjects[0].Rotation; // We don't average rotation in case of multi-selection
  208. Vector3 position;
  209. if (EditorApplication.ActivePivotMode == HandlePivotMode.Pivot)
  210. position = selectedSceneObjects[0].Position; // Just take pivot from the first one, no averaging
  211. else
  212. {
  213. List<SceneObject> flatenedHierarchy = new List<SceneObject>();
  214. foreach (var so in selectedSceneObjects)
  215. flatenedHierarchy.AddRange(EditorUtility.FlattenHierarchy(so));
  216. position = EditorUtility.CalculateCenter(flatenedHierarchy.ToArray());
  217. }
  218. activeHandle.Position = position;
  219. activeHandle.Rotation = rotation;
  220. }
  221. }
  222. /** @} */
  223. }