mirror of
https://github.com/dhewm/dhewm3.git
synced 2024-12-11 21:40:49 +00:00
79ad905e05
Excluding 3rd party files.
356 lines
11 KiB
C++
356 lines
11 KiB
C++
/*
|
|
===========================================================================
|
|
|
|
Doom 3 GPL Source Code
|
|
Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
|
|
|
|
This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code").
|
|
|
|
Doom 3 Source Code is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
Doom 3 Source Code is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below.
|
|
|
|
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
|
|
|
|
===========================================================================
|
|
*/
|
|
|
|
#include "../idlib/precompiled.h"
|
|
#pragma hdrstop
|
|
|
|
#include "tr_local.h"
|
|
|
|
int c_turboUsedVerts;
|
|
int c_turboUnusedVerts;
|
|
|
|
|
|
/*
|
|
=====================
|
|
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_CreateTurboShadowVolume
|
|
=====================
|
|
*/
|
|
srfTriangles_t *R_CreateTurboShadowVolume( const idRenderEntityLocal *ent,
|
|
const srfTriangles_t *tri, const idRenderLightLocal *light,
|
|
srfCullInfo_t &cullInfo ) {
|
|
int i, j;
|
|
idVec3 localLightOrigin;
|
|
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;
|
|
}
|
|
|
|
newTri = R_AllocStaticTriSurf();
|
|
|
|
#ifdef USE_TRI_DATA_ALLOCATOR
|
|
R_AllocStaticTriSurfShadowVerts( newTri, tri->numVerts * 2 );
|
|
shadowCache_t *shadowVerts = newTri->shadowVertexes;
|
|
#else
|
|
shadowCache_t *shadowVerts = (shadowCache_t *)_alloca16( tri->numVerts * 2 * sizeof( shadowVerts[0] ) );
|
|
#endif
|
|
|
|
R_GlobalPointToLocal( ent->modelMatrix, light->globalLightOrigin, localLightOrigin );
|
|
|
|
int *vertRemap = (int *)_alloca16( tri->numVerts * sizeof( vertRemap[0] ) );
|
|
|
|
SIMDProcessor->Memset( vertRemap, -1, tri->numVerts * sizeof( vertRemap[0] ) );
|
|
|
|
for ( i = 0, j = 0; i < tri->numIndexes; i += 3, j++ ) {
|
|
if ( facing[j] ) {
|
|
continue;
|
|
}
|
|
// this may pull in some vertexes that are outside
|
|
// the frustum, because they connect to vertexes inside
|
|
vertRemap[tri->silIndexes[i+0]] = 0;
|
|
vertRemap[tri->silIndexes[i+1]] = 0;
|
|
vertRemap[tri->silIndexes[i+2]] = 0;
|
|
}
|
|
|
|
newTri->numVerts = SIMDProcessor->CreateShadowCache( &shadowVerts->xyz, vertRemap, localLightOrigin, tri->verts, tri->numVerts );
|
|
|
|
c_turboUsedVerts += newTri->numVerts;
|
|
c_turboUnusedVerts += tri->numVerts * 2 - newTri->numVerts;
|
|
|
|
#ifdef USE_TRI_DATA_ALLOCATOR
|
|
R_ResizeStaticTriSurfShadowVerts( newTri, newTri->numVerts );
|
|
#else
|
|
R_AllocStaticTriSurfShadowVerts( newTri, newTri->numVerts );
|
|
SIMDProcessor->Memcpy( newTri->shadowVertexes, shadowVerts, newTri->numVerts * sizeof( shadowVerts[0] ) );
|
|
#endif
|
|
|
|
// 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 = vertRemap[sil->v1];
|
|
int v2 = vertRemap[sil->v2];
|
|
|
|
// 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->silIndexes;
|
|
shadowIndexes = newTri->indexes + numShadowIndexes;
|
|
for ( i = 0, j = 0; i < tri->numIndexes; i += 3, j++ ) {
|
|
if ( facing[j] ) {
|
|
continue;
|
|
}
|
|
|
|
int i0 = vertRemap[indexes[i+0]];
|
|
shadowIndexes[2] = i0;
|
|
shadowIndexes[3] = i0 ^ 1;
|
|
int i1 = vertRemap[indexes[i+1]];
|
|
shadowIndexes[1] = i1;
|
|
shadowIndexes[4] = i1 ^ 1;
|
|
int i2 = vertRemap[indexes[i+2]];
|
|
shadowIndexes[0] = i2;
|
|
shadowIndexes[5] = i2 ^ 1;
|
|
|
|
shadowIndexes += 6;
|
|
}
|
|
|
|
return newTri;
|
|
}
|