/* ==================== 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_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; }