Home | History | Annotate | Download | only in Tools
      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 ****************************************************************************/
     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 ****************************************************************************/
    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 ****************************************************************************/
    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 ****************************************************************************/
    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 *************************************************************************/
    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 *************************************************************************/
    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 *************************************************************************/
    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 *************************************************************************/
    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 *************************************************************************/
    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 *************************************************************************/
    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 *************************************************************************/
    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 *************************************************************************/
    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 *************************************************************************/
    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 *************************************************************************/
    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 *************************************************************************/
   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 *************************************************************************/
   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 *************************************************************************/
   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 *************************************************************************/
   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