PVRTQuaternionF.cpp 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302
  1. /******************************************************************************
  2. @File PVRTQuaternionF.cpp
  3. @Title PVRTQuaternionF
  4. @Version
  5. @Copyright Copyright (C) Imagination Technologies Limited.
  6. @Platform ANSI compatible
  7. @Description Set of mathematical functions for quaternions.
  8. ******************************************************************************/
  9. #include "PVRTGlobal.h"
  10. #include "PVRTContext.h"
  11. #include <math.h>
  12. #include <string.h>
  13. #include "PVRTFixedPoint.h" // Only needed for trig function float lookups
  14. #include "PVRTQuaternion.h"
  15. /****************************************************************************
  16. ** Functions
  17. ****************************************************************************/
  18. /*!***************************************************************************
  19. @Function PVRTMatrixQuaternionIdentityF
  20. @Output qOut Identity quaternion
  21. @Description Sets the quaternion to (0, 0, 0, 1), the identity quaternion.
  22. *****************************************************************************/
  23. void PVRTMatrixQuaternionIdentityF(PVRTQUATERNIONf &qOut)
  24. {
  25. qOut.x = 0;
  26. qOut.y = 0;
  27. qOut.z = 0;
  28. qOut.w = 1;
  29. }
  30. /*!***************************************************************************
  31. @Function PVRTMatrixQuaternionRotationAxisF
  32. @Output qOut Rotation quaternion
  33. @Input vAxis Axis to rotate around
  34. @Input fAngle Angle to rotate
  35. @Description Create quaternion corresponding to a rotation of fAngle
  36. radians around submitted vector.
  37. *****************************************************************************/
  38. void PVRTMatrixQuaternionRotationAxisF(
  39. PVRTQUATERNIONf &qOut,
  40. const PVRTVECTOR3f &vAxis,
  41. const float fAngle)
  42. {
  43. float fSin, fCos;
  44. fSin = (float)PVRTFSIN(fAngle * 0.5f);
  45. fCos = (float)PVRTFCOS(fAngle * 0.5f);
  46. /* Create quaternion */
  47. qOut.x = vAxis.x * fSin;
  48. qOut.y = vAxis.y * fSin;
  49. qOut.z = vAxis.z * fSin;
  50. qOut.w = fCos;
  51. /* Normalise it */
  52. PVRTMatrixQuaternionNormalizeF(qOut);
  53. }
  54. /*!***************************************************************************
  55. @Function PVRTMatrixQuaternionToAxisAngleF
  56. @Input qIn Quaternion to transform
  57. @Output vAxis Axis of rotation
  58. @Output fAngle Angle of rotation
  59. @Description Convert a quaternion to an axis and angle. Expects a unit
  60. quaternion.
  61. *****************************************************************************/
  62. void PVRTMatrixQuaternionToAxisAngleF(
  63. const PVRTQUATERNIONf &qIn,
  64. PVRTVECTOR3f &vAxis,
  65. float &fAngle)
  66. {
  67. float fCosAngle, fSinAngle;
  68. double temp;
  69. /* Compute some values */
  70. fCosAngle = qIn.w;
  71. temp = 1.0f - fCosAngle*fCosAngle;
  72. fAngle = (float)PVRTFACOS(fCosAngle)*2.0f;
  73. fSinAngle = (float)sqrt(temp);
  74. /* This is to avoid a division by zero */
  75. if ((float)fabs(fSinAngle)<0.0005f)
  76. fSinAngle = 1.0f;
  77. /* Get axis vector */
  78. vAxis.x = qIn.x / fSinAngle;
  79. vAxis.y = qIn.y / fSinAngle;
  80. vAxis.z = qIn.z / fSinAngle;
  81. }
  82. /*!***************************************************************************
  83. @Function PVRTMatrixQuaternionSlerpF
  84. @Output qOut Result of the interpolation
  85. @Input qA First quaternion to interpolate from
  86. @Input qB Second quaternion to interpolate from
  87. @Input t Coefficient of interpolation
  88. @Description Perform a Spherical Linear intERPolation between quaternion A
  89. and quaternion B at time t. t must be between 0.0f and 1.0f
  90. *****************************************************************************/
  91. void PVRTMatrixQuaternionSlerpF(
  92. PVRTQUATERNIONf &qOut,
  93. const PVRTQUATERNIONf &qA,
  94. const PVRTQUATERNIONf &qB,
  95. const float t)
  96. {
  97. float fCosine, fAngle, A, B;
  98. /* Parameter checking */
  99. if (t<0.0f || t>1.0f)
  100. {
  101. _RPT0(_CRT_WARN, "PVRTMatrixQuaternionSlerp : Bad parameters\n");
  102. qOut.x = 0;
  103. qOut.y = 0;
  104. qOut.z = 0;
  105. qOut.w = 1;
  106. return;
  107. }
  108. /* Find sine of Angle between Quaternion A and B (dot product between quaternion A and B) */
  109. fCosine = qA.w*qB.w + qA.x*qB.x + qA.y*qB.y + qA.z*qB.z;
  110. if (fCosine < 0)
  111. {
  112. PVRTQUATERNIONf qi;
  113. /*
  114. <http://www.magic-software.com/Documentation/Quaternions.pdf>
  115. "It is important to note that the quaternions q and -q represent
  116. the same rotation... while either quaternion will do, the
  117. interpolation methods require choosing one over the other.
  118. "Although q1 and -q1 represent the same rotation, the values of
  119. Slerp(t; q0, q1) and Slerp(t; q0,-q1) are not the same. It is
  120. customary to choose the sign... on q1 so that... the angle
  121. between q0 and q1 is acute. This choice avoids extra
  122. spinning caused by the interpolated rotations."
  123. */
  124. qi.x = -qB.x;
  125. qi.y = -qB.y;
  126. qi.z = -qB.z;
  127. qi.w = -qB.w;
  128. PVRTMatrixQuaternionSlerpF(qOut, qA, qi, t);
  129. return;
  130. }
  131. fCosine = PVRT_MIN(fCosine, 1.0f);
  132. fAngle = (float)PVRTFACOS(fCosine);
  133. /* Avoid a division by zero */
  134. if (fAngle==0.0f)
  135. {
  136. qOut = qA;
  137. return;
  138. }
  139. /* Precompute some values */
  140. A = (float)(PVRTFSIN((1.0f-t)*fAngle) / PVRTFSIN(fAngle));
  141. B = (float)(PVRTFSIN(t*fAngle) / PVRTFSIN(fAngle));
  142. /* Compute resulting quaternion */
  143. qOut.x = A * qA.x + B * qB.x;
  144. qOut.y = A * qA.y + B * qB.y;
  145. qOut.z = A * qA.z + B * qB.z;
  146. qOut.w = A * qA.w + B * qB.w;
  147. /* Normalise result */
  148. PVRTMatrixQuaternionNormalizeF(qOut);
  149. }
  150. /*!***************************************************************************
  151. @Function PVRTMatrixQuaternionNormalizeF
  152. @Modified quat Vector to normalize
  153. @Description Normalize quaternion.
  154. *****************************************************************************/
  155. void PVRTMatrixQuaternionNormalizeF(PVRTQUATERNIONf &quat)
  156. {
  157. float fMagnitude;
  158. double temp;
  159. /* Compute quaternion magnitude */
  160. temp = quat.w*quat.w + quat.x*quat.x + quat.y*quat.y + quat.z*quat.z;
  161. fMagnitude = (float)sqrt(temp);
  162. /* Divide each quaternion component by this magnitude */
  163. if (fMagnitude!=0.0f)
  164. {
  165. fMagnitude = 1.0f / fMagnitude;
  166. quat.x *= fMagnitude;
  167. quat.y *= fMagnitude;
  168. quat.z *= fMagnitude;
  169. quat.w *= fMagnitude;
  170. }
  171. }
  172. /*!***************************************************************************
  173. @Function PVRTMatrixRotationQuaternionF
  174. @Output mOut Resulting rotation matrix
  175. @Input quat Quaternion to transform
  176. @Description Create rotation matrix from submitted quaternion.
  177. Assuming the quaternion is of the form [X Y Z W]:
  178. | 2 2 |
  179. | 1 - 2Y - 2Z 2XY - 2ZW 2XZ + 2YW 0 |
  180. | |
  181. | 2 2 |
  182. M = | 2XY + 2ZW 1 - 2X - 2Z 2YZ - 2XW 0 |
  183. | |
  184. | 2 2 |
  185. | 2XZ - 2YW 2YZ + 2XW 1 - 2X - 2Y 0 |
  186. | |
  187. | 0 0 0 1 |
  188. *****************************************************************************/
  189. void PVRTMatrixRotationQuaternionF(
  190. PVRTMATRIXf &mOut,
  191. const PVRTQUATERNIONf &quat)
  192. {
  193. const PVRTQUATERNIONf *pQ;
  194. #if defined(BUILD_DX9) || defined(BUILD_D3DM) || defined(BUILD_DX10)
  195. PVRTQUATERNIONf qInv;
  196. qInv.x = -quat.x;
  197. qInv.y = -quat.y;
  198. qInv.z = -quat.z;
  199. qInv.w = quat.w;
  200. pQ = &qInv;
  201. #else
  202. pQ = &quat;
  203. #endif
  204. /* Fill matrix members */
  205. mOut.f[0] = 1.0f - 2.0f*pQ->y*pQ->y - 2.0f*pQ->z*pQ->z;
  206. mOut.f[1] = 2.0f*pQ->x*pQ->y - 2.0f*pQ->z*pQ->w;
  207. mOut.f[2] = 2.0f*pQ->x*pQ->z + 2.0f*pQ->y*pQ->w;
  208. mOut.f[3] = 0.0f;
  209. mOut.f[4] = 2.0f*pQ->x*pQ->y + 2.0f*pQ->z*pQ->w;
  210. mOut.f[5] = 1.0f - 2.0f*pQ->x*pQ->x - 2.0f*pQ->z*pQ->z;
  211. mOut.f[6] = 2.0f*pQ->y*pQ->z - 2.0f*pQ->x*pQ->w;
  212. mOut.f[7] = 0.0f;
  213. mOut.f[8] = 2.0f*pQ->x*pQ->z - 2*pQ->y*pQ->w;
  214. mOut.f[9] = 2.0f*pQ->y*pQ->z + 2.0f*pQ->x*pQ->w;
  215. mOut.f[10] = 1.0f - 2.0f*pQ->x*pQ->x - 2*pQ->y*pQ->y;
  216. mOut.f[11] = 0.0f;
  217. mOut.f[12] = 0.0f;
  218. mOut.f[13] = 0.0f;
  219. mOut.f[14] = 0.0f;
  220. mOut.f[15] = 1.0f;
  221. }
  222. /*!***************************************************************************
  223. @Function PVRTMatrixQuaternionMultiplyF
  224. @Output qOut Resulting quaternion
  225. @Input qA First quaternion to multiply
  226. @Input qB Second quaternion to multiply
  227. @Description Multiply quaternion A with quaternion B and return the
  228. result in qOut.
  229. *****************************************************************************/
  230. void PVRTMatrixQuaternionMultiplyF(
  231. PVRTQUATERNIONf &qOut,
  232. const PVRTQUATERNIONf &qA,
  233. const PVRTQUATERNIONf &qB)
  234. {
  235. PVRTVECTOR3f CrossProduct;
  236. /* Compute scalar component */
  237. qOut.w = (qA.w*qB.w) - (qA.x*qB.x + qA.y*qB.y + qA.z*qB.z);
  238. /* Compute cross product */
  239. CrossProduct.x = qA.y*qB.z - qA.z*qB.y;
  240. CrossProduct.y = qA.z*qB.x - qA.x*qB.z;
  241. CrossProduct.z = qA.x*qB.y - qA.y*qB.x;
  242. /* Compute result vector */
  243. qOut.x = (qA.w * qB.x) + (qB.w * qA.x) + CrossProduct.x;
  244. qOut.y = (qA.w * qB.y) + (qB.w * qA.y) + CrossProduct.y;
  245. qOut.z = (qA.w * qB.z) + (qB.w * qA.z) + CrossProduct.z;
  246. /* Normalize resulting quaternion */
  247. PVRTMatrixQuaternionNormalizeF(qOut);
  248. }
  249. /*****************************************************************************
  250. End of file (PVRTQuaternionF.cpp)
  251. *****************************************************************************/