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