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