| /****************************************************************************** | |
| @File PVRTTrans.cpp | |
| @Title PVRTTrans | |
| @Version | |
| @Copyright Copyright (c) Imagination Technologies Limited. | |
| @Platform ANSI compatible | |
| @Description Set of functions used for 3D transformations and projections. | |
| ******************************************************************************/ | |
| #include <string.h> | |
| #include "PVRTGlobal.h" | |
| #include "PVRTFixedPoint.h" | |
| #include "PVRTMatrix.h" | |
| #include "PVRTTrans.h" | |
| /**************************************************************************** | |
| ** Functions | |
| ****************************************************************************/ | |
| /*!*************************************************************************** | |
| @Function PVRTBoundingBoxCompute | |
| @Output pBoundingBox | |
| @Input pV | |
| @Input nNumberOfVertices | |
| @Description Calculate the eight vertices that surround an object. | |
| This "bounding box" is used later to determine whether | |
| the object is visible or not. | |
| This function should only be called once to determine the | |
| object's bounding box. | |
| *****************************************************************************/ | |
| void PVRTBoundingBoxCompute( | |
| PVRTBOUNDINGBOX * const pBoundingBox, | |
| const PVRTVECTOR3 * const pV, | |
| const int nNumberOfVertices) | |
| { | |
| int i; | |
| VERTTYPE MinX, MaxX, MinY, MaxY, MinZ, MaxZ; | |
| /* Inialise values to first vertex */ | |
| MinX=pV->x; MaxX=pV->x; | |
| MinY=pV->y; MaxY=pV->y; | |
| MinZ=pV->z; MaxZ=pV->z; | |
| /* Loop through all vertices to find extremas */ | |
| for (i=1; i<nNumberOfVertices; i++) | |
| { | |
| /* Minimum and Maximum X */ | |
| if (pV[i].x < MinX) MinX = pV[i].x; | |
| if (pV[i].x > MaxX) MaxX = pV[i].x; | |
| /* Minimum and Maximum Y */ | |
| if (pV[i].y < MinY) MinY = pV[i].y; | |
| if (pV[i].y > MaxY) MaxY = pV[i].y; | |
| /* Minimum and Maximum Z */ | |
| if (pV[i].z < MinZ) MinZ = pV[i].z; | |
| if (pV[i].z > MaxZ) MaxZ = pV[i].z; | |
| } | |
| /* Assign the resulting extremas to the bounding box structure */ | |
| /* Point 0 */ | |
| pBoundingBox->Point[0].x=MinX; | |
| pBoundingBox->Point[0].y=MinY; | |
| pBoundingBox->Point[0].z=MinZ; | |
| /* Point 1 */ | |
| pBoundingBox->Point[1].x=MinX; | |
| pBoundingBox->Point[1].y=MinY; | |
| pBoundingBox->Point[1].z=MaxZ; | |
| /* Point 2 */ | |
| pBoundingBox->Point[2].x=MinX; | |
| pBoundingBox->Point[2].y=MaxY; | |
| pBoundingBox->Point[2].z=MinZ; | |
| /* Point 3 */ | |
| pBoundingBox->Point[3].x=MinX; | |
| pBoundingBox->Point[3].y=MaxY; | |
| pBoundingBox->Point[3].z=MaxZ; | |
| /* Point 4 */ | |
| pBoundingBox->Point[4].x=MaxX; | |
| pBoundingBox->Point[4].y=MinY; | |
| pBoundingBox->Point[4].z=MinZ; | |
| /* Point 5 */ | |
| pBoundingBox->Point[5].x=MaxX; | |
| pBoundingBox->Point[5].y=MinY; | |
| pBoundingBox->Point[5].z=MaxZ; | |
| /* Point 6 */ | |
| pBoundingBox->Point[6].x=MaxX; | |
| pBoundingBox->Point[6].y=MaxY; | |
| pBoundingBox->Point[6].z=MinZ; | |
| /* Point 7 */ | |
| pBoundingBox->Point[7].x=MaxX; | |
| pBoundingBox->Point[7].y=MaxY; | |
| pBoundingBox->Point[7].z=MaxZ; | |
| } | |
| /*!*************************************************************************** | |
| @Function PVRTBoundingBoxComputeInterleaved | |
| @Output pBoundingBox | |
| @Input pV | |
| @Input nNumberOfVertices | |
| @Input i32Offset | |
| @Input i32Stride | |
| @Description Calculate the eight vertices that surround an object. | |
| This "bounding box" is used later to determine whether | |
| the object is visible or not. | |
| This function should only be called once to determine the | |
| object's bounding box. | |
| Takes interleaved data using the first vertex's offset | |
| and the stride to the next vertex thereafter | |
| *****************************************************************************/ | |
| void PVRTBoundingBoxComputeInterleaved( | |
| PVRTBOUNDINGBOX * const pBoundingBox, | |
| const unsigned char * const pV, | |
| const int nNumberOfVertices, | |
| const int i32Offset, | |
| const int i32Stride) | |
| { | |
| int i; | |
| VERTTYPE MinX, MaxX, MinY, MaxY, MinZ, MaxZ; | |
| // point ot first vertex | |
| PVRTVECTOR3 *pVertex =(PVRTVECTOR3*)(pV+i32Offset); | |
| /* Inialise values to first vertex */ | |
| MinX=pVertex->x; MaxX=pVertex->x; | |
| MinY=pVertex->y; MaxY=pVertex->y; | |
| MinZ=pVertex->z; MaxZ=pVertex->z; | |
| /* Loop through all vertices to find extremas */ | |
| for (i=1; i<nNumberOfVertices; i++) | |
| { | |
| pVertex = (PVRTVECTOR3*)( (unsigned char*)(pVertex)+i32Stride); | |
| /* Minimum and Maximum X */ | |
| if (pVertex->x < MinX) MinX = pVertex->x; | |
| if (pVertex->x > MaxX) MaxX = pVertex->x; | |
| /* Minimum and Maximum Y */ | |
| if (pVertex->y < MinY) MinY = pVertex->y; | |
| if (pVertex->y > MaxY) MaxY = pVertex->y; | |
| /* Minimum and Maximum Z */ | |
| if (pVertex->z < MinZ) MinZ = pVertex->z; | |
| if (pVertex->z > MaxZ) MaxZ = pVertex->z; | |
| } | |
| /* Assign the resulting extremas to the bounding box structure */ | |
| /* Point 0 */ | |
| pBoundingBox->Point[0].x=MinX; | |
| pBoundingBox->Point[0].y=MinY; | |
| pBoundingBox->Point[0].z=MinZ; | |
| /* Point 1 */ | |
| pBoundingBox->Point[1].x=MinX; | |
| pBoundingBox->Point[1].y=MinY; | |
| pBoundingBox->Point[1].z=MaxZ; | |
| /* Point 2 */ | |
| pBoundingBox->Point[2].x=MinX; | |
| pBoundingBox->Point[2].y=MaxY; | |
| pBoundingBox->Point[2].z=MinZ; | |
| /* Point 3 */ | |
| pBoundingBox->Point[3].x=MinX; | |
| pBoundingBox->Point[3].y=MaxY; | |
| pBoundingBox->Point[3].z=MaxZ; | |
| /* Point 4 */ | |
| pBoundingBox->Point[4].x=MaxX; | |
| pBoundingBox->Point[4].y=MinY; | |
| pBoundingBox->Point[4].z=MinZ; | |
| /* Point 5 */ | |
| pBoundingBox->Point[5].x=MaxX; | |
| pBoundingBox->Point[5].y=MinY; | |
| pBoundingBox->Point[5].z=MaxZ; | |
| /* Point 6 */ | |
| pBoundingBox->Point[6].x=MaxX; | |
| pBoundingBox->Point[6].y=MaxY; | |
| pBoundingBox->Point[6].z=MinZ; | |
| /* Point 7 */ | |
| pBoundingBox->Point[7].x=MaxX; | |
| pBoundingBox->Point[7].y=MaxY; | |
| pBoundingBox->Point[7].z=MaxZ; | |
| } | |
| /*!****************************************************************************** | |
| @Function PVRTBoundingBoxIsVisible | |
| @Output pNeedsZClipping | |
| @Input pBoundingBox | |
| @Input pMatrix | |
| @Return TRUE if the object is visible, FALSE if not. | |
| @Description Determine if a bounding box is "visible" or not along the | |
| Z axis. | |
| If the function returns TRUE, the object is visible and should | |
| be displayed (check bNeedsZClipping to know if Z Clipping needs | |
| to be done). | |
| If the function returns FALSE, the object is not visible and thus | |
| does not require to be displayed. | |
| bNeedsZClipping indicates whether the object needs Z Clipping | |
| (i.e. the object is partially visible). | |
| - *pBoundingBox is a pointer to the bounding box structure. | |
| - *pMatrix is the World, View & Projection matrices combined. | |
| - *bNeedsZClipping is TRUE if Z clipping is required. | |
| *****************************************************************************/ | |
| bool PVRTBoundingBoxIsVisible( | |
| const PVRTBOUNDINGBOX * const pBoundingBox, | |
| const PVRTMATRIX * const pMatrix, | |
| bool * const pNeedsZClipping) | |
| { | |
| VERTTYPE fX, fY, fZ, fW; | |
| int i, nX0, nX1, nY0, nY1, nZ; | |
| nX0 = 8; | |
| nX1 = 8; | |
| nY0 = 8; | |
| nY1 = 8; | |
| nZ = 8; | |
| /* Transform the eight bounding box vertices */ | |
| i = 8; | |
| while(i) | |
| { | |
| i--; | |
| fX = pMatrix->f[ 0]*pBoundingBox->Point[i].x + | |
| pMatrix->f[ 4]*pBoundingBox->Point[i].y + | |
| pMatrix->f[ 8]*pBoundingBox->Point[i].z + | |
| pMatrix->f[12]; | |
| fY = pMatrix->f[ 1]*pBoundingBox->Point[i].x + | |
| pMatrix->f[ 5]*pBoundingBox->Point[i].y + | |
| pMatrix->f[ 9]*pBoundingBox->Point[i].z + | |
| pMatrix->f[13]; | |
| fZ = pMatrix->f[ 2]*pBoundingBox->Point[i].x + | |
| pMatrix->f[ 6]*pBoundingBox->Point[i].y + | |
| pMatrix->f[10]*pBoundingBox->Point[i].z + | |
| pMatrix->f[14]; | |
| fW = pMatrix->f[ 3]*pBoundingBox->Point[i].x + | |
| pMatrix->f[ 7]*pBoundingBox->Point[i].y + | |
| pMatrix->f[11]*pBoundingBox->Point[i].z + | |
| pMatrix->f[15]; | |
| if(fX < -fW) | |
| nX0--; | |
| else if(fX > fW) | |
| nX1--; | |
| if(fY < -fW) | |
| nY0--; | |
| else if(fY > fW) | |
| nY1--; | |
| if(fZ < 0) | |
| nZ--; | |
| } | |
| if(nZ) | |
| { | |
| if(!(nX0 * nX1 * nY0 * nY1)) | |
| { | |
| *pNeedsZClipping = false; | |
| return false; | |
| } | |
| if(nZ == 8) | |
| { | |
| *pNeedsZClipping = false; | |
| return true; | |
| } | |
| *pNeedsZClipping = true; | |
| return true; | |
| } | |
| else | |
| { | |
| *pNeedsZClipping = false; | |
| return false; | |
| } | |
| } | |
| /*!*************************************************************************** | |
| @Function Name PVRTTransformVec3Array | |
| @Output pOut Destination for transformed vectors | |
| @Input nOutStride Stride between vectors in pOut array | |
| @Input pV Input vector array | |
| @Input nInStride Stride between vectors in pV array | |
| @Input pMatrix Matrix to transform the vectors | |
| @Input nNumberOfVertices Number of vectors to transform | |
| @Description Transform all vertices [X Y Z 1] in pV by pMatrix and | |
| store them in pOut. | |
| *****************************************************************************/ | |
| void PVRTTransformVec3Array( | |
| PVRTVECTOR4 * const pOut, | |
| const int nOutStride, | |
| const PVRTVECTOR3 * const pV, | |
| const int nInStride, | |
| const PVRTMATRIX * const pMatrix, | |
| const int nNumberOfVertices) | |
| { | |
| const PVRTVECTOR3 *pSrc; | |
| PVRTVECTOR4 *pDst; | |
| int i; | |
| pSrc = pV; | |
| pDst = pOut; | |
| /* Transform all vertices with *pMatrix */ | |
| for (i=0; i<nNumberOfVertices; ++i) | |
| { | |
| pDst->x = VERTTYPEMUL(pMatrix->f[ 0], pSrc->x) + | |
| VERTTYPEMUL(pMatrix->f[ 4], pSrc->y) + | |
| VERTTYPEMUL(pMatrix->f[ 8], pSrc->z) + | |
| pMatrix->f[12]; | |
| pDst->y = VERTTYPEMUL(pMatrix->f[ 1], pSrc->x) + | |
| VERTTYPEMUL(pMatrix->f[ 5], pSrc->y) + | |
| VERTTYPEMUL(pMatrix->f[ 9], pSrc->z) + | |
| pMatrix->f[13]; | |
| pDst->z = VERTTYPEMUL(pMatrix->f[ 2], pSrc->x) + | |
| VERTTYPEMUL(pMatrix->f[ 6], pSrc->y) + | |
| VERTTYPEMUL(pMatrix->f[10], pSrc->z) + | |
| pMatrix->f[14]; | |
| pDst->w = VERTTYPEMUL(pMatrix->f[ 3], pSrc->x) + | |
| VERTTYPEMUL(pMatrix->f[ 7], pSrc->y) + | |
| VERTTYPEMUL(pMatrix->f[11], pSrc->z) + | |
| pMatrix->f[15]; | |
| pDst = (PVRTVECTOR4*)((char*)pDst + nOutStride); | |
| pSrc = (PVRTVECTOR3*)((char*)pSrc + nInStride); | |
| } | |
| } | |
| /*!*************************************************************************** | |
| @Function PVRTTransformArray | |
| @Output pTransformedVertex Destination for transformed vectors | |
| @Input pV Input vector array | |
| @Input nNumberOfVertices Number of vectors to transform | |
| @Input pMatrix Matrix to transform the vectors | |
| @Input fW W coordinate of input vector (e.g. use 1 for position, 0 for normal) | |
| @Description Transform all vertices in pVertex by pMatrix and store them in | |
| pTransformedVertex | |
| - pTransformedVertex is the pointer that will receive transformed vertices. | |
| - pVertex is the pointer to untransformed object vertices. | |
| - nNumberOfVertices is the number of vertices of the object. | |
| - pMatrix is the matrix used to transform the object. | |
| *****************************************************************************/ | |
| void PVRTTransformArray( | |
| PVRTVECTOR3 * const pTransformedVertex, | |
| const PVRTVECTOR3 * const pV, | |
| const int nNumberOfVertices, | |
| const PVRTMATRIX * const pMatrix, | |
| const VERTTYPE fW) | |
| { | |
| int i; | |
| /* Transform all vertices with *pMatrix */ | |
| for (i=0; i<nNumberOfVertices; ++i) | |
| { | |
| pTransformedVertex[i].x = VERTTYPEMUL(pMatrix->f[ 0], pV[i].x) + | |
| VERTTYPEMUL(pMatrix->f[ 4], pV[i].y) + | |
| VERTTYPEMUL(pMatrix->f[ 8], pV[i].z) + | |
| VERTTYPEMUL(pMatrix->f[12], fW); | |
| pTransformedVertex[i].y = VERTTYPEMUL(pMatrix->f[ 1], pV[i].x) + | |
| VERTTYPEMUL(pMatrix->f[ 5], pV[i].y) + | |
| VERTTYPEMUL(pMatrix->f[ 9], pV[i].z) + | |
| VERTTYPEMUL(pMatrix->f[13], fW); | |
| pTransformedVertex[i].z = VERTTYPEMUL(pMatrix->f[ 2], pV[i].x) + | |
| VERTTYPEMUL(pMatrix->f[ 6], pV[i].y) + | |
| VERTTYPEMUL(pMatrix->f[10], pV[i].z) + | |
| VERTTYPEMUL(pMatrix->f[14], fW); | |
| } | |
| } | |
| /*!*************************************************************************** | |
| @Function PVRTTransformArrayBack | |
| @Output pTransformedVertex | |
| @Input pVertex | |
| @Input nNumberOfVertices | |
| @Input pMatrix | |
| @Description Transform all vertices in pVertex by the inverse of pMatrix | |
| and store them in pTransformedVertex. | |
| - pTransformedVertex is the pointer that will receive transformed vertices. | |
| - pVertex is the pointer to untransformed object vertices. | |
| - nNumberOfVertices is the number of vertices of the object. | |
| - pMatrix is the matrix used to transform the object. | |
| *****************************************************************************/ | |
| void PVRTTransformArrayBack( | |
| PVRTVECTOR3 * const pTransformedVertex, | |
| const PVRTVECTOR3 * const pVertex, | |
| const int nNumberOfVertices, | |
| const PVRTMATRIX * const pMatrix) | |
| { | |
| PVRTMATRIX mBack; | |
| PVRTMatrixInverse(mBack, *pMatrix); | |
| PVRTTransformArray(pTransformedVertex, pVertex, nNumberOfVertices, &mBack); | |
| } | |
| /*!*************************************************************************** | |
| @Function PVRTTransformBack | |
| @Output pOut | |
| @Input pV | |
| @Input pM | |
| @Description Transform vertex pV by the inverse of pMatrix | |
| and store in pOut. | |
| *****************************************************************************/ | |
| void PVRTTransformBack( | |
| PVRTVECTOR4 * const pOut, | |
| const PVRTVECTOR4 * const pV, | |
| const PVRTMATRIX * const pM) | |
| { | |
| VERTTYPE *ppfRows[4]; | |
| VERTTYPE pfIn[20]; | |
| int i; | |
| const PVRTMATRIX *pMa; | |
| #if defined(BUILD_OGL) || defined(BUILD_OGLES) || defined(BUILD_OGLES2) || defined(BUILD_OGLES3) | |
| PVRTMATRIX mT; | |
| PVRTMatrixTranspose(mT, *pM); | |
| pMa = &mT; | |
| #else | |
| pMa = pM; | |
| #endif | |
| for(i = 0; i < 4; ++i) | |
| { | |
| /* | |
| Set up the array of pointers to matrix coefficients | |
| */ | |
| ppfRows[i] = &pfIn[i * 5]; | |
| /* | |
| Copy the 4x4 matrix into RHS of the 5x4 matrix | |
| */ | |
| memcpy(&ppfRows[i][1], &pMa->f[i * 4], 4 * sizeof(float)); | |
| } | |
| /* | |
| Copy the "result" vector into the first column of the 5x4 matrix | |
| */ | |
| ppfRows[0][0] = pV->x; | |
| ppfRows[1][0] = pV->y; | |
| ppfRows[2][0] = pV->z; | |
| ppfRows[3][0] = pV->w; | |
| /* | |
| Solve a set of 4 linear equations | |
| */ | |
| PVRTMatrixLinearEqSolve(&pOut->x, ppfRows, 4); | |
| } | |
| /*!*************************************************************************** | |
| @Function PVRTTransform | |
| @Output pOut | |
| @Input pV | |
| @Input pM | |
| @Description Transform vertex pV by pMatrix and store in pOut. | |
| *****************************************************************************/ | |
| void PVRTTransform( | |
| PVRTVECTOR4 * const pOut, | |
| const PVRTVECTOR4 * const pV, | |
| const PVRTMATRIX * const pM) | |
| { | |
| 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); | |
| 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); | |
| 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); | |
| 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); | |
| } | |
| /***************************************************************************** | |
| End of file (PVRTTrans.cpp) | |
| *****************************************************************************/ | |