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