RotateHandle.cs 11 KB

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