arcball.c 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  1. /*************************************************************************************/
  2. /** **/
  3. /** Copyright (c) 1999-2009 Tatewake.com **/
  4. /** **/
  5. /** Permission is hereby granted, free of charge, to any person obtaining a copy **/
  6. /** of this software and associated documentation files (the "Software"), to deal **/
  7. /** in the Software without restriction, including without limitation the rights **/
  8. /** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell **/
  9. /** copies of the Software, and to permit persons to whom the Software is **/
  10. /** furnished to do so, subject to the following conditions: **/
  11. /** **/
  12. /** The above copyright notice and this permission notice shall be included in **/
  13. /** all copies or substantial portions of the Software. **/
  14. /** **/
  15. /** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR **/
  16. /** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, **/
  17. /** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE **/
  18. /** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER **/
  19. /** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, **/
  20. /** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN **/
  21. /** THE SOFTWARE. **/
  22. /** **/
  23. /*************************************************************************************/
  24. #include <glcomp/glcompdefs.h>
  25. #define ARCBALL_C
  26. #include "smyrnadefs.h"
  27. #include "arcball.h"
  28. static void setBounds(ArcBall_t *a, float NewWidth, float NewHeight) {
  29. assert((NewWidth > 1.0f) && (NewHeight > 1.0f));
  30. //Set adjustment factor for width/height
  31. a->AdjustWidth = 1.0f / ((NewWidth - 1.0f) * 0.5f);
  32. a->AdjustHeight = 1.0f / ((NewHeight - 1.0f) * 0.5f);
  33. }
  34. static void mapToSphere(ArcBall_t * a, const Point2fT * NewPt,
  35. Vector3fT * NewVec)
  36. {
  37. Point2fT TempPt;
  38. //Copy paramter into temp point
  39. TempPt = *NewPt;
  40. //Adjust point coords and scale down to range of [-1 ... 1]
  41. TempPt.s.X = (TempPt.s.X * a->AdjustWidth) - 1.0f;
  42. TempPt.s.Y = 1.0f - (TempPt.s.Y * a->AdjustHeight);
  43. //Compute the square of the length of the vector to the point from the center
  44. float length = TempPt.s.X * TempPt.s.X + TempPt.s.Y * TempPt.s.Y;
  45. //If the point is mapped outside of the sphere... (length > radius squared)
  46. if (length > 1.0f) {
  47. //Compute a normalizing factor (radius / sqrt(length))
  48. float norm = 1.0f / FuncSqrt(length);
  49. //Return the "normalized" vector, a point on the sphere
  50. NewVec->s.X = TempPt.s.X * norm;
  51. NewVec->s.Y = TempPt.s.Y * norm;
  52. NewVec->s.Z = 0.0f;
  53. } else //Else it's on the inside
  54. {
  55. //Return a vector to a point mapped inside the sphere sqrt(radius squared - length)
  56. NewVec->s.X = TempPt.s.X;
  57. NewVec->s.Y = TempPt.s.Y;
  58. NewVec->s.Z = FuncSqrt(1.0f - length);
  59. }
  60. }
  61. static Matrix4fT Transform = { {1.0f, 0.0f, 0.0f, 0.0f, // NEW: Final Transform
  62. 0.0f, 1.0f, 0.0f, 0.0f,
  63. 0.0f, 0.0f, 1.0f, 0.0f,
  64. 0.0f, 0.0f, 0.0f, 1.0f}
  65. };
  66. static Matrix3fT LastRot = { {1.0f, 0.0f, 0.0f, // NEW: Last Rotation
  67. 0.0f, 1.0f, 0.0f,
  68. 0.0f, 0.0f, 1.0f}
  69. };
  70. static Matrix3fT ThisRot = { {1.0f, 0.0f, 0.0f, // NEW: This Rotation
  71. 0.0f, 1.0f, 0.0f,
  72. 0.0f, 0.0f, 1.0f}
  73. };
  74. //Create/Destroy
  75. void init_arcBall(ArcBall_t *a, float NewWidth, float NewHeight) {
  76. a->Transform = Transform;
  77. a->LastRot = LastRot;
  78. a->ThisRot = ThisRot;
  79. //Clear initial values
  80. a->StVec.s.X =
  81. a->StVec.s.Y =
  82. a->StVec.s.Z = a->EnVec.s.X = a->EnVec.s.Y = a->EnVec.s.Z = 0.0f;
  83. //Set initial bounds
  84. setBounds(a, NewWidth, NewHeight);
  85. a->isClicked = 0;
  86. a->isRClicked = 0;
  87. a->isDragging = 0;
  88. }
  89. //Mouse down
  90. static void click(ArcBall_t * a, const Point2fT * NewPt)
  91. {
  92. //Map the point to the sphere
  93. mapToSphere(a, NewPt, &a->StVec);
  94. }
  95. //Mouse drag, calculate rotation
  96. static void drag(ArcBall_t * a, const Point2fT * NewPt, Quat4fT * NewRot)
  97. {
  98. //Map the point to the sphere
  99. mapToSphere(a, NewPt, &a->EnVec);
  100. //Return the quaternion equivalent to the rotation
  101. if (NewRot) {
  102. Vector3fT Perp;
  103. //Compute the vector perpendicular to the begin and end vectors
  104. Vector3fCross(&Perp, &a->StVec, &a->EnVec);
  105. //Compute the length of the perpendicular vector
  106. if (Vector3fLength(&Perp) > Epsilon) //if its non-zero
  107. {
  108. //We're ok, so return the perpendicular vector as the transform after all
  109. NewRot->s.X = Perp.s.X;
  110. NewRot->s.Y = Perp.s.Y;
  111. NewRot->s.Z = Perp.s.Z;
  112. //In the quaternion values, w is cosine (theta / 2), where theta is rotation angle
  113. NewRot->s.W = Vector3fDot(&a->StVec, &a->EnVec);
  114. } else //if its zero
  115. {
  116. //The begin and end vectors coincide, so return an identity transform
  117. NewRot->s.X = NewRot->s.Y = NewRot->s.Z = NewRot->s.W = 0.0f;
  118. }
  119. }
  120. }
  121. void arcmouseClick(void)
  122. {
  123. view->arcball->isDragging = 1; // Prepare For Dragging
  124. view->arcball->LastRot = view->arcball->ThisRot; // Set Last Static Rotation To Last Dynamic One
  125. click(view->arcball, &view->arcball->MousePt);
  126. }
  127. void arcmouseDrag(void)
  128. {
  129. Quat4fT ThisQuat;
  130. drag(view->arcball, &view->arcball->MousePt, &ThisQuat);
  131. Matrix3fSetRotationFromQuat4f(&view->arcball->ThisRot, &ThisQuat); // Convert Quaternion Into Matrix3fT
  132. Matrix3fMulMatrix3f(&view->arcball->ThisRot, &view->arcball->LastRot); // Accumulate Last Rotation Into This One
  133. Matrix4fSetRotationFromMatrix3f(&view->arcball->Transform, &view->arcball->ThisRot); // Set Our Final Transform's Rotation From This One
  134. }