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