BsHandleSliderDisc.cpp 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  1. #include "BsHandleSliderDisc.h"
  2. #include "BsHandleManager.h"
  3. #include "BsHandleSliderManager.h"
  4. #include "BsRay.h"
  5. #include "BsVector3.h"
  6. #include "BsQuaternion.h"
  7. #include "BsCamera.h"
  8. // DEBUG ONLY
  9. #include "BsDebug.h"
  10. namespace BansheeEngine
  11. {
  12. const float HandleSliderDisc::TORUS_RADIUS = 0.1f;
  13. HandleSliderDisc::HandleSliderDisc(const Vector3& normal, float radius, bool fixedScale)
  14. :HandleSlider(fixedScale), mRadius(radius), mNormal(normal), mDelta(0.0f)
  15. {
  16. mCollider = Torus(normal, radius, TORUS_RADIUS);
  17. HandleSliderManager& sliderManager = HandleManager::instance().getSliderManager();
  18. sliderManager._registerSlider(this);
  19. }
  20. HandleSliderDisc::~HandleSliderDisc()
  21. {
  22. HandleSliderManager& sliderManager = HandleManager::instance().getSliderManager();
  23. sliderManager._unregisterSlider(this);
  24. }
  25. bool HandleSliderDisc::intersects(const Ray& ray, float& t) const
  26. {
  27. Ray localRay = ray;
  28. localRay.transform(getTransformInv());
  29. auto intersect = mCollider.intersects(localRay);
  30. if (intersect.first)
  31. {
  32. t = intersect.second;
  33. return true;
  34. }
  35. return false;
  36. }
  37. Vector3 HandleSliderDisc::calculateClosestPointOnArc(const Ray& inputRay, const Vector3& center, const Vector3& up,
  38. float radius, Degree startAngle, Degree angleAmount)
  39. {
  40. Vector3 arcBasis[3];
  41. arcBasis[1] = up;
  42. arcBasis[1].orthogonalComplement(arcBasis[2], arcBasis[0]);
  43. Matrix4 worldToPlane = Matrix4::IDENTITY;
  44. worldToPlane.setColumn(0, (Vector4)arcBasis[0]);
  45. worldToPlane.setColumn(1, (Vector4)arcBasis[1]);
  46. worldToPlane.setColumn(2, (Vector4)arcBasis[2]);
  47. worldToPlane.setColumn(3, (Vector4)worldToPlane.multiplyAffine(-center));
  48. worldToPlane[3][3] = 1;
  49. Plane plane(up, (-center).dot(up));
  50. Vector3 pointOnPlane;
  51. auto intersectResult = plane.intersects(inputRay);
  52. float t = 0.0f;
  53. if (intersectResult.first)
  54. pointOnPlane = inputRay.getPoint(intersectResult.second);
  55. else
  56. pointOnPlane = Vector3::ZERO;
  57. pointOnPlane = worldToPlane.multiplyAffine(pointOnPlane);
  58. Vector2 pointOnPlane2D(pointOnPlane.x, pointOnPlane.z); // y always 0
  59. Vector2 closestPoint2D;
  60. float dist = pointOnPlane2D.length();
  61. if (dist > 0.0f)
  62. closestPoint2D = mRadius * (pointOnPlane2D / dist);
  63. else
  64. closestPoint2D = Vector2(mRadius, 0);
  65. Radian angle = Math::atan2(-closestPoint2D.y, -closestPoint2D.x) + Math::PI;
  66. float angleRad = angle.valueRadians();
  67. float angleAmountRad = Math::clamp(angleAmount.valueRadians(), 0.0f, Math::PI * 2);
  68. float startAngleRad = startAngle.wrap().valueRadians();
  69. float endAngleRad = startAngleRad + angleAmountRad;
  70. float clampedAngle = angleRad;
  71. if (endAngleRad <= Math::PI * 2)
  72. {
  73. clampedAngle = Math::clamp(angleRad, startAngleRad, endAngleRad);
  74. }
  75. else
  76. {
  77. if (angleRad >= startAngleRad)
  78. clampedAngle = Math::clamp(angleRad, startAngleRad, Math::PI * 2);
  79. else
  80. {
  81. endAngleRad -= Math::PI * 2;
  82. if (angleRad > endAngleRad)
  83. {
  84. if ((startAngleRad - angleRad) > (angleRad - endAngleRad))
  85. clampedAngle = endAngleRad;
  86. else
  87. clampedAngle = startAngleRad;
  88. }
  89. else
  90. clampedAngle = angleRad;
  91. }
  92. }
  93. Vector3 clampedAnglePoint;
  94. clampedAnglePoint.x = Math::cos(clampedAngle) * radius;
  95. clampedAnglePoint.z = Math::sin(clampedAngle) * radius;
  96. return worldToPlane.inverseAffine().multiplyAffine(clampedAnglePoint);
  97. }
  98. Degree HandleSliderDisc::pointOnCircleToAngle(Vector3 up, Vector3 point)
  99. {
  100. Quaternion rot = Quaternion::getRotationFromTo(up, Vector3::UNIT_Y);
  101. Matrix4 worldToPlane = Matrix4::TRS(Vector3::ZERO, rot, Vector3::ONE);
  102. point = worldToPlane.multiplyAffine(point);
  103. return Radian(Math::atan2(-point.z, -point.x) + Math::PI);
  104. }
  105. void HandleSliderDisc::activate(const CameraHandlerPtr& camera, const Vector2I& pointerPos)
  106. {
  107. Ray localRay = camera->screenPointToRay(pointerPos);
  108. localRay.transformAffine(getTransformInv());
  109. mStartPosition = calculateClosestPointOnArc(localRay, Vector3::ZERO, mNormal, mRadius, Degree(0.0f), Degree(360.0f));
  110. mStartAngle = pointOnCircleToAngle(mNormal, mStartPosition);
  111. mStartPosition = getTransform().multiplyAffine(mStartPosition);
  112. Vector3 toStart = mStartPosition - getPosition();
  113. mDirection = toStart.cross(mNormal);
  114. mDirection.normalize();
  115. }
  116. void HandleSliderDisc::handleInput(const CameraHandlerPtr& camera, const Vector2I& inputDelta)
  117. {
  118. assert(getState() == State::Active);
  119. mCurrentPointerPos += inputDelta;
  120. mDelta = calcDelta(camera, mStartPosition, mDirection, mStartPointerPos, mCurrentPointerPos) * Math::RAD2DEG;
  121. }
  122. }