Home | History | Annotate | Download | only in Tools
      1 /******************************************************************************
      2 
      3  @File         PVRTMisc.cpp
      4 
      5  @Title        PVRTMisc
      6 
      7  @Version
      8 
      9  @Copyright    Copyright (c) Imagination Technologies Limited.
     10 
     11  @Platform     ANSI compatible
     12 
     13  @Description  Miscellaneous functions used in 3D rendering.
     14 
     15 ******************************************************************************/
     16 #include <string.h>
     17 #include <stdlib.h>
     18 #include <ctype.h>
     19 #include <limits.h>
     20 #include <math.h>
     21 #include "PVRTGlobal.h"
     22 #include "PVRTContext.h"
     23 #include "PVRTFixedPoint.h"
     24 #include "PVRTMatrix.h"
     25 #include "PVRTMisc.h"
     26 
     27 
     28 
     29 /*!***************************************************************************
     30  @Function			PVRTMiscCalculateIntersectionLinePlane
     31  @Input				pfPlane			Length 4 [A,B,C,D], values for plane
     32 									equation
     33  @Input				pv0				A point on the line
     34  @Input				pv1				Another point on the line
     35  @Output			pvIntersection	The point of intersection
     36  @Description		Calculates coords of the intersection of a line and an
     37 					infinite plane
     38 *****************************************************************************/
     39 void PVRTMiscCalculateIntersectionLinePlane(
     40 	PVRTVECTOR3			* const pvIntersection,
     41 	const VERTTYPE		pfPlane[4],
     42 	const PVRTVECTOR3	* const pv0,
     43 	const PVRTVECTOR3	* const pv1)
     44 {
     45 	PVRTVECTOR3	vD;
     46 	VERTTYPE fN, fD, fT;
     47 
     48 	/* Calculate vector from point0 to point1 */
     49 	vD.x = pv1->x - pv0->x;
     50 	vD.y = pv1->y - pv0->y;
     51 	vD.z = pv1->z - pv0->z;
     52 
     53 	/* Denominator */
     54 	fD =
     55 		VERTTYPEMUL(pfPlane[0], vD.x) +
     56 		VERTTYPEMUL(pfPlane[1], vD.y) +
     57 		VERTTYPEMUL(pfPlane[2], vD.z);
     58 
     59 	/* Numerator */
     60 	fN =
     61 		VERTTYPEMUL(pfPlane[0], pv0->x) +
     62 		VERTTYPEMUL(pfPlane[1], pv0->y) +
     63 		VERTTYPEMUL(pfPlane[2], pv0->z) +
     64 		pfPlane[3];
     65 
     66 	fT = VERTTYPEDIV(-fN, fD);
     67 
     68 	/* And for a finale, calculate the intersection coordinate */
     69 	pvIntersection->x = pv0->x + VERTTYPEMUL(fT, vD.x);
     70 	pvIntersection->y = pv0->y + VERTTYPEMUL(fT, vD.y);
     71 	pvIntersection->z = pv0->z + VERTTYPEMUL(fT, vD.z);
     72 }
     73 
     74 
     75 /*!***************************************************************************
     76  @Function		PVRTMiscCalculateInfinitePlane
     77  @Input			nStride			Size of each vertex structure containing pfVtx
     78  @Input			pvPlane			Length 4 [A,B,C,D], values for plane equation
     79  @Input			pmViewProjInv	The inverse of the View Projection matrix
     80  @Input			pFrom			Position of the camera
     81  @Input			fFar			Far clipping distance
     82  @Output		pfVtx			Position of the first of 3 floats to receive
     83 								the position of vertex 0; up to 5 vertex positions
     84 								will be written (5 is the maximum number of vertices
     85 								required to draw an infinite polygon clipped to screen
     86 								and far clip plane).
     87  @Returns		Number of vertices in the polygon fan (Can be 0, 3, 4 or 5)
     88  @Description	Calculates world-space coords of a screen-filling
     89 				representation of an infinite plane The resulting vertices run
     90 				counter-clockwise around the screen, and can be simply drawn using
     91 				non-indexed TRIANGLEFAN
     92 *****************************************************************************/
     93 int PVRTMiscCalculateInfinitePlane(
     94 	VERTTYPE			* const pfVtx,
     95 	const int			nStride,
     96 	const PVRTVECTOR4	* const pvPlane,
     97 	const PVRTMATRIX 	* const pmViewProjInv,
     98 	const PVRTVECTOR3	* const pFrom,
     99 	const VERTTYPE		fFar)
    100 {
    101 	PVRTVECTOR3		pvWorld[5];
    102 	PVRTVECTOR3		*pvPolyPtr;
    103 	unsigned int	dwCount;
    104 	bool			bClip;
    105 	int				nVert;
    106 	VERTTYPE		fDotProduct;
    107 
    108 	/*
    109 		Check whether the plane faces the camera
    110 	*/
    111 	fDotProduct =
    112 		VERTTYPEMUL((pFrom->x + VERTTYPEMUL(pvPlane->x, pvPlane->w)), pvPlane->x) +
    113 		VERTTYPEMUL((pFrom->y + VERTTYPEMUL(pvPlane->y, pvPlane->w)), pvPlane->y) +
    114 		VERTTYPEMUL((pFrom->z + VERTTYPEMUL(pvPlane->z, pvPlane->w)), pvPlane->z);
    115 
    116 	if(fDotProduct < 0) {
    117 		/* Camera is behind plane, hence it's not visible */
    118 		return 0;
    119 	}
    120 
    121 	/*
    122 		Back transform front clipping plane into world space,
    123 		to give us a point on the line through each corner of the screen
    124 		(from the camera).
    125 	*/
    126 
    127 	/*             x = -1.0f;    y = -1.0f;     z = 1.0f;      w = 1.0f */
    128 	pvWorld[0].x = VERTTYPEMUL((-pmViewProjInv->f[ 0] - pmViewProjInv->f[ 4] + pmViewProjInv->f[ 8] + pmViewProjInv->f[12]), fFar);
    129 	pvWorld[0].y = VERTTYPEMUL((-pmViewProjInv->f[ 1] - pmViewProjInv->f[ 5] + pmViewProjInv->f[ 9] + pmViewProjInv->f[13]), fFar);
    130 	pvWorld[0].z = VERTTYPEMUL((-pmViewProjInv->f[ 2] - pmViewProjInv->f[ 6] + pmViewProjInv->f[10] + pmViewProjInv->f[14]), fFar);
    131 	/*             x =  1.0f,    y = -1.0f,     z = 1.0f;      w = 1.0f */
    132 	pvWorld[1].x = VERTTYPEMUL(( pmViewProjInv->f[ 0] - pmViewProjInv->f[ 4] + pmViewProjInv->f[ 8] + pmViewProjInv->f[12]), fFar);
    133 	pvWorld[1].y = VERTTYPEMUL(( pmViewProjInv->f[ 1] - pmViewProjInv->f[ 5] + pmViewProjInv->f[ 9] + pmViewProjInv->f[13]), fFar);
    134 	pvWorld[1].z = VERTTYPEMUL(( pmViewProjInv->f[ 2] - pmViewProjInv->f[ 6] + pmViewProjInv->f[10] + pmViewProjInv->f[14]), fFar);
    135 	/*             x =  1.0f,    y =  1.0f,     z = 1.0f;      w = 1.0f */
    136 	pvWorld[2].x = VERTTYPEMUL(( pmViewProjInv->f[ 0] + pmViewProjInv->f[ 4] + pmViewProjInv->f[ 8] + pmViewProjInv->f[12]), fFar);
    137 	pvWorld[2].y = VERTTYPEMUL(( pmViewProjInv->f[ 1] + pmViewProjInv->f[ 5] + pmViewProjInv->f[ 9] + pmViewProjInv->f[13]), fFar);
    138 	pvWorld[2].z = VERTTYPEMUL(( pmViewProjInv->f[ 2] + pmViewProjInv->f[ 6] + pmViewProjInv->f[10] + pmViewProjInv->f[14]), fFar);
    139 	/*             x = -1.0f,    y =  1.0f,     z = 1.0f;      w = 1.0f */
    140 	pvWorld[3].x = VERTTYPEMUL((-pmViewProjInv->f[ 0] + pmViewProjInv->f[ 4] + pmViewProjInv->f[ 8] + pmViewProjInv->f[12]), fFar);
    141 	pvWorld[3].y = VERTTYPEMUL((-pmViewProjInv->f[ 1] + pmViewProjInv->f[ 5] + pmViewProjInv->f[ 9] + pmViewProjInv->f[13]), fFar);
    142 	pvWorld[3].z = VERTTYPEMUL((-pmViewProjInv->f[ 2] + pmViewProjInv->f[ 6] + pmViewProjInv->f[10] + pmViewProjInv->f[14]), fFar);
    143 
    144 	/* We need to do a closed loop of the screen vertices, so copy the first vertex into the last */
    145 	pvWorld[4] = pvWorld[0];
    146 
    147 	/*
    148 		Now build a pre-clipped polygon
    149 	*/
    150 
    151 	/* Lets get ready to loop */
    152 	dwCount		= 0;
    153 	bClip		= false;
    154 	pvPolyPtr	= (PVRTVECTOR3*)pfVtx;
    155 
    156 	nVert = 5;
    157 	while(nVert)
    158 	{
    159 		nVert--;
    160 
    161 		/*
    162 			Check which side of the Plane this corner of the far clipping
    163 			plane is on. [A,B,C] of plane equation is the plane normal, D is
    164 			distance from origin; hence [pvPlane->x * -pvPlane->w,
    165 										 pvPlane->y * -pvPlane->w,
    166 										 pvPlane->z * -pvPlane->w]
    167 			is a point on the plane
    168 		*/
    169 		fDotProduct =
    170 			VERTTYPEMUL((pvWorld[nVert].x + VERTTYPEMUL(pvPlane->x, pvPlane->w)), pvPlane->x) +
    171 			VERTTYPEMUL((pvWorld[nVert].y + VERTTYPEMUL(pvPlane->y, pvPlane->w)), pvPlane->y) +
    172 			VERTTYPEMUL((pvWorld[nVert].z + VERTTYPEMUL(pvPlane->z, pvPlane->w)), pvPlane->z);
    173 
    174 		if(fDotProduct < 0)
    175 		{
    176 			/*
    177 				Behind plane; Vertex does NOT need clipping
    178 			*/
    179 			if(bClip == true)
    180 			{
    181 				/* Clipping finished */
    182 				bClip = false;
    183 
    184 				/*
    185 					We've been clipping, so we need to add an additional
    186 					point on the line to this point, where clipping was
    187 					stopped.
    188 				*/
    189 				PVRTMiscCalculateIntersectionLinePlane(pvPolyPtr, &pvPlane->x, &pvWorld[nVert+1], &pvWorld[nVert]);
    190 				pvPolyPtr = (PVRTVECTOR3*)((char*)pvPolyPtr + nStride);
    191 				dwCount++;
    192 			}
    193 
    194 			if(!nVert)
    195 			{
    196 				/* Abort, abort: we've closed the loop with the clipped point */
    197 				break;
    198 			}
    199 
    200 			/* Add the current point */
    201 			PVRTMiscCalculateIntersectionLinePlane(pvPolyPtr, &pvPlane->x, pFrom, &pvWorld[nVert]);
    202 			pvPolyPtr = (PVRTVECTOR3*)((char*)pvPolyPtr + nStride);
    203 			dwCount++;
    204 		}
    205 		else
    206 		{
    207 			/*
    208 				Before plane; Vertex DOES need clipping
    209 			*/
    210 			if(bClip == true)
    211 			{
    212 				/* Already in clipping, skip point */
    213 				continue;
    214 			}
    215 
    216 			/* Clipping initiated */
    217 			bClip = true;
    218 
    219 			/* Don't bother with entry point on first vertex; will take care of it on last vertex (which is a repeat of first vertex) */
    220 			if(nVert != 4)
    221 			{
    222 				/* We need to add an additional point on the line to this point, where clipping was started */
    223 				PVRTMiscCalculateIntersectionLinePlane(pvPolyPtr, &pvPlane->x, &pvWorld[nVert+1], &pvWorld[nVert]);
    224 				pvPolyPtr = (PVRTVECTOR3*)((char*)pvPolyPtr + nStride);
    225 				dwCount++;
    226 			}
    227 		}
    228 	}
    229 
    230 	/* Valid vertex counts are 0, 3, 4, 5 */
    231 	_ASSERT(dwCount <= 5);
    232 	_ASSERT(dwCount != 1);
    233 	_ASSERT(dwCount != 2);
    234 
    235 	return dwCount;
    236 }
    237 
    238 
    239 /*!***************************************************************************
    240  @Function			SetVertex
    241  @Modified			Vertices
    242  @Input				index
    243  @Input				x
    244  @Input				y
    245  @Input				z
    246  @Description		Writes a vertex in a vertex array
    247 *****************************************************************************/
    248 static void SetVertex(VERTTYPE** Vertices, int index, VERTTYPE x, VERTTYPE y, VERTTYPE z)
    249 {
    250 	(*Vertices)[index*3+0] = x;
    251 	(*Vertices)[index*3+1] = y;
    252 	(*Vertices)[index*3+2] = z;
    253 }
    254 
    255 /*!***************************************************************************
    256  @Function			SetUV
    257  @Modified			UVs
    258  @Input				index
    259  @Input				u
    260  @Input				v
    261  @Description		Writes a texture coordinate in a texture coordinate array
    262 *****************************************************************************/
    263 static void SetUV(VERTTYPE** UVs, int index, VERTTYPE u, VERTTYPE v)
    264 {
    265 	(*UVs)[index*2+0] = u;
    266 	(*UVs)[index*2+1] = v;
    267 }
    268 
    269 /*!***************************************************************************
    270  @Function		PVRTCreateSkybox
    271  @Input			scale			Scale the skybox
    272  @Input			adjustUV		Adjust or not UVs for PVRT compression
    273  @Input			textureSize		Texture size in pixels
    274  @Output		Vertices		Array of vertices
    275  @Output		UVs				Array of UVs
    276  @Description	Creates the vertices and texture coordinates for a skybox
    277 *****************************************************************************/
    278 void PVRTCreateSkybox(float scale, bool adjustUV, int textureSize, VERTTYPE** Vertices, VERTTYPE** UVs)
    279 {
    280 	*Vertices = new VERTTYPE[24*3];
    281 	*UVs = new VERTTYPE[24*2];
    282 
    283 	VERTTYPE unit = f2vt(1);
    284 	VERTTYPE a0 = 0, a1 = unit;
    285 
    286 	if (adjustUV)
    287 	{
    288 		VERTTYPE oneover = f2vt(1.0f / textureSize);
    289 		a0 = VERTTYPEMUL(f2vt(4.0f), oneover);
    290 		a1 = unit - a0;
    291 	}
    292 
    293 	// Front
    294 	SetVertex(Vertices, 0, -unit, +unit, -unit);
    295 	SetVertex(Vertices, 1, +unit, +unit, -unit);
    296 	SetVertex(Vertices, 2, -unit, -unit, -unit);
    297 	SetVertex(Vertices, 3, +unit, -unit, -unit);
    298 	SetUV(UVs, 0, a0, a1);
    299 	SetUV(UVs, 1, a1, a1);
    300 	SetUV(UVs, 2, a0, a0);
    301 	SetUV(UVs, 3, a1, a0);
    302 
    303 	// Right
    304 	SetVertex(Vertices, 4, +unit, +unit, -unit);
    305 	SetVertex(Vertices, 5, +unit, +unit, +unit);
    306 	SetVertex(Vertices, 6, +unit, -unit, -unit);
    307 	SetVertex(Vertices, 7, +unit, -unit, +unit);
    308 	SetUV(UVs, 4, a0, a1);
    309 	SetUV(UVs, 5, a1, a1);
    310 	SetUV(UVs, 6, a0, a0);
    311 	SetUV(UVs, 7, a1, a0);
    312 
    313 	// Back
    314 	SetVertex(Vertices, 8 , +unit, +unit, +unit);
    315 	SetVertex(Vertices, 9 , -unit, +unit, +unit);
    316 	SetVertex(Vertices, 10, +unit, -unit, +unit);
    317 	SetVertex(Vertices, 11, -unit, -unit, +unit);
    318 	SetUV(UVs, 8 , a0, a1);
    319 	SetUV(UVs, 9 , a1, a1);
    320 	SetUV(UVs, 10, a0, a0);
    321 	SetUV(UVs, 11, a1, a0);
    322 
    323 	// Left
    324 	SetVertex(Vertices, 12, -unit, +unit, +unit);
    325 	SetVertex(Vertices, 13, -unit, +unit, -unit);
    326 	SetVertex(Vertices, 14, -unit, -unit, +unit);
    327 	SetVertex(Vertices, 15, -unit, -unit, -unit);
    328 	SetUV(UVs, 12, a0, a1);
    329 	SetUV(UVs, 13, a1, a1);
    330 	SetUV(UVs, 14, a0, a0);
    331 	SetUV(UVs, 15, a1, a0);
    332 
    333 	// Top
    334 	SetVertex(Vertices, 16, -unit, +unit, +unit);
    335 	SetVertex(Vertices, 17, +unit, +unit, +unit);
    336 	SetVertex(Vertices, 18, -unit, +unit, -unit);
    337 	SetVertex(Vertices, 19, +unit, +unit, -unit);
    338 	SetUV(UVs, 16, a0, a1);
    339 	SetUV(UVs, 17, a1, a1);
    340 	SetUV(UVs, 18, a0, a0);
    341 	SetUV(UVs, 19, a1, a0);
    342 
    343 	// Bottom
    344 	SetVertex(Vertices, 20, -unit, -unit, -unit);
    345 	SetVertex(Vertices, 21, +unit, -unit, -unit);
    346 	SetVertex(Vertices, 22, -unit, -unit, +unit);
    347 	SetVertex(Vertices, 23, +unit, -unit, +unit);
    348 	SetUV(UVs, 20, a0, a1);
    349 	SetUV(UVs, 21, a1, a1);
    350 	SetUV(UVs, 22, a0, a0);
    351 	SetUV(UVs, 23, a1, a0);
    352 
    353 	for (int i=0; i<24*3; i++) (*Vertices)[i] = VERTTYPEMUL((*Vertices)[i], f2vt(scale));
    354 }
    355 
    356 /*!***************************************************************************
    357  @Function		PVRTDestroySkybox
    358  @Input			Vertices	Vertices array to destroy
    359  @Input			UVs			UVs array to destroy
    360  @Description	Destroy the memory allocated for a skybox
    361 *****************************************************************************/
    362 void PVRTDestroySkybox(VERTTYPE* Vertices, VERTTYPE* UVs)
    363 {
    364 	delete [] Vertices;
    365 	delete [] UVs;
    366 }
    367 
    368 /*!***************************************************************************
    369  @Function		PVRTGetPOTHigher
    370  @Input			uiOriginalValue	Base value
    371  @Input			iTimesHigher		Multiplier
    372  @Description	When iTimesHigher is one, this function will return the closest
    373 				power-of-two value above the base value.
    374 				For every increment beyond one for the iTimesHigher value,
    375 				the next highest power-of-two value will be calculated.
    376 *****************************************************************************/
    377 unsigned int PVRTGetPOTHigher(unsigned int uiOriginalValue, int iTimesHigher)
    378 {
    379 	if(uiOriginalValue == 0 || iTimesHigher < 0)
    380 	{
    381 		return 0;
    382 	}
    383 
    384 	unsigned int uiSize = 1;
    385 	while (uiSize < uiOriginalValue) uiSize *= 2;
    386 
    387 	// Keep increasing the POT value until the iTimesHigher value has been met
    388 	for(int i = 1 ; i < iTimesHigher; ++i)
    389 	{
    390 		uiSize *= 2;
    391 	}
    392 
    393 	return uiSize;
    394 }
    395 
    396 /*!***************************************************************************
    397  @Function		PVRTGetPOTLower
    398  @Input			uiOriginalValue	Base value
    399  @Input			iTimesLower		Multiplier
    400  @Description	When iTimesLower is one, this function will return the closest
    401 				power-of-two value below the base value.
    402 				For every increment beyond one for the iTimesLower value,
    403 				the next lowest power-of-two value will be calculated. The lowest
    404 				value that can be reached is 1.
    405 *****************************************************************************/
    406 // NOTE: This function should be optimised
    407 unsigned int PVRTGetPOTLower(unsigned int uiOriginalValue, int iTimesLower)
    408 {
    409 	if(uiOriginalValue == 0 || iTimesLower < 0)
    410 	{
    411 		return 0;
    412 	}
    413 	unsigned int uiSize = PVRTGetPOTHigher(uiOriginalValue,1);
    414 	uiSize >>= 1;//uiSize /=2;
    415 
    416 	for(int i = 1; i < iTimesLower; ++i)
    417 	{
    418 		uiSize >>= 1;//uiSize /=2;
    419 		if(uiSize == 1)
    420 		{
    421 			// Lowest possible value has been reached, so break
    422 			break;
    423 		}
    424 	}
    425 	return uiSize;
    426 }
    427 
    428 
    429 
    430 /*****************************************************************************
    431  End of file (PVRTMisc.cpp)
    432 *****************************************************************************/
    433 
    434