PVRTMisc.cpp 14 KB

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