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