Nicolas Capens | 7b21f27 | 2014-06-04 22:51:10 -0400 | [diff] [blame] | 1 | /****************************************************************************** |
| 2 | |
| 3 | @File PVRTMatrixF.cpp |
| 4 | |
| 5 | @Title PVRTMatrixF |
| 6 | |
| 7 | @Version |
| 8 | |
| 9 | @Copyright Copyright (c) Imagination Technologies Limited. |
| 10 | |
| 11 | @Platform ANSI compatible |
| 12 | |
| 13 | @Description Set of mathematical functions involving matrices, vectors and |
| 14 | quaternions. The general matrix format used is directly compatible |
| 15 | with, for example, both DirectX and OpenGL. For the reasons why, |
| 16 | read this: |
| 17 | http://research.microsoft.com/~hollasch/cgindex/math/matrix/column-vec.html |
| 18 | |
| 19 | ******************************************************************************/ |
| 20 | #include "PVRTGlobal.h" |
| 21 | #include <math.h> |
| 22 | #include <string.h> |
| 23 | #include "PVRTFixedPoint.h" // Only needed for trig function float lookups |
| 24 | #include "PVRTMatrix.h" |
| 25 | |
| 26 | |
| 27 | /**************************************************************************** |
| 28 | ** Constants |
| 29 | ****************************************************************************/ |
| 30 | static const PVRTMATRIXf c_mIdentity = { |
| 31 | { |
| 32 | 1, 0, 0, 0, |
| 33 | 0, 1, 0, 0, |
| 34 | 0, 0, 1, 0, |
| 35 | 0, 0, 0, 1 |
| 36 | } |
| 37 | }; |
| 38 | |
| 39 | /**************************************************************************** |
| 40 | ** Functions |
| 41 | ****************************************************************************/ |
| 42 | |
| 43 | /*!*************************************************************************** |
| 44 | @Function PVRTMatrixIdentityF |
| 45 | @Output mOut Set to identity |
| 46 | @Description Reset matrix to identity matrix. |
| 47 | *****************************************************************************/ |
| 48 | void PVRTMatrixIdentityF(PVRTMATRIXf &mOut) |
| 49 | { |
| 50 | mOut.f[ 0]=1.0f; mOut.f[ 4]=0.0f; mOut.f[ 8]=0.0f; mOut.f[12]=0.0f; |
| 51 | mOut.f[ 1]=0.0f; mOut.f[ 5]=1.0f; mOut.f[ 9]=0.0f; mOut.f[13]=0.0f; |
| 52 | mOut.f[ 2]=0.0f; mOut.f[ 6]=0.0f; mOut.f[10]=1.0f; mOut.f[14]=0.0f; |
| 53 | mOut.f[ 3]=0.0f; mOut.f[ 7]=0.0f; mOut.f[11]=0.0f; mOut.f[15]=1.0f; |
| 54 | } |
| 55 | |
| 56 | |
| 57 | /*!*************************************************************************** |
| 58 | @Function PVRTMatrixMultiplyF |
| 59 | @Output mOut Result of mA x mB |
| 60 | @Input mA First operand |
| 61 | @Input mB Second operand |
| 62 | @Description Multiply mA by mB and assign the result to mOut |
| 63 | (mOut = p1 * p2). A copy of the result matrix is done in |
| 64 | the function because mOut can be a parameter mA or mB. |
| 65 | *****************************************************************************/ |
| 66 | void PVRTMatrixMultiplyF( |
| 67 | PVRTMATRIXf &mOut, |
| 68 | const PVRTMATRIXf &mA, |
| 69 | const PVRTMATRIXf &mB) |
| 70 | { |
| 71 | PVRTMATRIXf mRet; |
| 72 | |
| 73 | /* Perform calculation on a dummy matrix (mRet) */ |
| 74 | 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]; |
| 75 | 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]; |
| 76 | 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]; |
| 77 | 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]; |
| 78 | |
| 79 | 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]; |
| 80 | 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]; |
| 81 | 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]; |
| 82 | 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]; |
| 83 | |
| 84 | 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]; |
| 85 | 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]; |
| 86 | 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]; |
| 87 | 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]; |
| 88 | |
| 89 | 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]; |
| 90 | 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]; |
| 91 | 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]; |
| 92 | 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]; |
| 93 | |
| 94 | /* Copy result to mOut */ |
| 95 | mOut = mRet; |
| 96 | } |
| 97 | |
| 98 | |
| 99 | /*!*************************************************************************** |
| 100 | @Function Name PVRTMatrixTranslationF |
| 101 | @Output mOut Translation matrix |
| 102 | @Input fX X component of the translation |
| 103 | @Input fY Y component of the translation |
| 104 | @Input fZ Z component of the translation |
| 105 | @Description Build a transaltion matrix mOut using fX, fY and fZ. |
| 106 | *****************************************************************************/ |
| 107 | void PVRTMatrixTranslationF( |
| 108 | PVRTMATRIXf &mOut, |
| 109 | const float fX, |
| 110 | const float fY, |
| 111 | const float fZ) |
| 112 | { |
| 113 | mOut.f[ 0]=1.0f; mOut.f[ 4]=0.0f; mOut.f[ 8]=0.0f; mOut.f[12]=fX; |
| 114 | mOut.f[ 1]=0.0f; mOut.f[ 5]=1.0f; mOut.f[ 9]=0.0f; mOut.f[13]=fY; |
| 115 | mOut.f[ 2]=0.0f; mOut.f[ 6]=0.0f; mOut.f[10]=1.0f; mOut.f[14]=fZ; |
| 116 | mOut.f[ 3]=0.0f; mOut.f[ 7]=0.0f; mOut.f[11]=0.0f; mOut.f[15]=1.0f; |
| 117 | } |
| 118 | |
| 119 | /*!*************************************************************************** |
| 120 | @Function Name PVRTMatrixScalingF |
| 121 | @Output mOut Scale matrix |
| 122 | @Input fX X component of the scaling |
| 123 | @Input fY Y component of the scaling |
| 124 | @Input fZ Z component of the scaling |
| 125 | @Description Build a scale matrix mOut using fX, fY and fZ. |
| 126 | *****************************************************************************/ |
| 127 | void PVRTMatrixScalingF( |
| 128 | PVRTMATRIXf &mOut, |
| 129 | const float fX, |
| 130 | const float fY, |
| 131 | const float fZ) |
| 132 | { |
| 133 | mOut.f[ 0]=fX; mOut.f[ 4]=0.0f; mOut.f[ 8]=0.0f; mOut.f[12]=0.0f; |
| 134 | mOut.f[ 1]=0.0f; mOut.f[ 5]=fY; mOut.f[ 9]=0.0f; mOut.f[13]=0.0f; |
| 135 | mOut.f[ 2]=0.0f; mOut.f[ 6]=0.0f; mOut.f[10]=fZ; mOut.f[14]=0.0f; |
| 136 | mOut.f[ 3]=0.0f; mOut.f[ 7]=0.0f; mOut.f[11]=0.0f; mOut.f[15]=1.0f; |
| 137 | } |
| 138 | |
| 139 | /*!*************************************************************************** |
| 140 | @Function Name PVRTMatrixRotationXF |
| 141 | @Output mOut Rotation matrix |
| 142 | @Input fAngle Angle of the rotation |
| 143 | @Description Create an X rotation matrix mOut. |
| 144 | *****************************************************************************/ |
| 145 | void PVRTMatrixRotationXF( |
| 146 | PVRTMATRIXf &mOut, |
| 147 | const float fAngle) |
| 148 | { |
| 149 | float fCosine, fSine; |
| 150 | |
| 151 | /* Precompute cos and sin */ |
| 152 | #if defined(BUILD_DX11) |
| 153 | fCosine = (float)PVRTFCOS(-fAngle); |
| 154 | fSine = (float)PVRTFSIN(-fAngle); |
| 155 | #else |
| 156 | fCosine = (float)PVRTFCOS(fAngle); |
| 157 | fSine = (float)PVRTFSIN(fAngle); |
| 158 | #endif |
| 159 | |
| 160 | /* Create the trigonometric matrix corresponding to X Rotation */ |
| 161 | mOut.f[ 0]=1.0f; mOut.f[ 4]=0.0f; mOut.f[ 8]=0.0f; mOut.f[12]=0.0f; |
| 162 | mOut.f[ 1]=0.0f; mOut.f[ 5]=fCosine; mOut.f[ 9]=fSine; mOut.f[13]=0.0f; |
| 163 | mOut.f[ 2]=0.0f; mOut.f[ 6]=-fSine; mOut.f[10]=fCosine; mOut.f[14]=0.0f; |
| 164 | mOut.f[ 3]=0.0f; mOut.f[ 7]=0.0f; mOut.f[11]=0.0f; mOut.f[15]=1.0f; |
| 165 | } |
| 166 | |
| 167 | /*!*************************************************************************** |
| 168 | @Function Name PVRTMatrixRotationYF |
| 169 | @Output mOut Rotation matrix |
| 170 | @Input fAngle Angle of the rotation |
| 171 | @Description Create an Y rotation matrix mOut. |
| 172 | *****************************************************************************/ |
| 173 | void PVRTMatrixRotationYF( |
| 174 | PVRTMATRIXf &mOut, |
| 175 | const float fAngle) |
| 176 | { |
| 177 | float fCosine, fSine; |
| 178 | |
| 179 | /* Precompute cos and sin */ |
| 180 | #if defined(BUILD_DX11) |
| 181 | fCosine = (float)PVRTFCOS(-fAngle); |
| 182 | fSine = (float)PVRTFSIN(-fAngle); |
| 183 | #else |
| 184 | fCosine = (float)PVRTFCOS(fAngle); |
| 185 | fSine = (float)PVRTFSIN(fAngle); |
| 186 | #endif |
| 187 | |
| 188 | /* Create the trigonometric matrix corresponding to Y Rotation */ |
| 189 | mOut.f[ 0]=fCosine; mOut.f[ 4]=0.0f; mOut.f[ 8]=-fSine; mOut.f[12]=0.0f; |
| 190 | mOut.f[ 1]=0.0f; mOut.f[ 5]=1.0f; mOut.f[ 9]=0.0f; mOut.f[13]=0.0f; |
| 191 | mOut.f[ 2]=fSine; mOut.f[ 6]=0.0f; mOut.f[10]=fCosine; mOut.f[14]=0.0f; |
| 192 | mOut.f[ 3]=0.0f; mOut.f[ 7]=0.0f; mOut.f[11]=0.0f; mOut.f[15]=1.0f; |
| 193 | } |
| 194 | |
| 195 | /*!*************************************************************************** |
| 196 | @Function Name PVRTMatrixRotationZF |
| 197 | @Output mOut Rotation matrix |
| 198 | @Input fAngle Angle of the rotation |
| 199 | @Description Create an Z rotation matrix mOut. |
| 200 | *****************************************************************************/ |
| 201 | void PVRTMatrixRotationZF( |
| 202 | PVRTMATRIXf &mOut, |
| 203 | const float fAngle) |
| 204 | { |
| 205 | float fCosine, fSine; |
| 206 | |
| 207 | /* Precompute cos and sin */ |
| 208 | #if defined(BUILD_DX11) |
| 209 | fCosine = (float)PVRTFCOS(-fAngle); |
| 210 | fSine = (float)PVRTFSIN(-fAngle); |
| 211 | #else |
| 212 | fCosine = (float)PVRTFCOS(fAngle); |
| 213 | fSine = (float)PVRTFSIN(fAngle); |
| 214 | #endif |
| 215 | |
| 216 | /* Create the trigonometric matrix corresponding to Z Rotation */ |
| 217 | mOut.f[ 0]=fCosine; mOut.f[ 4]=fSine; mOut.f[ 8]=0.0f; mOut.f[12]=0.0f; |
| 218 | mOut.f[ 1]=-fSine; mOut.f[ 5]=fCosine; mOut.f[ 9]=0.0f; mOut.f[13]=0.0f; |
| 219 | mOut.f[ 2]=0.0f; mOut.f[ 6]=0.0f; mOut.f[10]=1.0f; mOut.f[14]=0.0f; |
| 220 | mOut.f[ 3]=0.0f; mOut.f[ 7]=0.0f; mOut.f[11]=0.0f; mOut.f[15]=1.0f; |
| 221 | } |
| 222 | |
| 223 | /*!*************************************************************************** |
| 224 | @Function Name PVRTMatrixTransposeF |
| 225 | @Output mOut Transposed matrix |
| 226 | @Input mIn Original matrix |
| 227 | @Description Compute the transpose matrix of mIn. |
| 228 | *****************************************************************************/ |
| 229 | void PVRTMatrixTransposeF( |
| 230 | PVRTMATRIXf &mOut, |
| 231 | const PVRTMATRIXf &mIn) |
| 232 | { |
| 233 | PVRTMATRIXf mTmp; |
| 234 | |
| 235 | mTmp.f[ 0]=mIn.f[ 0]; mTmp.f[ 4]=mIn.f[ 1]; mTmp.f[ 8]=mIn.f[ 2]; mTmp.f[12]=mIn.f[ 3]; |
| 236 | mTmp.f[ 1]=mIn.f[ 4]; mTmp.f[ 5]=mIn.f[ 5]; mTmp.f[ 9]=mIn.f[ 6]; mTmp.f[13]=mIn.f[ 7]; |
| 237 | mTmp.f[ 2]=mIn.f[ 8]; mTmp.f[ 6]=mIn.f[ 9]; mTmp.f[10]=mIn.f[10]; mTmp.f[14]=mIn.f[11]; |
| 238 | mTmp.f[ 3]=mIn.f[12]; mTmp.f[ 7]=mIn.f[13]; mTmp.f[11]=mIn.f[14]; mTmp.f[15]=mIn.f[15]; |
| 239 | |
| 240 | mOut = mTmp; |
| 241 | } |
| 242 | |
| 243 | /*!*************************************************************************** |
| 244 | @Function PVRTMatrixInverseF |
| 245 | @Output mOut Inversed matrix |
| 246 | @Input mIn Original matrix |
| 247 | @Description Compute the inverse matrix of mIn. |
| 248 | The matrix must be of the form : |
| 249 | A 0 |
| 250 | C 1 |
| 251 | Where A is a 3x3 matrix and C is a 1x3 matrix. |
| 252 | *****************************************************************************/ |
| 253 | void PVRTMatrixInverseF( |
| 254 | PVRTMATRIXf &mOut, |
| 255 | const PVRTMATRIXf &mIn) |
| 256 | { |
| 257 | PVRTMATRIXf mDummyMatrix; |
| 258 | double det_1; |
| 259 | double pos, neg, temp; |
| 260 | |
| 261 | /* Calculate the determinant of submatrix A and determine if the |
| 262 | the matrix is singular as limited by the double precision |
| 263 | floating-point data representation. */ |
| 264 | pos = neg = 0.0; |
| 265 | temp = mIn.f[ 0] * mIn.f[ 5] * mIn.f[10]; |
| 266 | if (temp >= 0.0) pos += temp; else neg += temp; |
| 267 | temp = mIn.f[ 4] * mIn.f[ 9] * mIn.f[ 2]; |
| 268 | if (temp >= 0.0) pos += temp; else neg += temp; |
| 269 | temp = mIn.f[ 8] * mIn.f[ 1] * mIn.f[ 6]; |
| 270 | if (temp >= 0.0) pos += temp; else neg += temp; |
| 271 | temp = -mIn.f[ 8] * mIn.f[ 5] * mIn.f[ 2]; |
| 272 | if (temp >= 0.0) pos += temp; else neg += temp; |
| 273 | temp = -mIn.f[ 4] * mIn.f[ 1] * mIn.f[10]; |
| 274 | if (temp >= 0.0) pos += temp; else neg += temp; |
| 275 | temp = -mIn.f[ 0] * mIn.f[ 9] * mIn.f[ 6]; |
| 276 | if (temp >= 0.0) pos += temp; else neg += temp; |
| 277 | det_1 = pos + neg; |
| 278 | |
| 279 | /* Is the submatrix A singular? */ |
| 280 | if ((det_1 == 0.0) || (PVRTABS(det_1 / (pos - neg)) < 1.0e-15)) |
| 281 | { |
| 282 | /* Matrix M has no inverse */ |
| 283 | _RPT0(_CRT_WARN, "Matrix has no inverse : singular matrix\n"); |
| 284 | return; |
| 285 | } |
| 286 | else |
| 287 | { |
| 288 | /* Calculate inverse(A) = adj(A) / det(A) */ |
| 289 | det_1 = 1.0 / det_1; |
| 290 | mDummyMatrix.f[ 0] = ( mIn.f[ 5] * mIn.f[10] - mIn.f[ 9] * mIn.f[ 6] ) * (float)det_1; |
| 291 | mDummyMatrix.f[ 1] = - ( mIn.f[ 1] * mIn.f[10] - mIn.f[ 9] * mIn.f[ 2] ) * (float)det_1; |
| 292 | mDummyMatrix.f[ 2] = ( mIn.f[ 1] * mIn.f[ 6] - mIn.f[ 5] * mIn.f[ 2] ) * (float)det_1; |
| 293 | mDummyMatrix.f[ 4] = - ( mIn.f[ 4] * mIn.f[10] - mIn.f[ 8] * mIn.f[ 6] ) * (float)det_1; |
| 294 | mDummyMatrix.f[ 5] = ( mIn.f[ 0] * mIn.f[10] - mIn.f[ 8] * mIn.f[ 2] ) * (float)det_1; |
| 295 | mDummyMatrix.f[ 6] = - ( mIn.f[ 0] * mIn.f[ 6] - mIn.f[ 4] * mIn.f[ 2] ) * (float)det_1; |
| 296 | mDummyMatrix.f[ 8] = ( mIn.f[ 4] * mIn.f[ 9] - mIn.f[ 8] * mIn.f[ 5] ) * (float)det_1; |
| 297 | mDummyMatrix.f[ 9] = - ( mIn.f[ 0] * mIn.f[ 9] - mIn.f[ 8] * mIn.f[ 1] ) * (float)det_1; |
| 298 | mDummyMatrix.f[10] = ( mIn.f[ 0] * mIn.f[ 5] - mIn.f[ 4] * mIn.f[ 1] ) * (float)det_1; |
| 299 | |
| 300 | /* Calculate -C * inverse(A) */ |
| 301 | mDummyMatrix.f[12] = - ( mIn.f[12] * mDummyMatrix.f[ 0] + mIn.f[13] * mDummyMatrix.f[ 4] + mIn.f[14] * mDummyMatrix.f[ 8] ); |
| 302 | mDummyMatrix.f[13] = - ( mIn.f[12] * mDummyMatrix.f[ 1] + mIn.f[13] * mDummyMatrix.f[ 5] + mIn.f[14] * mDummyMatrix.f[ 9] ); |
| 303 | mDummyMatrix.f[14] = - ( mIn.f[12] * mDummyMatrix.f[ 2] + mIn.f[13] * mDummyMatrix.f[ 6] + mIn.f[14] * mDummyMatrix.f[10] ); |
| 304 | |
| 305 | /* Fill in last row */ |
| 306 | mDummyMatrix.f[ 3] = 0.0f; |
| 307 | mDummyMatrix.f[ 7] = 0.0f; |
| 308 | mDummyMatrix.f[11] = 0.0f; |
| 309 | mDummyMatrix.f[15] = 1.0f; |
| 310 | } |
| 311 | |
| 312 | /* Copy contents of dummy matrix in pfMatrix */ |
| 313 | mOut = mDummyMatrix; |
| 314 | } |
| 315 | |
| 316 | /*!*************************************************************************** |
| 317 | @Function PVRTMatrixInverseExF |
| 318 | @Output mOut Inversed matrix |
| 319 | @Input mIn Original matrix |
| 320 | @Description Compute the inverse matrix of mIn. |
| 321 | Uses a linear equation solver and the knowledge that M.M^-1=I. |
| 322 | Use this fn to calculate the inverse of matrices that |
| 323 | PVRTMatrixInverse() cannot. |
| 324 | *****************************************************************************/ |
| 325 | void PVRTMatrixInverseExF( |
| 326 | PVRTMATRIXf &mOut, |
| 327 | const PVRTMATRIXf &mIn) |
| 328 | { |
| 329 | PVRTMATRIXf mTmp = {0}; |
| 330 | float *ppfRows[4]; |
| 331 | float pfRes[4]; |
| 332 | float pfIn[20]; |
| 333 | int i, j; |
| 334 | |
| 335 | for(i = 0; i < 4; ++i) |
| 336 | ppfRows[i] = &pfIn[i * 5]; |
| 337 | |
| 338 | /* Solve 4 sets of 4 linear equations */ |
| 339 | for(i = 0; i < 4; ++i) |
| 340 | { |
| 341 | for(j = 0; j < 4; ++j) |
| 342 | { |
| 343 | ppfRows[j][0] = c_mIdentity.f[i + 4 * j]; |
| 344 | memcpy(&ppfRows[j][1], &mIn.f[j * 4], 4 * sizeof(float)); |
| 345 | } |
| 346 | |
| 347 | PVRTMatrixLinearEqSolveF(pfRes, (float**)ppfRows, 4); |
| 348 | |
| 349 | for(j = 0; j < 4; ++j) |
| 350 | { |
| 351 | mTmp.f[i + 4 * j] = pfRes[j]; |
| 352 | } |
| 353 | } |
| 354 | |
| 355 | mOut = mTmp; |
| 356 | } |
| 357 | |
| 358 | /*!*************************************************************************** |
| 359 | @Function PVRTMatrixLookAtLHF |
| 360 | @Output mOut Look-at view matrix |
| 361 | @Input vEye Position of the camera |
| 362 | @Input vAt Point the camera is looking at |
| 363 | @Input vUp Up direction for the camera |
| 364 | @Description Create a look-at view matrix. |
| 365 | *****************************************************************************/ |
| 366 | void PVRTMatrixLookAtLHF( |
| 367 | PVRTMATRIXf &mOut, |
| 368 | const PVRTVECTOR3f &vEye, |
| 369 | const PVRTVECTOR3f &vAt, |
| 370 | const PVRTVECTOR3f &vUp) |
| 371 | { |
| 372 | PVRTVECTOR3f f, s, u; |
| 373 | PVRTMATRIXf t; |
| 374 | |
| 375 | f.x = vEye.x - vAt.x; |
| 376 | f.y = vEye.y - vAt.y; |
| 377 | f.z = vEye.z - vAt.z; |
| 378 | |
| 379 | PVRTMatrixVec3NormalizeF(f, f); |
| 380 | PVRTMatrixVec3CrossProductF(s, f, vUp); |
| 381 | PVRTMatrixVec3NormalizeF(s, s); |
| 382 | PVRTMatrixVec3CrossProductF(u, s, f); |
| 383 | PVRTMatrixVec3NormalizeF(u, u); |
| 384 | |
| 385 | mOut.f[ 0] = s.x; |
| 386 | mOut.f[ 1] = u.x; |
| 387 | mOut.f[ 2] = -f.x; |
| 388 | mOut.f[ 3] = 0; |
| 389 | |
| 390 | mOut.f[ 4] = s.y; |
| 391 | mOut.f[ 5] = u.y; |
| 392 | mOut.f[ 6] = -f.y; |
| 393 | mOut.f[ 7] = 0; |
| 394 | |
| 395 | mOut.f[ 8] = s.z; |
| 396 | mOut.f[ 9] = u.z; |
| 397 | mOut.f[10] = -f.z; |
| 398 | mOut.f[11] = 0; |
| 399 | |
| 400 | mOut.f[12] = 0; |
| 401 | mOut.f[13] = 0; |
| 402 | mOut.f[14] = 0; |
| 403 | mOut.f[15] = 1; |
| 404 | |
| 405 | PVRTMatrixTranslationF(t, -vEye.x, -vEye.y, -vEye.z); |
| 406 | PVRTMatrixMultiplyF(mOut, t, mOut); |
| 407 | } |
| 408 | |
| 409 | /*!*************************************************************************** |
| 410 | @Function PVRTMatrixLookAtRHF |
| 411 | @Output mOut Look-at view matrix |
| 412 | @Input vEye Position of the camera |
| 413 | @Input vAt Point the camera is looking at |
| 414 | @Input vUp Up direction for the camera |
| 415 | @Description Create a look-at view matrix. |
| 416 | *****************************************************************************/ |
| 417 | void PVRTMatrixLookAtRHF( |
| 418 | PVRTMATRIXf &mOut, |
| 419 | const PVRTVECTOR3f &vEye, |
| 420 | const PVRTVECTOR3f &vAt, |
| 421 | const PVRTVECTOR3f &vUp) |
| 422 | { |
| 423 | PVRTVECTOR3f f, s, u; |
| 424 | PVRTMATRIXf t; |
| 425 | |
| 426 | f.x = vAt.x - vEye.x; |
| 427 | f.y = vAt.y - vEye.y; |
| 428 | f.z = vAt.z - vEye.z; |
| 429 | |
| 430 | PVRTMatrixVec3NormalizeF(f, f); |
| 431 | PVRTMatrixVec3CrossProductF(s, f, vUp); |
| 432 | PVRTMatrixVec3NormalizeF(s, s); |
| 433 | PVRTMatrixVec3CrossProductF(u, s, f); |
| 434 | PVRTMatrixVec3NormalizeF(u, u); |
| 435 | |
| 436 | mOut.f[ 0] = s.x; |
| 437 | mOut.f[ 1] = u.x; |
| 438 | mOut.f[ 2] = -f.x; |
| 439 | mOut.f[ 3] = 0; |
| 440 | |
| 441 | mOut.f[ 4] = s.y; |
| 442 | mOut.f[ 5] = u.y; |
| 443 | mOut.f[ 6] = -f.y; |
| 444 | mOut.f[ 7] = 0; |
| 445 | |
| 446 | mOut.f[ 8] = s.z; |
| 447 | mOut.f[ 9] = u.z; |
| 448 | mOut.f[10] = -f.z; |
| 449 | mOut.f[11] = 0; |
| 450 | |
| 451 | mOut.f[12] = 0; |
| 452 | mOut.f[13] = 0; |
| 453 | mOut.f[14] = 0; |
| 454 | mOut.f[15] = 1; |
| 455 | |
| 456 | PVRTMatrixTranslationF(t, -vEye.x, -vEye.y, -vEye.z); |
| 457 | PVRTMatrixMultiplyF(mOut, t, mOut); |
| 458 | } |
| 459 | |
| 460 | /*!*************************************************************************** |
| 461 | @Function PVRTMatrixPerspectiveFovLHF |
| 462 | @Output mOut Perspective matrix |
| 463 | @Input fFOVy Field of view |
| 464 | @Input fAspect Aspect ratio |
| 465 | @Input fNear Near clipping distance |
| 466 | @Input fFar Far clipping distance |
| 467 | @Input bRotate Should we rotate it ? (for upright screens) |
| 468 | @Description Create a perspective matrix. |
| 469 | *****************************************************************************/ |
| 470 | void PVRTMatrixPerspectiveFovLHF( |
| 471 | PVRTMATRIXf &mOut, |
| 472 | const float fFOVy, |
| 473 | const float fAspect, |
| 474 | const float fNear, |
| 475 | const float fFar, |
| 476 | const bool bRotate) |
| 477 | { |
| 478 | float f, n, fRealAspect; |
| 479 | |
| 480 | if (bRotate) |
| 481 | fRealAspect = 1.0f / fAspect; |
| 482 | else |
| 483 | fRealAspect = fAspect; |
| 484 | |
| 485 | // cotangent(a) == 1.0f / tan(a); |
| 486 | f = 1.0f / (float)PVRTFTAN(fFOVy * 0.5f); |
| 487 | n = 1.0f / (fFar - fNear); |
| 488 | |
| 489 | mOut.f[ 0] = f / fRealAspect; |
| 490 | mOut.f[ 1] = 0; |
| 491 | mOut.f[ 2] = 0; |
| 492 | mOut.f[ 3] = 0; |
| 493 | |
| 494 | mOut.f[ 4] = 0; |
| 495 | mOut.f[ 5] = f; |
| 496 | mOut.f[ 6] = 0; |
| 497 | mOut.f[ 7] = 0; |
| 498 | |
| 499 | mOut.f[ 8] = 0; |
| 500 | mOut.f[ 9] = 0; |
| 501 | mOut.f[10] = fFar * n; |
| 502 | mOut.f[11] = 1; |
| 503 | |
| 504 | mOut.f[12] = 0; |
| 505 | mOut.f[13] = 0; |
| 506 | mOut.f[14] = -fFar * fNear * n; |
| 507 | mOut.f[15] = 0; |
| 508 | |
| 509 | if (bRotate) |
| 510 | { |
| 511 | PVRTMATRIXf mRotation, mTemp = mOut; |
| 512 | PVRTMatrixRotationZF(mRotation, 90.0f*PVRT_PIf/180.0f); |
| 513 | PVRTMatrixMultiplyF(mOut, mTemp, mRotation); |
| 514 | } |
| 515 | } |
| 516 | |
| 517 | /*!*************************************************************************** |
| 518 | @Function PVRTMatrixPerspectiveFovRHF |
| 519 | @Output mOut Perspective matrix |
| 520 | @Input fFOVy Field of view |
| 521 | @Input fAspect Aspect ratio |
| 522 | @Input fNear Near clipping distance |
| 523 | @Input fFar Far clipping distance |
| 524 | @Input bRotate Should we rotate it ? (for upright screens) |
| 525 | @Description Create a perspective matrix. |
| 526 | *****************************************************************************/ |
| 527 | void PVRTMatrixPerspectiveFovRHF( |
| 528 | PVRTMATRIXf &mOut, |
| 529 | const float fFOVy, |
| 530 | const float fAspect, |
| 531 | const float fNear, |
| 532 | const float fFar, |
| 533 | const bool bRotate) |
| 534 | { |
| 535 | float f, n, fRealAspect; |
| 536 | |
| 537 | if (bRotate) |
| 538 | fRealAspect = 1.0f / fAspect; |
| 539 | else |
| 540 | fRealAspect = fAspect; |
| 541 | |
| 542 | // cotangent(a) == 1.0f / tan(a); |
| 543 | f = 1.0f / (float)PVRTFTAN(fFOVy * 0.5f); |
| 544 | n = 1.0f / (fNear - fFar); |
| 545 | |
| 546 | mOut.f[ 0] = f / fRealAspect; |
| 547 | mOut.f[ 1] = 0; |
| 548 | mOut.f[ 2] = 0; |
| 549 | mOut.f[ 3] = 0; |
| 550 | |
| 551 | mOut.f[ 4] = 0; |
| 552 | mOut.f[ 5] = f; |
| 553 | mOut.f[ 6] = 0; |
| 554 | mOut.f[ 7] = 0; |
| 555 | |
| 556 | mOut.f[ 8] = 0; |
| 557 | mOut.f[ 9] = 0; |
| 558 | mOut.f[10] = (fFar + fNear) * n; |
| 559 | mOut.f[11] = -1; |
| 560 | |
| 561 | mOut.f[12] = 0; |
| 562 | mOut.f[13] = 0; |
| 563 | mOut.f[14] = (2 * fFar * fNear) * n; |
| 564 | mOut.f[15] = 0; |
| 565 | |
| 566 | if (bRotate) |
| 567 | { |
| 568 | PVRTMATRIXf mRotation, mTemp = mOut; |
| 569 | PVRTMatrixRotationZF(mRotation, -90.0f*PVRT_PIf/180.0f); |
| 570 | PVRTMatrixMultiplyF(mOut, mTemp, mRotation); |
| 571 | } |
| 572 | } |
| 573 | |
| 574 | /*!*************************************************************************** |
| 575 | @Function PVRTMatrixOrthoLHF |
| 576 | @Output mOut Orthographic matrix |
| 577 | @Input w Width of the screen |
| 578 | @Input h Height of the screen |
| 579 | @Input zn Near clipping distance |
| 580 | @Input zf Far clipping distance |
| 581 | @Input bRotate Should we rotate it ? (for upright screens) |
| 582 | @Description Create an orthographic matrix. |
| 583 | *****************************************************************************/ |
| 584 | void PVRTMatrixOrthoLHF( |
| 585 | PVRTMATRIXf &mOut, |
| 586 | const float w, |
| 587 | const float h, |
| 588 | const float zn, |
| 589 | const float zf, |
| 590 | const bool bRotate) |
| 591 | { |
| 592 | mOut.f[ 0] = 2 / w; |
| 593 | mOut.f[ 1] = 0; |
| 594 | mOut.f[ 2] = 0; |
| 595 | mOut.f[ 3] = 0; |
| 596 | |
| 597 | mOut.f[ 4] = 0; |
| 598 | mOut.f[ 5] = 2 / h; |
| 599 | mOut.f[ 6] = 0; |
| 600 | mOut.f[ 7] = 0; |
| 601 | |
| 602 | mOut.f[ 8] = 0; |
| 603 | mOut.f[ 9] = 0; |
| 604 | mOut.f[10] = 1 / (zf - zn); |
| 605 | mOut.f[11] = zn / (zn - zf); |
| 606 | |
| 607 | mOut.f[12] = 0; |
| 608 | mOut.f[13] = 0; |
| 609 | mOut.f[14] = 0; |
| 610 | mOut.f[15] = 1; |
| 611 | |
| 612 | if (bRotate) |
| 613 | { |
| 614 | PVRTMATRIXf mRotation, mTemp = mOut; |
| 615 | PVRTMatrixRotationZF(mRotation, -90.0f*PVRT_PIf/180.0f); |
| 616 | PVRTMatrixMultiplyF(mOut, mRotation, mTemp); |
| 617 | } |
| 618 | } |
| 619 | |
| 620 | /*!*************************************************************************** |
| 621 | @Function PVRTMatrixOrthoRHF |
| 622 | @Output mOut Orthographic matrix |
| 623 | @Input w Width of the screen |
| 624 | @Input h Height of the screen |
| 625 | @Input zn Near clipping distance |
| 626 | @Input zf Far clipping distance |
| 627 | @Input bRotate Should we rotate it ? (for upright screens) |
| 628 | @Description Create an orthographic matrix. |
| 629 | *****************************************************************************/ |
| 630 | void PVRTMatrixOrthoRHF( |
| 631 | PVRTMATRIXf &mOut, |
| 632 | const float w, |
| 633 | const float h, |
| 634 | const float zn, |
| 635 | const float zf, |
| 636 | const bool bRotate) |
| 637 | { |
| 638 | mOut.f[ 0] = 2 / w; |
| 639 | mOut.f[ 1] = 0; |
| 640 | mOut.f[ 2] = 0; |
| 641 | mOut.f[ 3] = 0; |
| 642 | |
| 643 | mOut.f[ 4] = 0; |
| 644 | mOut.f[ 5] = 2 / h; |
| 645 | mOut.f[ 6] = 0; |
| 646 | mOut.f[ 7] = 0; |
| 647 | |
| 648 | mOut.f[ 8] = 0; |
| 649 | mOut.f[ 9] = 0; |
| 650 | mOut.f[10] = 1 / (zn - zf); |
| 651 | mOut.f[11] = zn / (zn - zf); |
| 652 | |
| 653 | mOut.f[12] = 0; |
| 654 | mOut.f[13] = 0; |
| 655 | mOut.f[14] = 0; |
| 656 | mOut.f[15] = 1; |
| 657 | |
| 658 | if (bRotate) |
| 659 | { |
| 660 | PVRTMATRIXf mRotation, mTemp = mOut; |
| 661 | PVRTMatrixRotationZF(mRotation, -90.0f*PVRT_PIf/180.0f); |
| 662 | PVRTMatrixMultiplyF(mOut, mRotation, mTemp); |
| 663 | } |
| 664 | } |
| 665 | |
| 666 | /*!*************************************************************************** |
| 667 | @Function PVRTMatrixVec3LerpF |
| 668 | @Output vOut Result of the interpolation |
| 669 | @Input v1 First vector to interpolate from |
| 670 | @Input v2 Second vector to interpolate form |
| 671 | @Input s Coefficient of interpolation |
| 672 | @Description This function performs the linear interpolation based on |
| 673 | the following formula: V1 + s(V2-V1). |
| 674 | *****************************************************************************/ |
| 675 | void PVRTMatrixVec3LerpF( |
| 676 | PVRTVECTOR3f &vOut, |
| 677 | const PVRTVECTOR3f &v1, |
| 678 | const PVRTVECTOR3f &v2, |
| 679 | const float s) |
| 680 | { |
| 681 | vOut.x = v1.x + s * (v2.x - v1.x); |
| 682 | vOut.y = v1.y + s * (v2.y - v1.y); |
| 683 | vOut.z = v1.z + s * (v2.z - v1.z); |
| 684 | } |
| 685 | |
| 686 | /*!*************************************************************************** |
| 687 | @Function PVRTMatrixVec3DotProductF |
| 688 | @Input v1 First vector |
| 689 | @Input v2 Second vector |
| 690 | @Return Dot product of the two vectors. |
| 691 | @Description This function performs the dot product of the two |
| 692 | supplied vectors. |
| 693 | *****************************************************************************/ |
| 694 | float PVRTMatrixVec3DotProductF( |
| 695 | const PVRTVECTOR3f &v1, |
| 696 | const PVRTVECTOR3f &v2) |
| 697 | { |
| 698 | return (v1.x*v2.x + v1.y*v2.y + v1.z*v2.z); |
| 699 | } |
| 700 | |
| 701 | /*!*************************************************************************** |
| 702 | @Function PVRTMatrixVec3CrossProductF |
| 703 | @Output vOut Cross product of the two vectors |
| 704 | @Input v1 First vector |
| 705 | @Input v2 Second vector |
| 706 | @Description This function performs the cross product of the two |
| 707 | supplied vectors. |
| 708 | *****************************************************************************/ |
| 709 | void PVRTMatrixVec3CrossProductF( |
| 710 | PVRTVECTOR3f &vOut, |
| 711 | const PVRTVECTOR3f &v1, |
| 712 | const PVRTVECTOR3f &v2) |
| 713 | { |
| 714 | PVRTVECTOR3f result; |
| 715 | |
| 716 | /* Perform calculation on a dummy VECTOR (result) */ |
| 717 | result.x = v1.y * v2.z - v1.z * v2.y; |
| 718 | result.y = v1.z * v2.x - v1.x * v2.z; |
| 719 | result.z = v1.x * v2.y - v1.y * v2.x; |
| 720 | |
| 721 | /* Copy result in pOut */ |
| 722 | vOut = result; |
| 723 | } |
| 724 | |
| 725 | /*!*************************************************************************** |
| 726 | @Function PVRTMatrixVec3NormalizeF |
| 727 | @Output vOut Normalized vector |
| 728 | @Input vIn Vector to normalize |
| 729 | @Description Normalizes the supplied vector. |
| 730 | *****************************************************************************/ |
| 731 | void PVRTMatrixVec3NormalizeF( |
| 732 | PVRTVECTOR3f &vOut, |
| 733 | const PVRTVECTOR3f &vIn) |
| 734 | { |
| 735 | float f; |
| 736 | double temp; |
| 737 | |
| 738 | temp = (double)(vIn.x * vIn.x + vIn.y * vIn.y + vIn.z * vIn.z); |
| 739 | temp = 1.0 / sqrt(temp); |
| 740 | f = (float)temp; |
| 741 | |
| 742 | vOut.x = vIn.x * f; |
| 743 | vOut.y = vIn.y * f; |
| 744 | vOut.z = vIn.z * f; |
| 745 | } |
| 746 | |
| 747 | /*!*************************************************************************** |
| 748 | @Function PVRTMatrixVec3LengthF |
| 749 | @Input vIn Vector to get the length of |
| 750 | @Return The length of the vector |
| 751 | @Description Gets the length of the supplied vector. |
| 752 | *****************************************************************************/ |
| 753 | float PVRTMatrixVec3LengthF( |
| 754 | const PVRTVECTOR3f &vIn) |
| 755 | { |
| 756 | double temp; |
| 757 | |
| 758 | temp = (double)(vIn.x * vIn.x + vIn.y * vIn.y + vIn.z * vIn.z); |
| 759 | return (float) sqrt(temp); |
| 760 | } |
| 761 | |
| 762 | /*!*************************************************************************** |
| 763 | @Function PVRTMatrixLinearEqSolveF |
| 764 | @Input pSrc 2D array of floats. 4 Eq linear problem is 5x4 |
| 765 | matrix, constants in first column |
| 766 | @Input nCnt Number of equations to solve |
| 767 | @Output pRes Result |
| 768 | @Description Solves 'nCnt' simultaneous equations of 'nCnt' variables. |
| 769 | pRes should be an array large enough to contain the |
| 770 | results: the values of the 'nCnt' variables. |
| 771 | This fn recursively uses Gaussian Elimination. |
| 772 | *****************************************************************************/ |
| 773 | void PVRTMatrixLinearEqSolveF( |
| 774 | float * const pRes, |
| 775 | float ** const pSrc, // 2D array of floats. 4 Eq linear problem is 5x4 matrix, constants in first column. |
| 776 | const int nCnt) |
| 777 | { |
| 778 | int i, j, k; |
| 779 | float f; |
| 780 | |
| 781 | #if 0 |
| 782 | /* |
| 783 | Show the matrix in debug output |
| 784 | */ |
| 785 | _RPT1(_CRT_WARN, "LinearEqSolve(%d)\n", nCnt); |
| 786 | for(i = 0; i < nCnt; ++i) |
| 787 | { |
| 788 | _RPT1(_CRT_WARN, "%.8f |", pSrc[i][0]); |
| 789 | for(j = 1; j <= nCnt; ++j) |
| 790 | _RPT1(_CRT_WARN, " %.8f", pSrc[i][j]); |
| 791 | _RPT0(_CRT_WARN, "\n"); |
| 792 | } |
| 793 | #endif |
| 794 | |
| 795 | if(nCnt == 1) |
| 796 | { |
| 797 | _ASSERT(pSrc[0][1] != 0); |
| 798 | pRes[0] = pSrc[0][0] / pSrc[0][1]; |
| 799 | return; |
| 800 | } |
| 801 | |
| 802 | // Loop backwards in an attempt avoid the need to swap rows |
| 803 | i = nCnt; |
| 804 | while(i) |
| 805 | { |
| 806 | --i; |
| 807 | |
| 808 | if(pSrc[i][nCnt] != 0) |
| 809 | { |
| 810 | // Row i can be used to zero the other rows; let's move it to the bottom |
| 811 | if(i != (nCnt-1)) |
| 812 | { |
| 813 | for(j = 0; j <= nCnt; ++j) |
| 814 | { |
| 815 | // Swap the two values |
| 816 | f = pSrc[nCnt-1][j]; |
| 817 | pSrc[nCnt-1][j] = pSrc[i][j]; |
| 818 | pSrc[i][j] = f; |
| 819 | } |
| 820 | } |
| 821 | |
| 822 | // Now zero the last columns of the top rows |
| 823 | for(j = 0; j < (nCnt-1); ++j) |
| 824 | { |
| 825 | _ASSERT(pSrc[nCnt-1][nCnt] != 0); |
| 826 | f = pSrc[j][nCnt] / pSrc[nCnt-1][nCnt]; |
| 827 | |
| 828 | // No need to actually calculate a zero for the final column |
| 829 | for(k = 0; k < nCnt; ++k) |
| 830 | { |
| 831 | pSrc[j][k] -= f * pSrc[nCnt-1][k]; |
| 832 | } |
| 833 | } |
| 834 | |
| 835 | break; |
| 836 | } |
| 837 | } |
| 838 | |
| 839 | // Solve the top-left sub matrix |
| 840 | PVRTMatrixLinearEqSolveF(pRes, pSrc, nCnt - 1); |
| 841 | |
| 842 | // Now calc the solution for the bottom row |
| 843 | f = pSrc[nCnt-1][0]; |
| 844 | for(k = 1; k < nCnt; ++k) |
| 845 | { |
| 846 | f -= pSrc[nCnt-1][k] * pRes[k-1]; |
| 847 | } |
| 848 | _ASSERT(pSrc[nCnt-1][nCnt] != 0); |
| 849 | f /= pSrc[nCnt-1][nCnt]; |
| 850 | pRes[nCnt-1] = f; |
| 851 | |
| 852 | #if 0 |
| 853 | { |
| 854 | float fCnt; |
| 855 | |
| 856 | /* |
| 857 | Verify that the result is correct |
| 858 | */ |
| 859 | fCnt = 0; |
| 860 | for(i = 1; i <= nCnt; ++i) |
| 861 | fCnt += pSrc[nCnt-1][i] * pRes[i-1]; |
| 862 | |
| 863 | _ASSERT(abs(fCnt - pSrc[nCnt-1][0]) < 1e-3); |
| 864 | } |
| 865 | #endif |
| 866 | } |
| 867 | |
| 868 | /***************************************************************************** |
| 869 | End of file (PVRTMatrixF.cpp) |
| 870 | *****************************************************************************/ |
| 871 | |