RotateHandle.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253
  1. //********************************** Banshee Engine (www.banshee3d.com) **************************************************//
  2. //**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
  3. using bs;
  4. namespace bs.Editor
  5. {
  6. /** @addtogroup Handles
  7. * @{
  8. */
  9. /// <summary>
  10. /// Handle that allows an object to be rotated around the three primary axes, as well as a free axis currently
  11. /// facing the camera.
  12. /// </summary>
  13. public sealed class RotateHandle : DefaultHandle
  14. {
  15. private Quaternion delta;
  16. private HandleSliderDisc xAxis;
  17. private HandleSliderDisc yAxis;
  18. private HandleSliderDisc zAxis;
  19. private HandleSliderDisc freeAxis;
  20. private bool isDragged;
  21. private Quaternion dragStartRotation;
  22. /// <summary>
  23. /// Amount of rotation applied since the last frame. Only valid while the handle is being dragged.
  24. /// </summary>
  25. public Quaternion Delta
  26. {
  27. get { return delta; }
  28. }
  29. /// <inheritdoc/>
  30. internal override bool IsDragged()
  31. {
  32. return xAxis.State == HandleSlider.StateType.Active ||
  33. yAxis.State == HandleSlider.StateType.Active ||
  34. zAxis.State == HandleSlider.StateType.Active ||
  35. freeAxis.State == HandleSlider.StateType.Active;
  36. }
  37. /// <summary>
  38. /// Creates a new rotation handle.
  39. /// </summary>
  40. public RotateHandle()
  41. {
  42. xAxis = new HandleSliderDisc(this, Vector3.XAxis, 1.0f);
  43. yAxis = new HandleSliderDisc(this, Vector3.YAxis, 1.0f);
  44. zAxis = new HandleSliderDisc(this, Vector3.ZAxis, 1.0f);
  45. freeAxis = new HandleSliderDisc(this, -Vector3.ZAxis, 1.2f);
  46. }
  47. /// <inheritdoc/>
  48. protected internal override void PreInput()
  49. {
  50. xAxis.Position = position;
  51. yAxis.Position = position;
  52. zAxis.Position = position;
  53. freeAxis.Position = position;
  54. Quaternion handleRotation = isDragged ? dragStartRotation : Rotation;
  55. xAxis.Rotation = handleRotation;
  56. yAxis.Rotation = handleRotation;
  57. zAxis.Rotation = handleRotation;
  58. freeAxis.Rotation = EditorApplication.SceneViewCamera.SceneObject.Rotation;
  59. xAxis.SetCutoffPlane(GetXStartAngle(isDragged), true);
  60. yAxis.SetCutoffPlane(GetYStartAngle(isDragged), true);
  61. zAxis.SetCutoffPlane(GetZStartAngle(isDragged), true);
  62. }
  63. /// <inheritdoc/>
  64. protected internal override void PostInput()
  65. {
  66. if (IsDragged())
  67. {
  68. if (!isDragged)
  69. {
  70. isDragged = true;
  71. dragStartRotation = Rotation;
  72. }
  73. }
  74. else
  75. {
  76. isDragged = false;
  77. dragStartRotation = Quaternion.Identity;
  78. }
  79. Degree xValue = (Degree)0.0f;
  80. Degree yValue = (Degree)0.0f;
  81. Degree zValue = (Degree)0.0f;
  82. Degree freeAxisValue = (Degree)0.0f;
  83. if (Handles.RotateHandleSnapActive)
  84. {
  85. xValue = Handles.SnapValue(xAxis.Delta, Handles.RotateSnapAmount);
  86. yValue = Handles.SnapValue(yAxis.Delta, Handles.RotateSnapAmount);
  87. zValue = Handles.SnapValue(zAxis.Delta, Handles.RotateSnapAmount);
  88. freeAxisValue = Handles.SnapValue(freeAxis.Delta, Handles.RotateSnapAmount);
  89. }
  90. else
  91. {
  92. xValue = xAxis.Delta;
  93. yValue = yAxis.Delta;
  94. zValue = zAxis.Delta;
  95. freeAxisValue = freeAxis.Delta;
  96. }
  97. Vector3 cameraForward = -(dragStartRotation.Inverse * EditorApplication.SceneViewCamera.SceneObject.Rotation).Forward;
  98. delta = Quaternion.FromEuler(xValue, yValue, zValue);
  99. delta *= Quaternion.FromAxisAngle(cameraForward, freeAxisValue);
  100. }
  101. /// <inheritdoc/>
  102. protected internal override void Draw()
  103. {
  104. HandleDrawing.Layer = 1;
  105. HandleDrawing.Transform = Matrix4.TRS(Position, Rotation, Vector3.One);
  106. float handleSize = Handles.GetHandleSize(EditorApplication.SceneViewCamera, position);
  107. // Draw arcs
  108. if (xAxis.State == HandleSlider.StateType.Active)
  109. HandleDrawing.Color = Color.White;
  110. else if(xAxis.State == HandleSlider.StateType.Hover)
  111. HandleDrawing.Color = Color.BansheeOrange;
  112. else
  113. HandleDrawing.Color = Color.Red;
  114. HandleDrawing.DrawWireArc(Vector3.Zero, Vector3.XAxis, 1.0f, GetXStartAngle(false), new Degree(180.0f), handleSize);
  115. if (yAxis.State == HandleSlider.StateType.Active)
  116. HandleDrawing.Color = Color.White;
  117. else if (yAxis.State == HandleSlider.StateType.Hover)
  118. HandleDrawing.Color = Color.BansheeOrange;
  119. else
  120. HandleDrawing.Color = Color.Green;
  121. HandleDrawing.DrawWireArc(Vector3.Zero, Vector3.YAxis, 1.0f, GetYStartAngle(false), new Degree(180.0f), handleSize);
  122. if (zAxis.State == HandleSlider.StateType.Active)
  123. HandleDrawing.Color = Color.White;
  124. else if (zAxis.State == HandleSlider.StateType.Hover)
  125. HandleDrawing.Color = Color.BansheeOrange;
  126. else
  127. HandleDrawing.Color = Color.Blue;
  128. HandleDrawing.DrawWireArc(Vector3.Zero, Vector3.ZAxis, 1.0f, GetZStartAngle(false), new Degree(180.0f), handleSize);
  129. // Draw "bounds" and free handle
  130. Color gray = new Color(1.0f, 1.0f, 1.0f, 0.3f);
  131. Vector3 cameraNormal = EditorApplication.SceneViewCamera.SceneObject.Rotation.Rotate(Vector3.ZAxis);
  132. HandleDrawing.Transform = Matrix4.TRS(Position, Quaternion.Identity, Vector3.One);
  133. HandleDrawing.Color = gray;
  134. HandleDrawing.DrawWireDisc(cameraNormal * 0.1f, cameraNormal, 1.0f, handleSize);
  135. if (freeAxis.State == HandleSlider.StateType.Active)
  136. HandleDrawing.Color = Color.White;
  137. else if (freeAxis.State == HandleSlider.StateType.Hover)
  138. HandleDrawing.Color = Color.BansheeOrange;
  139. else
  140. HandleDrawing.Color = gray;
  141. HandleDrawing.DrawWireDisc(Vector3.Zero, cameraNormal, 1.2f, handleSize);
  142. // Draw active rotation pie
  143. HandleDrawing.Color = gray;
  144. HandleDrawing.Transform = Matrix4.TRS(Position, EditorApplication.SceneViewCamera.SceneObject.Rotation, Vector3.One);
  145. if (freeAxis.State == HandleSlider.StateType.Active)
  146. HandleDrawing.DrawArc(Vector3.Zero, -Vector3.ZAxis, 1.2f, freeAxis.StartAngle, -freeAxis.Delta, handleSize);
  147. HandleDrawing.Transform = Matrix4.TRS(Position, dragStartRotation, Vector3.One);
  148. if (xAxis.State == HandleSlider.StateType.Active)
  149. HandleDrawing.DrawArc(Vector3.Zero, Vector3.XAxis, 1.0f, xAxis.StartAngle, -xAxis.Delta, handleSize);
  150. else if (yAxis.State == HandleSlider.StateType.Active)
  151. HandleDrawing.DrawArc(Vector3.Zero, Vector3.YAxis, 1.0f, yAxis.StartAngle, -yAxis.Delta, handleSize);
  152. else if (zAxis.State == HandleSlider.StateType.Active)
  153. HandleDrawing.DrawArc(Vector3.Zero, Vector3.ZAxis, 1.0f, zAxis.StartAngle, -zAxis.Delta, handleSize);
  154. }
  155. /// <summary>
  156. /// The rotate handle only displays the 180 degree arc facing the camera and this method returns the angle at which
  157. /// the arc starts for the X axis.
  158. /// </summary>
  159. /// <param name="frozen">Determines should the local handle rotation be taken into account, or should it be frozen
  160. /// to the value when handle drag started. This is useful because we do not want the visible
  161. /// arc to change while the user is in the process of rotating the handle.</param>
  162. /// <returns>Angle at which to display the visible arc for the X axis rotations.</returns>
  163. private Degree GetXStartAngle(bool frozen)
  164. {
  165. Quaternion handleRotation = frozen ? dragStartRotation : Rotation;
  166. Vector3 xStartDir = Vector3.Cross(handleRotation.Inverse.Rotate(EditorApplication.SceneViewCamera.SceneObject.Forward), Vector3.XAxis);
  167. return PointOnCircleToAngle(Vector3.XAxis, xStartDir);
  168. }
  169. /// <summary>
  170. /// The rotate handle only displays the 180 degree arc facing the camera and this method returns the angle at which
  171. /// the arc starts for the Y axis.
  172. /// </summary>
  173. /// <param name="frozen">Determines should the local handle rotation be taken into account, or should it be frozen
  174. /// to the value when handle drag started. This is useful because we do not want the visible
  175. /// arc to change while the user is in the process of rotating the handle.</param>
  176. /// <returns>Angle at which to display the visible arc for the Y axis rotations.</returns>
  177. private Degree GetYStartAngle(bool frozen)
  178. {
  179. Quaternion handleRotation = frozen ? dragStartRotation : Rotation;
  180. Vector3 yStartDir = Vector3.Cross(handleRotation.Inverse.Rotate(EditorApplication.SceneViewCamera.SceneObject.Forward), Vector3.YAxis);
  181. return PointOnCircleToAngle(Vector3.YAxis, yStartDir);
  182. }
  183. /// <summary>
  184. /// The rotate handle only displays the 180 degree arc facing the camera and this method returns the angle at which
  185. /// the arc starts for the Z axis.
  186. /// </summary>
  187. /// <param name="frozen">Determines should the local handle rotation be taken into account, or should it be frozen
  188. /// to the value when handle drag started. This is useful because we do not want the visible
  189. /// arc to change while the user is in the process of rotating the handle.</param>
  190. /// <returns>Angle at which to display the visible arc for the Z axis rotations.</returns>
  191. private Degree GetZStartAngle(bool frozen)
  192. {
  193. Quaternion handleRotation = frozen ? dragStartRotation : Rotation;
  194. Vector3 zStartDir = Vector3.Cross(handleRotation.Inverse.Rotate(EditorApplication.SceneViewCamera.SceneObject.Forward), Vector3.ZAxis);
  195. return PointOnCircleToAngle(Vector3.ZAxis, zStartDir);
  196. }
  197. /// <summary>
  198. /// Converts a point on the circle to an angle on the circle.
  199. /// </summary>
  200. /// <param name="up">Up vector determining the orientation of the circle.</param>
  201. /// <param name="point">Point along a unit circle centered around the origin.</param>
  202. /// <returns>Angle at which the provided point is located on the circle.</returns>
  203. private Degree PointOnCircleToAngle(Vector3 up, Vector3 point)
  204. {
  205. Quaternion rot = Quaternion.FromToRotation(up, Vector3.YAxis);
  206. Matrix4 worldToPlane = Matrix4.TRS(Vector3.Zero, rot, Vector3.One);
  207. point = worldToPlane.MultiplyDirection(point);
  208. return (MathEx.Atan2(-point.z, -point.x) + MathEx.Pi);
  209. }
  210. }
  211. /** @} */
  212. }