Nicolas Capens | 7b21f27 | 2014-06-04 22:51:10 -0400 | [diff] [blame] | 1 | /****************************************************************************** |
| 2 | |
| 3 | @File PVRTTrans.cpp |
| 4 | |
| 5 | @Title PVRTTrans |
| 6 | |
| 7 | @Version |
| 8 | |
| 9 | @Copyright Copyright (c) Imagination Technologies Limited. |
| 10 | |
| 11 | @Platform ANSI compatible |
| 12 | |
| 13 | @Description Set of functions used for 3D transformations and projections. |
| 14 | |
| 15 | ******************************************************************************/ |
| 16 | #include <string.h> |
| 17 | |
| 18 | #include "PVRTGlobal.h" |
| 19 | #include "PVRTFixedPoint.h" |
| 20 | #include "PVRTMatrix.h" |
| 21 | #include "PVRTTrans.h" |
| 22 | |
| 23 | /**************************************************************************** |
| 24 | ** Functions |
| 25 | ****************************************************************************/ |
| 26 | |
| 27 | /*!*************************************************************************** |
| 28 | @Function PVRTBoundingBoxCompute |
| 29 | @Output pBoundingBox |
| 30 | @Input pV |
| 31 | @Input nNumberOfVertices |
| 32 | @Description Calculate the eight vertices that surround an object. |
| 33 | This "bounding box" is used later to determine whether |
| 34 | the object is visible or not. |
| 35 | This function should only be called once to determine the |
| 36 | object's bounding box. |
| 37 | *****************************************************************************/ |
| 38 | void PVRTBoundingBoxCompute( |
| 39 | PVRTBOUNDINGBOX * const pBoundingBox, |
| 40 | const PVRTVECTOR3 * const pV, |
| 41 | const int nNumberOfVertices) |
| 42 | { |
| 43 | int i; |
| 44 | VERTTYPE MinX, MaxX, MinY, MaxY, MinZ, MaxZ; |
| 45 | |
| 46 | /* Inialise values to first vertex */ |
| 47 | MinX=pV->x; MaxX=pV->x; |
| 48 | MinY=pV->y; MaxY=pV->y; |
| 49 | MinZ=pV->z; MaxZ=pV->z; |
| 50 | |
| 51 | /* Loop through all vertices to find extremas */ |
| 52 | for (i=1; i<nNumberOfVertices; i++) |
| 53 | { |
| 54 | /* Minimum and Maximum X */ |
| 55 | if (pV[i].x < MinX) MinX = pV[i].x; |
| 56 | if (pV[i].x > MaxX) MaxX = pV[i].x; |
| 57 | |
| 58 | /* Minimum and Maximum Y */ |
| 59 | if (pV[i].y < MinY) MinY = pV[i].y; |
| 60 | if (pV[i].y > MaxY) MaxY = pV[i].y; |
| 61 | |
| 62 | /* Minimum and Maximum Z */ |
| 63 | if (pV[i].z < MinZ) MinZ = pV[i].z; |
| 64 | if (pV[i].z > MaxZ) MaxZ = pV[i].z; |
| 65 | } |
| 66 | |
| 67 | /* Assign the resulting extremas to the bounding box structure */ |
| 68 | /* Point 0 */ |
| 69 | pBoundingBox->Point[0].x=MinX; |
| 70 | pBoundingBox->Point[0].y=MinY; |
| 71 | pBoundingBox->Point[0].z=MinZ; |
| 72 | |
| 73 | /* Point 1 */ |
| 74 | pBoundingBox->Point[1].x=MinX; |
| 75 | pBoundingBox->Point[1].y=MinY; |
| 76 | pBoundingBox->Point[1].z=MaxZ; |
| 77 | |
| 78 | /* Point 2 */ |
| 79 | pBoundingBox->Point[2].x=MinX; |
| 80 | pBoundingBox->Point[2].y=MaxY; |
| 81 | pBoundingBox->Point[2].z=MinZ; |
| 82 | |
| 83 | /* Point 3 */ |
| 84 | pBoundingBox->Point[3].x=MinX; |
| 85 | pBoundingBox->Point[3].y=MaxY; |
| 86 | pBoundingBox->Point[3].z=MaxZ; |
| 87 | |
| 88 | /* Point 4 */ |
| 89 | pBoundingBox->Point[4].x=MaxX; |
| 90 | pBoundingBox->Point[4].y=MinY; |
| 91 | pBoundingBox->Point[4].z=MinZ; |
| 92 | |
| 93 | /* Point 5 */ |
| 94 | pBoundingBox->Point[5].x=MaxX; |
| 95 | pBoundingBox->Point[5].y=MinY; |
| 96 | pBoundingBox->Point[5].z=MaxZ; |
| 97 | |
| 98 | /* Point 6 */ |
| 99 | pBoundingBox->Point[6].x=MaxX; |
| 100 | pBoundingBox->Point[6].y=MaxY; |
| 101 | pBoundingBox->Point[6].z=MinZ; |
| 102 | |
| 103 | /* Point 7 */ |
| 104 | pBoundingBox->Point[7].x=MaxX; |
| 105 | pBoundingBox->Point[7].y=MaxY; |
| 106 | pBoundingBox->Point[7].z=MaxZ; |
| 107 | } |
| 108 | |
| 109 | /*!*************************************************************************** |
| 110 | @Function PVRTBoundingBoxComputeInterleaved |
| 111 | @Output pBoundingBox |
| 112 | @Input pV |
| 113 | @Input nNumberOfVertices |
| 114 | @Input i32Offset |
| 115 | @Input i32Stride |
| 116 | @Description Calculate the eight vertices that surround an object. |
| 117 | This "bounding box" is used later to determine whether |
| 118 | the object is visible or not. |
| 119 | This function should only be called once to determine the |
| 120 | object's bounding box. |
| 121 | Takes interleaved data using the first vertex's offset |
| 122 | and the stride to the next vertex thereafter |
| 123 | *****************************************************************************/ |
| 124 | void PVRTBoundingBoxComputeInterleaved( |
| 125 | PVRTBOUNDINGBOX * const pBoundingBox, |
| 126 | const unsigned char * const pV, |
| 127 | const int nNumberOfVertices, |
| 128 | const int i32Offset, |
| 129 | const int i32Stride) |
| 130 | { |
| 131 | int i; |
| 132 | VERTTYPE MinX, MaxX, MinY, MaxY, MinZ, MaxZ; |
| 133 | |
| 134 | // point ot first vertex |
| 135 | PVRTVECTOR3 *pVertex =(PVRTVECTOR3*)(pV+i32Offset); |
| 136 | |
| 137 | /* Inialise values to first vertex */ |
| 138 | MinX=pVertex->x; MaxX=pVertex->x; |
| 139 | MinY=pVertex->y; MaxY=pVertex->y; |
| 140 | MinZ=pVertex->z; MaxZ=pVertex->z; |
| 141 | |
| 142 | /* Loop through all vertices to find extremas */ |
| 143 | for (i=1; i<nNumberOfVertices; i++) |
| 144 | { |
| 145 | pVertex = (PVRTVECTOR3*)( (unsigned char*)(pVertex)+i32Stride); |
| 146 | |
| 147 | /* Minimum and Maximum X */ |
| 148 | if (pVertex->x < MinX) MinX = pVertex->x; |
| 149 | if (pVertex->x > MaxX) MaxX = pVertex->x; |
| 150 | |
| 151 | /* Minimum and Maximum Y */ |
| 152 | if (pVertex->y < MinY) MinY = pVertex->y; |
| 153 | if (pVertex->y > MaxY) MaxY = pVertex->y; |
| 154 | |
| 155 | /* Minimum and Maximum Z */ |
| 156 | if (pVertex->z < MinZ) MinZ = pVertex->z; |
| 157 | if (pVertex->z > MaxZ) MaxZ = pVertex->z; |
| 158 | } |
| 159 | |
| 160 | /* Assign the resulting extremas to the bounding box structure */ |
| 161 | /* Point 0 */ |
| 162 | pBoundingBox->Point[0].x=MinX; |
| 163 | pBoundingBox->Point[0].y=MinY; |
| 164 | pBoundingBox->Point[0].z=MinZ; |
| 165 | |
| 166 | /* Point 1 */ |
| 167 | pBoundingBox->Point[1].x=MinX; |
| 168 | pBoundingBox->Point[1].y=MinY; |
| 169 | pBoundingBox->Point[1].z=MaxZ; |
| 170 | |
| 171 | /* Point 2 */ |
| 172 | pBoundingBox->Point[2].x=MinX; |
| 173 | pBoundingBox->Point[2].y=MaxY; |
| 174 | pBoundingBox->Point[2].z=MinZ; |
| 175 | |
| 176 | /* Point 3 */ |
| 177 | pBoundingBox->Point[3].x=MinX; |
| 178 | pBoundingBox->Point[3].y=MaxY; |
| 179 | pBoundingBox->Point[3].z=MaxZ; |
| 180 | |
| 181 | /* Point 4 */ |
| 182 | pBoundingBox->Point[4].x=MaxX; |
| 183 | pBoundingBox->Point[4].y=MinY; |
| 184 | pBoundingBox->Point[4].z=MinZ; |
| 185 | |
| 186 | /* Point 5 */ |
| 187 | pBoundingBox->Point[5].x=MaxX; |
| 188 | pBoundingBox->Point[5].y=MinY; |
| 189 | pBoundingBox->Point[5].z=MaxZ; |
| 190 | |
| 191 | /* Point 6 */ |
| 192 | pBoundingBox->Point[6].x=MaxX; |
| 193 | pBoundingBox->Point[6].y=MaxY; |
| 194 | pBoundingBox->Point[6].z=MinZ; |
| 195 | |
| 196 | /* Point 7 */ |
| 197 | pBoundingBox->Point[7].x=MaxX; |
| 198 | pBoundingBox->Point[7].y=MaxY; |
| 199 | pBoundingBox->Point[7].z=MaxZ; |
| 200 | } |
| 201 | |
| 202 | /*!****************************************************************************** |
| 203 | @Function PVRTBoundingBoxIsVisible |
| 204 | @Output pNeedsZClipping |
| 205 | @Input pBoundingBox |
| 206 | @Input pMatrix |
| 207 | @Return TRUE if the object is visible, FALSE if not. |
| 208 | @Description Determine if a bounding box is "visible" or not along the |
| 209 | Z axis. |
| 210 | If the function returns TRUE, the object is visible and should |
| 211 | be displayed (check bNeedsZClipping to know if Z Clipping needs |
| 212 | to be done). |
| 213 | If the function returns FALSE, the object is not visible and thus |
| 214 | does not require to be displayed. |
| 215 | bNeedsZClipping indicates whether the object needs Z Clipping |
| 216 | (i.e. the object is partially visible). |
| 217 | - *pBoundingBox is a pointer to the bounding box structure. |
| 218 | - *pMatrix is the World, View & Projection matrices combined. |
| 219 | - *bNeedsZClipping is TRUE if Z clipping is required. |
| 220 | *****************************************************************************/ |
| 221 | bool PVRTBoundingBoxIsVisible( |
| 222 | const PVRTBOUNDINGBOX * const pBoundingBox, |
| 223 | const PVRTMATRIX * const pMatrix, |
| 224 | bool * const pNeedsZClipping) |
| 225 | { |
| 226 | VERTTYPE fX, fY, fZ, fW; |
| 227 | int i, nX0, nX1, nY0, nY1, nZ; |
| 228 | |
| 229 | nX0 = 8; |
| 230 | nX1 = 8; |
| 231 | nY0 = 8; |
| 232 | nY1 = 8; |
| 233 | nZ = 8; |
| 234 | |
| 235 | /* Transform the eight bounding box vertices */ |
| 236 | i = 8; |
| 237 | while(i) |
| 238 | { |
| 239 | i--; |
| 240 | fX = pMatrix->f[ 0]*pBoundingBox->Point[i].x + |
| 241 | pMatrix->f[ 4]*pBoundingBox->Point[i].y + |
| 242 | pMatrix->f[ 8]*pBoundingBox->Point[i].z + |
| 243 | pMatrix->f[12]; |
| 244 | fY = pMatrix->f[ 1]*pBoundingBox->Point[i].x + |
| 245 | pMatrix->f[ 5]*pBoundingBox->Point[i].y + |
| 246 | pMatrix->f[ 9]*pBoundingBox->Point[i].z + |
| 247 | pMatrix->f[13]; |
| 248 | fZ = pMatrix->f[ 2]*pBoundingBox->Point[i].x + |
| 249 | pMatrix->f[ 6]*pBoundingBox->Point[i].y + |
| 250 | pMatrix->f[10]*pBoundingBox->Point[i].z + |
| 251 | pMatrix->f[14]; |
| 252 | fW = pMatrix->f[ 3]*pBoundingBox->Point[i].x + |
| 253 | pMatrix->f[ 7]*pBoundingBox->Point[i].y + |
| 254 | pMatrix->f[11]*pBoundingBox->Point[i].z + |
| 255 | pMatrix->f[15]; |
| 256 | |
| 257 | if(fX < -fW) |
| 258 | nX0--; |
| 259 | else if(fX > fW) |
| 260 | nX1--; |
| 261 | |
| 262 | if(fY < -fW) |
| 263 | nY0--; |
| 264 | else if(fY > fW) |
| 265 | nY1--; |
| 266 | |
| 267 | if(fZ < 0) |
| 268 | nZ--; |
| 269 | } |
| 270 | |
| 271 | if(nZ) |
| 272 | { |
| 273 | if(!(nX0 * nX1 * nY0 * nY1)) |
| 274 | { |
| 275 | *pNeedsZClipping = false; |
| 276 | return false; |
| 277 | } |
| 278 | |
| 279 | if(nZ == 8) |
| 280 | { |
| 281 | *pNeedsZClipping = false; |
| 282 | return true; |
| 283 | } |
| 284 | |
| 285 | *pNeedsZClipping = true; |
| 286 | return true; |
| 287 | } |
| 288 | else |
| 289 | { |
| 290 | *pNeedsZClipping = false; |
| 291 | return false; |
| 292 | } |
| 293 | } |
| 294 | |
| 295 | /*!*************************************************************************** |
| 296 | @Function Name PVRTTransformVec3Array |
| 297 | @Output pOut Destination for transformed vectors |
| 298 | @Input nOutStride Stride between vectors in pOut array |
| 299 | @Input pV Input vector array |
| 300 | @Input nInStride Stride between vectors in pV array |
| 301 | @Input pMatrix Matrix to transform the vectors |
| 302 | @Input nNumberOfVertices Number of vectors to transform |
| 303 | @Description Transform all vertices [X Y Z 1] in pV by pMatrix and |
| 304 | store them in pOut. |
| 305 | *****************************************************************************/ |
| 306 | void PVRTTransformVec3Array( |
| 307 | PVRTVECTOR4 * const pOut, |
| 308 | const int nOutStride, |
| 309 | const PVRTVECTOR3 * const pV, |
| 310 | const int nInStride, |
| 311 | const PVRTMATRIX * const pMatrix, |
| 312 | const int nNumberOfVertices) |
| 313 | { |
| 314 | const PVRTVECTOR3 *pSrc; |
| 315 | PVRTVECTOR4 *pDst; |
| 316 | int i; |
| 317 | |
| 318 | pSrc = pV; |
| 319 | pDst = pOut; |
| 320 | |
| 321 | /* Transform all vertices with *pMatrix */ |
| 322 | for (i=0; i<nNumberOfVertices; ++i) |
| 323 | { |
| 324 | pDst->x = VERTTYPEMUL(pMatrix->f[ 0], pSrc->x) + |
| 325 | VERTTYPEMUL(pMatrix->f[ 4], pSrc->y) + |
| 326 | VERTTYPEMUL(pMatrix->f[ 8], pSrc->z) + |
| 327 | pMatrix->f[12]; |
| 328 | pDst->y = VERTTYPEMUL(pMatrix->f[ 1], pSrc->x) + |
| 329 | VERTTYPEMUL(pMatrix->f[ 5], pSrc->y) + |
| 330 | VERTTYPEMUL(pMatrix->f[ 9], pSrc->z) + |
| 331 | pMatrix->f[13]; |
| 332 | pDst->z = VERTTYPEMUL(pMatrix->f[ 2], pSrc->x) + |
| 333 | VERTTYPEMUL(pMatrix->f[ 6], pSrc->y) + |
| 334 | VERTTYPEMUL(pMatrix->f[10], pSrc->z) + |
| 335 | pMatrix->f[14]; |
| 336 | pDst->w = VERTTYPEMUL(pMatrix->f[ 3], pSrc->x) + |
| 337 | VERTTYPEMUL(pMatrix->f[ 7], pSrc->y) + |
| 338 | VERTTYPEMUL(pMatrix->f[11], pSrc->z) + |
| 339 | pMatrix->f[15]; |
| 340 | |
| 341 | pDst = (PVRTVECTOR4*)((char*)pDst + nOutStride); |
| 342 | pSrc = (PVRTVECTOR3*)((char*)pSrc + nInStride); |
| 343 | } |
| 344 | } |
| 345 | |
| 346 | /*!*************************************************************************** |
| 347 | @Function PVRTTransformArray |
| 348 | @Output pTransformedVertex Destination for transformed vectors |
| 349 | @Input pV Input vector array |
| 350 | @Input nNumberOfVertices Number of vectors to transform |
| 351 | @Input pMatrix Matrix to transform the vectors |
| 352 | @Input fW W coordinate of input vector (e.g. use 1 for position, 0 for normal) |
| 353 | @Description Transform all vertices in pVertex by pMatrix and store them in |
| 354 | pTransformedVertex |
| 355 | - pTransformedVertex is the pointer that will receive transformed vertices. |
| 356 | - pVertex is the pointer to untransformed object vertices. |
| 357 | - nNumberOfVertices is the number of vertices of the object. |
| 358 | - pMatrix is the matrix used to transform the object. |
| 359 | *****************************************************************************/ |
| 360 | void PVRTTransformArray( |
| 361 | PVRTVECTOR3 * const pTransformedVertex, |
| 362 | const PVRTVECTOR3 * const pV, |
| 363 | const int nNumberOfVertices, |
| 364 | const PVRTMATRIX * const pMatrix, |
| 365 | const VERTTYPE fW) |
| 366 | { |
| 367 | int i; |
| 368 | |
| 369 | /* Transform all vertices with *pMatrix */ |
| 370 | for (i=0; i<nNumberOfVertices; ++i) |
| 371 | { |
| 372 | pTransformedVertex[i].x = VERTTYPEMUL(pMatrix->f[ 0], pV[i].x) + |
| 373 | VERTTYPEMUL(pMatrix->f[ 4], pV[i].y) + |
| 374 | VERTTYPEMUL(pMatrix->f[ 8], pV[i].z) + |
| 375 | VERTTYPEMUL(pMatrix->f[12], fW); |
| 376 | pTransformedVertex[i].y = VERTTYPEMUL(pMatrix->f[ 1], pV[i].x) + |
| 377 | VERTTYPEMUL(pMatrix->f[ 5], pV[i].y) + |
| 378 | VERTTYPEMUL(pMatrix->f[ 9], pV[i].z) + |
| 379 | VERTTYPEMUL(pMatrix->f[13], fW); |
| 380 | pTransformedVertex[i].z = VERTTYPEMUL(pMatrix->f[ 2], pV[i].x) + |
| 381 | VERTTYPEMUL(pMatrix->f[ 6], pV[i].y) + |
| 382 | VERTTYPEMUL(pMatrix->f[10], pV[i].z) + |
| 383 | VERTTYPEMUL(pMatrix->f[14], fW); |
| 384 | } |
| 385 | } |
| 386 | |
| 387 | /*!*************************************************************************** |
| 388 | @Function PVRTTransformArrayBack |
| 389 | @Output pTransformedVertex |
| 390 | @Input pVertex |
| 391 | @Input nNumberOfVertices |
| 392 | @Input pMatrix |
| 393 | @Description Transform all vertices in pVertex by the inverse of pMatrix |
| 394 | and store them in pTransformedVertex. |
| 395 | - pTransformedVertex is the pointer that will receive transformed vertices. |
| 396 | - pVertex is the pointer to untransformed object vertices. |
| 397 | - nNumberOfVertices is the number of vertices of the object. |
| 398 | - pMatrix is the matrix used to transform the object. |
| 399 | *****************************************************************************/ |
| 400 | void PVRTTransformArrayBack( |
| 401 | PVRTVECTOR3 * const pTransformedVertex, |
| 402 | const PVRTVECTOR3 * const pVertex, |
| 403 | const int nNumberOfVertices, |
| 404 | const PVRTMATRIX * const pMatrix) |
| 405 | { |
| 406 | PVRTMATRIX mBack; |
| 407 | |
| 408 | PVRTMatrixInverse(mBack, *pMatrix); |
| 409 | PVRTTransformArray(pTransformedVertex, pVertex, nNumberOfVertices, &mBack); |
| 410 | } |
| 411 | |
| 412 | /*!*************************************************************************** |
| 413 | @Function PVRTTransformBack |
| 414 | @Output pOut |
| 415 | @Input pV |
| 416 | @Input pM |
| 417 | @Description Transform vertex pV by the inverse of pMatrix |
| 418 | and store in pOut. |
| 419 | *****************************************************************************/ |
| 420 | void PVRTTransformBack( |
| 421 | PVRTVECTOR4 * const pOut, |
| 422 | const PVRTVECTOR4 * const pV, |
| 423 | const PVRTMATRIX * const pM) |
| 424 | { |
| 425 | VERTTYPE *ppfRows[4]; |
| 426 | VERTTYPE pfIn[20]; |
| 427 | int i; |
| 428 | const PVRTMATRIX *pMa; |
| 429 | |
| 430 | #if defined(BUILD_OGL) || defined(BUILD_OGLES) || defined(BUILD_OGLES2) || defined(BUILD_OGLES3) |
| 431 | PVRTMATRIX mT; |
| 432 | PVRTMatrixTranspose(mT, *pM); |
| 433 | pMa = &mT; |
| 434 | #else |
| 435 | pMa = pM; |
| 436 | #endif |
| 437 | |
| 438 | for(i = 0; i < 4; ++i) |
| 439 | { |
| 440 | /* |
| 441 | Set up the array of pointers to matrix coefficients |
| 442 | */ |
| 443 | ppfRows[i] = &pfIn[i * 5]; |
| 444 | |
| 445 | /* |
| 446 | Copy the 4x4 matrix into RHS of the 5x4 matrix |
| 447 | */ |
| 448 | memcpy(&ppfRows[i][1], &pMa->f[i * 4], 4 * sizeof(float)); |
| 449 | } |
| 450 | |
| 451 | /* |
| 452 | Copy the "result" vector into the first column of the 5x4 matrix |
| 453 | */ |
| 454 | ppfRows[0][0] = pV->x; |
| 455 | ppfRows[1][0] = pV->y; |
| 456 | ppfRows[2][0] = pV->z; |
| 457 | ppfRows[3][0] = pV->w; |
| 458 | |
| 459 | /* |
| 460 | Solve a set of 4 linear equations |
| 461 | */ |
| 462 | PVRTMatrixLinearEqSolve(&pOut->x, ppfRows, 4); |
| 463 | } |
| 464 | |
| 465 | /*!*************************************************************************** |
| 466 | @Function PVRTTransform |
| 467 | @Output pOut |
| 468 | @Input pV |
| 469 | @Input pM |
| 470 | @Description Transform vertex pV by pMatrix and store in pOut. |
| 471 | *****************************************************************************/ |
| 472 | void PVRTTransform( |
| 473 | PVRTVECTOR4 * const pOut, |
| 474 | const PVRTVECTOR4 * const pV, |
| 475 | const PVRTMATRIX * const pM) |
| 476 | { |
| 477 | pOut->x = VERTTYPEMUL(pM->f[0], pV->x) + VERTTYPEMUL(pM->f[4], pV->y) + VERTTYPEMUL(pM->f[8], pV->z) + VERTTYPEMUL(pM->f[12], pV->w); |
| 478 | pOut->y = VERTTYPEMUL(pM->f[1], pV->x) + VERTTYPEMUL(pM->f[5], pV->y) + VERTTYPEMUL(pM->f[9], pV->z) + VERTTYPEMUL(pM->f[13], pV->w); |
| 479 | pOut->z = VERTTYPEMUL(pM->f[2], pV->x) + VERTTYPEMUL(pM->f[6], pV->y) + VERTTYPEMUL(pM->f[10], pV->z) + VERTTYPEMUL(pM->f[14], pV->w); |
| 480 | pOut->w = VERTTYPEMUL(pM->f[3], pV->x) + VERTTYPEMUL(pM->f[7], pV->y) + VERTTYPEMUL(pM->f[11], pV->z) + VERTTYPEMUL(pM->f[15], pV->w); |
| 481 | } |
| 482 | |
| 483 | /***************************************************************************** |
| 484 | End of file (PVRTTrans.cpp) |
| 485 | *****************************************************************************/ |
| 486 | |