123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313 |
- /******************************************************************************
- @File PVRTQuaternionX.cpp
- @Title PVRTQuaternionX
- @Version
- @Copyright Copyright (C) Imagination Technologies Limited.
- @Platform ANSI compatible
- @Description Set of mathematical functions for quaternions.
- ******************************************************************************/
- #include "PVRTContext.h"
- #include <math.h>
- #include <string.h>
- #include "PVRTFixedPoint.h"
- #include "PVRTQuaternion.h"
- /****************************************************************************
- ** Functions
- ****************************************************************************/
- /*!***************************************************************************
- @Function PVRTMatrixQuaternionIdentityX
- @Output qOut Identity quaternion
- @Description Sets the quaternion to (0, 0, 0, 1), the identity quaternion.
- *****************************************************************************/
- void PVRTMatrixQuaternionIdentityX(PVRTQUATERNIONx &qOut)
- {
- qOut.x = PVRTF2X(0.0f);
- qOut.y = PVRTF2X(0.0f);
- qOut.z = PVRTF2X(0.0f);
- qOut.w = PVRTF2X(1.0f);
- }
- /*!***************************************************************************
- @Function PVRTMatrixQuaternionRotationAxisX
- @Output qOut Rotation quaternion
- @Input vAxis Axis to rotate around
- @Input fAngle Angle to rotate
- @Description Create quaternion corresponding to a rotation of fAngle
- radians around submitted vector.
- *****************************************************************************/
- void PVRTMatrixQuaternionRotationAxisX(
- PVRTQUATERNIONx &qOut,
- const PVRTVECTOR3x &vAxis,
- const int fAngle)
- {
- int fSin, fCos;
- fSin = PVRTXSIN(fAngle>>1);
- fCos = PVRTXCOS(fAngle>>1);
- /* Create quaternion */
- qOut.x = PVRTXMUL(vAxis.x, fSin);
- qOut.y = PVRTXMUL(vAxis.y, fSin);
- qOut.z = PVRTXMUL(vAxis.z, fSin);
- qOut.w = fCos;
- /* Normalise it */
- PVRTMatrixQuaternionNormalizeX(qOut);
- }
- /*!***************************************************************************
- @Function PVRTMatrixQuaternionToAxisAngleX
- @Input qIn Quaternion to transform
- @Output vAxis Axis of rotation
- @Output fAngle Angle of rotation
- @Description Convert a quaternion to an axis and angle. Expects a unit
- quaternion.
- *****************************************************************************/
- void PVRTMatrixQuaternionToAxisAngleX(
- const PVRTQUATERNIONx &qIn,
- PVRTVECTOR3x &vAxis,
- int &fAngle)
- {
- int fCosAngle, fSinAngle;
- int temp;
- /* Compute some values */
- fCosAngle = qIn.w;
- temp = PVRTF2X(1.0f) - PVRTXMUL(fCosAngle, fCosAngle);
- fAngle = PVRTXMUL(PVRTXACOS(fCosAngle), PVRTF2X(2.0f));
- fSinAngle = PVRTF2X(((float)sqrt(PVRTX2F(temp))));
- /* This is to avoid a division by zero */
- if (PVRTABS(fSinAngle)<PVRTF2X(0.0005f))
- {
- fSinAngle = PVRTF2X(1.0f);
- }
- /* Get axis vector */
- vAxis.x = PVRTXDIV(qIn.x, fSinAngle);
- vAxis.y = PVRTXDIV(qIn.y, fSinAngle);
- vAxis.z = PVRTXDIV(qIn.z, fSinAngle);
- }
- /*!***************************************************************************
- @Function PVRTMatrixQuaternionSlerpX
- @Output qOut Result of the interpolation
- @Input qA First quaternion to interpolate from
- @Input qB Second quaternion to interpolate from
- @Input t Coefficient of interpolation
- @Description Perform a Spherical Linear intERPolation between quaternion A
- and quaternion B at time t. t must be between 0.0f and 1.0f
- Requires input quaternions to be normalized
- *****************************************************************************/
- void PVRTMatrixQuaternionSlerpX(
- PVRTQUATERNIONx &qOut,
- const PVRTQUATERNIONx &qA,
- const PVRTQUATERNIONx &qB,
- const int t)
- {
- int fCosine, fAngle, A, B;
- /* Parameter checking */
- if (t<PVRTF2X(0.0f) || t>PVRTF2X(1.0f))
- {
- _RPT0(_CRT_WARN, "PVRTMatrixQuaternionSlerp : Bad parameters\n");
- qOut.x = PVRTF2X(0.0f);
- qOut.y = PVRTF2X(0.0f);
- qOut.z = PVRTF2X(0.0f);
- qOut.w = PVRTF2X(1.0f);
- return;
- }
- /* Find sine of Angle between Quaternion A and B (dot product between quaternion A and B) */
- fCosine = PVRTXMUL(qA.w, qB.w) +
- PVRTXMUL(qA.x, qB.x) + PVRTXMUL(qA.y, qB.y) + PVRTXMUL(qA.z, qB.z);
- if(fCosine < PVRTF2X(0.0f))
- {
- PVRTQUATERNIONx qi;
- /*
- <http://www.magic-software.com/Documentation/Quaternions.pdf>
- "It is important to note that the quaternions q and -q represent
- the same rotation... while either quaternion will do, the
- interpolation methods require choosing one over the other.
- "Although q1 and -q1 represent the same rotation, the values of
- Slerp(t; q0, q1) and Slerp(t; q0,-q1) are not the same. It is
- customary to choose the sign... on q1 so that... the angle
- between q0 and q1 is acute. This choice avoids extra
- spinning caused by the interpolated rotations."
- */
- qi.x = -qB.x;
- qi.y = -qB.y;
- qi.z = -qB.z;
- qi.w = -qB.w;
- PVRTMatrixQuaternionSlerpX(qOut, qA, qi, t);
- return;
- }
- fCosine = PVRT_MIN(fCosine, PVRTF2X(1.0f));
- fAngle = PVRTXACOS(fCosine);
- /* Avoid a division by zero */
- if (fAngle==PVRTF2X(0.0f))
- {
- qOut = qA;
- return;
- }
- /* Precompute some values */
- A = PVRTXDIV(PVRTXSIN(PVRTXMUL((PVRTF2X(1.0f)-t), fAngle)), PVRTXSIN(fAngle));
- B = PVRTXDIV(PVRTXSIN(PVRTXMUL(t, fAngle)), PVRTXSIN(fAngle));
- /* Compute resulting quaternion */
- qOut.x = PVRTXMUL(A, qA.x) + PVRTXMUL(B, qB.x);
- qOut.y = PVRTXMUL(A, qA.y) + PVRTXMUL(B, qB.y);
- qOut.z = PVRTXMUL(A, qA.z) + PVRTXMUL(B, qB.z);
- qOut.w = PVRTXMUL(A, qA.w) + PVRTXMUL(B, qB.w);
- /* Normalise result */
- PVRTMatrixQuaternionNormalizeX(qOut);
- }
- /*!***************************************************************************
- @Function PVRTMatrixQuaternionNormalizeX
- @Modified quat Vector to normalize
- @Description Normalize quaternion.
- Original quaternion is scaled down prior to be normalized in
- order to avoid overflow issues.
- *****************************************************************************/
- void PVRTMatrixQuaternionNormalizeX(PVRTQUATERNIONx &quat)
- {
- PVRTQUATERNIONx qTemp;
- int f, n;
- /* Scale vector by uniform value */
- n = PVRTABS(quat.w) + PVRTABS(quat.x) + PVRTABS(quat.y) + PVRTABS(quat.z);
- qTemp.w = PVRTXDIV(quat.w, n);
- qTemp.x = PVRTXDIV(quat.x, n);
- qTemp.y = PVRTXDIV(quat.y, n);
- qTemp.z = PVRTXDIV(quat.z, n);
- /* Compute quaternion magnitude */
- f = PVRTXMUL(qTemp.w, qTemp.w) + PVRTXMUL(qTemp.x, qTemp.x) + PVRTXMUL(qTemp.y, qTemp.y) + PVRTXMUL(qTemp.z, qTemp.z);
- f = PVRTXDIV(PVRTF2X(1.0f), PVRTF2X(sqrt(PVRTX2F(f))));
- /* Multiply vector components by f */
- quat.x = PVRTXMUL(qTemp.x, f);
- quat.y = PVRTXMUL(qTemp.y, f);
- quat.z = PVRTXMUL(qTemp.z, f);
- quat.w = PVRTXMUL(qTemp.w, f);
- }
- /*!***************************************************************************
- @Function PVRTMatrixRotationQuaternionX
- @Output mOut Resulting rotation matrix
- @Input quat Quaternion to transform
- @Description Create rotation matrix from submitted quaternion.
- Assuming the quaternion is of the form [X Y Z W]:
- | 2 2 |
- | 1 - 2Y - 2Z 2XY - 2ZW 2XZ + 2YW 0 |
- | |
- | 2 2 |
- M = | 2XY + 2ZW 1 - 2X - 2Z 2YZ - 2XW 0 |
- | |
- | 2 2 |
- | 2XZ - 2YW 2YZ + 2XW 1 - 2X - 2Y 0 |
- | |
- | 0 0 0 1 |
- *****************************************************************************/
- void PVRTMatrixRotationQuaternionX(
- PVRTMATRIXx &mOut,
- const PVRTQUATERNIONx &quat)
- {
- const PVRTQUATERNIONx *pQ;
- #if defined(BUILD_DX9) || defined(BUILD_D3DM) || defined(BUILD_DX10)
- PVRTQUATERNIONx qInv;
- qInv.x = -quat.x;
- qInv.y = -quat.y;
- qInv.z = -quat.z;
- qInv.w = quat.w;
- pQ = &qInv;
- #else
- pQ = &quat;
- #endif
- /* Fill matrix members */
- mOut.f[0] = PVRTF2X(1.0f) - (PVRTXMUL(pQ->y, pQ->y)<<1) - (PVRTXMUL(pQ->z, pQ->z)<<1);
- mOut.f[1] = (PVRTXMUL(pQ->x, pQ->y)<<1) - (PVRTXMUL(pQ->z, pQ->w)<<1);
- mOut.f[2] = (PVRTXMUL(pQ->x, pQ->z)<<1) + (PVRTXMUL(pQ->y, pQ->w)<<1);
- mOut.f[3] = PVRTF2X(0.0f);
- mOut.f[4] = (PVRTXMUL(pQ->x, pQ->y)<<1) + (PVRTXMUL(pQ->z, pQ->w)<<1);
- mOut.f[5] = PVRTF2X(1.0f) - (PVRTXMUL(pQ->x, pQ->x)<<1) - (PVRTXMUL(pQ->z, pQ->z)<<1);
- mOut.f[6] = (PVRTXMUL(pQ->y, pQ->z)<<1) - (PVRTXMUL(pQ->x, pQ->w)<<1);
- mOut.f[7] = PVRTF2X(0.0f);
- mOut.f[8] = (PVRTXMUL(pQ->x, pQ->z)<<1) - (PVRTXMUL(pQ->y, pQ->w)<<1);
- mOut.f[9] = (PVRTXMUL(pQ->y, pQ->z)<<1) + (PVRTXMUL(pQ->x, pQ->w)<<1);
- mOut.f[10] = PVRTF2X(1.0f) - (PVRTXMUL(pQ->x, pQ->x)<<1) - (PVRTXMUL(pQ->y, pQ->y)<<1);
- mOut.f[11] = PVRTF2X(0.0f);
- mOut.f[12] = PVRTF2X(0.0f);
- mOut.f[13] = PVRTF2X(0.0f);
- mOut.f[14] = PVRTF2X(0.0f);
- mOut.f[15] = PVRTF2X(1.0f);
- }
- /*!***************************************************************************
- @Function PVRTMatrixQuaternionMultiplyX
- @Output qOut Resulting quaternion
- @Input qA First quaternion to multiply
- @Input qB Second quaternion to multiply
- @Description Multiply quaternion A with quaternion B and return the
- result in qOut.
- Input quaternions must be normalized.
- *****************************************************************************/
- void PVRTMatrixQuaternionMultiplyX(
- PVRTQUATERNIONx &qOut,
- const PVRTQUATERNIONx &qA,
- const PVRTQUATERNIONx &qB)
- {
- PVRTVECTOR3x CrossProduct;
- /* Compute scalar component */
- qOut.w = PVRTXMUL(qA.w, qB.w) -
- (PVRTXMUL(qA.x, qB.x) + PVRTXMUL(qA.y, qB.y) + PVRTXMUL(qA.z, qB.z));
- /* Compute cross product */
- CrossProduct.x = PVRTXMUL(qA.y, qB.z) - PVRTXMUL(qA.z, qB.y);
- CrossProduct.y = PVRTXMUL(qA.z, qB.x) - PVRTXMUL(qA.x, qB.z);
- CrossProduct.z = PVRTXMUL(qA.x, qB.y) - PVRTXMUL(qA.y, qB.x);
- /* Compute result vector */
- qOut.x = PVRTXMUL(qA.w, qB.x) + PVRTXMUL(qB.w, qA.x) + CrossProduct.x;
- qOut.y = PVRTXMUL(qA.w, qB.y) + PVRTXMUL(qB.w, qA.y) + CrossProduct.y;
- qOut.z = PVRTXMUL(qA.w, qB.z) + PVRTXMUL(qB.w, qA.z) + CrossProduct.z;
- /* Normalize resulting quaternion */
- PVRTMatrixQuaternionNormalizeX(qOut);
- }
- /*****************************************************************************
- End of file (PVRTQuaternionX.cpp)
- *****************************************************************************/
|