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