PVRTShadowVol.cpp 40 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310
  1. /******************************************************************************
  2. @File PVRTShadowVol.cpp
  3. @Title PVRTShadowVol
  4. @Version
  5. @Copyright Copyright (C) Imagination Technologies Limited.
  6. @Platform ANSI compatible
  7. @Description Declarations of functions relating to shadow volume generation.
  8. ******************************************************************************/
  9. #include <stdlib.h>
  10. #include <string.h>
  11. #include "PVRTGlobal.h"
  12. #include "PVRTContext.h"
  13. #include "PVRTFixedPoint.h"
  14. #include "PVRTMatrix.h"
  15. #include "PVRTTrans.h"
  16. #include "PVRTShadowVol.h"
  17. #include "PVRTError.h"
  18. /****************************************************************************
  19. ** Build options
  20. ****************************************************************************/
  21. /****************************************************************************
  22. ** Defines
  23. ****************************************************************************/
  24. /****************************************************************************
  25. ** Macros
  26. ****************************************************************************/
  27. /****************************************************************************
  28. ** Structures
  29. ****************************************************************************/
  30. struct SVertexShVol {
  31. float x, y, z;
  32. unsigned int dwExtrude;
  33. #if defined(BUILD_OGLES)
  34. float fWeight;
  35. #endif
  36. };
  37. /****************************************************************************
  38. ** Constants
  39. ****************************************************************************/
  40. const static unsigned short c_pwLinesHyperCube[64] = {
  41. // Cube0
  42. 0, 1, 2, 3, 0, 2, 1, 3,
  43. 4, 5, 6, 7, 4, 6, 5, 7,
  44. 0, 4, 1, 5, 2, 6, 3, 7,
  45. // Cube1
  46. 8, 9, 10, 11, 8, 10, 9, 11,
  47. 12, 13, 14, 15, 12, 14, 13, 15,
  48. 8, 12, 9, 13, 10, 14, 11, 15,
  49. // Hyper cube jn
  50. 0, 8, 1, 9, 2, 10, 3, 11,
  51. 4, 12, 5, 13, 6, 14, 7, 15
  52. };
  53. const static PVRTVECTOR3 c_pvRect[4] = {
  54. { -1, -1, 1 },
  55. { -1, 1, 1 },
  56. { 1, -1, 1 },
  57. { 1, 1, 1 }
  58. };
  59. /****************************************************************************
  60. ** Shared globals
  61. ****************************************************************************/
  62. /****************************************************************************
  63. ** Globals
  64. ****************************************************************************/
  65. /****************************************************************************
  66. ** Declarations
  67. ****************************************************************************/
  68. /****************************************************************************
  69. ** Code
  70. ****************************************************************************/
  71. /****************************************************************************
  72. @Function FindOrCreateVertex
  73. @Modified psMesh The mesh to check against/add to
  74. @Input pV The vertex to compare/add
  75. @Return unsigned short The array index of the vertex
  76. @Description Searches through the mesh data to see if the vertex has
  77. already been used. If it has, the array index of the vertex
  78. is returned. If the mesh does not already use the vertex,
  79. it is appended to the vertex array and the array count is incremented.
  80. The index in the array of the new vertex is then returned.
  81. ****************************************************************************/
  82. static unsigned short FindOrCreateVertex(PVRTShadowVolShadowMesh * const psMesh, const PVRTVECTOR3 * const pV) {
  83. unsigned short wCurr;
  84. /*
  85. First check whether we already have a vertex here
  86. */
  87. for(wCurr = 0; wCurr < psMesh->nV; wCurr++) {
  88. if(memcmp(&psMesh->pV[wCurr], pV, sizeof(*pV)) == 0) {
  89. /* Don't do anything more if the vertex already exists */
  90. return wCurr;
  91. }
  92. }
  93. /*
  94. Add the vertex then!
  95. */
  96. psMesh->pV[psMesh->nV] = *pV;
  97. return (unsigned short) psMesh->nV++;
  98. }
  99. /****************************************************************************
  100. @Function FindOrCreateEdge
  101. @Modified psMesh The mesh to check against/add to
  102. @Input pv0 The first point that defines the edge
  103. @Input pv1 The second point that defines the edge
  104. @Return PVRTShadowVolMEdge The index of the found/created edge in the
  105. mesh's array
  106. @Description Searches through the mesh data to see if the edge has
  107. already been used. If it has, the array index of the edge
  108. is returned. If the mesh does not already use the edge,
  109. it is appended to the edge array and the array cound is incremented.
  110. The index in the array of the new edge is then returned.
  111. ****************************************************************************/
  112. static PVRTShadowVolMEdge *FindOrCreateEdge(PVRTShadowVolShadowMesh * const psMesh, const PVRTVECTOR3 * const pv0, const PVRTVECTOR3 * const pv1) {
  113. unsigned int nCurr;
  114. unsigned short wV0, wV1;
  115. wV0 = FindOrCreateVertex(psMesh, pv0);
  116. wV1 = FindOrCreateVertex(psMesh, pv1);
  117. /*
  118. First check whether we already have a edge here
  119. */
  120. for(nCurr = 0; nCurr < psMesh->nE; nCurr++) {
  121. if(
  122. (psMesh->pE[nCurr].wV0 == wV0 && psMesh->pE[nCurr].wV1 == wV1) ||
  123. (psMesh->pE[nCurr].wV0 == wV1 && psMesh->pE[nCurr].wV1 == wV0))
  124. {
  125. /* Don't do anything more if the edge already exists */
  126. return &psMesh->pE[nCurr];
  127. }
  128. }
  129. /*
  130. Add the edge then!
  131. */
  132. psMesh->pE[psMesh->nE].wV0 = wV0;
  133. psMesh->pE[psMesh->nE].wV1 = wV1;
  134. psMesh->pE[psMesh->nE].nVis = 0;
  135. return &psMesh->pE[psMesh->nE++];
  136. }
  137. /****************************************************************************
  138. @Function CrossProduct
  139. @Output pvOut The resultant vector
  140. @Input pv0 Vector zero
  141. @Input pv1 Vector one
  142. @Input pv2 Vector two
  143. @Description Finds the vector between vector zero and vector one,
  144. and the vector between vector zero and vector two.
  145. These two resultant vectors are then multiplied together
  146. and the result is assigned to the output vector.
  147. ****************************************************************************/
  148. static void CrossProduct(
  149. PVRTVECTOR3 * const pvOut,
  150. const PVRTVECTOR3 * const pv0,
  151. const PVRTVECTOR3 * const pv1,
  152. const PVRTVECTOR3 * const pv2)
  153. {
  154. PVRTVECTOR3 v0, v1;
  155. v0.x = pv1->x - pv0->x;
  156. v0.y = pv1->y - pv0->y;
  157. v0.z = pv1->z - pv0->z;
  158. v1.x = pv2->x - pv0->x;
  159. v1.y = pv2->y - pv0->y;
  160. v1.z = pv2->z - pv0->z;
  161. PVRTMatrixVec3CrossProduct(*pvOut, v0, v1);
  162. }
  163. /****************************************************************************
  164. @Function FindOrCreateTriangle
  165. @Modified psMesh The mesh to check against/add to
  166. @Input pv0 Vertex zero
  167. @Input pv1 Vertex one
  168. @Input pv2 Vertex two
  169. @Description Searches through the mesh data to see if the triangle has
  170. already been used. If it has, the function returns.
  171. If the mesh does not already use the triangle,
  172. it is appended to the triangle array and the array cound is incremented.
  173. ****************************************************************************/
  174. static void FindOrCreateTriangle(
  175. PVRTShadowVolShadowMesh * const psMesh,
  176. const PVRTVECTOR3 * const pv0,
  177. const PVRTVECTOR3 * const pv1,
  178. const PVRTVECTOR3 * const pv2)
  179. {
  180. unsigned int nCurr;
  181. PVRTShadowVolMEdge *psE0, *psE1, *psE2;
  182. psE0 = FindOrCreateEdge(psMesh, pv0, pv1);
  183. psE1 = FindOrCreateEdge(psMesh, pv1, pv2);
  184. psE2 = FindOrCreateEdge(psMesh, pv2, pv0);
  185. _ASSERT(psE0);
  186. _ASSERT(psE1);
  187. _ASSERT(psE2);
  188. if(psE0 == psE1 || psE1 == psE2 || psE2 == psE0) {
  189. /* Don't add degenerate triangles */
  190. _RPT0(_CRT_WARN, "FindOrCreateTriangle() Degenerate triangle.\n");
  191. return;
  192. }
  193. /*
  194. First check whether we already have a triangle here
  195. */
  196. for(nCurr = 0; nCurr < psMesh->nT; nCurr++) {
  197. if(
  198. (psMesh->pT[nCurr].pE0 == psE0 || psMesh->pT[nCurr].pE0 == psE1 || psMesh->pT[nCurr].pE0 == psE2) &&
  199. (psMesh->pT[nCurr].pE1 == psE0 || psMesh->pT[nCurr].pE1 == psE1 || psMesh->pT[nCurr].pE1 == psE2) &&
  200. (psMesh->pT[nCurr].pE2 == psE0 || psMesh->pT[nCurr].pE2 == psE1 || psMesh->pT[nCurr].pE2 == psE2))
  201. {
  202. /* Don't do anything more if the triangle already exists */
  203. return;
  204. }
  205. }
  206. /*
  207. Add the triangle then!
  208. */
  209. psMesh->pT[psMesh->nT].pE0 = psE0;
  210. psMesh->pT[psMesh->nT].pE1 = psE1;
  211. psMesh->pT[psMesh->nT].pE2 = psE2;
  212. /*
  213. Store the triangle indices; these are indices into the shadow mesh, not the source model indices
  214. */
  215. if(psE0->wV0 == psE1->wV0 || psE0->wV0 == psE1->wV1)
  216. psMesh->pT[psMesh->nT].w[0] = psE0->wV1;
  217. else
  218. psMesh->pT[psMesh->nT].w[0] = psE0->wV0;
  219. if(psE1->wV0 == psE2->wV0 || psE1->wV0 == psE2->wV1)
  220. psMesh->pT[psMesh->nT].w[1] = psE1->wV1;
  221. else
  222. psMesh->pT[psMesh->nT].w[1] = psE1->wV0;
  223. if(psE2->wV0 == psE0->wV0 || psE2->wV0 == psE0->wV1)
  224. psMesh->pT[psMesh->nT].w[2] = psE2->wV1;
  225. else
  226. psMesh->pT[psMesh->nT].w[2] = psE2->wV0;
  227. /* Calculate the triangle normal */
  228. CrossProduct(&psMesh->pT[psMesh->nT].vNormal, pv0, pv1, pv2);
  229. /* Check which edges have the correct winding order for this triangle */
  230. psMesh->pT[psMesh->nT].nWinding = 0;
  231. if(memcmp(&psMesh->pV[psE0->wV0], pv0, sizeof(*pv0)) == 0) psMesh->pT[psMesh->nT].nWinding |= 0x01;
  232. if(memcmp(&psMesh->pV[psE1->wV0], pv1, sizeof(*pv1)) == 0) psMesh->pT[psMesh->nT].nWinding |= 0x02;
  233. if(memcmp(&psMesh->pV[psE2->wV0], pv2, sizeof(*pv2)) == 0) psMesh->pT[psMesh->nT].nWinding |= 0x04;
  234. psMesh->nT++;
  235. }
  236. /*!***********************************************************************
  237. @Function PVRTShadowVolMeshCreateMesh
  238. @Modified psMesh The shadow volume mesh to populate
  239. @Input pVertex A list of vertices
  240. @Input nNumVertex The number of vertices
  241. @Input pFaces A list of faces
  242. @Input nNumFaces The number of faces
  243. @Description Creates a mesh format suitable for generating shadow volumes
  244. *************************************************************************/
  245. void PVRTShadowVolMeshCreateMesh(
  246. PVRTShadowVolShadowMesh * const psMesh,
  247. const float * const pVertex,
  248. const unsigned int nNumVertex,
  249. const unsigned short * const pFaces,
  250. const unsigned int nNumFaces)
  251. {
  252. unsigned int nCurr;
  253. /*
  254. Prep the structure to return
  255. */
  256. memset(psMesh, 0, sizeof(*psMesh));
  257. /*
  258. Allocate some working space to find the unique vertices
  259. */
  260. psMesh->pV = (PVRTVECTOR3*)malloc(nNumVertex * sizeof(*psMesh->pV));
  261. psMesh->pE = (PVRTShadowVolMEdge*)malloc(nNumFaces * sizeof(*psMesh->pE) * 3);
  262. psMesh->pT = (PVRTShadowVolMTriangle*)malloc(nNumFaces * sizeof(*psMesh->pT));
  263. _ASSERT(psMesh->pV);
  264. _ASSERT(psMesh->pE);
  265. _ASSERT(psMesh->pT);
  266. for(nCurr = 0; nCurr < nNumFaces; nCurr++) {
  267. FindOrCreateTriangle(psMesh,
  268. (PVRTVECTOR3*)&pVertex[3 * pFaces[3 * nCurr + 0]],
  269. (PVRTVECTOR3*)&pVertex[3 * pFaces[3 * nCurr + 1]],
  270. (PVRTVECTOR3*)&pVertex[3 * pFaces[3 * nCurr + 2]]);
  271. }
  272. _ASSERT(psMesh->nV <= nNumVertex);
  273. _ASSERT(psMesh->nE < nNumFaces * 3);
  274. _ASSERT(psMesh->nT == nNumFaces);
  275. _RPT2(_CRT_WARN, "Unique vertices : %d (from %d)\n", psMesh->nV, nNumVertex);
  276. _RPT2(_CRT_WARN, "Unique edges : %d (from %d)\n", psMesh->nE, nNumFaces * 3);
  277. _RPT2(_CRT_WARN, "Unique triangles: %d (from %d)\n", psMesh->nT, nNumFaces);
  278. /*
  279. Create the real unique lists
  280. */
  281. psMesh->pV = (PVRTVECTOR3*)realloc(psMesh->pV, psMesh->nV * sizeof(*psMesh->pV));
  282. psMesh->pE = (PVRTShadowVolMEdge*)realloc(psMesh->pE, psMesh->nE * sizeof(*psMesh->pE));
  283. psMesh->pT = (PVRTShadowVolMTriangle*)realloc(psMesh->pT, psMesh->nT * sizeof(*psMesh->pT));
  284. _ASSERT(psMesh->pV);
  285. _ASSERT(psMesh->pE);
  286. _ASSERT(psMesh->pT);
  287. #if defined(_DEBUG) && !defined(_UNICODE) && defined(WIN32)
  288. /*
  289. Check we have sensible model data
  290. */
  291. {
  292. unsigned int nTri, nEdge;
  293. PVRTERROR_OUTPUT_DEBUG("ShadowMeshCreate() Sanity check...");
  294. for(nEdge = 0; nEdge < psMesh->nE; nEdge++) {
  295. nCurr = 0;
  296. for(nTri = 0; nTri < psMesh->nT; nTri++) {
  297. if(psMesh->pT[nTri].pE0 == &psMesh->pE[nEdge])
  298. nCurr++;
  299. if(psMesh->pT[nTri].pE1 == &psMesh->pE[nEdge])
  300. nCurr++;
  301. if(psMesh->pT[nTri].pE2 == &psMesh->pE[nEdge])
  302. nCurr++;
  303. }
  304. /*
  305. Every edge should be referenced exactly twice
  306. */
  307. _ASSERTE(nCurr == 2);
  308. }
  309. PVRTERROR_OUTPUT_DEBUG("done.\n");
  310. }
  311. #endif
  312. }
  313. /*!***********************************************************************
  314. @Function PVRTShadowVolMeshInitMesh
  315. @Input psMesh The shadow volume mesh
  316. @Input pContext A struct for API specific data
  317. @Returns True on success
  318. @Description Init the mesh
  319. *************************************************************************/
  320. bool PVRTShadowVolMeshInitMesh(
  321. PVRTShadowVolShadowMesh * const psMesh,
  322. const SPVRTContext * const pContext)
  323. {
  324. unsigned int nCurr;
  325. #if defined(BUILD_DX9) || defined(BUILD_DX10)
  326. HRESULT hRes;
  327. #endif
  328. SVertexShVol *pvData;
  329. #if defined(BUILD_OGL)
  330. _ASSERT(pContext && pContext->pglExt);
  331. if(!pContext || !pContext->pglExt)
  332. return false;
  333. #endif
  334. #if defined(BUILD_OGLES2) || defined(BUILD_OGLES)
  335. PVRT_UNREFERENCED_PARAMETER(pContext);
  336. #endif
  337. _ASSERT(psMesh);
  338. _ASSERT(psMesh->nV);
  339. _ASSERT(psMesh->nE);
  340. _ASSERT(psMesh->nT);
  341. /*
  342. Allocate a vertex buffer for the shadow volumes
  343. */
  344. _ASSERT(psMesh->pivb == NULL);
  345. _RPT3(_CRT_WARN, "ShadowMeshInitMesh() %5d byte VB (%3dv x 2 x size(%d))\n", psMesh->nV * 2 * sizeof(*pvData), psMesh->nV, sizeof(*pvData));
  346. #if defined(BUILD_DX9)
  347. hRes = pContext->pDev->CreateVertexBuffer(psMesh->nV * 2 * sizeof(*pvData), D3DUSAGE_WRITEONLY, 0, D3DPOOL_DEFAULT, &psMesh->pivb, NULL);
  348. if(FAILED(hRes)) {
  349. _ASSERT(false);
  350. return false;
  351. }
  352. hRes = psMesh->pivb->Lock(0, 0, (void**)&pvData, 0);
  353. if(FAILED(hRes)) {
  354. _ASSERT(false);
  355. return false;
  356. }
  357. #endif
  358. #if defined(BUILD_DX10)
  359. pvData = (SVertexShVol*)psMesh->pivb;
  360. #endif
  361. #if defined(BUILD_OGL) || defined(BUILD_OGLES) || defined(BUILD_OGLES2)
  362. psMesh->pivb = malloc(psMesh->nV * 2 * sizeof(*pvData));
  363. pvData = (SVertexShVol*)psMesh->pivb;
  364. #endif
  365. /*
  366. Fill the vertex buffer with two subtly different copies of the vertices
  367. */
  368. for(nCurr = 0; nCurr < psMesh->nV; ++nCurr) {
  369. pvData[nCurr].x = psMesh->pV[nCurr].x;
  370. pvData[nCurr].y = psMesh->pV[nCurr].y;
  371. pvData[nCurr].z = psMesh->pV[nCurr].z;
  372. pvData[nCurr].dwExtrude = 0;
  373. #if defined(BUILD_OGLES)
  374. pvData[nCurr].fWeight = 1;
  375. pvData[nCurr + psMesh->nV].fWeight = 1;
  376. #endif
  377. pvData[nCurr + psMesh->nV] = pvData[nCurr];
  378. pvData[nCurr + psMesh->nV].dwExtrude = 0x04030201; // Order is wzyx
  379. }
  380. #if defined(BUILD_DX9)
  381. psMesh->pivb->Unlock();
  382. #endif
  383. #if defined(BUILD_DX10)
  384. D3D10_BUFFER_DESC sBufDesc;
  385. sBufDesc.ByteWidth = psMesh->nV * 2 * sizeof(*pvData);
  386. sBufDesc.Usage = D3D10_USAGE_IMMUTABLE;
  387. sBufDesc.BindFlags = D3D10_BIND_VERTEX_BUFFER;
  388. sBufDesc.CPUAccessFlags = 0;
  389. sBufDesc.MiscFlags = 0;
  390. D3D10_SUBRESOURCE_DATA sSRData;
  391. sSRData.pSysMem = pvData;
  392. hRes = pContext->pDev->CreateBuffer(&sBufDesc, &sSRData, &psMesh->pivb);
  393. if(FAILED(hRes))
  394. {
  395. _ASSERT(false);
  396. return false;
  397. }
  398. #endif
  399. return true;
  400. }
  401. /*!***********************************************************************
  402. @Function PVRTShadowVolMeshInitVol
  403. @Modified psVol The shadow volume struct
  404. @Input psMesh The shadow volume mesh
  405. @Input pContext A struct for API specific data
  406. @Returns True on success
  407. @Description Init the renderable shadow volume information.
  408. *************************************************************************/
  409. bool PVRTShadowVolMeshInitVol(
  410. PVRTShadowVolShadowVol * const psVol,
  411. const PVRTShadowVolShadowMesh * const psMesh,
  412. const SPVRTContext * const pContext)
  413. {
  414. #if defined(BUILD_DX9)
  415. HRESULT hRes;
  416. #endif
  417. #if defined(BUILD_OGLES2) || defined(BUILD_OGLES) || defined(BUILD_OGL)
  418. PVRT_UNREFERENCED_PARAMETER(pContext);
  419. #endif
  420. _ASSERT(psVol);
  421. _ASSERT(psMesh);
  422. _ASSERT(psMesh->nV);
  423. _ASSERT(psMesh->nE);
  424. _ASSERT(psMesh->nT);
  425. _RPT1(_CRT_WARN, "ShadowMeshInitVol() %5d byte IB\n", psMesh->nT * 2 * 3 * sizeof(unsigned short));
  426. /*
  427. Allocate a index buffer for the shadow volumes
  428. */
  429. #if defined(_DEBUG)
  430. psVol->nIdxCntMax = psMesh->nT * 2 * 3;
  431. #endif
  432. #if defined(BUILD_DX9)
  433. hRes = pContext->pDev->CreateIndexBuffer(psMesh->nT * 2 * 3 * sizeof(unsigned short),
  434. D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY, D3DFMT_INDEX16, D3DPOOL_DEFAULT, &psVol->piib, NULL);
  435. if(FAILED(hRes)) {
  436. _ASSERT(false);
  437. return false;
  438. }
  439. #endif
  440. #if defined(BUILD_OGL) || defined(BUILD_OGLES) || defined(BUILD_OGLES2)
  441. psVol->piib = (unsigned short*)malloc(psMesh->nT * 2 * 3 * sizeof(unsigned short));
  442. #endif
  443. return true;
  444. }
  445. /*!***********************************************************************
  446. @Function PVRTShadowVolMeshDestroyMesh
  447. @Input psMesh The shadow volume mesh to destroy
  448. @Description Destroys all shadow volume mesh data created by PVRTShadowVolMeshCreateMesh
  449. *************************************************************************/
  450. void PVRTShadowVolMeshDestroyMesh(
  451. PVRTShadowVolShadowMesh * const psMesh)
  452. {
  453. FREE(psMesh->pV);
  454. FREE(psMesh->pE);
  455. FREE(psMesh->pT);
  456. }
  457. /*!***********************************************************************
  458. @Function PVRTShadowVolMeshReleaseMesh
  459. @Input psMesh The shadow volume mesh to release
  460. @Description Releases all shadow volume mesh data created by PVRTShadowVolMeshInitMesh
  461. *************************************************************************/
  462. void PVRTShadowVolMeshReleaseMesh(
  463. PVRTShadowVolShadowMesh * const psMesh)
  464. {
  465. #if defined(BUILD_DX9)
  466. RELEASE(psMesh->pivb);
  467. #endif
  468. #if defined(BUILD_OGL) || defined(BUILD_OGLES) || defined(BUILD_OGLES2)
  469. FREE(psMesh->pivb);
  470. #endif
  471. }
  472. /*!***********************************************************************
  473. @Function PVRTShadowVolMeshReleaseVol
  474. @Input psVol The shadow volume information to release
  475. @Description Releases all data create by PVRTShadowVolMeshInitVol
  476. *************************************************************************/
  477. void PVRTShadowVolMeshReleaseVol(
  478. PVRTShadowVolShadowVol * const psVol)
  479. {
  480. #if defined(BUILD_DX9)
  481. RELEASE(psVol->piib);
  482. #endif
  483. #if defined(BUILD_OGL) || defined(BUILD_OGLES) || defined(BUILD_OGLES2)
  484. FREE(psVol->piib);
  485. #endif
  486. }
  487. /*!***********************************************************************
  488. @Function PVRTShadowVolSilhouetteProjectedBuild
  489. @Modified psVol The shadow volume information
  490. @Input dwVisFlags Shadow volume creation flags
  491. @Input psMesh The shadow volume mesh
  492. @Input pvLightModel The light position/direction
  493. @Input bPointLight Is the light a point light
  494. @Description Using the light set up the shadow volume so it can be extruded.
  495. *************************************************************************/
  496. void PVRTShadowVolSilhouetteProjectedBuild(
  497. PVRTShadowVolShadowVol * const psVol,
  498. const unsigned int dwVisFlags,
  499. const PVRTShadowVolShadowMesh * const psMesh,
  500. const PVRTVec3 * const pvLightModel,
  501. const bool bPointLight)
  502. {
  503. PVRTShadowVolSilhouetteProjectedBuild(psVol, dwVisFlags,psMesh, (PVRTVECTOR3*) pvLightModel, bPointLight);
  504. }
  505. /*!***********************************************************************
  506. @Function PVRTShadowVolSilhouetteProjectedBuild
  507. @Modified psVol The shadow volume information
  508. @Input dwVisFlags Shadow volume creation flags
  509. @Input psMesh The shadow volume mesh
  510. @Input pvLightModel The light position/direction
  511. @Input bPointLight Is the light a point light
  512. @Description Using the light set up the shadow volume so it can be extruded.
  513. *************************************************************************/
  514. void PVRTShadowVolSilhouetteProjectedBuild(
  515. PVRTShadowVolShadowVol * const psVol,
  516. const unsigned int dwVisFlags,
  517. const PVRTShadowVolShadowMesh * const psMesh,
  518. const PVRTVECTOR3 * const pvLightModel,
  519. const bool bPointLight)
  520. {
  521. PVRTVECTOR3 v;
  522. PVRTShadowVolMTriangle *psTri;
  523. PVRTShadowVolMEdge *psEdge;
  524. unsigned short *pwIdx;
  525. #if defined(BUILD_DX9) || defined(BUILD_DX10)
  526. HRESULT hRes;
  527. #endif
  528. unsigned int nCurr;
  529. float f;
  530. /*
  531. Lock the index buffer; this is where we create the shadow volume
  532. */
  533. _ASSERT(psVol && psVol->piib);
  534. #if defined(BUILD_DX9)
  535. hRes = psVol->piib->Lock(0, 0, (void**)&pwIdx, D3DLOCK_DISCARD);
  536. _ASSERT(SUCCEEDED(hRes));
  537. #endif
  538. #if defined(BUILD_OGL) || defined(BUILD_OGLES) || defined(BUILD_OGLES2)
  539. pwIdx = psVol->piib;
  540. #endif
  541. psVol->nIdxCnt = 0;
  542. /*
  543. Run through triangles, testing which face the From point
  544. */
  545. for(nCurr = 0; nCurr < psMesh->nT; nCurr++) {
  546. psTri = &psMesh->pT[nCurr];
  547. if(bPointLight) {
  548. v.x = psMesh->pV[psTri->pE0->wV0].x - pvLightModel->x;
  549. v.y = psMesh->pV[psTri->pE0->wV0].y - pvLightModel->y;
  550. v.z = psMesh->pV[psTri->pE0->wV0].z - pvLightModel->z;
  551. f = PVRTMatrixVec3DotProduct(psTri->vNormal, v);
  552. } else {
  553. f = PVRTMatrixVec3DotProduct(psTri->vNormal, *pvLightModel);
  554. }
  555. if(f >= 0) {
  556. /* Triangle is in the light */
  557. psTri->pE0->nVis |= 0x01;
  558. psTri->pE1->nVis |= 0x01;
  559. psTri->pE2->nVis |= 0x01;
  560. if(dwVisFlags & PVRTSHADOWVOLUME_NEED_CAP_FRONT) {
  561. // Add the triangle to the volume, unextruded.
  562. pwIdx[psVol->nIdxCnt+0] = psTri->w[0];
  563. pwIdx[psVol->nIdxCnt+1] = psTri->w[1];
  564. pwIdx[psVol->nIdxCnt+2] = psTri->w[2];
  565. psVol->nIdxCnt += 3;
  566. }
  567. } else {
  568. /* Triangle is in shade; set Bit3 if the winding order needs reversed */
  569. psTri->pE0->nVis |= 0x02 | (psTri->nWinding & 0x01) << 2;
  570. psTri->pE1->nVis |= 0x02 | (psTri->nWinding & 0x02) << 1;
  571. psTri->pE2->nVis |= 0x02 | (psTri->nWinding & 0x04);
  572. if(dwVisFlags & PVRTSHADOWVOLUME_NEED_CAP_BACK) {
  573. // Add the triangle to the volume, extruded.
  574. // psMesh->nV is used as an offst so that the new index refers to the
  575. // corresponding position in the second array of vertices (which are extruded)
  576. pwIdx[psVol->nIdxCnt+0] = (unsigned short) psMesh->nV + psTri->w[0];
  577. pwIdx[psVol->nIdxCnt+1] = (unsigned short) psMesh->nV + psTri->w[1];
  578. pwIdx[psVol->nIdxCnt+2] = (unsigned short) psMesh->nV + psTri->w[2];
  579. psVol->nIdxCnt += 3;
  580. }
  581. }
  582. }
  583. #if defined(_DEBUG)
  584. _ASSERT(psVol->nIdxCnt <= psVol->nIdxCntMax);
  585. for(nCurr = 0; nCurr < psVol->nIdxCnt; ++nCurr) {
  586. _ASSERT(pwIdx[nCurr] < psMesh->nV*2);
  587. }
  588. #endif
  589. /*
  590. Run through edges, testing which are silhouette edges
  591. */
  592. for(nCurr = 0; nCurr < psMesh->nE; nCurr++) {
  593. psEdge = &psMesh->pE[nCurr];
  594. if((psEdge->nVis & 0x03) == 0x03) {
  595. /*
  596. Silhouette edge found!
  597. The edge is both visible and hidden,
  598. so it is along the silhouette of the model
  599. (See header notes for more info)
  600. */
  601. if(psEdge->nVis & 0x04) {
  602. pwIdx[psVol->nIdxCnt+0] = psEdge->wV0;
  603. pwIdx[psVol->nIdxCnt+1] = psEdge->wV1;
  604. pwIdx[psVol->nIdxCnt+2] = psEdge->wV0 + (unsigned short) psMesh->nV;
  605. pwIdx[psVol->nIdxCnt+3] = psEdge->wV0 + (unsigned short) psMesh->nV;
  606. pwIdx[psVol->nIdxCnt+4] = psEdge->wV1;
  607. pwIdx[psVol->nIdxCnt+5] = psEdge->wV1 + (unsigned short) psMesh->nV;
  608. } else {
  609. pwIdx[psVol->nIdxCnt+0] = psEdge->wV1;
  610. pwIdx[psVol->nIdxCnt+1] = psEdge->wV0;
  611. pwIdx[psVol->nIdxCnt+2] = psEdge->wV1 + (unsigned short) psMesh->nV;
  612. pwIdx[psVol->nIdxCnt+3] = psEdge->wV1 + (unsigned short) psMesh->nV;
  613. pwIdx[psVol->nIdxCnt+4] = psEdge->wV0;
  614. pwIdx[psVol->nIdxCnt+5] = psEdge->wV0 + (unsigned short) psMesh->nV;
  615. }
  616. psVol->nIdxCnt += 6;
  617. }
  618. /* Zero for next render */
  619. psEdge->nVis = 0;
  620. }
  621. #if defined(_DEBUG)
  622. _ASSERT(psVol->nIdxCnt <= psVol->nIdxCntMax);
  623. for(nCurr = 0; nCurr < psVol->nIdxCnt; ++nCurr) {
  624. _ASSERT(pwIdx[nCurr] < psMesh->nV*2);
  625. }
  626. #endif
  627. #if defined(BUILD_DX9)
  628. psVol->piib->Unlock();
  629. #endif
  630. #if defined(BUILD_DX10)
  631. D3D10_BUFFER_DESC sIdxBufferDesc;
  632. sIdxBufferDesc.ByteWidth = psVol->nIdxCnt * sizeof(WORD);
  633. sIdxBufferDesc.Usage = D3D10_USAGE_DEFAULT;
  634. sIdxBufferDesc.BindFlags = D3D10_BIND_INDEX_BUFFER;
  635. sIdxBufferDesc.CPUAccessFlags = 0;
  636. sIdxBufferDesc.MiscFlags = 0;
  637. D3D10_SUBRESOURCE_DATA sIdxBufferData;
  638. ZeroMemory(&sIdxBufferData, sizeof(D3D10_SUBRESOURCE_DATA));
  639. sIdxBufferData.pSysMem = pwIdx;
  640. hRes = pContext->pDev->CreateBuffer(&sIdxBufferDesc, &sIdxBufferData, &psVol->piib));
  641. _ASSERT(SUCCEEDED(hRes));
  642. #endif
  643. }
  644. /*!***********************************************************************
  645. @Function IsBoundingBoxVisibleEx
  646. @Input pBoundingHyperCube The hypercube to test against
  647. @Input fCamZ The camera's position along the z-axis
  648. @Return bool Returns true if the bounding box is visible
  649. @Description This method tests the bounding box's position against
  650. the camera's position to determine if it is visible.
  651. If it is visible, the function returns true.
  652. *************************************************************************/
  653. static bool IsBoundingBoxVisibleEx(
  654. const PVRTVECTOR4 * const pBoundingHyperCube,
  655. const float fCamZ)
  656. {
  657. PVRTVECTOR3 v, vShift[16];
  658. unsigned int dwClipFlags;
  659. int i, j;
  660. unsigned short w0, w1;
  661. dwClipFlags = 0; // Assume all are off-screen
  662. i = 8;
  663. while(i)
  664. {
  665. i--;
  666. if(pBoundingHyperCube[i].x < pBoundingHyperCube[i].w)
  667. dwClipFlags |= 1 << 0;
  668. if(pBoundingHyperCube[i].x > -pBoundingHyperCube[i].w)
  669. dwClipFlags |= 1 << 1;
  670. if(pBoundingHyperCube[i].y < pBoundingHyperCube[i].w)
  671. dwClipFlags |= 1 << 2;
  672. if(pBoundingHyperCube[i].y > -pBoundingHyperCube[i].w)
  673. dwClipFlags |= 1 << 3;
  674. if(pBoundingHyperCube[i].z > 0)
  675. dwClipFlags |= 1 << 4;
  676. }
  677. /*
  678. Volume is hidden if all the vertices are over a screen edge
  679. */
  680. if(dwClipFlags != 0x1F)
  681. return false;
  682. /*
  683. Well, according to the simple bounding box check, it might be
  684. visible. Let's now test the view frustrum against the bounding
  685. cube. (Basically the reverse of the previous test!)
  686. This catches those cases where a diagonal cube passes near a
  687. screen edge.
  688. */
  689. // Subtract the camera position from the vertices. I.e. move the camera to 0,0,0
  690. for(i = 0; i < 8; ++i) {
  691. vShift[i].x = pBoundingHyperCube[i].x;
  692. vShift[i].y = pBoundingHyperCube[i].y;
  693. vShift[i].z = pBoundingHyperCube[i].z - fCamZ;
  694. }
  695. i = 12;
  696. while(i) {
  697. --i;
  698. w0 = c_pwLinesHyperCube[2 * i + 0];
  699. w1 = c_pwLinesHyperCube[2 * i + 1];
  700. PVRTMatrixVec3CrossProduct(v, vShift[w0], vShift[w1]);
  701. dwClipFlags = 0;
  702. j = 4;
  703. while(j) {
  704. --j;
  705. if(PVRTMatrixVec3DotProduct(c_pvRect[j], v) < 0)
  706. ++dwClipFlags;
  707. }
  708. // dwClipFlagsA will be 0 or 4 if the screen edges are on the outside of
  709. // this bounding-box-silhouette-edge.
  710. if(dwClipFlags % 4)
  711. continue;
  712. j = 8;
  713. while(j) {
  714. --j;
  715. if((j != w0) & (j != w1) && (PVRTMatrixVec3DotProduct(vShift[j], v) > 0))
  716. ++dwClipFlags;
  717. }
  718. // dwClipFlagsA will be 0 or 18 if this is a silhouette edge of the bounding box
  719. if(dwClipFlags % 12)
  720. continue;
  721. return false;
  722. }
  723. return true;
  724. }
  725. /*!***********************************************************************
  726. @Function IsHyperBoundingBoxVisibleEx
  727. @Input pBoundingHyperCube The hypercube to test against
  728. @Input fCamZ The camera's position along the z-axis
  729. @Return bool Returns true if the bounding box is visible
  730. @Description This method tests the hypercube bounding box's position against
  731. the camera's position to determine if it is visible.
  732. If it is visible, the function returns true.
  733. *************************************************************************/
  734. static bool IsHyperBoundingBoxVisibleEx(
  735. const PVRTVECTOR4 * const pBoundingHyperCube,
  736. const float fCamZ)
  737. {
  738. const PVRTVECTOR4 *pv0;
  739. PVRTVECTOR3 v, vShift[16];
  740. unsigned int dwClipFlagsA, dwClipFlagsB;
  741. int i, j;
  742. unsigned short w0, w1;
  743. pv0 = &pBoundingHyperCube[8];
  744. dwClipFlagsA = 0; // Assume all are off-screen
  745. dwClipFlagsB = 0;
  746. i = 8;
  747. while(i)
  748. {
  749. i--;
  750. // Far
  751. if(pv0[i].x < pv0[i].w)
  752. dwClipFlagsA |= 1 << 0;
  753. if(pv0[i].x > -pv0[i].w)
  754. dwClipFlagsA |= 1 << 1;
  755. if(pv0[i].y < pv0[i].w)
  756. dwClipFlagsA |= 1 << 2;
  757. if(pv0[i].y > -pv0[i].w)
  758. dwClipFlagsA |= 1 << 3;
  759. if(pv0[i].z > 0)
  760. dwClipFlagsA |= 1 << 4;
  761. // Near
  762. if(pBoundingHyperCube[i].x < pBoundingHyperCube[i].w)
  763. dwClipFlagsB |= 1 << 0;
  764. if(pBoundingHyperCube[i].x > -pBoundingHyperCube[i].w)
  765. dwClipFlagsB |= 1 << 1;
  766. if(pBoundingHyperCube[i].y < pBoundingHyperCube[i].w)
  767. dwClipFlagsB |= 1 << 2;
  768. if(pBoundingHyperCube[i].y > -pBoundingHyperCube[i].w)
  769. dwClipFlagsB |= 1 << 3;
  770. if(pBoundingHyperCube[i].z > 0)
  771. dwClipFlagsB |= 1 << 4;
  772. }
  773. /*
  774. Volume is hidden if all the vertices are over a screen edge
  775. */
  776. if((dwClipFlagsA | dwClipFlagsB) != 0x1F)
  777. return false;
  778. /*
  779. Well, according to the simple bounding box check, it might be
  780. visible. Let's now test the view frustrum against the bounding
  781. hyper cube. (Basically the reverse of the previous test!)
  782. This catches those cases where a diagonal hyper cube passes near a
  783. screen edge.
  784. */
  785. // Subtract the camera position from the vertices. I.e. move the camera to 0,0,0
  786. for(i = 0; i < 16; ++i) {
  787. vShift[i].x = pBoundingHyperCube[i].x;
  788. vShift[i].y = pBoundingHyperCube[i].y;
  789. vShift[i].z = pBoundingHyperCube[i].z - fCamZ;
  790. }
  791. i = 32;
  792. while(i) {
  793. --i;
  794. w0 = c_pwLinesHyperCube[2 * i + 0];
  795. w1 = c_pwLinesHyperCube[2 * i + 1];
  796. PVRTMatrixVec3CrossProduct(v, vShift[w0], vShift[w1]);
  797. dwClipFlagsA = 0;
  798. j = 4;
  799. while(j) {
  800. --j;
  801. if(PVRTMatrixVec3DotProduct(c_pvRect[j], v) < 0)
  802. ++dwClipFlagsA;
  803. }
  804. // dwClipFlagsA will be 0 or 4 if the screen edges are on the outside of
  805. // this bounding-box-silhouette-edge.
  806. if(dwClipFlagsA % 4)
  807. continue;
  808. j = 16;
  809. while(j) {
  810. --j;
  811. if((j != w0) & (j != w1) && (PVRTMatrixVec3DotProduct(vShift[j], v) > 0))
  812. ++dwClipFlagsA;
  813. }
  814. // dwClipFlagsA will be 0 or 18 if this is a silhouette edge of the bounding box
  815. if(dwClipFlagsA % 18)
  816. continue;
  817. return false;
  818. }
  819. return true;
  820. }
  821. /*!***********************************************************************
  822. @Function IsFrontClipInVolume
  823. @Input pBoundingHyperCube The hypercube to test against
  824. @Return bool
  825. @Description Returns true if the hypercube is within the view frustrum.
  826. *************************************************************************/
  827. static bool IsFrontClipInVolume(
  828. const PVRTVECTOR4 * const pBoundingHyperCube)
  829. {
  830. const PVRTVECTOR4 *pv0, *pv1;
  831. unsigned int dwClipFlags;
  832. int i;
  833. float fScale, x, y, w;
  834. /*
  835. OK. The hyper-bounding-box is in the view frustrum.
  836. Now decide if we can use Z-pass instead of Z-fail.
  837. TODO: if we calculate the convex hull of the front-clip intersection
  838. points, we can use the connecting lines to do a more accurate on-
  839. screen check (currently it just uses the bounding box of the
  840. intersection points.)
  841. */
  842. dwClipFlags = 0;
  843. i = 32;
  844. while(i) {
  845. --i;
  846. pv0 = &pBoundingHyperCube[c_pwLinesHyperCube[2 * i + 0]];
  847. pv1 = &pBoundingHyperCube[c_pwLinesHyperCube[2 * i + 1]];
  848. // If both coords are negative, or both coords are positive, it doesn't cross the Z=0 plane
  849. if(pv0->z * pv1->z > 0)
  850. continue;
  851. // TODO: if fScale > 0.5f, do the lerp in the other direction; this is
  852. // because we want fScale to be close to 0, not 1, to retain accuracy.
  853. fScale = (0 - pv0->z) / (pv1->z - pv0->z);
  854. x = fScale * pv1->x + (1.0f - fScale) * pv0->x;
  855. y = fScale * pv1->y + (1.0f - fScale) * pv0->y;
  856. w = fScale * pv1->w + (1.0f - fScale) * pv0->w;
  857. if(x > -w)
  858. dwClipFlags |= 1 << 0;
  859. if(x < w)
  860. dwClipFlags |= 1 << 1;
  861. if(y > -w)
  862. dwClipFlags |= 1 << 2;
  863. if(y < w)
  864. dwClipFlags |= 1 << 3;
  865. }
  866. if(dwClipFlags == 0x0F)
  867. return true;
  868. return false;
  869. }
  870. /*!***********************************************************************
  871. @Function PVRTShadowVolBoundingBoxExtrude
  872. @Modified pvExtrudedCube 8 Vertices to represent the extruded box
  873. @Input pBoundingBox The bounding box to extrude
  874. @Input pvLightMdl The light position/direction
  875. @Input bPointLight Is the light a point light
  876. @Input fVolLength The length the volume has been extruded by
  877. @Description Extrudes the bounding box of the volume
  878. *************************************************************************/
  879. void PVRTShadowVolBoundingBoxExtrude(
  880. PVRTVECTOR3 * const pvExtrudedCube,
  881. const PVRTBOUNDINGBOX * const pBoundingBox,
  882. const PVRTVECTOR3 * const pvLightMdl,
  883. const bool bPointLight,
  884. const float fVolLength)
  885. {
  886. int i;
  887. if(bPointLight) {
  888. i = 8;
  889. while(i)
  890. {
  891. i--;
  892. pvExtrudedCube[i].x = pBoundingBox->Point[i].x + fVolLength * (pBoundingBox->Point[i].x - pvLightMdl->x);
  893. pvExtrudedCube[i].y = pBoundingBox->Point[i].y + fVolLength * (pBoundingBox->Point[i].y - pvLightMdl->y);
  894. pvExtrudedCube[i].z = pBoundingBox->Point[i].z + fVolLength * (pBoundingBox->Point[i].z - pvLightMdl->z);
  895. }
  896. } else {
  897. i = 8;
  898. while(i)
  899. {
  900. i--;
  901. pvExtrudedCube[i].x = pBoundingBox->Point[i].x + fVolLength * pvLightMdl->x;
  902. pvExtrudedCube[i].y = pBoundingBox->Point[i].y + fVolLength * pvLightMdl->y;
  903. pvExtrudedCube[i].z = pBoundingBox->Point[i].z + fVolLength * pvLightMdl->z;
  904. }
  905. }
  906. }
  907. /*!***********************************************************************
  908. @Function PVRTShadowVolBoundingBoxIsVisible
  909. @Modified pdwVisFlags Visibility flags
  910. @Input bObVisible Unused set to true
  911. @Input bNeedsZClipping Unused set to true
  912. @Input pBoundingBox The volumes bounding box
  913. @Input pmTrans The projection matrix
  914. @Input pvLightMdl The light position/direction
  915. @Input bPointLight Is the light a point light
  916. @Input fCamZProj The camera's z projection value
  917. @Input fVolLength The length the volume is extruded by
  918. @Description Determines if the volume is visible and if it needs caps
  919. *************************************************************************/
  920. void PVRTShadowVolBoundingBoxIsVisible(
  921. unsigned int * const pdwVisFlags,
  922. const bool bObVisible, // Is the object visible?
  923. const bool bNeedsZClipping, // Does the object require Z clipping?
  924. const PVRTBOUNDINGBOX * const pBoundingBox,
  925. const PVRTMATRIX * const pmTrans,
  926. const PVRTVECTOR3 * const pvLightMdl,
  927. const bool bPointLight,
  928. const float fCamZProj,
  929. const float fVolLength)
  930. {
  931. PVRTVECTOR3 pvExtrudedCube[8];
  932. PVRTVECTOR4 BoundingHyperCubeT[16];
  933. int i;
  934. unsigned int dwClipFlagsA, dwClipZCnt;
  935. float fLightProjZ;
  936. PVRT_UNREFERENCED_PARAMETER(bObVisible);
  937. PVRT_UNREFERENCED_PARAMETER(bNeedsZClipping);
  938. _ASSERT((bObVisible && bNeedsZClipping) || !bNeedsZClipping);
  939. /*
  940. Transform the eight bounding box points into projection space
  941. */
  942. PVRTTransformVec3Array(&BoundingHyperCubeT[0], sizeof(*BoundingHyperCubeT), pBoundingBox->Point, sizeof(*pBoundingBox->Point), pmTrans, 8);
  943. /*
  944. Get the light Z coordinate in projection space
  945. */
  946. fLightProjZ =
  947. pmTrans->f[ 2] * pvLightMdl->x +
  948. pmTrans->f[ 6] * pvLightMdl->y +
  949. pmTrans->f[10] * pvLightMdl->z +
  950. pmTrans->f[14];
  951. /*
  952. Where is the object relative to the near clip plane and light?
  953. */
  954. dwClipZCnt = 0;
  955. dwClipFlagsA = 0;
  956. i = 8;
  957. while(i) {
  958. --i;
  959. if(BoundingHyperCubeT[i].z <= 0)
  960. ++dwClipZCnt;
  961. if(BoundingHyperCubeT[i].z <= fLightProjZ)
  962. ++dwClipFlagsA;
  963. }
  964. if(dwClipZCnt == 8 && dwClipFlagsA == 8) {
  965. // hidden
  966. *pdwVisFlags = 0;
  967. return;
  968. }
  969. /*
  970. Shadow the bounding box into pvExtrudedCube.
  971. */
  972. PVRTShadowVolBoundingBoxExtrude(pvExtrudedCube, pBoundingBox, pvLightMdl, bPointLight, fVolLength);
  973. /*
  974. Transform to projection space
  975. */
  976. PVRTTransformVec3Array(&BoundingHyperCubeT[8], sizeof(*BoundingHyperCubeT), pvExtrudedCube, sizeof(*pvExtrudedCube), pmTrans, 8);
  977. /*
  978. Check whether any part of the hyper bounding box is even visible
  979. */
  980. if(!IsHyperBoundingBoxVisibleEx(BoundingHyperCubeT, fCamZProj)) {
  981. *pdwVisFlags = 0;
  982. return;
  983. }
  984. /*
  985. It's visible, so choose a render method
  986. */
  987. if(dwClipZCnt == 8) {
  988. // 1
  989. if(IsFrontClipInVolume(BoundingHyperCubeT)) {
  990. *pdwVisFlags = PVRTSHADOWVOLUME_VISIBLE | PVRTSHADOWVOLUME_NEED_ZFAIL;
  991. if(IsBoundingBoxVisibleEx(&BoundingHyperCubeT[8], fCamZProj))
  992. {
  993. *pdwVisFlags |= PVRTSHADOWVOLUME_NEED_CAP_BACK;
  994. }
  995. } else {
  996. *pdwVisFlags = PVRTSHADOWVOLUME_VISIBLE;
  997. }
  998. } else {
  999. if(!(dwClipZCnt | dwClipFlagsA)) {
  1000. // 3
  1001. *pdwVisFlags = PVRTSHADOWVOLUME_VISIBLE;
  1002. } else {
  1003. // 5
  1004. if(IsFrontClipInVolume(BoundingHyperCubeT)) {
  1005. *pdwVisFlags = PVRTSHADOWVOLUME_VISIBLE | PVRTSHADOWVOLUME_NEED_ZFAIL;
  1006. if(IsBoundingBoxVisibleEx(BoundingHyperCubeT, fCamZProj))
  1007. {
  1008. *pdwVisFlags |= PVRTSHADOWVOLUME_NEED_CAP_FRONT;
  1009. }
  1010. if(IsBoundingBoxVisibleEx(&BoundingHyperCubeT[8], fCamZProj))
  1011. {
  1012. *pdwVisFlags |= PVRTSHADOWVOLUME_NEED_CAP_BACK;
  1013. }
  1014. } else {
  1015. *pdwVisFlags = PVRTSHADOWVOLUME_VISIBLE;
  1016. }
  1017. }
  1018. }
  1019. }
  1020. /*!***********************************************************************
  1021. @Function PVRTShadowVolSilhouetteProjectedRender
  1022. @Input psMesh Shadow volume mesh
  1023. @Input psVol Renderable shadow volume information
  1024. @Input pContext A struct for passing in API specific data
  1025. @Description Draws the shadow volume
  1026. *************************************************************************/
  1027. int PVRTShadowVolSilhouetteProjectedRender(
  1028. const PVRTShadowVolShadowMesh * const psMesh,
  1029. const PVRTShadowVolShadowVol * const psVol,
  1030. const SPVRTContext * const pContext)
  1031. {
  1032. #if defined(BUILD_DX9)
  1033. HRESULT hRes;
  1034. _ASSERT(psMesh->pivb);
  1035. pContext->pDev->SetStreamSource(0, psMesh->pivb, 0, sizeof(SVertexShVol));
  1036. pContext->pDev->SetIndices(psVol->piib);
  1037. _ASSERT(psVol->nIdxCnt <= psVol->nIdxCntMax);
  1038. _ASSERT(psVol->nIdxCnt % 3 == 0);
  1039. _ASSERT(psVol->nIdxCnt / 3 <= 0xFFFF);
  1040. hRes = pContext->pDev->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 0, psMesh->nV * 2, 0, psVol->nIdxCnt / 3);
  1041. _ASSERT(SUCCEEDED(hRes));
  1042. return psVol->nIdxCnt / 3;
  1043. #endif
  1044. #if defined(BUILD_OGL) || defined(BUILD_OGLES2) || defined(BUILD_OGLES)
  1045. _ASSERT(psMesh->pivb);
  1046. #if defined(_DEBUG) // To fix error in Linux
  1047. _ASSERT(psVol->nIdxCnt <= psVol->nIdxCntMax);
  1048. _ASSERT(psVol->nIdxCnt % 3 == 0);
  1049. _ASSERT(psVol->nIdxCnt / 3 <= 0xFFFF);
  1050. #endif
  1051. #if defined(BUILD_OGL)
  1052. _ASSERT(pContext && pContext->pglExt);
  1053. pContext->pglExt->glVertexAttribPointerARB(0, 3, GL_FLOAT, GL_FALSE, sizeof(SVertexShVol), &((SVertexShVol*)psMesh->pivb)[0].x);
  1054. pContext->pglExt->glEnableVertexAttribArrayARB(0);
  1055. pContext->pglExt->glVertexAttribPointerARB(1, 4, GL_UNSIGNED_BYTE, GL_FALSE, sizeof(SVertexShVol), &((SVertexShVol*)psMesh->pivb)[0].dwExtrude);
  1056. pContext->pglExt->glEnableVertexAttribArrayARB(1);
  1057. glDrawElements(GL_TRIANGLES, psVol->nIdxCnt, GL_UNSIGNED_SHORT, psVol->piib);
  1058. pContext->pglExt->glDisableVertexAttribArrayARB(0);
  1059. pContext->pglExt->glDisableVertexAttribArrayARB(1);
  1060. return psVol->nIdxCnt / 3;
  1061. #else
  1062. #if defined(BUILD_OGLES2)
  1063. PVRT_UNREFERENCED_PARAMETER(pContext);
  1064. GLint i32CurrentProgram;
  1065. glGetIntegerv(GL_CURRENT_PROGRAM, &i32CurrentProgram);
  1066. _ASSERT(i32CurrentProgram); //no program currently set
  1067. glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(SVertexShVol), &((SVertexShVol*)psMesh->pivb)[0].x);
  1068. glEnableVertexAttribArray(0);
  1069. glVertexAttribPointer(1, 4, GL_UNSIGNED_BYTE, GL_FALSE, sizeof(SVertexShVol), &((SVertexShVol*)psMesh->pivb)[0].dwExtrude);
  1070. glEnableVertexAttribArray(1);
  1071. glDrawElements(GL_TRIANGLES, psVol->nIdxCnt, GL_UNSIGNED_SHORT, psVol->piib);
  1072. glDisableVertexAttribArray(0);
  1073. glDisableVertexAttribArray(1);
  1074. return psVol->nIdxCnt / 3;
  1075. #else
  1076. #if defined(BUILD_OGLES)
  1077. #if defined(__BADA__) && defined(_WIN32)
  1078. return 0; // The bada simulator is missing the matrix palette defines
  1079. #else
  1080. _ASSERT(pContext && pContext->pglesExt);
  1081. glEnableClientState(GL_VERTEX_ARRAY);
  1082. glEnableClientState(GL_MATRIX_INDEX_ARRAY_OES);
  1083. glEnableClientState(GL_WEIGHT_ARRAY_OES);
  1084. glVertexPointer(3, GL_FLOAT, sizeof(SVertexShVol), &((SVertexShVol*)psMesh->pivb)[0].x);
  1085. pContext->pglesExt->glMatrixIndexPointerOES(1, GL_UNSIGNED_BYTE, sizeof(SVertexShVol), &((SVertexShVol*)psMesh->pivb)[0].dwExtrude);
  1086. pContext->pglesExt->glWeightPointerOES(1, GL_FLOAT, sizeof(SVertexShVol), &((SVertexShVol*)psMesh->pivb)[0].fWeight);
  1087. glDrawElements(GL_TRIANGLES, psVol->nIdxCnt, GL_UNSIGNED_SHORT, psVol->piib);
  1088. glDisableClientState(GL_VERTEX_ARRAY);
  1089. glDisableClientState(GL_MATRIX_INDEX_ARRAY_OES);
  1090. glDisableClientState(GL_WEIGHT_ARRAY_OES);
  1091. return psVol->nIdxCnt / 3;
  1092. #endif
  1093. #endif
  1094. #endif
  1095. #endif
  1096. #endif
  1097. }
  1098. /*****************************************************************************
  1099. End of file (PVRTShadowVol.cpp)
  1100. *****************************************************************************/