PVRTQuaternionX.cpp 10 KB

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