|  | /****************************************************************************** | 
|  |  | 
|  | @File         PVRTMisc.cpp | 
|  |  | 
|  | @Title        PVRTMisc | 
|  |  | 
|  | @Version | 
|  |  | 
|  | @Copyright    Copyright (c) Imagination Technologies Limited. | 
|  |  | 
|  | @Platform     ANSI compatible | 
|  |  | 
|  | @Description  Miscellaneous functions used in 3D rendering. | 
|  |  | 
|  | ******************************************************************************/ | 
|  | #include <string.h> | 
|  | #include <stdlib.h> | 
|  | #include <ctype.h> | 
|  | #include <limits.h> | 
|  | #include <math.h> | 
|  | #include "PVRTGlobal.h" | 
|  | #include "PVRTContext.h" | 
|  | #include "PVRTFixedPoint.h" | 
|  | #include "PVRTMatrix.h" | 
|  | #include "PVRTMisc.h" | 
|  |  | 
|  |  | 
|  |  | 
|  | /*!*************************************************************************** | 
|  | @Function			PVRTMiscCalculateIntersectionLinePlane | 
|  | @Input				pfPlane			Length 4 [A,B,C,D], values for plane | 
|  | equation | 
|  | @Input				pv0				A point on the line | 
|  | @Input				pv1				Another point on the line | 
|  | @Output			pvIntersection	The point of intersection | 
|  | @Description		Calculates coords of the intersection of a line and an | 
|  | infinite plane | 
|  | *****************************************************************************/ | 
|  | void PVRTMiscCalculateIntersectionLinePlane( | 
|  | PVRTVECTOR3			* const pvIntersection, | 
|  | const VERTTYPE		pfPlane[4], | 
|  | const PVRTVECTOR3	* const pv0, | 
|  | const PVRTVECTOR3	* const pv1) | 
|  | { | 
|  | PVRTVECTOR3	vD; | 
|  | VERTTYPE fN, fD, fT; | 
|  |  | 
|  | /* Calculate vector from point0 to point1 */ | 
|  | vD.x = pv1->x - pv0->x; | 
|  | vD.y = pv1->y - pv0->y; | 
|  | vD.z = pv1->z - pv0->z; | 
|  |  | 
|  | /* Denominator */ | 
|  | fD = | 
|  | VERTTYPEMUL(pfPlane[0], vD.x) + | 
|  | VERTTYPEMUL(pfPlane[1], vD.y) + | 
|  | VERTTYPEMUL(pfPlane[2], vD.z); | 
|  |  | 
|  | /* Numerator */ | 
|  | fN = | 
|  | VERTTYPEMUL(pfPlane[0], pv0->x) + | 
|  | VERTTYPEMUL(pfPlane[1], pv0->y) + | 
|  | VERTTYPEMUL(pfPlane[2], pv0->z) + | 
|  | pfPlane[3]; | 
|  |  | 
|  | fT = VERTTYPEDIV(-fN, fD); | 
|  |  | 
|  | /* And for a finale, calculate the intersection coordinate */ | 
|  | pvIntersection->x = pv0->x + VERTTYPEMUL(fT, vD.x); | 
|  | pvIntersection->y = pv0->y + VERTTYPEMUL(fT, vD.y); | 
|  | pvIntersection->z = pv0->z + VERTTYPEMUL(fT, vD.z); | 
|  | } | 
|  |  | 
|  |  | 
|  | /*!*************************************************************************** | 
|  | @Function		PVRTMiscCalculateInfinitePlane | 
|  | @Input			nStride			Size of each vertex structure containing pfVtx | 
|  | @Input			pvPlane			Length 4 [A,B,C,D], values for plane equation | 
|  | @Input			pmViewProjInv	The inverse of the View Projection matrix | 
|  | @Input			pFrom			Position of the camera | 
|  | @Input			fFar			Far clipping distance | 
|  | @Output		pfVtx			Position of the first of 3 floats to receive | 
|  | the position of vertex 0; up to 5 vertex positions | 
|  | will be written (5 is the maximum number of vertices | 
|  | required to draw an infinite polygon clipped to screen | 
|  | and far clip plane). | 
|  | @Returns		Number of vertices in the polygon fan (Can be 0, 3, 4 or 5) | 
|  | @Description	Calculates world-space coords of a screen-filling | 
|  | representation of an infinite plane The resulting vertices run | 
|  | counter-clockwise around the screen, and can be simply drawn using | 
|  | non-indexed TRIANGLEFAN | 
|  | *****************************************************************************/ | 
|  | int PVRTMiscCalculateInfinitePlane( | 
|  | VERTTYPE			* const pfVtx, | 
|  | const int			nStride, | 
|  | const PVRTVECTOR4	* const pvPlane, | 
|  | const PVRTMATRIX 	* const pmViewProjInv, | 
|  | const PVRTVECTOR3	* const pFrom, | 
|  | const VERTTYPE		fFar) | 
|  | { | 
|  | PVRTVECTOR3		pvWorld[5]; | 
|  | PVRTVECTOR3		*pvPolyPtr; | 
|  | unsigned int	dwCount; | 
|  | bool			bClip; | 
|  | int				nVert; | 
|  | VERTTYPE		fDotProduct; | 
|  |  | 
|  | /* | 
|  | Check whether the plane faces the camera | 
|  | */ | 
|  | fDotProduct = | 
|  | VERTTYPEMUL((pFrom->x + VERTTYPEMUL(pvPlane->x, pvPlane->w)), pvPlane->x) + | 
|  | VERTTYPEMUL((pFrom->y + VERTTYPEMUL(pvPlane->y, pvPlane->w)), pvPlane->y) + | 
|  | VERTTYPEMUL((pFrom->z + VERTTYPEMUL(pvPlane->z, pvPlane->w)), pvPlane->z); | 
|  |  | 
|  | if(fDotProduct < 0) { | 
|  | /* Camera is behind plane, hence it's not visible */ | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /* | 
|  | Back transform front clipping plane into world space, | 
|  | to give us a point on the line through each corner of the screen | 
|  | (from the camera). | 
|  | */ | 
|  |  | 
|  | /*             x = -1.0f;    y = -1.0f;     z = 1.0f;      w = 1.0f */ | 
|  | pvWorld[0].x = VERTTYPEMUL((-pmViewProjInv->f[ 0] - pmViewProjInv->f[ 4] + pmViewProjInv->f[ 8] + pmViewProjInv->f[12]), fFar); | 
|  | pvWorld[0].y = VERTTYPEMUL((-pmViewProjInv->f[ 1] - pmViewProjInv->f[ 5] + pmViewProjInv->f[ 9] + pmViewProjInv->f[13]), fFar); | 
|  | pvWorld[0].z = VERTTYPEMUL((-pmViewProjInv->f[ 2] - pmViewProjInv->f[ 6] + pmViewProjInv->f[10] + pmViewProjInv->f[14]), fFar); | 
|  | /*             x =  1.0f,    y = -1.0f,     z = 1.0f;      w = 1.0f */ | 
|  | pvWorld[1].x = VERTTYPEMUL(( pmViewProjInv->f[ 0] - pmViewProjInv->f[ 4] + pmViewProjInv->f[ 8] + pmViewProjInv->f[12]), fFar); | 
|  | pvWorld[1].y = VERTTYPEMUL(( pmViewProjInv->f[ 1] - pmViewProjInv->f[ 5] + pmViewProjInv->f[ 9] + pmViewProjInv->f[13]), fFar); | 
|  | pvWorld[1].z = VERTTYPEMUL(( pmViewProjInv->f[ 2] - pmViewProjInv->f[ 6] + pmViewProjInv->f[10] + pmViewProjInv->f[14]), fFar); | 
|  | /*             x =  1.0f,    y =  1.0f,     z = 1.0f;      w = 1.0f */ | 
|  | pvWorld[2].x = VERTTYPEMUL(( pmViewProjInv->f[ 0] + pmViewProjInv->f[ 4] + pmViewProjInv->f[ 8] + pmViewProjInv->f[12]), fFar); | 
|  | pvWorld[2].y = VERTTYPEMUL(( pmViewProjInv->f[ 1] + pmViewProjInv->f[ 5] + pmViewProjInv->f[ 9] + pmViewProjInv->f[13]), fFar); | 
|  | pvWorld[2].z = VERTTYPEMUL(( pmViewProjInv->f[ 2] + pmViewProjInv->f[ 6] + pmViewProjInv->f[10] + pmViewProjInv->f[14]), fFar); | 
|  | /*             x = -1.0f,    y =  1.0f,     z = 1.0f;      w = 1.0f */ | 
|  | pvWorld[3].x = VERTTYPEMUL((-pmViewProjInv->f[ 0] + pmViewProjInv->f[ 4] + pmViewProjInv->f[ 8] + pmViewProjInv->f[12]), fFar); | 
|  | pvWorld[3].y = VERTTYPEMUL((-pmViewProjInv->f[ 1] + pmViewProjInv->f[ 5] + pmViewProjInv->f[ 9] + pmViewProjInv->f[13]), fFar); | 
|  | pvWorld[3].z = VERTTYPEMUL((-pmViewProjInv->f[ 2] + pmViewProjInv->f[ 6] + pmViewProjInv->f[10] + pmViewProjInv->f[14]), fFar); | 
|  |  | 
|  | /* We need to do a closed loop of the screen vertices, so copy the first vertex into the last */ | 
|  | pvWorld[4] = pvWorld[0]; | 
|  |  | 
|  | /* | 
|  | Now build a pre-clipped polygon | 
|  | */ | 
|  |  | 
|  | /* Lets get ready to loop */ | 
|  | dwCount		= 0; | 
|  | bClip		= false; | 
|  | pvPolyPtr	= (PVRTVECTOR3*)pfVtx; | 
|  |  | 
|  | nVert = 5; | 
|  | while(nVert) | 
|  | { | 
|  | nVert--; | 
|  |  | 
|  | /* | 
|  | Check which side of the Plane this corner of the far clipping | 
|  | plane is on. [A,B,C] of plane equation is the plane normal, D is | 
|  | distance from origin; hence [pvPlane->x * -pvPlane->w, | 
|  | pvPlane->y * -pvPlane->w, | 
|  | pvPlane->z * -pvPlane->w] | 
|  | is a point on the plane | 
|  | */ | 
|  | fDotProduct = | 
|  | VERTTYPEMUL((pvWorld[nVert].x + VERTTYPEMUL(pvPlane->x, pvPlane->w)), pvPlane->x) + | 
|  | VERTTYPEMUL((pvWorld[nVert].y + VERTTYPEMUL(pvPlane->y, pvPlane->w)), pvPlane->y) + | 
|  | VERTTYPEMUL((pvWorld[nVert].z + VERTTYPEMUL(pvPlane->z, pvPlane->w)), pvPlane->z); | 
|  |  | 
|  | if(fDotProduct < 0) | 
|  | { | 
|  | /* | 
|  | Behind plane; Vertex does NOT need clipping | 
|  | */ | 
|  | if(bClip == true) | 
|  | { | 
|  | /* Clipping finished */ | 
|  | bClip = false; | 
|  |  | 
|  | /* | 
|  | We've been clipping, so we need to add an additional | 
|  | point on the line to this point, where clipping was | 
|  | stopped. | 
|  | */ | 
|  | PVRTMiscCalculateIntersectionLinePlane(pvPolyPtr, &pvPlane->x, &pvWorld[nVert+1], &pvWorld[nVert]); | 
|  | pvPolyPtr = (PVRTVECTOR3*)((char*)pvPolyPtr + nStride); | 
|  | dwCount++; | 
|  | } | 
|  |  | 
|  | if(!nVert) | 
|  | { | 
|  | /* Abort, abort: we've closed the loop with the clipped point */ | 
|  | break; | 
|  | } | 
|  |  | 
|  | /* Add the current point */ | 
|  | PVRTMiscCalculateIntersectionLinePlane(pvPolyPtr, &pvPlane->x, pFrom, &pvWorld[nVert]); | 
|  | pvPolyPtr = (PVRTVECTOR3*)((char*)pvPolyPtr + nStride); | 
|  | dwCount++; | 
|  | } | 
|  | else | 
|  | { | 
|  | /* | 
|  | Before plane; Vertex DOES need clipping | 
|  | */ | 
|  | if(bClip == true) | 
|  | { | 
|  | /* Already in clipping, skip point */ | 
|  | continue; | 
|  | } | 
|  |  | 
|  | /* Clipping initiated */ | 
|  | bClip = true; | 
|  |  | 
|  | /* Don't bother with entry point on first vertex; will take care of it on last vertex (which is a repeat of first vertex) */ | 
|  | if(nVert != 4) | 
|  | { | 
|  | /* We need to add an additional point on the line to this point, where clipping was started */ | 
|  | PVRTMiscCalculateIntersectionLinePlane(pvPolyPtr, &pvPlane->x, &pvWorld[nVert+1], &pvWorld[nVert]); | 
|  | pvPolyPtr = (PVRTVECTOR3*)((char*)pvPolyPtr + nStride); | 
|  | dwCount++; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | /* Valid vertex counts are 0, 3, 4, 5 */ | 
|  | _ASSERT(dwCount <= 5); | 
|  | _ASSERT(dwCount != 1); | 
|  | _ASSERT(dwCount != 2); | 
|  |  | 
|  | return dwCount; | 
|  | } | 
|  |  | 
|  |  | 
|  | /*!*************************************************************************** | 
|  | @Function			SetVertex | 
|  | @Modified			Vertices | 
|  | @Input				index | 
|  | @Input				x | 
|  | @Input				y | 
|  | @Input				z | 
|  | @Description		Writes a vertex in a vertex array | 
|  | *****************************************************************************/ | 
|  | static void SetVertex(VERTTYPE** Vertices, int index, VERTTYPE x, VERTTYPE y, VERTTYPE z) | 
|  | { | 
|  | (*Vertices)[index*3+0] = x; | 
|  | (*Vertices)[index*3+1] = y; | 
|  | (*Vertices)[index*3+2] = z; | 
|  | } | 
|  |  | 
|  | /*!*************************************************************************** | 
|  | @Function			SetUV | 
|  | @Modified			UVs | 
|  | @Input				index | 
|  | @Input				u | 
|  | @Input				v | 
|  | @Description		Writes a texture coordinate in a texture coordinate array | 
|  | *****************************************************************************/ | 
|  | static void SetUV(VERTTYPE** UVs, int index, VERTTYPE u, VERTTYPE v) | 
|  | { | 
|  | (*UVs)[index*2+0] = u; | 
|  | (*UVs)[index*2+1] = v; | 
|  | } | 
|  |  | 
|  | /*!*************************************************************************** | 
|  | @Function		PVRTCreateSkybox | 
|  | @Input			scale			Scale the skybox | 
|  | @Input			adjustUV		Adjust or not UVs for PVRT compression | 
|  | @Input			textureSize		Texture size in pixels | 
|  | @Output		Vertices		Array of vertices | 
|  | @Output		UVs				Array of UVs | 
|  | @Description	Creates the vertices and texture coordinates for a skybox | 
|  | *****************************************************************************/ | 
|  | void PVRTCreateSkybox(float scale, bool adjustUV, int textureSize, VERTTYPE** Vertices, VERTTYPE** UVs) | 
|  | { | 
|  | *Vertices = new VERTTYPE[24*3]; | 
|  | *UVs = new VERTTYPE[24*2]; | 
|  |  | 
|  | VERTTYPE unit = f2vt(1); | 
|  | VERTTYPE a0 = 0, a1 = unit; | 
|  |  | 
|  | if (adjustUV) | 
|  | { | 
|  | VERTTYPE oneover = f2vt(1.0f / textureSize); | 
|  | a0 = VERTTYPEMUL(f2vt(4.0f), oneover); | 
|  | a1 = unit - a0; | 
|  | } | 
|  |  | 
|  | // Front | 
|  | SetVertex(Vertices, 0, -unit, +unit, -unit); | 
|  | SetVertex(Vertices, 1, +unit, +unit, -unit); | 
|  | SetVertex(Vertices, 2, -unit, -unit, -unit); | 
|  | SetVertex(Vertices, 3, +unit, -unit, -unit); | 
|  | SetUV(UVs, 0, a0, a1); | 
|  | SetUV(UVs, 1, a1, a1); | 
|  | SetUV(UVs, 2, a0, a0); | 
|  | SetUV(UVs, 3, a1, a0); | 
|  |  | 
|  | // Right | 
|  | SetVertex(Vertices, 4, +unit, +unit, -unit); | 
|  | SetVertex(Vertices, 5, +unit, +unit, +unit); | 
|  | SetVertex(Vertices, 6, +unit, -unit, -unit); | 
|  | SetVertex(Vertices, 7, +unit, -unit, +unit); | 
|  | SetUV(UVs, 4, a0, a1); | 
|  | SetUV(UVs, 5, a1, a1); | 
|  | SetUV(UVs, 6, a0, a0); | 
|  | SetUV(UVs, 7, a1, a0); | 
|  |  | 
|  | // Back | 
|  | SetVertex(Vertices, 8 , +unit, +unit, +unit); | 
|  | SetVertex(Vertices, 9 , -unit, +unit, +unit); | 
|  | SetVertex(Vertices, 10, +unit, -unit, +unit); | 
|  | SetVertex(Vertices, 11, -unit, -unit, +unit); | 
|  | SetUV(UVs, 8 , a0, a1); | 
|  | SetUV(UVs, 9 , a1, a1); | 
|  | SetUV(UVs, 10, a0, a0); | 
|  | SetUV(UVs, 11, a1, a0); | 
|  |  | 
|  | // Left | 
|  | SetVertex(Vertices, 12, -unit, +unit, +unit); | 
|  | SetVertex(Vertices, 13, -unit, +unit, -unit); | 
|  | SetVertex(Vertices, 14, -unit, -unit, +unit); | 
|  | SetVertex(Vertices, 15, -unit, -unit, -unit); | 
|  | SetUV(UVs, 12, a0, a1); | 
|  | SetUV(UVs, 13, a1, a1); | 
|  | SetUV(UVs, 14, a0, a0); | 
|  | SetUV(UVs, 15, a1, a0); | 
|  |  | 
|  | // Top | 
|  | SetVertex(Vertices, 16, -unit, +unit, +unit); | 
|  | SetVertex(Vertices, 17, +unit, +unit, +unit); | 
|  | SetVertex(Vertices, 18, -unit, +unit, -unit); | 
|  | SetVertex(Vertices, 19, +unit, +unit, -unit); | 
|  | SetUV(UVs, 16, a0, a1); | 
|  | SetUV(UVs, 17, a1, a1); | 
|  | SetUV(UVs, 18, a0, a0); | 
|  | SetUV(UVs, 19, a1, a0); | 
|  |  | 
|  | // Bottom | 
|  | SetVertex(Vertices, 20, -unit, -unit, -unit); | 
|  | SetVertex(Vertices, 21, +unit, -unit, -unit); | 
|  | SetVertex(Vertices, 22, -unit, -unit, +unit); | 
|  | SetVertex(Vertices, 23, +unit, -unit, +unit); | 
|  | SetUV(UVs, 20, a0, a1); | 
|  | SetUV(UVs, 21, a1, a1); | 
|  | SetUV(UVs, 22, a0, a0); | 
|  | SetUV(UVs, 23, a1, a0); | 
|  |  | 
|  | for (int i=0; i<24*3; i++) (*Vertices)[i] = VERTTYPEMUL((*Vertices)[i], f2vt(scale)); | 
|  | } | 
|  |  | 
|  | /*!*************************************************************************** | 
|  | @Function		PVRTDestroySkybox | 
|  | @Input			Vertices	Vertices array to destroy | 
|  | @Input			UVs			UVs array to destroy | 
|  | @Description	Destroy the memory allocated for a skybox | 
|  | *****************************************************************************/ | 
|  | void PVRTDestroySkybox(VERTTYPE* Vertices, VERTTYPE* UVs) | 
|  | { | 
|  | delete [] Vertices; | 
|  | delete [] UVs; | 
|  | } | 
|  |  | 
|  | /*!*************************************************************************** | 
|  | @Function		PVRTGetPOTHigher | 
|  | @Input			uiOriginalValue	Base value | 
|  | @Input			iTimesHigher		Multiplier | 
|  | @Description	When iTimesHigher is one, this function will return the closest | 
|  | power-of-two value above the base value. | 
|  | For every increment beyond one for the iTimesHigher value, | 
|  | the next highest power-of-two value will be calculated. | 
|  | *****************************************************************************/ | 
|  | unsigned int PVRTGetPOTHigher(unsigned int uiOriginalValue, int iTimesHigher) | 
|  | { | 
|  | if(uiOriginalValue == 0 || iTimesHigher < 0) | 
|  | { | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | unsigned int uiSize = 1; | 
|  | while (uiSize < uiOriginalValue) uiSize *= 2; | 
|  |  | 
|  | // Keep increasing the POT value until the iTimesHigher value has been met | 
|  | for(int i = 1 ; i < iTimesHigher; ++i) | 
|  | { | 
|  | uiSize *= 2; | 
|  | } | 
|  |  | 
|  | return uiSize; | 
|  | } | 
|  |  | 
|  | /*!*************************************************************************** | 
|  | @Function		PVRTGetPOTLower | 
|  | @Input			uiOriginalValue	Base value | 
|  | @Input			iTimesLower		Multiplier | 
|  | @Description	When iTimesLower is one, this function will return the closest | 
|  | power-of-two value below the base value. | 
|  | For every increment beyond one for the iTimesLower value, | 
|  | the next lowest power-of-two value will be calculated. The lowest | 
|  | value that can be reached is 1. | 
|  | *****************************************************************************/ | 
|  | // NOTE: This function should be optimised | 
|  | unsigned int PVRTGetPOTLower(unsigned int uiOriginalValue, int iTimesLower) | 
|  | { | 
|  | if(uiOriginalValue == 0 || iTimesLower < 0) | 
|  | { | 
|  | return 0; | 
|  | } | 
|  | unsigned int uiSize = PVRTGetPOTHigher(uiOriginalValue,1); | 
|  | uiSize >>= 1;//uiSize /=2; | 
|  |  | 
|  | for(int i = 1; i < iTimesLower; ++i) | 
|  | { | 
|  | uiSize >>= 1;//uiSize /=2; | 
|  | if(uiSize == 1) | 
|  | { | 
|  | // Lowest possible value has been reached, so break | 
|  | break; | 
|  | } | 
|  | } | 
|  | return uiSize; | 
|  | } | 
|  |  | 
|  |  | 
|  |  | 
|  | /***************************************************************************** | 
|  | End of file (PVRTMisc.cpp) | 
|  | *****************************************************************************/ | 
|  |  |