/* ==================== R_CreateLightTris The resulting surface will be a subset of the original triangles, it will never clip triangles, but it may cull on a per-triangle basis. ==================== */ static srfTriangles_t *R_CreateLightTris( const idRenderEntityLocal *ent, const srfTriangles_t *tri, const idRenderLightLocal *light, const idMaterial *shader, srfCullInfo_t &cullInfo ) { int i; int numIndexes; glIndex_t *indexes; srfTriangles_t *newTri; int c_backfaced; int c_distance; idBounds bounds; bool includeBackFaces; int faceNum; tr.pc.c_createLightTris++; c_backfaced = 0; c_distance = 0; numIndexes = 0; indexes = NULL; // it is debatable if non-shadowing lights should light back faces. we aren't at the moment if ( r_lightAllBackFaces.GetBool() || light->lightShader->LightEffectsBackSides() || shader->ReceivesLightingOnBackSides() || ent->parms.noSelfShadow || ent->parms.noShadow ) { includeBackFaces = true; } else { includeBackFaces = false; } // allocate a new surface for the lit triangles newTri = R_AllocStaticTriSurf(); // save a reference to the original surface newTri->ambientSurface = const_cast<srfTriangles_t *>(tri); // the light surface references the verts of the ambient surface newTri->numVerts = tri->numVerts; R_ReferenceStaticTriSurfVerts( newTri, tri ); // calculate cull information if ( !includeBackFaces ) { R_CalcInteractionFacing( ent, tri, light, cullInfo ); } R_CalcInteractionCullBits( ent, tri, light, cullInfo ); // if the surface is completely inside the light frustum if ( cullInfo.cullBits == LIGHT_CULL_ALL_FRONT ) { // if we aren't self shadowing, let back facing triangles get // through so the smooth shaded bump maps light all the way around if ( includeBackFaces ) { // the whole surface is lit so the light surface just references the indexes of the ambient surface R_ReferenceStaticTriSurfIndexes( newTri, tri ); numIndexes = tri->numIndexes; bounds = tri->bounds; } else { // the light tris indexes are going to be a subset of the original indexes so we generally // allocate too much memory here but we decrease the memory block when the number of indexes is known R_AllocStaticTriSurfIndexes( newTri, tri->numIndexes ); // back face cull the individual triangles indexes = newTri->indexes; const byte *facing = cullInfo.facing; for ( faceNum = i = 0; i < tri->numIndexes; i += 3, faceNum++ ) { if ( !facing[ faceNum ] ) { c_backfaced++; continue; } indexes[numIndexes+0] = tri->indexes[i+0]; indexes[numIndexes+1] = tri->indexes[i+1]; indexes[numIndexes+2] = tri->indexes[i+2]; numIndexes += 3; } // get bounds for the surface SIMDProcessor->MinMax( bounds[0], bounds[1], tri->verts, indexes, numIndexes ); // decrease the size of the memory block to the size of the number of used indexes R_ResizeStaticTriSurfIndexes( newTri, numIndexes ); } } else { // the light tris indexes are going to be a subset of the original indexes so we generally // allocate too much memory here but we decrease the memory block when the number of indexes is known R_AllocStaticTriSurfIndexes( newTri, tri->numIndexes ); // cull individual triangles indexes = newTri->indexes; const byte *facing = cullInfo.facing; const byte *cullBits = cullInfo.cullBits; for ( faceNum = i = 0; i < tri->numIndexes; i += 3, faceNum++ ) { int i1, i2, i3; // if we aren't self shadowing, let back facing triangles get // through so the smooth shaded bump maps light all the way around if ( !includeBackFaces ) { // back face cull if ( !facing[ faceNum ] ) { c_backfaced++; continue; } } i1 = tri->indexes[i+0]; i2 = tri->indexes[i+1]; i3 = tri->indexes[i+2]; // fast cull outside the frustum // if all three points are off one plane side, it definately isn't visible if ( cullBits[i1] & cullBits[i2] & cullBits[i3] ) { c_distance++; continue; } if ( r_usePreciseTriangleInteractions.GetBool() ) { // do a precise clipped cull if none of the points is completely inside the frustum // note that we do not actually use the clipped triangle, which would have Z fighting issues. if ( cullBits[i1] && cullBits[i2] && cullBits[i3] ) { int cull = cullBits[i1] | cullBits[i2] | cullBits[i3]; if ( !R_ClipTriangleToLight( tri->verts[i1].xyz, tri->verts[i2].xyz, tri->verts[i3].xyz, cull, cullInfo.localClipPlanes ) ) { continue; } } } // add to the list indexes[numIndexes+0] = i1; indexes[numIndexes+1] = i2; indexes[numIndexes+2] = i3; numIndexes += 3; } // get bounds for the surface SIMDProcessor->MinMax( bounds[0], bounds[1], tri->verts, indexes, numIndexes ); // decrease the size of the memory block to the size of the number of used indexes R_ResizeStaticTriSurfIndexes( newTri, numIndexes ); } if ( !numIndexes ) { R_ReallyFreeStaticTriSurf( newTri ); return NULL; } newTri->numIndexes = numIndexes; newTri->bounds = bounds; return newTri; }
/* ===================== R_CreateInteractionShadowVolume Note that dangling edges outside the light frustum don't make silhouette planes because a triangle outside the light frustum is considered facing and the "fake triangle" on the outside of the dangling edge is also set to facing: cullInfo.facing[numFaces] = 1; ===================== */ static srfTriangles_t *R_CreateInteractionShadowVolume( const idRenderEntityLocal * ent, const srfTriangles_t * tri, const idRenderLightLocal * light ) { SCOPED_PROFILE_EVENT( "R_CreateInteractionShadowVolume" ); srfCullInfo_t cullInfo = {}; R_CalcInteractionFacing( ent, tri, light, cullInfo ); R_CalcInteractionCullBits( ent, tri, light, cullInfo ); int numFaces = tri->numIndexes / 3; int numShadowingFaces = 0; const byte * facing = cullInfo.facing; // if all the triangles are inside the light frustum if ( cullInfo.cullBits == LIGHT_CULL_ALL_FRONT ) { // count the number of shadowing faces for ( int i = 0; i < numFaces; i++ ) { numShadowingFaces += facing[i]; } numShadowingFaces = numFaces - numShadowingFaces; } else { // make all triangles that are outside the light frustum "facing", so they won't cast shadows const triIndex_t * indexes = tri->indexes; byte *modifyFacing = cullInfo.facing; const byte *cullBits = cullInfo.cullBits; for ( int i = 0, j = 0; i < tri->numIndexes; i += 3, j++ ) { if ( !modifyFacing[j] ) { int i1 = indexes[i+0]; int i2 = indexes[i+1]; int i3 = indexes[i+2]; if ( cullBits[i1] & cullBits[i2] & cullBits[i3] ) { modifyFacing[j] = 1; } else { numShadowingFaces++; } } } } if ( !numShadowingFaces ) { // no faces are inside the light frustum and still facing the right way R_FreeInteractionCullInfo( cullInfo ); return NULL; } // shadowVerts will be NULL on these surfaces, so the shadowVerts will be taken from the ambient surface srfTriangles_t * newTri = R_AllocStaticTriSurf(); newTri->numVerts = tri->numVerts * 2; // alloc the max possible size R_AllocStaticTriSurfIndexes( newTri, ( numShadowingFaces + tri->numSilEdges ) * 6 ); triIndex_t * tempIndexes = newTri->indexes; triIndex_t * shadowIndexes = newTri->indexes; // create new triangles along sil planes const silEdge_t * sil = tri->silEdges; for ( int i = tri->numSilEdges; i > 0; i--, sil++ ) { int f1 = facing[sil->p1]; int f2 = facing[sil->p2]; if ( !( f1 ^ f2 ) ) { continue; } int v1 = sil->v1 << 1; int v2 = sil->v2 << 1; // set the two triangle winding orders based on facing // without using a poorly-predictable branch shadowIndexes[0] = v1; shadowIndexes[1] = v2 ^ f1; shadowIndexes[2] = v2 ^ f2; shadowIndexes[3] = v1 ^ f2; shadowIndexes[4] = v1 ^ f1; shadowIndexes[5] = v2 ^ 1; shadowIndexes += 6; } int numShadowIndexes = shadowIndexes - tempIndexes; // we aren't bothering to separate front and back caps on these newTri->numIndexes = newTri->numShadowIndexesNoFrontCaps = numShadowIndexes + numShadowingFaces * 6; newTri->numShadowIndexesNoCaps = numShadowIndexes; newTri->shadowCapPlaneBits = SHADOW_CAP_INFINITE; // decrease the size of the memory block to only store the used indexes // R_ResizeStaticTriSurfIndexes( newTri, newTri->numIndexes ); // these have no effect, because they extend to infinity newTri->bounds.Clear(); // put some faces on the model and some on the distant projection const triIndex_t * indexes = tri->indexes; shadowIndexes = newTri->indexes + numShadowIndexes; for ( int i = 0, j = 0; i < tri->numIndexes; i += 3, j++ ) { if ( facing[j] ) { continue; } int i0 = indexes[i+0] << 1; int i1 = indexes[i+1] << 1; int i2 = indexes[i+2] << 1; shadowIndexes[0] = i2; shadowIndexes[1] = i1; shadowIndexes[2] = i0; shadowIndexes[3] = i0 ^ 1; shadowIndexes[4] = i1 ^ 1; shadowIndexes[5] = i2 ^ 1; shadowIndexes += 6; } R_FreeInteractionCullInfo( cullInfo ); return newTri; }
/* ===================== R_CreateVertexProgramTurboShadowVolume are dangling edges that are outside the light frustum still making planes? ===================== */ srfTriangles_t *R_CreateVertexProgramTurboShadowVolume( const idRenderEntityLocal *ent, const srfTriangles_t *tri, const idRenderLightLocal *light, srfCullInfo_t &cullInfo ) { int i, j; srfTriangles_t *newTri; silEdge_t *sil; const glIndex_t *indexes; const byte *facing; R_CalcInteractionFacing( ent, tri, light, cullInfo ); if ( r_useShadowProjectedCull.GetBool() ) { R_CalcInteractionCullBits( ent, tri, light, cullInfo ); } int numFaces = tri->numIndexes / 3; int numShadowingFaces = 0; facing = cullInfo.facing; // if all the triangles are inside the light frustum if ( cullInfo.cullBits == LIGHT_CULL_ALL_FRONT || !r_useShadowProjectedCull.GetBool() ) { // count the number of shadowing faces for ( i = 0; i < numFaces; i++ ) { numShadowingFaces += facing[i]; } numShadowingFaces = numFaces - numShadowingFaces; } else { // make all triangles that are outside the light frustum "facing", so they won't cast shadows indexes = tri->indexes; byte *modifyFacing = cullInfo.facing; const byte *cullBits = cullInfo.cullBits; for ( j = i = 0; i < tri->numIndexes; i += 3, j++ ) { if ( !modifyFacing[j] ) { int i1 = indexes[i+0]; int i2 = indexes[i+1]; int i3 = indexes[i+2]; if ( cullBits[i1] & cullBits[i2] & cullBits[i3] ) { modifyFacing[j] = 1; } else { numShadowingFaces++; } } } } if ( !numShadowingFaces ) { // no faces are inside the light frustum and still facing the right way return NULL; } // shadowVerts will be NULL on these surfaces, so the shadowVerts will be taken from the ambient surface newTri = R_AllocStaticTriSurf(); newTri->numVerts = tri->numVerts * 2; // alloc the max possible size #ifdef USE_TRI_DATA_ALLOCATOR R_AllocStaticTriSurfIndexes( newTri, ( numShadowingFaces + tri->numSilEdges ) * 6 ); glIndex_t *tempIndexes = newTri->indexes; glIndex_t *shadowIndexes = newTri->indexes; #else glIndex_t *tempIndexes = (glIndex_t *)_alloca16( tri->numSilEdges * 6 * sizeof( tempIndexes[0] ) ); glIndex_t *shadowIndexes = tempIndexes; #endif // create new triangles along sil planes for ( sil = tri->silEdges, i = tri->numSilEdges; i > 0; i--, sil++ ) { int f1 = facing[sil->p1]; int f2 = facing[sil->p2]; if ( !( f1 ^ f2 ) ) { continue; } int v1 = sil->v1 << 1; int v2 = sil->v2 << 1; // set the two triangle winding orders based on facing // without using a poorly-predictable branch shadowIndexes[0] = v1; shadowIndexes[1] = v2 ^ f1; shadowIndexes[2] = v2 ^ f2; shadowIndexes[3] = v1 ^ f2; shadowIndexes[4] = v1 ^ f1; shadowIndexes[5] = v2 ^ 1; shadowIndexes += 6; } int numShadowIndexes = shadowIndexes - tempIndexes; // we aren't bothering to separate front and back caps on these newTri->numIndexes = newTri->numShadowIndexesNoFrontCaps = numShadowIndexes + numShadowingFaces * 6; newTri->numShadowIndexesNoCaps = numShadowIndexes; newTri->shadowCapPlaneBits = SHADOW_CAP_INFINITE; #ifdef USE_TRI_DATA_ALLOCATOR // decrease the size of the memory block to only store the used indexes R_ResizeStaticTriSurfIndexes( newTri, newTri->numIndexes ); #else // allocate memory for the indexes R_AllocStaticTriSurfIndexes( newTri, newTri->numIndexes ); // copy the indexes we created for the sil planes SIMDProcessor->Memcpy( newTri->indexes, tempIndexes, numShadowIndexes * sizeof( tempIndexes[0] ) ); #endif // these have no effect, because they extend to infinity newTri->bounds.Clear(); // put some faces on the model and some on the distant projection indexes = tri->indexes; shadowIndexes = newTri->indexes + numShadowIndexes; for ( i = 0, j = 0; i < tri->numIndexes; i += 3, j++ ) { if ( facing[j] ) { continue; } int i0 = indexes[i+0] << 1; shadowIndexes[2] = i0; shadowIndexes[3] = i0 ^ 1; int i1 = indexes[i+1] << 1; shadowIndexes[1] = i1; shadowIndexes[4] = i1 ^ 1; int i2 = indexes[i+2] << 1; shadowIndexes[0] = i2; shadowIndexes[5] = i2 ^ 1; shadowIndexes += 6; } return newTri; }
/* ==================== R_CreateInteractionLightTris This is only used for the static interaction case, dynamic interactions just draw everything and let the GPU deal with it. The resulting surface will be a subset of the original triangles, it will never clip triangles, but it may cull on a per-triangle basis. ==================== */ static srfTriangles_t* R_CreateInteractionLightTris( const idRenderEntityLocal* ent, const srfTriangles_t* tri, const idRenderLightLocal* light, const idMaterial* shader ) { SCOPED_PROFILE_EVENT( "R_CreateInteractionLightTris" ); int i; int numIndexes; triIndex_t* indexes; srfTriangles_t* newTri; int c_backfaced; int c_distance; idBounds bounds; bool includeBackFaces; int faceNum; c_backfaced = 0; c_distance = 0; numIndexes = 0; indexes = NULL; // it is debatable if non-shadowing lights should light back faces. we aren't at the moment // RB: now we do with r_useHalfLambert, so don't cull back faces if we have smooth shadowing enabled if( r_lightAllBackFaces.GetBool() || light->lightShader->LightEffectsBackSides() || shader->ReceivesLightingOnBackSides() || ent->parms.noSelfShadow || ent->parms.noShadow || ( r_useHalfLambertLighting.GetInteger() && r_useShadowMapping.GetBool() ) ) { includeBackFaces = true; } else { includeBackFaces = false; } // allocate a new surface for the lit triangles newTri = R_AllocStaticTriSurf(); // save a reference to the original surface newTri->ambientSurface = const_cast<srfTriangles_t*>( tri ); // the light surface references the verts of the ambient surface newTri->numVerts = tri->numVerts; R_ReferenceStaticTriSurfVerts( newTri, tri ); // calculate cull information srfCullInfo_t cullInfo = {}; if( !includeBackFaces ) { R_CalcInteractionFacing( ent, tri, light, cullInfo ); } R_CalcInteractionCullBits( ent, tri, light, cullInfo ); // if the surface is completely inside the light frustum if( cullInfo.cullBits == LIGHT_CULL_ALL_FRONT ) { // if we aren't self shadowing, let back facing triangles get // through so the smooth shaded bump maps light all the way around if( includeBackFaces ) { // the whole surface is lit so the light surface just references the indexes of the ambient surface newTri->indexes = tri->indexes; newTri->indexCache = tri->indexCache; // R_ReferenceStaticTriSurfIndexes( newTri, tri ); numIndexes = tri->numIndexes; bounds = tri->bounds; } else { // the light tris indexes are going to be a subset of the original indexes so we generally // allocate too much memory here but we decrease the memory block when the number of indexes is known R_AllocStaticTriSurfIndexes( newTri, tri->numIndexes ); // back face cull the individual triangles indexes = newTri->indexes; const byte* facing = cullInfo.facing; for( faceNum = i = 0; i < tri->numIndexes; i += 3, faceNum++ ) { if( !facing[ faceNum ] ) { c_backfaced++; continue; } indexes[numIndexes + 0] = tri->indexes[i + 0]; indexes[numIndexes + 1] = tri->indexes[i + 1]; indexes[numIndexes + 2] = tri->indexes[i + 2]; numIndexes += 3; } // get bounds for the surface SIMDProcessor->MinMax( bounds[0], bounds[1], tri->verts, indexes, numIndexes ); // decrease the size of the memory block to the size of the number of used indexes newTri->numIndexes = numIndexes; R_ResizeStaticTriSurfIndexes( newTri, numIndexes ); } } else { // the light tris indexes are going to be a subset of the original indexes so we generally // allocate too much memory here but we decrease the memory block when the number of indexes is known R_AllocStaticTriSurfIndexes( newTri, tri->numIndexes ); // cull individual triangles indexes = newTri->indexes; const byte* facing = cullInfo.facing; const byte* cullBits = cullInfo.cullBits; for( faceNum = i = 0; i < tri->numIndexes; i += 3, faceNum++ ) { int i1, i2, i3; // if we aren't self shadowing, let back facing triangles get // through so the smooth shaded bump maps light all the way around if( !includeBackFaces ) { // back face cull if( !facing[ faceNum ] ) { c_backfaced++; continue; } } i1 = tri->indexes[i + 0]; i2 = tri->indexes[i + 1]; i3 = tri->indexes[i + 2]; // fast cull outside the frustum // if all three points are off one plane side, it definately isn't visible if( cullBits[i1] & cullBits[i2] & cullBits[i3] ) { c_distance++; continue; } // add to the list indexes[numIndexes + 0] = i1; indexes[numIndexes + 1] = i2; indexes[numIndexes + 2] = i3; numIndexes += 3; } // get bounds for the surface SIMDProcessor->MinMax( bounds[0], bounds[1], tri->verts, indexes, numIndexes ); // decrease the size of the memory block to the size of the number of used indexes newTri->numIndexes = numIndexes; R_ResizeStaticTriSurfIndexes( newTri, numIndexes ); } // free the cull information when it's no longer needed R_FreeInteractionCullInfo( cullInfo ); if( !numIndexes ) { R_FreeStaticTriSurf( newTri ); return NULL; } newTri->numIndexes = numIndexes; newTri->bounds = bounds; return newTri; }