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 *****************************************************************************/
PVRTMiscCalculateIntersectionLinePlane(PVRTVECTOR3 * const pvIntersection,const VERTTYPE pfPlane[4],const PVRTVECTOR3 * const pv0,const PVRTVECTOR3 * const pv1)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 *****************************************************************************/
PVRTMiscCalculateInfinitePlane(VERTTYPE * const pfVtx,const int nStride,const PVRTVECTOR4 * const pvPlane,const PVRTMATRIX * const pmViewProjInv,const PVRTVECTOR3 * const pFrom,const VERTTYPE fFar)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 *****************************************************************************/
SetVertex(VERTTYPE ** Vertices,int index,VERTTYPE x,VERTTYPE y,VERTTYPE z)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 *****************************************************************************/
SetUV(VERTTYPE ** UVs,int index,VERTTYPE u,VERTTYPE v)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 *****************************************************************************/
PVRTCreateSkybox(float scale,bool adjustUV,int textureSize,VERTTYPE ** Vertices,VERTTYPE ** UVs)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 *****************************************************************************/
PVRTDestroySkybox(VERTTYPE * Vertices,VERTTYPE * UVs)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 *****************************************************************************/
PVRTGetPOTHigher(unsigned int uiOriginalValue,int iTimesHigher)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
PVRTGetPOTLower(unsigned int uiOriginalValue,int iTimesLower)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