/****************************************************************************** @File PVRTMatrixX.cpp @Title PVRTMatrixX @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 "PVRTContext.h" #include <math.h> #include <string.h> #include "PVRTFixedPoint.h" #include "PVRTMatrix.h" /**************************************************************************** ** Constants ****************************************************************************/ static const PVRTMATRIXx c_mIdentity = { { PVRTF2X(1.0f), PVRTF2X(0.0f), PVRTF2X(0.0f), PVRTF2X(0.0f), PVRTF2X(0.0f), PVRTF2X(1.0f), PVRTF2X(0.0f), PVRTF2X(0.0f), PVRTF2X(0.0f), PVRTF2X(0.0f), PVRTF2X(1.0f), PVRTF2X(0.0f), PVRTF2X(0.0f), PVRTF2X(0.0f), PVRTF2X(0.0f), PVRTF2X(1.0f) } }; /**************************************************************************** ** Functions ****************************************************************************/ /*!*************************************************************************** @Function PVRTMatrixIdentityX @Output mOut Set to identity @Description Reset matrix to identity matrix. *****************************************************************************/ void PVRTMatrixIdentityX(PVRTMATRIXx &mOut) { mOut.f[ 0]=PVRTF2X(1.0f); mOut.f[ 4]=PVRTF2X(0.0f); mOut.f[ 8]=PVRTF2X(0.0f); mOut.f[12]=PVRTF2X(0.0f); mOut.f[ 1]=PVRTF2X(0.0f); mOut.f[ 5]=PVRTF2X(1.0f); mOut.f[ 9]=PVRTF2X(0.0f); mOut.f[13]=PVRTF2X(0.0f); mOut.f[ 2]=PVRTF2X(0.0f); mOut.f[ 6]=PVRTF2X(0.0f); mOut.f[10]=PVRTF2X(1.0f); mOut.f[14]=PVRTF2X(0.0f); mOut.f[ 3]=PVRTF2X(0.0f); mOut.f[ 7]=PVRTF2X(0.0f); mOut.f[11]=PVRTF2X(0.0f); mOut.f[15]=PVRTF2X(1.0f); } /*!*************************************************************************** @Function PVRTMatrixMultiplyX @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. The fixed-point shift could be performed after adding all four intermediate results together however this might cause some overflow issues. ****************************************************************************/ void PVRTMatrixMultiplyX( PVRTMATRIXx &mOut, const PVRTMATRIXx &mA, const PVRTMATRIXx &mB) { PVRTMATRIXx mRet; /* Perform calculation on a dummy matrix (mRet) */ mRet.f[ 0] = PVRTXMUL(mA.f[ 0], mB.f[ 0]) + PVRTXMUL(mA.f[ 1], mB.f[ 4]) + PVRTXMUL(mA.f[ 2], mB.f[ 8]) + PVRTXMUL(mA.f[ 3], mB.f[12]); mRet.f[ 1] = PVRTXMUL(mA.f[ 0], mB.f[ 1]) + PVRTXMUL(mA.f[ 1], mB.f[ 5]) + PVRTXMUL(mA.f[ 2], mB.f[ 9]) + PVRTXMUL(mA.f[ 3], mB.f[13]); mRet.f[ 2] = PVRTXMUL(mA.f[ 0], mB.f[ 2]) + PVRTXMUL(mA.f[ 1], mB.f[ 6]) + PVRTXMUL(mA.f[ 2], mB.f[10]) + PVRTXMUL(mA.f[ 3], mB.f[14]); mRet.f[ 3] = PVRTXMUL(mA.f[ 0], mB.f[ 3]) + PVRTXMUL(mA.f[ 1], mB.f[ 7]) + PVRTXMUL(mA.f[ 2], mB.f[11]) + PVRTXMUL(mA.f[ 3], mB.f[15]); mRet.f[ 4] = PVRTXMUL(mA.f[ 4], mB.f[ 0]) + PVRTXMUL(mA.f[ 5], mB.f[ 4]) + PVRTXMUL(mA.f[ 6], mB.f[ 8]) + PVRTXMUL(mA.f[ 7], mB.f[12]); mRet.f[ 5] = PVRTXMUL(mA.f[ 4], mB.f[ 1]) + PVRTXMUL(mA.f[ 5], mB.f[ 5]) + PVRTXMUL(mA.f[ 6], mB.f[ 9]) + PVRTXMUL(mA.f[ 7], mB.f[13]); mRet.f[ 6] = PVRTXMUL(mA.f[ 4], mB.f[ 2]) + PVRTXMUL(mA.f[ 5], mB.f[ 6]) + PVRTXMUL(mA.f[ 6], mB.f[10]) + PVRTXMUL(mA.f[ 7], mB.f[14]); mRet.f[ 7] = PVRTXMUL(mA.f[ 4], mB.f[ 3]) + PVRTXMUL(mA.f[ 5], mB.f[ 7]) + PVRTXMUL(mA.f[ 6], mB.f[11]) + PVRTXMUL(mA.f[ 7], mB.f[15]); mRet.f[ 8] = PVRTXMUL(mA.f[ 8], mB.f[ 0]) + PVRTXMUL(mA.f[ 9], mB.f[ 4]) + PVRTXMUL(mA.f[10], mB.f[ 8]) + PVRTXMUL(mA.f[11], mB.f[12]); mRet.f[ 9] = PVRTXMUL(mA.f[ 8], mB.f[ 1]) + PVRTXMUL(mA.f[ 9], mB.f[ 5]) + PVRTXMUL(mA.f[10], mB.f[ 9]) + PVRTXMUL(mA.f[11], mB.f[13]); mRet.f[10] = PVRTXMUL(mA.f[ 8], mB.f[ 2]) + PVRTXMUL(mA.f[ 9], mB.f[ 6]) + PVRTXMUL(mA.f[10], mB.f[10]) + PVRTXMUL(mA.f[11], mB.f[14]); mRet.f[11] = PVRTXMUL(mA.f[ 8], mB.f[ 3]) + PVRTXMUL(mA.f[ 9], mB.f[ 7]) + PVRTXMUL(mA.f[10], mB.f[11]) + PVRTXMUL(mA.f[11], mB.f[15]); mRet.f[12] = PVRTXMUL(mA.f[12], mB.f[ 0]) + PVRTXMUL(mA.f[13], mB.f[ 4]) + PVRTXMUL(mA.f[14], mB.f[ 8]) + PVRTXMUL(mA.f[15], mB.f[12]); mRet.f[13] = PVRTXMUL(mA.f[12], mB.f[ 1]) + PVRTXMUL(mA.f[13], mB.f[ 5]) + PVRTXMUL(mA.f[14], mB.f[ 9]) + PVRTXMUL(mA.f[15], mB.f[13]); mRet.f[14] = PVRTXMUL(mA.f[12], mB.f[ 2]) + PVRTXMUL(mA.f[13], mB.f[ 6]) + PVRTXMUL(mA.f[14], mB.f[10]) + PVRTXMUL(mA.f[15], mB.f[14]); mRet.f[15] = PVRTXMUL(mA.f[12], mB.f[ 3]) + PVRTXMUL(mA.f[13], mB.f[ 7]) + PVRTXMUL(mA.f[14], mB.f[11]) + PVRTXMUL(mA.f[15], mB.f[15]); /* Copy result in pResultMatrix */ mOut = mRet; } /*!*************************************************************************** @Function Name PVRTMatrixTranslationX @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 PVRTMatrixTranslationX( PVRTMATRIXx &mOut, const int fX, const int fY, const int fZ) { mOut.f[ 0]=PVRTF2X(1.0f); mOut.f[ 4]=PVRTF2X(0.0f); mOut.f[ 8]=PVRTF2X(0.0f); mOut.f[12]=fX; mOut.f[ 1]=PVRTF2X(0.0f); mOut.f[ 5]=PVRTF2X(1.0f); mOut.f[ 9]=PVRTF2X(0.0f); mOut.f[13]=fY; mOut.f[ 2]=PVRTF2X(0.0f); mOut.f[ 6]=PVRTF2X(0.0f); mOut.f[10]=PVRTF2X(1.0f); mOut.f[14]=fZ; mOut.f[ 3]=PVRTF2X(0.0f); mOut.f[ 7]=PVRTF2X(0.0f); mOut.f[11]=PVRTF2X(0.0f); mOut.f[15]=PVRTF2X(1.0f); } /*!*************************************************************************** @Function Name PVRTMatrixScalingX @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 PVRTMatrixScalingX( PVRTMATRIXx &mOut, const int fX, const int fY, const int fZ) { mOut.f[ 0]=fX; mOut.f[ 4]=PVRTF2X(0.0f); mOut.f[ 8]=PVRTF2X(0.0f); mOut.f[12]=PVRTF2X(0.0f); mOut.f[ 1]=PVRTF2X(0.0f); mOut.f[ 5]=fY; mOut.f[ 9]=PVRTF2X(0.0f); mOut.f[13]=PVRTF2X(0.0f); mOut.f[ 2]=PVRTF2X(0.0f); mOut.f[ 6]=PVRTF2X(0.0f); mOut.f[10]=fZ; mOut.f[14]=PVRTF2X(0.0f); mOut.f[ 3]=PVRTF2X(0.0f); mOut.f[ 7]=PVRTF2X(0.0f); mOut.f[11]=PVRTF2X(0.0f); mOut.f[15]=PVRTF2X(1.0f); } /*!*************************************************************************** @Function Name PVRTMatrixRotationXX @Output mOut Rotation matrix @Input fAngle Angle of the rotation @Description Create an X rotation matrix mOut. *****************************************************************************/ void PVRTMatrixRotationXX( PVRTMATRIXx &mOut, const int fAngle) { int fCosine, fSine; /* Precompute cos and sin */ #if defined(BUILD_DX11) fCosine = PVRTXCOS(-fAngle); fSine = PVRTXSIN(-fAngle); #else fCosine = PVRTXCOS(fAngle); fSine = PVRTXSIN(fAngle); #endif /* Create the trigonometric matrix corresponding to X Rotation */ mOut.f[ 0]=PVRTF2X(1.0f); mOut.f[ 4]=PVRTF2X(0.0f); mOut.f[ 8]=PVRTF2X(0.0f); mOut.f[12]=PVRTF2X(0.0f); mOut.f[ 1]=PVRTF2X(0.0f); mOut.f[ 5]=fCosine; mOut.f[ 9]=fSine; mOut.f[13]=PVRTF2X(0.0f); mOut.f[ 2]=PVRTF2X(0.0f); mOut.f[ 6]=-fSine; mOut.f[10]=fCosine; mOut.f[14]=PVRTF2X(0.0f); mOut.f[ 3]=PVRTF2X(0.0f); mOut.f[ 7]=PVRTF2X(0.0f); mOut.f[11]=PVRTF2X(0.0f); mOut.f[15]=PVRTF2X(1.0f); } /*!*************************************************************************** @Function Name PVRTMatrixRotationYX @Output mOut Rotation matrix @Input fAngle Angle of the rotation @Description Create an Y rotation matrix mOut. *****************************************************************************/ void PVRTMatrixRotationYX( PVRTMATRIXx &mOut, const int fAngle) { int fCosine, fSine; /* Precompute cos and sin */ #if defined(BUILD_DX11) fCosine = PVRTXCOS(-fAngle); fSine = PVRTXSIN(-fAngle); #else fCosine = PVRTXCOS(fAngle); fSine = PVRTXSIN(fAngle); #endif /* Create the trigonometric matrix corresponding to Y Rotation */ mOut.f[ 0]=fCosine; mOut.f[ 4]=PVRTF2X(0.0f); mOut.f[ 8]=-fSine; mOut.f[12]=PVRTF2X(0.0f); mOut.f[ 1]=PVRTF2X(0.0f); mOut.f[ 5]=PVRTF2X(1.0f); mOut.f[ 9]=PVRTF2X(0.0f); mOut.f[13]=PVRTF2X(0.0f); mOut.f[ 2]=fSine; mOut.f[ 6]=PVRTF2X(0.0f); mOut.f[10]=fCosine; mOut.f[14]=PVRTF2X(0.0f); mOut.f[ 3]=PVRTF2X(0.0f); mOut.f[ 7]=PVRTF2X(0.0f); mOut.f[11]=PVRTF2X(0.0f); mOut.f[15]=PVRTF2X(1.0f); } /*!*************************************************************************** @Function Name PVRTMatrixRotationZX @Output mOut Rotation matrix @Input fAngle Angle of the rotation @Description Create an Z rotation matrix mOut. *****************************************************************************/ void PVRTMatrixRotationZX( PVRTMATRIXx &mOut, const int fAngle) { int fCosine, fSine; /* Precompute cos and sin */ #if defined(BUILD_DX11) fCosine = PVRTXCOS(-fAngle); fSine = PVRTXSIN(-fAngle); #else fCosine = PVRTXCOS(fAngle); fSine = PVRTXSIN(fAngle); #endif /* Create the trigonometric matrix corresponding to Z Rotation */ mOut.f[ 0]=fCosine; mOut.f[ 4]=fSine; mOut.f[ 8]=PVRTF2X(0.0f); mOut.f[12]=PVRTF2X(0.0f); mOut.f[ 1]=-fSine; mOut.f[ 5]=fCosine; mOut.f[ 9]=PVRTF2X(0.0f); mOut.f[13]=PVRTF2X(0.0f); mOut.f[ 2]=PVRTF2X(0.0f); mOut.f[ 6]=PVRTF2X(0.0f); mOut.f[10]=PVRTF2X(1.0f); mOut.f[14]=PVRTF2X(0.0f); mOut.f[ 3]=PVRTF2X(0.0f); mOut.f[ 7]=PVRTF2X(0.0f); mOut.f[11]=PVRTF2X(0.0f); mOut.f[15]=PVRTF2X(1.0f); } /*!*************************************************************************** @Function Name PVRTMatrixTransposeX @Output mOut Transposed matrix @Input mIn Original matrix @Description Compute the transpose matrix of mIn. *****************************************************************************/ void PVRTMatrixTransposeX( PVRTMATRIXx &mOut, const PVRTMATRIXx &mIn) { PVRTMATRIXx 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 PVRTMatrixInverseX @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 PVRTMatrixInverseX( PVRTMATRIXx &mOut, const PVRTMATRIXx &mIn) { PVRTMATRIXx mDummyMatrix; int det_1; int 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; temp = PVRTXMUL(PVRTXMUL(mIn.f[ 0], mIn.f[ 5]), mIn.f[10]); if (temp >= 0) pos += temp; else neg += temp; temp = PVRTXMUL(PVRTXMUL(mIn.f[ 4], mIn.f[ 9]), mIn.f[ 2]); if (temp >= 0) pos += temp; else neg += temp; temp = PVRTXMUL(PVRTXMUL(mIn.f[ 8], mIn.f[ 1]), mIn.f[ 6]); if (temp >= 0) pos += temp; else neg += temp; temp = PVRTXMUL(PVRTXMUL(-mIn.f[ 8], mIn.f[ 5]), mIn.f[ 2]); if (temp >= 0) pos += temp; else neg += temp; temp = PVRTXMUL(PVRTXMUL(-mIn.f[ 4], mIn.f[ 1]), mIn.f[10]); if (temp >= 0) pos += temp; else neg += temp; temp = PVRTXMUL(PVRTXMUL(-mIn.f[ 0], mIn.f[ 9]), mIn.f[ 6]); if (temp >= 0) pos += temp; else neg += temp; det_1 = pos + neg; /* Is the submatrix A singular? */ if (det_1 == 0) { /* 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; det_1 = PVRTXDIV(PVRTF2X(1.0f), det_1); mDummyMatrix.f[ 0] = PVRTXMUL(( PVRTXMUL(mIn.f[ 5], mIn.f[10]) - PVRTXMUL(mIn.f[ 9], mIn.f[ 6]) ), det_1); mDummyMatrix.f[ 1] = - PVRTXMUL(( PVRTXMUL(mIn.f[ 1], mIn.f[10]) - PVRTXMUL(mIn.f[ 9], mIn.f[ 2]) ), det_1); mDummyMatrix.f[ 2] = PVRTXMUL(( PVRTXMUL(mIn.f[ 1], mIn.f[ 6]) - PVRTXMUL(mIn.f[ 5], mIn.f[ 2]) ), det_1); mDummyMatrix.f[ 4] = - PVRTXMUL(( PVRTXMUL(mIn.f[ 4], mIn.f[10]) - PVRTXMUL(mIn.f[ 8], mIn.f[ 6]) ), det_1); mDummyMatrix.f[ 5] = PVRTXMUL(( PVRTXMUL(mIn.f[ 0], mIn.f[10]) - PVRTXMUL(mIn.f[ 8], mIn.f[ 2]) ), det_1); mDummyMatrix.f[ 6] = - PVRTXMUL(( PVRTXMUL(mIn.f[ 0], mIn.f[ 6]) - PVRTXMUL(mIn.f[ 4], mIn.f[ 2]) ), det_1); mDummyMatrix.f[ 8] = PVRTXMUL(( PVRTXMUL(mIn.f[ 4], mIn.f[ 9]) - PVRTXMUL(mIn.f[ 8], mIn.f[ 5]) ), det_1); mDummyMatrix.f[ 9] = - PVRTXMUL(( PVRTXMUL(mIn.f[ 0], mIn.f[ 9]) - PVRTXMUL(mIn.f[ 8], mIn.f[ 1]) ), det_1); mDummyMatrix.f[10] = PVRTXMUL(( PVRTXMUL(mIn.f[ 0], mIn.f[ 5]) - PVRTXMUL(mIn.f[ 4], mIn.f[ 1]) ), det_1); /* Calculate -C * inverse(A) */ mDummyMatrix.f[12] = - ( PVRTXMUL(mIn.f[12], mDummyMatrix.f[ 0]) + PVRTXMUL(mIn.f[13], mDummyMatrix.f[ 4]) + PVRTXMUL(mIn.f[14], mDummyMatrix.f[ 8]) ); mDummyMatrix.f[13] = - ( PVRTXMUL(mIn.f[12], mDummyMatrix.f[ 1]) + PVRTXMUL(mIn.f[13], mDummyMatrix.f[ 5]) + PVRTXMUL(mIn.f[14], mDummyMatrix.f[ 9]) ); mDummyMatrix.f[14] = - ( PVRTXMUL(mIn.f[12], mDummyMatrix.f[ 2]) + PVRTXMUL(mIn.f[13], mDummyMatrix.f[ 6]) + PVRTXMUL(mIn.f[14], mDummyMatrix.f[10]) ); /* Fill in last row */ mDummyMatrix.f[ 3] = PVRTF2X(0.0f); mDummyMatrix.f[ 7] = PVRTF2X(0.0f); mDummyMatrix.f[11] = PVRTF2X(0.0f); mDummyMatrix.f[15] = PVRTF2X(1.0f); } /* Copy contents of dummy matrix in pfMatrix */ mOut = mDummyMatrix; } /*!*************************************************************************** @Function PVRTMatrixInverseExX @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 PVRTMatrixInverseExX( PVRTMATRIXx &mOut, const PVRTMATRIXx &mIn) { PVRTMATRIXx mTmp; int *ppfRows[4], pfRes[4], 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)); } PVRTMatrixLinearEqSolveX(pfRes, (int**)ppfRows, 4); for(j = 0; j < 4; ++j) { mTmp.f[i + 4 * j] = pfRes[j]; } } mOut = mTmp; } /*!*************************************************************************** @Function PVRTMatrixLookAtLHX @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 PVRTMatrixLookAtLHX( PVRTMATRIXx &mOut, const PVRTVECTOR3x &vEye, const PVRTVECTOR3x &vAt, const PVRTVECTOR3x &vUp) { PVRTVECTOR3x f, vUpActual, s, u; PVRTMATRIXx t; f.x = vEye.x - vAt.x; f.y = vEye.y - vAt.y; f.z = vEye.z - vAt.z; PVRTMatrixVec3NormalizeX(f, f); PVRTMatrixVec3NormalizeX(vUpActual, vUp); PVRTMatrixVec3CrossProductX(s, f, vUpActual); PVRTMatrixVec3CrossProductX(u, s, f); mOut.f[ 0] = s.x; mOut.f[ 1] = u.x; mOut.f[ 2] = -f.x; mOut.f[ 3] = PVRTF2X(0.0f); mOut.f[ 4] = s.y; mOut.f[ 5] = u.y; mOut.f[ 6] = -f.y; mOut.f[ 7] = PVRTF2X(0.0f); mOut.f[ 8] = s.z; mOut.f[ 9] = u.z; mOut.f[10] = -f.z; 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); PVRTMatrixTranslationX(t, -vEye.x, -vEye.y, -vEye.z); PVRTMatrixMultiplyX(mOut, t, mOut); } /*!*************************************************************************** @Function PVRTMatrixLookAtRHX @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 PVRTMatrixLookAtRHX( PVRTMATRIXx &mOut, const PVRTVECTOR3x &vEye, const PVRTVECTOR3x &vAt, const PVRTVECTOR3x &vUp) { PVRTVECTOR3x f, vUpActual, s, u; PVRTMATRIXx t; f.x = vAt.x - vEye.x; f.y = vAt.y - vEye.y; f.z = vAt.z - vEye.z; PVRTMatrixVec3NormalizeX(f, f); PVRTMatrixVec3NormalizeX(vUpActual, vUp); PVRTMatrixVec3CrossProductX(s, f, vUpActual); PVRTMatrixVec3CrossProductX(u, s, f); mOut.f[ 0] = s.x; mOut.f[ 1] = u.x; mOut.f[ 2] = -f.x; mOut.f[ 3] = PVRTF2X(0.0f); mOut.f[ 4] = s.y; mOut.f[ 5] = u.y; mOut.f[ 6] = -f.y; mOut.f[ 7] = PVRTF2X(0.0f); mOut.f[ 8] = s.z; mOut.f[ 9] = u.z; mOut.f[10] = -f.z; 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); PVRTMatrixTranslationX(t, -vEye.x, -vEye.y, -vEye.z); PVRTMatrixMultiplyX(mOut, t, mOut); } /*!*************************************************************************** @Function PVRTMatrixPerspectiveFovLHX @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 PVRTMatrixPerspectiveFovLHX( PVRTMATRIXx &mOut, const int fFOVy, const int fAspect, const int fNear, const int fFar, const bool bRotate) { int f, fRealAspect; if (bRotate) fRealAspect = PVRTXDIV(PVRTF2X(1.0f), fAspect); else fRealAspect = fAspect; f = PVRTXDIV(PVRTF2X(1.0f), PVRTXTAN(PVRTXMUL(fFOVy, PVRTF2X(0.5f)))); mOut.f[ 0] = PVRTXDIV(f, fRealAspect); mOut.f[ 1] = PVRTF2X(0.0f); mOut.f[ 2] = PVRTF2X(0.0f); mOut.f[ 3] = PVRTF2X(0.0f); mOut.f[ 4] = PVRTF2X(0.0f); mOut.f[ 5] = f; mOut.f[ 6] = PVRTF2X(0.0f); mOut.f[ 7] = PVRTF2X(0.0f); mOut.f[ 8] = PVRTF2X(0.0f); mOut.f[ 9] = PVRTF2X(0.0f); mOut.f[10] = PVRTXDIV(fFar, fFar - fNear); mOut.f[11] = PVRTF2X(1.0f); mOut.f[12] = PVRTF2X(0.0f); mOut.f[13] = PVRTF2X(0.0f); mOut.f[14] = -PVRTXMUL(PVRTXDIV(fFar, fFar - fNear), fNear); mOut.f[15] = PVRTF2X(0.0f); if (bRotate) { PVRTMATRIXx mRotation, mTemp = mOut; PVRTMatrixRotationZX(mRotation, PVRTF2X(90.0f*PVRT_PIf/180.0f)); PVRTMatrixMultiplyX(mOut, mTemp, mRotation); } } /*!*************************************************************************** @Function PVRTMatrixPerspectiveFovRHX @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 PVRTMatrixPerspectiveFovRHX( PVRTMATRIXx &mOut, const int fFOVy, const int fAspect, const int fNear, const int fFar, const bool bRotate) { int f; int fCorrectAspect = fAspect; if (bRotate) { fCorrectAspect = PVRTXDIV(PVRTF2X(1.0f), fAspect); } f = PVRTXDIV(PVRTF2X(1.0f), PVRTXTAN(PVRTXMUL(fFOVy, PVRTF2X(0.5f)))); mOut.f[ 0] = PVRTXDIV(f, fCorrectAspect); mOut.f[ 1] = PVRTF2X(0.0f); mOut.f[ 2] = PVRTF2X(0.0f); mOut.f[ 3] = PVRTF2X(0.0f); mOut.f[ 4] = PVRTF2X(0.0f); mOut.f[ 5] = f; mOut.f[ 6] = PVRTF2X(0.0f); mOut.f[ 7] = PVRTF2X(0.0f); mOut.f[ 8] = PVRTF2X(0.0f); mOut.f[ 9] = PVRTF2X(0.0f); mOut.f[10] = PVRTXDIV(fFar + fNear, fNear - fFar); mOut.f[11] = PVRTF2X(-1.0f); mOut.f[12] = PVRTF2X(0.0f); mOut.f[13] = PVRTF2X(0.0f); mOut.f[14] = PVRTXMUL(PVRTXDIV(fFar, fNear - fFar), fNear) << 1; // Cheap 2x mOut.f[15] = PVRTF2X(0.0f); if (bRotate) { PVRTMATRIXx mRotation, mTemp = mOut; PVRTMatrixRotationZX(mRotation, PVRTF2X(-90.0f*PVRT_PIf/180.0f)); PVRTMatrixMultiplyX(mOut, mTemp, mRotation); } } /*!*************************************************************************** @Function PVRTMatrixOrthoLHX @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 PVRTMatrixOrthoLHX( PVRTMATRIXx &mOut, const int w, const int h, const int zn, const int zf, const bool bRotate) { int fCorrectW = w; int fCorrectH = h; if (bRotate) { fCorrectW = h; fCorrectH = w; } mOut.f[ 0] = PVRTXDIV(PVRTF2X(2.0f), fCorrectW); mOut.f[ 1] = PVRTF2X(0.0f); mOut.f[ 2] = PVRTF2X(0.0f); mOut.f[ 3] = PVRTF2X(0.0f); mOut.f[ 4] = PVRTF2X(0.0f); mOut.f[ 5] = PVRTXDIV(PVRTF2X(2.0f), fCorrectH); mOut.f[ 6] = PVRTF2X(0.0f); mOut.f[ 7] = PVRTF2X(0.0f); mOut.f[ 8] = PVRTF2X(0.0f); mOut.f[ 9] = PVRTF2X(0.0f); mOut.f[10] = PVRTXDIV(PVRTF2X(1.0f), zf - zn); mOut.f[11] = PVRTXDIV(zn, zn - zf); mOut.f[12] = PVRTF2X(0.0f); mOut.f[13] = PVRTF2X(0.0f); mOut.f[14] = PVRTF2X(0.0f); mOut.f[15] = PVRTF2X(1.0f); if (bRotate) { PVRTMATRIXx mRotation, mTemp = mOut; PVRTMatrixRotationZX(mRotation, PVRTF2X(-90.0f*PVRT_PIf/180.0f)); PVRTMatrixMultiplyX(mOut, mRotation, mTemp); } } /*!*************************************************************************** @Function PVRTMatrixOrthoRHX @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 PVRTMatrixOrthoRHX( PVRTMATRIXx &mOut, const int w, const int h, const int zn, const int zf, const bool bRotate) { int fCorrectW = w; int fCorrectH = h; if (bRotate) { fCorrectW = h; fCorrectH = w; } mOut.f[ 0] = PVRTXDIV(PVRTF2X(2.0f), fCorrectW); mOut.f[ 1] = PVRTF2X(0.0f); mOut.f[ 2] = PVRTF2X(0.0f); mOut.f[ 3] = PVRTF2X(0.0f); mOut.f[ 4] = PVRTF2X(0.0f); mOut.f[ 5] = PVRTXDIV(PVRTF2X(2.0f), fCorrectH); mOut.f[ 6] = PVRTF2X(0.0f); mOut.f[ 7] = PVRTF2X(0.0f); mOut.f[ 8] = PVRTF2X(0.0f); mOut.f[ 9] = PVRTF2X(0.0f); mOut.f[10] = PVRTXDIV(PVRTF2X(1.0f), zn - zf); mOut.f[11] = PVRTXDIV(zn, zn - zf); mOut.f[12] = PVRTF2X(0.0f); mOut.f[13] = PVRTF2X(0.0f); mOut.f[14] = PVRTF2X(0.0f); mOut.f[15] = PVRTF2X(1.0f); if (bRotate) { PVRTMATRIXx mRotation, mTemp = mOut; PVRTMatrixRotationZX(mRotation, PVRTF2X(-90.0f*PVRT_PIf/180.0f)); PVRTMatrixMultiplyX(mOut, mRotation, mTemp); } } /*!*************************************************************************** @Function PVRTMatrixVec3LerpX @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 PVRTMatrixVec3LerpX( PVRTVECTOR3x &vOut, const PVRTVECTOR3x &v1, const PVRTVECTOR3x &v2, const int s) { vOut.x = v1.x + PVRTXMUL(s, v2.x - v1.x); vOut.y = v1.y + PVRTXMUL(s, v2.y - v1.y); vOut.z = v1.z + PVRTXMUL(s, v2.z - v1.z); } /*!*************************************************************************** @Function PVRTMatrixVec3DotProductX @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. A single >> 16 shift could be applied to the final accumulated result however this runs the risk of overflow between the results of the intermediate additions. *****************************************************************************/ int PVRTMatrixVec3DotProductX( const PVRTVECTOR3x &v1, const PVRTVECTOR3x &v2) { return (PVRTXMUL(v1.x, v2.x) + PVRTXMUL(v1.y, v2.y) + PVRTXMUL(v1.z, v2.z)); } /*!*************************************************************************** @Function PVRTMatrixVec3CrossProductX @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 PVRTMatrixVec3CrossProductX( PVRTVECTOR3x &vOut, const PVRTVECTOR3x &v1, const PVRTVECTOR3x &v2) { PVRTVECTOR3x result; /* Perform calculation on a dummy VECTOR (result) */ result.x = PVRTXMUL(v1.y, v2.z) - PVRTXMUL(v1.z, v2.y); result.y = PVRTXMUL(v1.z, v2.x) - PVRTXMUL(v1.x, v2.z); result.z = PVRTXMUL(v1.x, v2.y) - PVRTXMUL(v1.y, v2.x); /* Copy result in pOut */ vOut = result; } /*!*************************************************************************** @Function PVRTMatrixVec3NormalizeX @Output vOut Normalized vector @Input vIn Vector to normalize @Description Normalizes the supplied vector. The square root function is currently still performed in floating-point. Original vector is scaled down prior to be normalized in order to avoid overflow issues. ****************************************************************************/ void PVRTMatrixVec3NormalizeX( PVRTVECTOR3x &vOut, const PVRTVECTOR3x &vIn) { int f, n; PVRTVECTOR3x vTemp; /* Scale vector by uniform value */ n = PVRTABS(vIn.x) + PVRTABS(vIn.y) + PVRTABS(vIn.z); vTemp.x = PVRTXDIV(vIn.x, n); vTemp.y = PVRTXDIV(vIn.y, n); vTemp.z = PVRTXDIV(vIn.z, n); /* Calculate x2+y2+z2/sqrt(x2+y2+z2) */ f = PVRTMatrixVec3DotProductX(vTemp, vTemp); f = PVRTXDIV(PVRTF2X(1.0f), PVRTF2X(sqrt(PVRTX2F(f)))); /* Multiply vector components by f */ vOut.x = PVRTXMUL(vTemp.x, f); vOut.y = PVRTXMUL(vTemp.y, f); vOut.z = PVRTXMUL(vTemp.z, f); } /*!*************************************************************************** @Function PVRTMatrixVec3LengthX @Input vIn Vector to get the length of @Return The length of the vector @Description Gets the length of the supplied vector *****************************************************************************/ int PVRTMatrixVec3LengthX( const PVRTVECTOR3x &vIn) { int temp; temp = PVRTXMUL(vIn.x,vIn.x) + PVRTXMUL(vIn.y,vIn.y) + PVRTXMUL(vIn.z,vIn.z); return PVRTF2X(sqrt(PVRTX2F(temp))); } /*!*************************************************************************** @Function PVRTMatrixLinearEqSolveX @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 PVRTMatrixLinearEqSolveX( int * const pRes, int ** const pSrc, const int nCnt) { int i, j, k; int f; if (nCnt == 1) { _ASSERT(pSrc[0][1] != 0); pRes[0] = PVRTXDIV(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] != PVRTF2X(0.0f)) { // 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] != PVRTF2X(0.0f)); f = PVRTXDIV(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] -= PVRTXMUL(f, pSrc[nCnt-1][k]); } } break; } } // Solve the top-left sub matrix PVRTMatrixLinearEqSolveX(pRes, pSrc, nCnt - 1); // Now calc the solution for the bottom row f = pSrc[nCnt-1][0]; for(k = 1; k < nCnt; ++k) { f -= PVRTXMUL(pSrc[nCnt-1][k], pRes[k-1]); } _ASSERT(pSrc[nCnt-1][nCnt] != PVRTF2X(0)); f = PVRTXDIV(f, pSrc[nCnt-1][nCnt]); pRes[nCnt-1] = f; } /***************************************************************************** End of file (PVRTMatrixX.cpp) *****************************************************************************/