/* ================= R_CreateShadowVolumeInFrustum Adds new verts and indexes to the shadow volume. If the frustum completely defines the projected light, makeClippedPlanes should be true, which will cause sil quads to be added along all clipped edges. If the frustum is just part of a point light, clipped planes don't need to be added. ================= */ static void R_CreateShadowVolumeInFrustum( const idRenderEntityLocal *ent, const srfTriangles_t *tri, const idRenderLightLocal *light, const idVec3 lightOrigin, const idPlane frustum[6], const idPlane &farPlane, bool makeClippedPlanes ) { int i; int numTris; unsigned short *pointCull; int numCapIndexes; int firstShadowIndex; int firstShadowVert; int cullBits; pointCull = (unsigned short *)_alloca16( tri->numVerts * sizeof( pointCull[0] ) ); // test the vertexes for inside the light frustum, which will allow // us to completely cull away some triangles from consideration. R_CalcPointCull( tri, frustum, pointCull ); // this may not be the first frustum added to the volume firstShadowIndex = numShadowIndexes; firstShadowVert = numShadowVerts; // decide which triangles front shadow volumes, clipping as needed int numFace = 0; numClipSilEdges = 0; numTris = tri->numIndexes / 3; for ( i = 0 ; i < numTris ; i++ ) { int i1, i2, i3; faceCastsShadow[i] = 0; // until shown otherwise // if it isn't facing the right way, don't add it // to the shadow volume if ( globalFacing[i] ) { continue; } ++numFace; i1 = tri->silIndexes[ i*3 + 0 ]; i2 = tri->silIndexes[ i*3 + 1 ]; i3 = tri->silIndexes[ i*3 + 2 ]; // if all the verts are off one side of the frustum, // don't add any of them if ( TRIANGLE_CULLED( i1, i2, i3 ) ) { continue; } // make sure the verts that are not on the negative sides // of the frustum are copied over. // we need to get the original verts even from clipped triangles // so the edges reference correctly, because an edge may be unclipped // even when a triangle is clipped. if ( numShadowVerts + 6 > MAX_SHADOW_VERTS ) { overflowed = true; return; } if ( !POINT_CULLED(i1) && remap[i1] == -1 ) { remap[i1] = numShadowVerts; shadowVerts[ numShadowVerts ].ToVec3() = tri->verts[i1].xyz; numShadowVerts+=2; } if ( !POINT_CULLED(i2) && remap[i2] == -1 ) { remap[i2] = numShadowVerts; shadowVerts[ numShadowVerts ].ToVec3() = tri->verts[i2].xyz; numShadowVerts+=2; } if ( !POINT_CULLED(i3) && remap[i3] == -1 ) { remap[i3] = numShadowVerts; shadowVerts[ numShadowVerts ].ToVec3() = tri->verts[i3].xyz; numShadowVerts+=2; } // clip the triangle if any points are on the negative sides if ( TRIANGLE_CLIPPED( i1, i2, i3 ) ) { cullBits = ( ( pointCull[ i1 ] ^ 0xfc0 ) | ( pointCull[ i2 ] ^ 0xfc0 ) | ( pointCull[ i3 ] ^ 0xfc0 ) ) >> 6; // this will also define clip edges that will become // silhouette planes if ( R_ClipTriangleToLight( tri->verts[i1].xyz, tri->verts[i2].xyz, tri->verts[i3].xyz, cullBits, frustum ) ) { faceCastsShadow[i] = 1; } } else { // instead of overflowing or drawing a streamer shadow, don't draw a shadow at all if ( numShadowIndexes + 3 > MAX_SHADOW_INDEXES ) { overflowed = true; return; } if ( remap[i1] == -1 || remap[i2] == -1 || remap[i3] == -1 ) { common->Error( "R_CreateShadowVolumeInFrustum: bad remap[]" ); } shadowIndexes[numShadowIndexes++] = remap[i3]; shadowIndexes[numShadowIndexes++] = remap[i2]; shadowIndexes[numShadowIndexes++] = remap[i1]; faceCastsShadow[i] = 1; } }
/* ==================== 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; }