• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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