| /****************************************************************************** |
| |
| @File PVRTMatrixF.cpp |
| |
| @Title PVRTMatrixF |
| |
| @Version |
| |
| @Copyright Copyright (c) Imagination Technologies Limited. |
| |
| @Platform ANSI compatible |
| |
| @Description Set of mathematical functions involving matrices, vectors and |
| quaternions. The general matrix format used is directly compatible |
| with, for example, both DirectX and OpenGL. For the reasons why, |
| read this: |
| http://research.microsoft.com/~hollasch/cgindex/math/matrix/column-vec.html |
| |
| ******************************************************************************/ |
| #include "PVRTGlobal.h" |
| #include <math.h> |
| #include <string.h> |
| #include "PVRTFixedPoint.h" // Only needed for trig function float lookups |
| #include "PVRTMatrix.h" |
| |
| |
| /**************************************************************************** |
| ** Constants |
| ****************************************************************************/ |
| static const PVRTMATRIXf c_mIdentity = { |
| { |
| 1, 0, 0, 0, |
| 0, 1, 0, 0, |
| 0, 0, 1, 0, |
| 0, 0, 0, 1 |
| } |
| }; |
| |
| /**************************************************************************** |
| ** Functions |
| ****************************************************************************/ |
| |
| /*!*************************************************************************** |
| @Function PVRTMatrixIdentityF |
| @Output mOut Set to identity |
| @Description Reset matrix to identity matrix. |
| *****************************************************************************/ |
| void PVRTMatrixIdentityF(PVRTMATRIXf &mOut) |
| { |
| mOut.f[ 0]=1.0f; mOut.f[ 4]=0.0f; mOut.f[ 8]=0.0f; mOut.f[12]=0.0f; |
| mOut.f[ 1]=0.0f; mOut.f[ 5]=1.0f; mOut.f[ 9]=0.0f; mOut.f[13]=0.0f; |
| mOut.f[ 2]=0.0f; mOut.f[ 6]=0.0f; mOut.f[10]=1.0f; mOut.f[14]=0.0f; |
| mOut.f[ 3]=0.0f; mOut.f[ 7]=0.0f; mOut.f[11]=0.0f; mOut.f[15]=1.0f; |
| } |
| |
| |
| /*!*************************************************************************** |
| @Function PVRTMatrixMultiplyF |
| @Output mOut Result of mA x mB |
| @Input mA First operand |
| @Input mB Second operand |
| @Description Multiply mA by mB and assign the result to mOut |
| (mOut = p1 * p2). A copy of the result matrix is done in |
| the function because mOut can be a parameter mA or mB. |
| *****************************************************************************/ |
| void PVRTMatrixMultiplyF( |
| PVRTMATRIXf &mOut, |
| const PVRTMATRIXf &mA, |
| const PVRTMATRIXf &mB) |
| { |
| PVRTMATRIXf mRet; |
| |
| /* Perform calculation on a dummy matrix (mRet) */ |
| mRet.f[ 0] = mA.f[ 0]*mB.f[ 0] + mA.f[ 1]*mB.f[ 4] + mA.f[ 2]*mB.f[ 8] + mA.f[ 3]*mB.f[12]; |
| mRet.f[ 1] = mA.f[ 0]*mB.f[ 1] + mA.f[ 1]*mB.f[ 5] + mA.f[ 2]*mB.f[ 9] + mA.f[ 3]*mB.f[13]; |
| mRet.f[ 2] = mA.f[ 0]*mB.f[ 2] + mA.f[ 1]*mB.f[ 6] + mA.f[ 2]*mB.f[10] + mA.f[ 3]*mB.f[14]; |
| mRet.f[ 3] = mA.f[ 0]*mB.f[ 3] + mA.f[ 1]*mB.f[ 7] + mA.f[ 2]*mB.f[11] + mA.f[ 3]*mB.f[15]; |
| |
| mRet.f[ 4] = mA.f[ 4]*mB.f[ 0] + mA.f[ 5]*mB.f[ 4] + mA.f[ 6]*mB.f[ 8] + mA.f[ 7]*mB.f[12]; |
| mRet.f[ 5] = mA.f[ 4]*mB.f[ 1] + mA.f[ 5]*mB.f[ 5] + mA.f[ 6]*mB.f[ 9] + mA.f[ 7]*mB.f[13]; |
| mRet.f[ 6] = mA.f[ 4]*mB.f[ 2] + mA.f[ 5]*mB.f[ 6] + mA.f[ 6]*mB.f[10] + mA.f[ 7]*mB.f[14]; |
| mRet.f[ 7] = mA.f[ 4]*mB.f[ 3] + mA.f[ 5]*mB.f[ 7] + mA.f[ 6]*mB.f[11] + mA.f[ 7]*mB.f[15]; |
| |
| mRet.f[ 8] = mA.f[ 8]*mB.f[ 0] + mA.f[ 9]*mB.f[ 4] + mA.f[10]*mB.f[ 8] + mA.f[11]*mB.f[12]; |
| mRet.f[ 9] = mA.f[ 8]*mB.f[ 1] + mA.f[ 9]*mB.f[ 5] + mA.f[10]*mB.f[ 9] + mA.f[11]*mB.f[13]; |
| mRet.f[10] = mA.f[ 8]*mB.f[ 2] + mA.f[ 9]*mB.f[ 6] + mA.f[10]*mB.f[10] + mA.f[11]*mB.f[14]; |
| mRet.f[11] = mA.f[ 8]*mB.f[ 3] + mA.f[ 9]*mB.f[ 7] + mA.f[10]*mB.f[11] + mA.f[11]*mB.f[15]; |
| |
| mRet.f[12] = mA.f[12]*mB.f[ 0] + mA.f[13]*mB.f[ 4] + mA.f[14]*mB.f[ 8] + mA.f[15]*mB.f[12]; |
| mRet.f[13] = mA.f[12]*mB.f[ 1] + mA.f[13]*mB.f[ 5] + mA.f[14]*mB.f[ 9] + mA.f[15]*mB.f[13]; |
| mRet.f[14] = mA.f[12]*mB.f[ 2] + mA.f[13]*mB.f[ 6] + mA.f[14]*mB.f[10] + mA.f[15]*mB.f[14]; |
| mRet.f[15] = mA.f[12]*mB.f[ 3] + mA.f[13]*mB.f[ 7] + mA.f[14]*mB.f[11] + mA.f[15]*mB.f[15]; |
| |
| /* Copy result to mOut */ |
| mOut = mRet; |
| } |
| |
| |
| /*!*************************************************************************** |
| @Function Name PVRTMatrixTranslationF |
| @Output mOut Translation matrix |
| @Input fX X component of the translation |
| @Input fY Y component of the translation |
| @Input fZ Z component of the translation |
| @Description Build a transaltion matrix mOut using fX, fY and fZ. |
| *****************************************************************************/ |
| void PVRTMatrixTranslationF( |
| PVRTMATRIXf &mOut, |
| const float fX, |
| const float fY, |
| const float fZ) |
| { |
| mOut.f[ 0]=1.0f; mOut.f[ 4]=0.0f; mOut.f[ 8]=0.0f; mOut.f[12]=fX; |
| mOut.f[ 1]=0.0f; mOut.f[ 5]=1.0f; mOut.f[ 9]=0.0f; mOut.f[13]=fY; |
| mOut.f[ 2]=0.0f; mOut.f[ 6]=0.0f; mOut.f[10]=1.0f; mOut.f[14]=fZ; |
| mOut.f[ 3]=0.0f; mOut.f[ 7]=0.0f; mOut.f[11]=0.0f; mOut.f[15]=1.0f; |
| } |
| |
| /*!*************************************************************************** |
| @Function Name PVRTMatrixScalingF |
| @Output mOut Scale matrix |
| @Input fX X component of the scaling |
| @Input fY Y component of the scaling |
| @Input fZ Z component of the scaling |
| @Description Build a scale matrix mOut using fX, fY and fZ. |
| *****************************************************************************/ |
| void PVRTMatrixScalingF( |
| PVRTMATRIXf &mOut, |
| const float fX, |
| const float fY, |
| const float fZ) |
| { |
| mOut.f[ 0]=fX; mOut.f[ 4]=0.0f; mOut.f[ 8]=0.0f; mOut.f[12]=0.0f; |
| mOut.f[ 1]=0.0f; mOut.f[ 5]=fY; mOut.f[ 9]=0.0f; mOut.f[13]=0.0f; |
| mOut.f[ 2]=0.0f; mOut.f[ 6]=0.0f; mOut.f[10]=fZ; mOut.f[14]=0.0f; |
| mOut.f[ 3]=0.0f; mOut.f[ 7]=0.0f; mOut.f[11]=0.0f; mOut.f[15]=1.0f; |
| } |
| |
| /*!*************************************************************************** |
| @Function Name PVRTMatrixRotationXF |
| @Output mOut Rotation matrix |
| @Input fAngle Angle of the rotation |
| @Description Create an X rotation matrix mOut. |
| *****************************************************************************/ |
| void PVRTMatrixRotationXF( |
| PVRTMATRIXf &mOut, |
| const float fAngle) |
| { |
| float fCosine, fSine; |
| |
| /* Precompute cos and sin */ |
| #if defined(BUILD_DX11) |
| fCosine = (float)PVRTFCOS(-fAngle); |
| fSine = (float)PVRTFSIN(-fAngle); |
| #else |
| fCosine = (float)PVRTFCOS(fAngle); |
| fSine = (float)PVRTFSIN(fAngle); |
| #endif |
| |
| /* Create the trigonometric matrix corresponding to X Rotation */ |
| mOut.f[ 0]=1.0f; mOut.f[ 4]=0.0f; mOut.f[ 8]=0.0f; mOut.f[12]=0.0f; |
| mOut.f[ 1]=0.0f; mOut.f[ 5]=fCosine; mOut.f[ 9]=fSine; mOut.f[13]=0.0f; |
| mOut.f[ 2]=0.0f; mOut.f[ 6]=-fSine; mOut.f[10]=fCosine; mOut.f[14]=0.0f; |
| mOut.f[ 3]=0.0f; mOut.f[ 7]=0.0f; mOut.f[11]=0.0f; mOut.f[15]=1.0f; |
| } |
| |
| /*!*************************************************************************** |
| @Function Name PVRTMatrixRotationYF |
| @Output mOut Rotation matrix |
| @Input fAngle Angle of the rotation |
| @Description Create an Y rotation matrix mOut. |
| *****************************************************************************/ |
| void PVRTMatrixRotationYF( |
| PVRTMATRIXf &mOut, |
| const float fAngle) |
| { |
| float fCosine, fSine; |
| |
| /* Precompute cos and sin */ |
| #if defined(BUILD_DX11) |
| fCosine = (float)PVRTFCOS(-fAngle); |
| fSine = (float)PVRTFSIN(-fAngle); |
| #else |
| fCosine = (float)PVRTFCOS(fAngle); |
| fSine = (float)PVRTFSIN(fAngle); |
| #endif |
| |
| /* Create the trigonometric matrix corresponding to Y Rotation */ |
| mOut.f[ 0]=fCosine; mOut.f[ 4]=0.0f; mOut.f[ 8]=-fSine; mOut.f[12]=0.0f; |
| mOut.f[ 1]=0.0f; mOut.f[ 5]=1.0f; mOut.f[ 9]=0.0f; mOut.f[13]=0.0f; |
| mOut.f[ 2]=fSine; mOut.f[ 6]=0.0f; mOut.f[10]=fCosine; mOut.f[14]=0.0f; |
| mOut.f[ 3]=0.0f; mOut.f[ 7]=0.0f; mOut.f[11]=0.0f; mOut.f[15]=1.0f; |
| } |
| |
| /*!*************************************************************************** |
| @Function Name PVRTMatrixRotationZF |
| @Output mOut Rotation matrix |
| @Input fAngle Angle of the rotation |
| @Description Create an Z rotation matrix mOut. |
| *****************************************************************************/ |
| void PVRTMatrixRotationZF( |
| PVRTMATRIXf &mOut, |
| const float fAngle) |
| { |
| float fCosine, fSine; |
| |
| /* Precompute cos and sin */ |
| #if defined(BUILD_DX11) |
| fCosine = (float)PVRTFCOS(-fAngle); |
| fSine = (float)PVRTFSIN(-fAngle); |
| #else |
| fCosine = (float)PVRTFCOS(fAngle); |
| fSine = (float)PVRTFSIN(fAngle); |
| #endif |
| |
| /* Create the trigonometric matrix corresponding to Z Rotation */ |
| mOut.f[ 0]=fCosine; mOut.f[ 4]=fSine; mOut.f[ 8]=0.0f; mOut.f[12]=0.0f; |
| mOut.f[ 1]=-fSine; mOut.f[ 5]=fCosine; mOut.f[ 9]=0.0f; mOut.f[13]=0.0f; |
| mOut.f[ 2]=0.0f; mOut.f[ 6]=0.0f; mOut.f[10]=1.0f; mOut.f[14]=0.0f; |
| mOut.f[ 3]=0.0f; mOut.f[ 7]=0.0f; mOut.f[11]=0.0f; mOut.f[15]=1.0f; |
| } |
| |
| /*!*************************************************************************** |
| @Function Name PVRTMatrixTransposeF |
| @Output mOut Transposed matrix |
| @Input mIn Original matrix |
| @Description Compute the transpose matrix of mIn. |
| *****************************************************************************/ |
| void PVRTMatrixTransposeF( |
| PVRTMATRIXf &mOut, |
| const PVRTMATRIXf &mIn) |
| { |
| PVRTMATRIXf mTmp; |
| |
| mTmp.f[ 0]=mIn.f[ 0]; mTmp.f[ 4]=mIn.f[ 1]; mTmp.f[ 8]=mIn.f[ 2]; mTmp.f[12]=mIn.f[ 3]; |
| mTmp.f[ 1]=mIn.f[ 4]; mTmp.f[ 5]=mIn.f[ 5]; mTmp.f[ 9]=mIn.f[ 6]; mTmp.f[13]=mIn.f[ 7]; |
| mTmp.f[ 2]=mIn.f[ 8]; mTmp.f[ 6]=mIn.f[ 9]; mTmp.f[10]=mIn.f[10]; mTmp.f[14]=mIn.f[11]; |
| mTmp.f[ 3]=mIn.f[12]; mTmp.f[ 7]=mIn.f[13]; mTmp.f[11]=mIn.f[14]; mTmp.f[15]=mIn.f[15]; |
| |
| mOut = mTmp; |
| } |
| |
| /*!*************************************************************************** |
| @Function PVRTMatrixInverseF |
| @Output mOut Inversed matrix |
| @Input mIn Original matrix |
| @Description Compute the inverse matrix of mIn. |
| The matrix must be of the form : |
| A 0 |
| C 1 |
| Where A is a 3x3 matrix and C is a 1x3 matrix. |
| *****************************************************************************/ |
| void PVRTMatrixInverseF( |
| PVRTMATRIXf &mOut, |
| const PVRTMATRIXf &mIn) |
| { |
| PVRTMATRIXf mDummyMatrix; |
| double det_1; |
| double pos, neg, temp; |
| |
| /* Calculate the determinant of submatrix A and determine if the |
| the matrix is singular as limited by the double precision |
| floating-point data representation. */ |
| pos = neg = 0.0; |
| temp = mIn.f[ 0] * mIn.f[ 5] * mIn.f[10]; |
| if (temp >= 0.0) pos += temp; else neg += temp; |
| temp = mIn.f[ 4] * mIn.f[ 9] * mIn.f[ 2]; |
| if (temp >= 0.0) pos += temp; else neg += temp; |
| temp = mIn.f[ 8] * mIn.f[ 1] * mIn.f[ 6]; |
| if (temp >= 0.0) pos += temp; else neg += temp; |
| temp = -mIn.f[ 8] * mIn.f[ 5] * mIn.f[ 2]; |
| if (temp >= 0.0) pos += temp; else neg += temp; |
| temp = -mIn.f[ 4] * mIn.f[ 1] * mIn.f[10]; |
| if (temp >= 0.0) pos += temp; else neg += temp; |
| temp = -mIn.f[ 0] * mIn.f[ 9] * mIn.f[ 6]; |
| if (temp >= 0.0) pos += temp; else neg += temp; |
| det_1 = pos + neg; |
| |
| /* Is the submatrix A singular? */ |
| if ((det_1 == 0.0) || (PVRTABS(det_1 / (pos - neg)) < 1.0e-15)) |
| { |
| /* Matrix M has no inverse */ |
| _RPT0(_CRT_WARN, "Matrix has no inverse : singular matrix\n"); |
| return; |
| } |
| else |
| { |
| /* Calculate inverse(A) = adj(A) / det(A) */ |
| det_1 = 1.0 / det_1; |
| mDummyMatrix.f[ 0] = ( mIn.f[ 5] * mIn.f[10] - mIn.f[ 9] * mIn.f[ 6] ) * (float)det_1; |
| mDummyMatrix.f[ 1] = - ( mIn.f[ 1] * mIn.f[10] - mIn.f[ 9] * mIn.f[ 2] ) * (float)det_1; |
| mDummyMatrix.f[ 2] = ( mIn.f[ 1] * mIn.f[ 6] - mIn.f[ 5] * mIn.f[ 2] ) * (float)det_1; |
| mDummyMatrix.f[ 4] = - ( mIn.f[ 4] * mIn.f[10] - mIn.f[ 8] * mIn.f[ 6] ) * (float)det_1; |
| mDummyMatrix.f[ 5] = ( mIn.f[ 0] * mIn.f[10] - mIn.f[ 8] * mIn.f[ 2] ) * (float)det_1; |
| mDummyMatrix.f[ 6] = - ( mIn.f[ 0] * mIn.f[ 6] - mIn.f[ 4] * mIn.f[ 2] ) * (float)det_1; |
| mDummyMatrix.f[ 8] = ( mIn.f[ 4] * mIn.f[ 9] - mIn.f[ 8] * mIn.f[ 5] ) * (float)det_1; |
| mDummyMatrix.f[ 9] = - ( mIn.f[ 0] * mIn.f[ 9] - mIn.f[ 8] * mIn.f[ 1] ) * (float)det_1; |
| mDummyMatrix.f[10] = ( mIn.f[ 0] * mIn.f[ 5] - mIn.f[ 4] * mIn.f[ 1] ) * (float)det_1; |
| |
| /* Calculate -C * inverse(A) */ |
| mDummyMatrix.f[12] = - ( mIn.f[12] * mDummyMatrix.f[ 0] + mIn.f[13] * mDummyMatrix.f[ 4] + mIn.f[14] * mDummyMatrix.f[ 8] ); |
| mDummyMatrix.f[13] = - ( mIn.f[12] * mDummyMatrix.f[ 1] + mIn.f[13] * mDummyMatrix.f[ 5] + mIn.f[14] * mDummyMatrix.f[ 9] ); |
| mDummyMatrix.f[14] = - ( mIn.f[12] * mDummyMatrix.f[ 2] + mIn.f[13] * mDummyMatrix.f[ 6] + mIn.f[14] * mDummyMatrix.f[10] ); |
| |
| /* Fill in last row */ |
| mDummyMatrix.f[ 3] = 0.0f; |
| mDummyMatrix.f[ 7] = 0.0f; |
| mDummyMatrix.f[11] = 0.0f; |
| mDummyMatrix.f[15] = 1.0f; |
| } |
| |
| /* Copy contents of dummy matrix in pfMatrix */ |
| mOut = mDummyMatrix; |
| } |
| |
| /*!*************************************************************************** |
| @Function PVRTMatrixInverseExF |
| @Output mOut Inversed matrix |
| @Input mIn Original matrix |
| @Description Compute the inverse matrix of mIn. |
| Uses a linear equation solver and the knowledge that M.M^-1=I. |
| Use this fn to calculate the inverse of matrices that |
| PVRTMatrixInverse() cannot. |
| *****************************************************************************/ |
| void PVRTMatrixInverseExF( |
| PVRTMATRIXf &mOut, |
| const PVRTMATRIXf &mIn) |
| { |
| PVRTMATRIXf mTmp = {0}; |
| float *ppfRows[4]; |
| float pfRes[4]; |
| float pfIn[20]; |
| int i, j; |
| |
| for(i = 0; i < 4; ++i) |
| ppfRows[i] = &pfIn[i * 5]; |
| |
| /* Solve 4 sets of 4 linear equations */ |
| for(i = 0; i < 4; ++i) |
| { |
| for(j = 0; j < 4; ++j) |
| { |
| ppfRows[j][0] = c_mIdentity.f[i + 4 * j]; |
| memcpy(&ppfRows[j][1], &mIn.f[j * 4], 4 * sizeof(float)); |
| } |
| |
| PVRTMatrixLinearEqSolveF(pfRes, (float**)ppfRows, 4); |
| |
| for(j = 0; j < 4; ++j) |
| { |
| mTmp.f[i + 4 * j] = pfRes[j]; |
| } |
| } |
| |
| mOut = mTmp; |
| } |
| |
| /*!*************************************************************************** |
| @Function PVRTMatrixLookAtLHF |
| @Output mOut Look-at view matrix |
| @Input vEye Position of the camera |
| @Input vAt Point the camera is looking at |
| @Input vUp Up direction for the camera |
| @Description Create a look-at view matrix. |
| *****************************************************************************/ |
| void PVRTMatrixLookAtLHF( |
| PVRTMATRIXf &mOut, |
| const PVRTVECTOR3f &vEye, |
| const PVRTVECTOR3f &vAt, |
| const PVRTVECTOR3f &vUp) |
| { |
| PVRTVECTOR3f f, s, u; |
| PVRTMATRIXf t; |
| |
| f.x = vEye.x - vAt.x; |
| f.y = vEye.y - vAt.y; |
| f.z = vEye.z - vAt.z; |
| |
| PVRTMatrixVec3NormalizeF(f, f); |
| PVRTMatrixVec3CrossProductF(s, f, vUp); |
| PVRTMatrixVec3NormalizeF(s, s); |
| PVRTMatrixVec3CrossProductF(u, s, f); |
| PVRTMatrixVec3NormalizeF(u, u); |
| |
| mOut.f[ 0] = s.x; |
| mOut.f[ 1] = u.x; |
| mOut.f[ 2] = -f.x; |
| mOut.f[ 3] = 0; |
| |
| mOut.f[ 4] = s.y; |
| mOut.f[ 5] = u.y; |
| mOut.f[ 6] = -f.y; |
| mOut.f[ 7] = 0; |
| |
| mOut.f[ 8] = s.z; |
| mOut.f[ 9] = u.z; |
| mOut.f[10] = -f.z; |
| mOut.f[11] = 0; |
| |
| mOut.f[12] = 0; |
| mOut.f[13] = 0; |
| mOut.f[14] = 0; |
| mOut.f[15] = 1; |
| |
| PVRTMatrixTranslationF(t, -vEye.x, -vEye.y, -vEye.z); |
| PVRTMatrixMultiplyF(mOut, t, mOut); |
| } |
| |
| /*!*************************************************************************** |
| @Function PVRTMatrixLookAtRHF |
| @Output mOut Look-at view matrix |
| @Input vEye Position of the camera |
| @Input vAt Point the camera is looking at |
| @Input vUp Up direction for the camera |
| @Description Create a look-at view matrix. |
| *****************************************************************************/ |
| void PVRTMatrixLookAtRHF( |
| PVRTMATRIXf &mOut, |
| const PVRTVECTOR3f &vEye, |
| const PVRTVECTOR3f &vAt, |
| const PVRTVECTOR3f &vUp) |
| { |
| PVRTVECTOR3f f, s, u; |
| PVRTMATRIXf t; |
| |
| f.x = vAt.x - vEye.x; |
| f.y = vAt.y - vEye.y; |
| f.z = vAt.z - vEye.z; |
| |
| PVRTMatrixVec3NormalizeF(f, f); |
| PVRTMatrixVec3CrossProductF(s, f, vUp); |
| PVRTMatrixVec3NormalizeF(s, s); |
| PVRTMatrixVec3CrossProductF(u, s, f); |
| PVRTMatrixVec3NormalizeF(u, u); |
| |
| mOut.f[ 0] = s.x; |
| mOut.f[ 1] = u.x; |
| mOut.f[ 2] = -f.x; |
| mOut.f[ 3] = 0; |
| |
| mOut.f[ 4] = s.y; |
| mOut.f[ 5] = u.y; |
| mOut.f[ 6] = -f.y; |
| mOut.f[ 7] = 0; |
| |
| mOut.f[ 8] = s.z; |
| mOut.f[ 9] = u.z; |
| mOut.f[10] = -f.z; |
| mOut.f[11] = 0; |
| |
| mOut.f[12] = 0; |
| mOut.f[13] = 0; |
| mOut.f[14] = 0; |
| mOut.f[15] = 1; |
| |
| PVRTMatrixTranslationF(t, -vEye.x, -vEye.y, -vEye.z); |
| PVRTMatrixMultiplyF(mOut, t, mOut); |
| } |
| |
| /*!*************************************************************************** |
| @Function PVRTMatrixPerspectiveFovLHF |
| @Output mOut Perspective matrix |
| @Input fFOVy Field of view |
| @Input fAspect Aspect ratio |
| @Input fNear Near clipping distance |
| @Input fFar Far clipping distance |
| @Input bRotate Should we rotate it ? (for upright screens) |
| @Description Create a perspective matrix. |
| *****************************************************************************/ |
| void PVRTMatrixPerspectiveFovLHF( |
| PVRTMATRIXf &mOut, |
| const float fFOVy, |
| const float fAspect, |
| const float fNear, |
| const float fFar, |
| const bool bRotate) |
| { |
| float f, n, fRealAspect; |
| |
| if (bRotate) |
| fRealAspect = 1.0f / fAspect; |
| else |
| fRealAspect = fAspect; |
| |
| // cotangent(a) == 1.0f / tan(a); |
| f = 1.0f / (float)PVRTFTAN(fFOVy * 0.5f); |
| n = 1.0f / (fFar - fNear); |
| |
| mOut.f[ 0] = f / fRealAspect; |
| mOut.f[ 1] = 0; |
| mOut.f[ 2] = 0; |
| mOut.f[ 3] = 0; |
| |
| mOut.f[ 4] = 0; |
| mOut.f[ 5] = f; |
| mOut.f[ 6] = 0; |
| mOut.f[ 7] = 0; |
| |
| mOut.f[ 8] = 0; |
| mOut.f[ 9] = 0; |
| mOut.f[10] = fFar * n; |
| mOut.f[11] = 1; |
| |
| mOut.f[12] = 0; |
| mOut.f[13] = 0; |
| mOut.f[14] = -fFar * fNear * n; |
| mOut.f[15] = 0; |
| |
| if (bRotate) |
| { |
| PVRTMATRIXf mRotation, mTemp = mOut; |
| PVRTMatrixRotationZF(mRotation, 90.0f*PVRT_PIf/180.0f); |
| PVRTMatrixMultiplyF(mOut, mTemp, mRotation); |
| } |
| } |
| |
| /*!*************************************************************************** |
| @Function PVRTMatrixPerspectiveFovRHF |
| @Output mOut Perspective matrix |
| @Input fFOVy Field of view |
| @Input fAspect Aspect ratio |
| @Input fNear Near clipping distance |
| @Input fFar Far clipping distance |
| @Input bRotate Should we rotate it ? (for upright screens) |
| @Description Create a perspective matrix. |
| *****************************************************************************/ |
| void PVRTMatrixPerspectiveFovRHF( |
| PVRTMATRIXf &mOut, |
| const float fFOVy, |
| const float fAspect, |
| const float fNear, |
| const float fFar, |
| const bool bRotate) |
| { |
| float f, n, fRealAspect; |
| |
| if (bRotate) |
| fRealAspect = 1.0f / fAspect; |
| else |
| fRealAspect = fAspect; |
| |
| // cotangent(a) == 1.0f / tan(a); |
| f = 1.0f / (float)PVRTFTAN(fFOVy * 0.5f); |
| n = 1.0f / (fNear - fFar); |
| |
| mOut.f[ 0] = f / fRealAspect; |
| mOut.f[ 1] = 0; |
| mOut.f[ 2] = 0; |
| mOut.f[ 3] = 0; |
| |
| mOut.f[ 4] = 0; |
| mOut.f[ 5] = f; |
| mOut.f[ 6] = 0; |
| mOut.f[ 7] = 0; |
| |
| mOut.f[ 8] = 0; |
| mOut.f[ 9] = 0; |
| mOut.f[10] = (fFar + fNear) * n; |
| mOut.f[11] = -1; |
| |
| mOut.f[12] = 0; |
| mOut.f[13] = 0; |
| mOut.f[14] = (2 * fFar * fNear) * n; |
| mOut.f[15] = 0; |
| |
| if (bRotate) |
| { |
| PVRTMATRIXf mRotation, mTemp = mOut; |
| PVRTMatrixRotationZF(mRotation, -90.0f*PVRT_PIf/180.0f); |
| PVRTMatrixMultiplyF(mOut, mTemp, mRotation); |
| } |
| } |
| |
| /*!*************************************************************************** |
| @Function PVRTMatrixOrthoLHF |
| @Output mOut Orthographic matrix |
| @Input w Width of the screen |
| @Input h Height of the screen |
| @Input zn Near clipping distance |
| @Input zf Far clipping distance |
| @Input bRotate Should we rotate it ? (for upright screens) |
| @Description Create an orthographic matrix. |
| *****************************************************************************/ |
| void PVRTMatrixOrthoLHF( |
| PVRTMATRIXf &mOut, |
| const float w, |
| const float h, |
| const float zn, |
| const float zf, |
| const bool bRotate) |
| { |
| mOut.f[ 0] = 2 / w; |
| mOut.f[ 1] = 0; |
| mOut.f[ 2] = 0; |
| mOut.f[ 3] = 0; |
| |
| mOut.f[ 4] = 0; |
| mOut.f[ 5] = 2 / h; |
| mOut.f[ 6] = 0; |
| mOut.f[ 7] = 0; |
| |
| mOut.f[ 8] = 0; |
| mOut.f[ 9] = 0; |
| mOut.f[10] = 1 / (zf - zn); |
| mOut.f[11] = zn / (zn - zf); |
| |
| mOut.f[12] = 0; |
| mOut.f[13] = 0; |
| mOut.f[14] = 0; |
| mOut.f[15] = 1; |
| |
| if (bRotate) |
| { |
| PVRTMATRIXf mRotation, mTemp = mOut; |
| PVRTMatrixRotationZF(mRotation, -90.0f*PVRT_PIf/180.0f); |
| PVRTMatrixMultiplyF(mOut, mRotation, mTemp); |
| } |
| } |
| |
| /*!*************************************************************************** |
| @Function PVRTMatrixOrthoRHF |
| @Output mOut Orthographic matrix |
| @Input w Width of the screen |
| @Input h Height of the screen |
| @Input zn Near clipping distance |
| @Input zf Far clipping distance |
| @Input bRotate Should we rotate it ? (for upright screens) |
| @Description Create an orthographic matrix. |
| *****************************************************************************/ |
| void PVRTMatrixOrthoRHF( |
| PVRTMATRIXf &mOut, |
| const float w, |
| const float h, |
| const float zn, |
| const float zf, |
| const bool bRotate) |
| { |
| mOut.f[ 0] = 2 / w; |
| mOut.f[ 1] = 0; |
| mOut.f[ 2] = 0; |
| mOut.f[ 3] = 0; |
| |
| mOut.f[ 4] = 0; |
| mOut.f[ 5] = 2 / h; |
| mOut.f[ 6] = 0; |
| mOut.f[ 7] = 0; |
| |
| mOut.f[ 8] = 0; |
| mOut.f[ 9] = 0; |
| mOut.f[10] = 1 / (zn - zf); |
| mOut.f[11] = zn / (zn - zf); |
| |
| mOut.f[12] = 0; |
| mOut.f[13] = 0; |
| mOut.f[14] = 0; |
| mOut.f[15] = 1; |
| |
| if (bRotate) |
| { |
| PVRTMATRIXf mRotation, mTemp = mOut; |
| PVRTMatrixRotationZF(mRotation, -90.0f*PVRT_PIf/180.0f); |
| PVRTMatrixMultiplyF(mOut, mRotation, mTemp); |
| } |
| } |
| |
| /*!*************************************************************************** |
| @Function PVRTMatrixVec3LerpF |
| @Output vOut Result of the interpolation |
| @Input v1 First vector to interpolate from |
| @Input v2 Second vector to interpolate form |
| @Input s Coefficient of interpolation |
| @Description This function performs the linear interpolation based on |
| the following formula: V1 + s(V2-V1). |
| *****************************************************************************/ |
| void PVRTMatrixVec3LerpF( |
| PVRTVECTOR3f &vOut, |
| const PVRTVECTOR3f &v1, |
| const PVRTVECTOR3f &v2, |
| const float s) |
| { |
| vOut.x = v1.x + s * (v2.x - v1.x); |
| vOut.y = v1.y + s * (v2.y - v1.y); |
| vOut.z = v1.z + s * (v2.z - v1.z); |
| } |
| |
| /*!*************************************************************************** |
| @Function PVRTMatrixVec3DotProductF |
| @Input v1 First vector |
| @Input v2 Second vector |
| @Return Dot product of the two vectors. |
| @Description This function performs the dot product of the two |
| supplied vectors. |
| *****************************************************************************/ |
| float PVRTMatrixVec3DotProductF( |
| const PVRTVECTOR3f &v1, |
| const PVRTVECTOR3f &v2) |
| { |
| return (v1.x*v2.x + v1.y*v2.y + v1.z*v2.z); |
| } |
| |
| /*!*************************************************************************** |
| @Function PVRTMatrixVec3CrossProductF |
| @Output vOut Cross product of the two vectors |
| @Input v1 First vector |
| @Input v2 Second vector |
| @Description This function performs the cross product of the two |
| supplied vectors. |
| *****************************************************************************/ |
| void PVRTMatrixVec3CrossProductF( |
| PVRTVECTOR3f &vOut, |
| const PVRTVECTOR3f &v1, |
| const PVRTVECTOR3f &v2) |
| { |
| PVRTVECTOR3f result; |
| |
| /* Perform calculation on a dummy VECTOR (result) */ |
| result.x = v1.y * v2.z - v1.z * v2.y; |
| result.y = v1.z * v2.x - v1.x * v2.z; |
| result.z = v1.x * v2.y - v1.y * v2.x; |
| |
| /* Copy result in pOut */ |
| vOut = result; |
| } |
| |
| /*!*************************************************************************** |
| @Function PVRTMatrixVec3NormalizeF |
| @Output vOut Normalized vector |
| @Input vIn Vector to normalize |
| @Description Normalizes the supplied vector. |
| *****************************************************************************/ |
| void PVRTMatrixVec3NormalizeF( |
| PVRTVECTOR3f &vOut, |
| const PVRTVECTOR3f &vIn) |
| { |
| float f; |
| double temp; |
| |
| temp = (double)(vIn.x * vIn.x + vIn.y * vIn.y + vIn.z * vIn.z); |
| temp = 1.0 / sqrt(temp); |
| f = (float)temp; |
| |
| vOut.x = vIn.x * f; |
| vOut.y = vIn.y * f; |
| vOut.z = vIn.z * f; |
| } |
| |
| /*!*************************************************************************** |
| @Function PVRTMatrixVec3LengthF |
| @Input vIn Vector to get the length of |
| @Return The length of the vector |
| @Description Gets the length of the supplied vector. |
| *****************************************************************************/ |
| float PVRTMatrixVec3LengthF( |
| const PVRTVECTOR3f &vIn) |
| { |
| double temp; |
| |
| temp = (double)(vIn.x * vIn.x + vIn.y * vIn.y + vIn.z * vIn.z); |
| return (float) sqrt(temp); |
| } |
| |
| /*!*************************************************************************** |
| @Function PVRTMatrixLinearEqSolveF |
| @Input pSrc 2D array of floats. 4 Eq linear problem is 5x4 |
| matrix, constants in first column |
| @Input nCnt Number of equations to solve |
| @Output pRes Result |
| @Description Solves 'nCnt' simultaneous equations of 'nCnt' variables. |
| pRes should be an array large enough to contain the |
| results: the values of the 'nCnt' variables. |
| This fn recursively uses Gaussian Elimination. |
| *****************************************************************************/ |
| void PVRTMatrixLinearEqSolveF( |
| float * const pRes, |
| float ** const pSrc, // 2D array of floats. 4 Eq linear problem is 5x4 matrix, constants in first column. |
| const int nCnt) |
| { |
| int i, j, k; |
| float f; |
| |
| #if 0 |
| /* |
| Show the matrix in debug output |
| */ |
| _RPT1(_CRT_WARN, "LinearEqSolve(%d)\n", nCnt); |
| for(i = 0; i < nCnt; ++i) |
| { |
| _RPT1(_CRT_WARN, "%.8f |", pSrc[i][0]); |
| for(j = 1; j <= nCnt; ++j) |
| _RPT1(_CRT_WARN, " %.8f", pSrc[i][j]); |
| _RPT0(_CRT_WARN, "\n"); |
| } |
| #endif |
| |
| if(nCnt == 1) |
| { |
| _ASSERT(pSrc[0][1] != 0); |
| pRes[0] = pSrc[0][0] / pSrc[0][1]; |
| return; |
| } |
| |
| // Loop backwards in an attempt avoid the need to swap rows |
| i = nCnt; |
| while(i) |
| { |
| --i; |
| |
| if(pSrc[i][nCnt] != 0) |
| { |
| // Row i can be used to zero the other rows; let's move it to the bottom |
| if(i != (nCnt-1)) |
| { |
| for(j = 0; j <= nCnt; ++j) |
| { |
| // Swap the two values |
| f = pSrc[nCnt-1][j]; |
| pSrc[nCnt-1][j] = pSrc[i][j]; |
| pSrc[i][j] = f; |
| } |
| } |
| |
| // Now zero the last columns of the top rows |
| for(j = 0; j < (nCnt-1); ++j) |
| { |
| _ASSERT(pSrc[nCnt-1][nCnt] != 0); |
| f = pSrc[j][nCnt] / pSrc[nCnt-1][nCnt]; |
| |
| // No need to actually calculate a zero for the final column |
| for(k = 0; k < nCnt; ++k) |
| { |
| pSrc[j][k] -= f * pSrc[nCnt-1][k]; |
| } |
| } |
| |
| break; |
| } |
| } |
| |
| // Solve the top-left sub matrix |
| PVRTMatrixLinearEqSolveF(pRes, pSrc, nCnt - 1); |
| |
| // Now calc the solution for the bottom row |
| f = pSrc[nCnt-1][0]; |
| for(k = 1; k < nCnt; ++k) |
| { |
| f -= pSrc[nCnt-1][k] * pRes[k-1]; |
| } |
| _ASSERT(pSrc[nCnt-1][nCnt] != 0); |
| f /= pSrc[nCnt-1][nCnt]; |
| pRes[nCnt-1] = f; |
| |
| #if 0 |
| { |
| float fCnt; |
| |
| /* |
| Verify that the result is correct |
| */ |
| fCnt = 0; |
| for(i = 1; i <= nCnt; ++i) |
| fCnt += pSrc[nCnt-1][i] * pRes[i-1]; |
| |
| _ASSERT(abs(fCnt - pSrc[nCnt-1][0]) < 1e-3); |
| } |
| #endif |
| } |
| |
| /***************************************************************************** |
| End of file (PVRTMatrixF.cpp) |
| *****************************************************************************/ |
| |