/******************************************************************************
@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)
*****************************************************************************/