2012-11-26 18:58:24 +00:00
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
Doom 3 BFG Edition GPL Source Code
2012-11-28 15:47:07 +00:00
Copyright ( C ) 1993 - 2012 id Software LLC , a ZeniMax Media company .
2012-11-26 18:58:24 +00:00
2012-11-28 15:47:07 +00:00
This file is part of the Doom 3 BFG Edition GPL Source Code ( " Doom 3 BFG Edition Source Code " ) .
2012-11-26 18:58:24 +00:00
Doom 3 BFG Edition 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 BFG Edition 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 BFG Edition Source Code . If not , see < http : //www.gnu.org/licenses/>.
In addition , the Doom 3 BFG Edition 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 BFG Edition 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 .
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
# pragma hdrstop
2012-12-22 15:18:19 +00:00
# include "precompiled.h"
2012-11-26 18:58:24 +00:00
# include "tr_local.h"
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
TRIANGLE MESH PROCESSING
The functions in this file have no vertex / index count limits .
Truly identical vertexes that match in position , normal , and texcoord can
be merged away .
Vertexes that match in position and texcoord , but have distinct normals will
remain distinct for all purposes . This is usually a poor choice for models ,
as adding a bevel face will not add any more vertexes , and will tend to
look better .
Match in position and normal , but differ in texcoords are referenced together
for calculating tangent vectors for bump mapping .
Artists should take care to have identical texels in all maps ( bump / diffuse / specular )
in this case
Vertexes that only match in position are merged for shadow edge finding .
Degenerate triangles .
Overlapped triangles , even if normals or texcoords differ , must be removed .
for the silhoette based stencil shadow algorithm to function properly .
Is this true ? ? ?
Is the overlapped triangle problem just an example of the trippled edge problem ?
Interpenetrating triangles are not currently clipped to surfaces .
Do they effect the shadows ?
if vertexes are intended to deform apart , make sure that no vertexes
are on top of each other in the base frame , or the sil edges may be
calculated incorrectly .
We might be able to identify this from topology .
Dangling edges are acceptable , but three way edges are not .
Are any combinations of two way edges unacceptable , like one facing
the backside of the other ?
Topology is determined by a collection of triangle indexes .
The edge list can be built up from this , and stays valid even under
deformations .
Somewhat non - intuitively , concave edges cannot be optimized away , or the
stencil shadow algorithm miscounts .
Face normals are needed for generating shadow volumes and for calculating
the silhouette , but they will change with any deformation .
Vertex normals and vertex tangents will change with each deformation ,
but they may be able to be transformed instead of recalculated .
bounding volume , both box and sphere will change with deformation .
silhouette indexes
shade indexes
texture indexes
shade indexes will only be > silhouette indexes if there is facet shading present
lookups from texture to sil and texture to shade ?
The normal and tangent vector smoothing is simple averaging , no attempt is
made to better handle the cases where the distribution around the shared vertex
is highly uneven .
we may get degenerate triangles even with the uniquing and removal
if the vertexes have different texcoords .
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
// this shouldn't change anything, but previously renderbumped models seem to need it
# define USE_INVA
// instead of using the texture T vector, cross the normal and S vector for an orthogonal axis
# define DERIVE_UNSMOOTHED_BITANGENT
/*
= = = = = = = = = = = = = = = = =
R_TriSurfMemory
For memory profiling
= = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
int R_TriSurfMemory ( const srfTriangles_t * tri )
{
2012-11-26 18:58:24 +00:00
int total = 0 ;
2012-11-28 15:47:07 +00:00
if ( tri = = NULL )
{
2012-11-26 18:58:24 +00:00
return total ;
}
2012-11-28 15:47:07 +00:00
if ( tri - > preLightShadowVertexes ! = NULL )
{
2012-11-26 18:58:24 +00:00
total + = tri - > numVerts * 2 * sizeof ( tri - > preLightShadowVertexes [ 0 ] ) ;
}
2012-11-28 15:47:07 +00:00
if ( tri - > staticShadowVertexes ! = NULL )
{
2012-11-26 18:58:24 +00:00
total + = tri - > numVerts * 2 * sizeof ( tri - > staticShadowVertexes [ 0 ] ) ;
}
2012-11-28 15:47:07 +00:00
if ( tri - > verts ! = NULL )
{
if ( tri - > ambientSurface = = NULL | | tri - > verts ! = tri - > ambientSurface - > verts )
{
2012-11-26 18:58:24 +00:00
total + = tri - > numVerts * sizeof ( tri - > verts [ 0 ] ) ;
}
}
2012-11-28 15:47:07 +00:00
if ( tri - > indexes ! = NULL )
{
if ( tri - > ambientSurface = = NULL | | tri - > indexes ! = tri - > ambientSurface - > indexes )
{
2012-11-26 18:58:24 +00:00
total + = tri - > numIndexes * sizeof ( tri - > indexes [ 0 ] ) ;
}
}
2012-11-28 15:47:07 +00:00
if ( tri - > silIndexes ! = NULL )
{
2012-11-26 18:58:24 +00:00
total + = tri - > numIndexes * sizeof ( tri - > silIndexes [ 0 ] ) ;
}
2012-11-28 15:47:07 +00:00
if ( tri - > silEdges ! = NULL )
{
2012-11-26 18:58:24 +00:00
total + = tri - > numSilEdges * sizeof ( tri - > silEdges [ 0 ] ) ;
}
2012-11-28 15:47:07 +00:00
if ( tri - > dominantTris ! = NULL )
{
2012-11-26 18:58:24 +00:00
total + = tri - > numVerts * sizeof ( tri - > dominantTris [ 0 ] ) ;
}
2012-11-28 15:47:07 +00:00
if ( tri - > mirroredVerts ! = NULL )
{
2012-11-26 18:58:24 +00:00
total + = tri - > numMirroredVerts * sizeof ( tri - > mirroredVerts [ 0 ] ) ;
}
2012-11-28 15:47:07 +00:00
if ( tri - > dupVerts ! = NULL )
{
2012-11-26 18:58:24 +00:00
total + = tri - > numDupVerts * sizeof ( tri - > dupVerts [ 0 ] ) ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
total + = sizeof ( * tri ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
return total ;
}
/*
= = = = = = = = = = = = = =
R_FreeStaticTriSurfVertexCaches
= = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void R_FreeStaticTriSurfVertexCaches ( srfTriangles_t * tri )
{
2012-11-26 18:58:24 +00:00
// we don't support reclaiming static geometry memory
// without a level change
tri - > ambientCache = 0 ;
tri - > indexCache = 0 ;
tri - > shadowCache = 0 ;
}
/*
= = = = = = = = = = = = = =
R_FreeStaticTriSurf
= = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void R_FreeStaticTriSurf ( srfTriangles_t * tri )
{
if ( ! tri )
{
2012-11-26 18:58:24 +00:00
return ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
R_FreeStaticTriSurfVertexCaches ( tri ) ;
2012-11-28 15:47:07 +00:00
if ( ! tri - > referencedVerts )
{
if ( tri - > verts ! = NULL )
{
2012-11-26 18:58:24 +00:00
// R_CreateLightTris points tri->verts at the verts of the ambient surface
2012-11-28 15:47:07 +00:00
if ( tri - > ambientSurface = = NULL | | tri - > verts ! = tri - > ambientSurface - > verts )
{
2012-11-26 18:58:24 +00:00
Mem_Free ( tri - > verts ) ;
}
}
}
2012-11-28 15:47:07 +00:00
if ( ! tri - > referencedIndexes )
{
if ( tri - > indexes ! = NULL )
{
2012-11-26 18:58:24 +00:00
// if a surface is completely inside a light volume R_CreateLightTris points tri->indexes at the indexes of the ambient surface
2012-11-28 15:47:07 +00:00
if ( tri - > ambientSurface = = NULL | | tri - > indexes ! = tri - > ambientSurface - > indexes )
{
2012-11-26 18:58:24 +00:00
Mem_Free ( tri - > indexes ) ;
}
}
2012-11-28 15:47:07 +00:00
if ( tri - > silIndexes ! = NULL )
{
2012-11-26 18:58:24 +00:00
Mem_Free ( tri - > silIndexes ) ;
}
2012-11-28 15:47:07 +00:00
if ( tri - > silEdges ! = NULL )
{
2012-11-26 18:58:24 +00:00
Mem_Free ( tri - > silEdges ) ;
}
2012-11-28 15:47:07 +00:00
if ( tri - > dominantTris ! = NULL )
{
2012-11-26 18:58:24 +00:00
Mem_Free ( tri - > dominantTris ) ;
}
2012-11-28 15:47:07 +00:00
if ( tri - > mirroredVerts ! = NULL )
{
2012-11-26 18:58:24 +00:00
Mem_Free ( tri - > mirroredVerts ) ;
}
2012-11-28 15:47:07 +00:00
if ( tri - > dupVerts ! = NULL )
{
2012-11-26 18:58:24 +00:00
Mem_Free ( tri - > dupVerts ) ;
}
}
2012-11-28 15:47:07 +00:00
if ( tri - > preLightShadowVertexes ! = NULL )
{
2012-11-26 18:58:24 +00:00
Mem_Free ( tri - > preLightShadowVertexes ) ;
}
2012-11-28 15:47:07 +00:00
if ( tri - > staticShadowVertexes ! = NULL )
{
2012-11-26 18:58:24 +00:00
Mem_Free ( tri - > staticShadowVertexes ) ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// clear the tri out so we don't retain stale data
memset ( tri , 0 , sizeof ( srfTriangles_t ) ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
Mem_Free ( tri ) ;
}
/*
= = = = = = = = = = = = = =
R_FreeStaticTriSurfVerts
= = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void R_FreeStaticTriSurfVerts ( srfTriangles_t * tri )
{
2012-11-26 18:58:24 +00:00
// we don't support reclaiming static geometry memory
// without a level change
tri - > ambientCache = 0 ;
2012-11-28 15:47:07 +00:00
if ( tri - > verts ! = NULL )
{
2012-11-26 18:58:24 +00:00
// R_CreateLightTris points tri->verts at the verts of the ambient surface
2012-11-28 15:47:07 +00:00
if ( tri - > ambientSurface = = NULL | | tri - > verts ! = tri - > ambientSurface - > verts )
{
2012-11-26 18:58:24 +00:00
Mem_Free ( tri - > verts ) ;
}
}
}
/*
= = = = = = = = = = = = = =
R_AllocStaticTriSurf
= = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
srfTriangles_t * R_AllocStaticTriSurf ( )
{
srfTriangles_t * tris = ( srfTriangles_t * ) Mem_ClearedAlloc ( sizeof ( srfTriangles_t ) , TAG_SRFTRIS ) ;
2012-11-26 18:58:24 +00:00
return tris ;
}
/*
= = = = = = = = = = = = = = = = =
R_CopyStaticTriSurf
This only duplicates the indexes and verts , not any of the derived data .
= = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
srfTriangles_t * R_CopyStaticTriSurf ( const srfTriangles_t * tri )
{
srfTriangles_t * newTri ;
2012-11-26 18:58:24 +00:00
newTri = R_AllocStaticTriSurf ( ) ;
R_AllocStaticTriSurfVerts ( newTri , tri - > numVerts ) ;
R_AllocStaticTriSurfIndexes ( newTri , tri - > numIndexes ) ;
newTri - > numVerts = tri - > numVerts ;
newTri - > numIndexes = tri - > numIndexes ;
memcpy ( newTri - > verts , tri - > verts , tri - > numVerts * sizeof ( newTri - > verts [ 0 ] ) ) ;
memcpy ( newTri - > indexes , tri - > indexes , tri - > numIndexes * sizeof ( newTri - > indexes [ 0 ] ) ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
return newTri ;
}
/*
= = = = = = = = = = = = = = = = =
R_AllocStaticTriSurfVerts
= = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void R_AllocStaticTriSurfVerts ( srfTriangles_t * tri , int numVerts )
{
2012-11-26 18:58:24 +00:00
assert ( tri - > verts = = NULL ) ;
2012-11-28 15:47:07 +00:00
tri - > verts = ( idDrawVert * ) Mem_Alloc16 ( numVerts * sizeof ( idDrawVert ) , TAG_TRI_VERTS ) ;
2012-11-26 18:58:24 +00:00
}
/*
= = = = = = = = = = = = = = = = =
R_AllocStaticTriSurfIndexes
= = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void R_AllocStaticTriSurfIndexes ( srfTriangles_t * tri , int numIndexes )
{
2012-11-26 18:58:24 +00:00
assert ( tri - > indexes = = NULL ) ;
2012-11-28 15:47:07 +00:00
tri - > indexes = ( triIndex_t * ) Mem_Alloc16 ( numIndexes * sizeof ( triIndex_t ) , TAG_TRI_INDEXES ) ;
2012-11-26 18:58:24 +00:00
}
/*
= = = = = = = = = = = = = = = = =
R_AllocStaticTriSurfSilIndexes
= = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void R_AllocStaticTriSurfSilIndexes ( srfTriangles_t * tri , int numIndexes )
{
2012-11-26 18:58:24 +00:00
assert ( tri - > silIndexes = = NULL ) ;
2012-11-28 15:47:07 +00:00
tri - > silIndexes = ( triIndex_t * ) Mem_Alloc16 ( numIndexes * sizeof ( triIndex_t ) , TAG_TRI_SIL_INDEXES ) ;
2012-11-26 18:58:24 +00:00
}
/*
= = = = = = = = = = = = = = = = =
R_AllocStaticTriSurfDominantTris
= = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void R_AllocStaticTriSurfDominantTris ( srfTriangles_t * tri , int numVerts )
{
2012-11-26 18:58:24 +00:00
assert ( tri - > dominantTris = = NULL ) ;
2012-11-28 15:47:07 +00:00
tri - > dominantTris = ( dominantTri_t * ) Mem_Alloc16 ( numVerts * sizeof ( dominantTri_t ) , TAG_TRI_DOMINANT_TRIS ) ;
2012-11-26 18:58:24 +00:00
}
/*
= = = = = = = = = = = = = = = = =
R_AllocStaticTriSurfMirroredVerts
= = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void R_AllocStaticTriSurfMirroredVerts ( srfTriangles_t * tri , int numMirroredVerts )
{
2012-11-26 18:58:24 +00:00
assert ( tri - > mirroredVerts = = NULL ) ;
2012-11-28 15:47:07 +00:00
tri - > mirroredVerts = ( int * ) Mem_Alloc16 ( numMirroredVerts * sizeof ( * tri - > mirroredVerts ) , TAG_TRI_MIR_VERT ) ;
2012-11-26 18:58:24 +00:00
}
/*
= = = = = = = = = = = = = = = = =
R_AllocStaticTriSurfDupVerts
= = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void R_AllocStaticTriSurfDupVerts ( srfTriangles_t * tri , int numDupVerts )
{
2012-11-26 18:58:24 +00:00
assert ( tri - > dupVerts = = NULL ) ;
2012-11-28 15:47:07 +00:00
tri - > dupVerts = ( int * ) Mem_Alloc16 ( numDupVerts * 2 * sizeof ( * tri - > dupVerts ) , TAG_TRI_DUP_VERT ) ;
2012-11-26 18:58:24 +00:00
}
/*
= = = = = = = = = = = = = = = = =
R_AllocStaticTriSurfSilEdges
= = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void R_AllocStaticTriSurfSilEdges ( srfTriangles_t * tri , int numSilEdges )
{
2012-11-26 18:58:24 +00:00
assert ( tri - > silEdges = = NULL ) ;
2012-11-28 15:47:07 +00:00
tri - > silEdges = ( silEdge_t * ) Mem_Alloc16 ( numSilEdges * sizeof ( silEdge_t ) , TAG_TRI_SIL_EDGE ) ;
2012-11-26 18:58:24 +00:00
}
/*
= = = = = = = = = = = = = = = = =
R_AllocStaticTriSurfPreLightShadowVerts
= = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void R_AllocStaticTriSurfPreLightShadowVerts ( srfTriangles_t * tri , int numVerts )
{
2012-11-26 18:58:24 +00:00
assert ( tri - > preLightShadowVertexes = = NULL ) ;
2012-11-28 15:47:07 +00:00
tri - > preLightShadowVertexes = ( idShadowVert * ) Mem_Alloc16 ( numVerts * sizeof ( idShadowVert ) , TAG_TRI_SHADOW ) ;
2012-11-26 18:58:24 +00:00
}
/*
= = = = = = = = = = = = = = = = =
R_ResizeStaticTriSurfVerts
= = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void R_ResizeStaticTriSurfVerts ( srfTriangles_t * tri , int numVerts )
{
idDrawVert * newVerts = ( idDrawVert * ) Mem_Alloc16 ( numVerts * sizeof ( idDrawVert ) , TAG_TRI_VERTS ) ;
2012-11-26 18:58:24 +00:00
const int copy = std : : min ( numVerts , tri - > numVerts ) ;
memcpy ( newVerts , tri - > verts , copy * sizeof ( idDrawVert ) ) ;
Mem_Free ( tri - > verts ) ;
tri - > verts = newVerts ;
}
/*
= = = = = = = = = = = = = = = = =
R_ResizeStaticTriSurfIndexes
= = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void R_ResizeStaticTriSurfIndexes ( srfTriangles_t * tri , int numIndexes )
{
triIndex_t * newIndexes = ( triIndex_t * ) Mem_Alloc16 ( numIndexes * sizeof ( triIndex_t ) , TAG_TRI_INDEXES ) ;
2012-11-26 18:58:24 +00:00
const int copy = std : : min ( numIndexes , tri - > numIndexes ) ;
memcpy ( newIndexes , tri - > indexes , copy * sizeof ( triIndex_t ) ) ;
Mem_Free ( tri - > indexes ) ;
tri - > indexes = newIndexes ;
}
/*
= = = = = = = = = = = = = = = = =
R_ReferenceStaticTriSurfVerts
= = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void R_ReferenceStaticTriSurfVerts ( srfTriangles_t * tri , const srfTriangles_t * reference )
{
2012-11-26 18:58:24 +00:00
tri - > verts = reference - > verts ;
}
/*
= = = = = = = = = = = = = = = = =
R_ReferenceStaticTriSurfIndexes
= = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void R_ReferenceStaticTriSurfIndexes ( srfTriangles_t * tri , const srfTriangles_t * reference )
{
2012-11-26 18:58:24 +00:00
tri - > indexes = reference - > indexes ;
}
/*
= = = = = = = = = = = = = = = = =
R_FreeStaticTriSurfSilIndexes
= = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void R_FreeStaticTriSurfSilIndexes ( srfTriangles_t * tri )
{
2012-11-26 18:58:24 +00:00
Mem_Free ( tri - > silIndexes ) ;
tri - > silIndexes = NULL ;
}
/*
= = = = = = = = = = = = = = =
R_RangeCheckIndexes
Check for syntactically incorrect indexes , like out of range values .
Does not check for semantics , like degenerate triangles .
No vertexes is acceptable if no indexes .
No indexes is acceptable .
More vertexes than are referenced by indexes are acceptable .
= = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void R_RangeCheckIndexes ( const srfTriangles_t * tri )
{
2012-11-26 18:58:24 +00:00
int i ;
2012-11-28 15:47:07 +00:00
if ( tri - > numIndexes < 0 )
{
2012-11-26 18:58:24 +00:00
common - > Error ( " R_RangeCheckIndexes: numIndexes < 0 " ) ;
}
2012-11-28 15:47:07 +00:00
if ( tri - > numVerts < 0 )
{
2012-11-26 18:58:24 +00:00
common - > Error ( " R_RangeCheckIndexes: numVerts < 0 " ) ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// must specify an integral number of triangles
2012-11-28 15:47:07 +00:00
if ( tri - > numIndexes % 3 ! = 0 )
{
2012-11-26 18:58:24 +00:00
common - > Error ( " R_RangeCheckIndexes: numIndexes %% 3 " ) ;
}
2012-11-28 15:47:07 +00:00
for ( i = 0 ; i < tri - > numIndexes ; i + + )
{
if ( tri - > indexes [ i ] > = tri - > numVerts )
{
2012-11-26 18:58:24 +00:00
common - > Error ( " R_RangeCheckIndexes: index out of range " ) ;
}
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// this should not be possible unless there are unused verts
2012-11-28 15:47:07 +00:00
if ( tri - > numVerts > tri - > numIndexes )
{
2012-11-26 18:58:24 +00:00
// FIXME: find the causes of these
// common->Printf( "R_RangeCheckIndexes: tri->numVerts > tri->numIndexes\n" );
}
}
/*
= = = = = = = = = = = = = = = = =
R_BoundTriSurf
= = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void R_BoundTriSurf ( srfTriangles_t * tri )
{
2012-11-26 18:58:24 +00:00
SIMDProcessor - > MinMax ( tri - > bounds [ 0 ] , tri - > bounds [ 1 ] , tri - > verts , tri - > numVerts ) ;
}
/*
= = = = = = = = = = = = = = = = =
R_CreateSilRemap
= = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
static int * R_CreateSilRemap ( const srfTriangles_t * tri )
{
2012-11-26 18:58:24 +00:00
int c_removed , c_unique ;
2012-11-28 15:47:07 +00:00
int * remap ;
2012-11-26 18:58:24 +00:00
int i , j , hashKey ;
2012-11-28 15:47:07 +00:00
const idDrawVert * v1 , * v2 ;
remap = ( int * ) R_ClearedStaticAlloc ( tri - > numVerts * sizeof ( remap [ 0 ] ) ) ;
if ( ! r_useSilRemap . GetBool ( ) )
{
for ( i = 0 ; i < tri - > numVerts ; i + + )
{
2012-11-26 18:58:24 +00:00
remap [ i ] = i ;
}
return remap ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
idHashIndex hash ( 1024 , tri - > numVerts ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
c_removed = 0 ;
c_unique = 0 ;
2012-11-28 15:47:07 +00:00
for ( i = 0 ; i < tri - > numVerts ; i + + )
{
2012-11-26 18:58:24 +00:00
v1 = & tri - > verts [ i ] ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// see if there is an earlier vert that it can map to
hashKey = hash . GenerateKey ( v1 - > xyz ) ;
2012-11-28 15:47:07 +00:00
for ( j = hash . First ( hashKey ) ; j > = 0 ; j = hash . Next ( j ) )
{
2012-11-26 18:58:24 +00:00
v2 = & tri - > verts [ j ] ;
2012-11-28 15:47:07 +00:00
if ( v2 - > xyz [ 0 ] = = v1 - > xyz [ 0 ]
& & v2 - > xyz [ 1 ] = = v1 - > xyz [ 1 ]
& & v2 - > xyz [ 2 ] = = v1 - > xyz [ 2 ] )
{
2012-11-26 18:58:24 +00:00
c_removed + + ;
remap [ i ] = j ;
break ;
}
}
2012-11-28 15:47:07 +00:00
if ( j < 0 )
{
2012-11-26 18:58:24 +00:00
c_unique + + ;
remap [ i ] = i ;
hash . Add ( hashKey , i ) ;
}
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
return remap ;
}
/*
= = = = = = = = = = = = = = = = =
R_CreateSilIndexes
Uniquing vertexes only on xyz before creating sil edges reduces
the edge count by about 20 % on Q3 models
= = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void R_CreateSilIndexes ( srfTriangles_t * tri )
{
2012-11-26 18:58:24 +00:00
int i ;
2012-11-28 15:47:07 +00:00
int * remap ;
if ( tri - > silIndexes )
{
2012-11-26 18:58:24 +00:00
Mem_Free ( tri - > silIndexes ) ;
tri - > silIndexes = NULL ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
remap = R_CreateSilRemap ( tri ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// remap indexes to the first one
R_AllocStaticTriSurfSilIndexes ( tri , tri - > numIndexes ) ;
assert ( tri - > silIndexes ! = NULL ) ;
2012-11-28 15:47:07 +00:00
for ( i = 0 ; i < tri - > numIndexes ; i + + )
{
2012-11-26 18:58:24 +00:00
tri - > silIndexes [ i ] = remap [ tri - > indexes [ i ] ] ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
R_StaticFree ( remap ) ;
}
/*
= = = = = = = = = = = = = = = = = = = = =
R_CreateDupVerts
= = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void R_CreateDupVerts ( srfTriangles_t * tri )
{
2012-11-26 18:58:24 +00:00
int i ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
idTempArray < int > remap ( tri - > numVerts ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// initialize vertex remap in case there are unused verts
2012-11-28 15:47:07 +00:00
for ( i = 0 ; i < tri - > numVerts ; i + + )
{
2012-11-26 18:58:24 +00:00
remap [ i ] = i ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// set the remap based on how the silhouette indexes are remapped
2012-11-28 15:47:07 +00:00
for ( i = 0 ; i < tri - > numIndexes ; i + + )
{
2012-11-26 18:58:24 +00:00
remap [ tri - > indexes [ i ] ] = tri - > silIndexes [ i ] ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// create duplicate vertex index based on the vertex remap
idTempArray < int > tempDupVerts ( tri - > numVerts * 2 ) ;
tri - > numDupVerts = 0 ;
2012-11-28 15:47:07 +00:00
for ( i = 0 ; i < tri - > numVerts ; i + + )
{
if ( remap [ i ] ! = i )
{
tempDupVerts [ tri - > numDupVerts * 2 + 0 ] = i ;
tempDupVerts [ tri - > numDupVerts * 2 + 1 ] = remap [ i ] ;
2012-11-26 18:58:24 +00:00
tri - > numDupVerts + + ;
}
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
R_AllocStaticTriSurfDupVerts ( tri , tri - > numDupVerts ) ;
memcpy ( tri - > dupVerts , tempDupVerts . Ptr ( ) , tri - > numDupVerts * 2 * sizeof ( tri - > dupVerts [ 0 ] ) ) ;
}
/*
= = = = = = = = = = = = = = =
R_DefineEdge
= = = = = = = = = = = = = = =
*/
static int c_duplicatedEdges , c_tripledEdges ;
static const int MAX_SIL_EDGES = 0x7ffff ;
static void R_DefineEdge ( const int v1 , const int v2 , const int planeNum , const int numPlanes ,
2012-11-28 15:47:07 +00:00
idList < silEdge_t > & silEdges , idHashIndex & silEdgeHash )
{
2012-11-26 18:58:24 +00:00
int i , hashKey ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// check for degenerate edge
2012-11-28 15:47:07 +00:00
if ( v1 = = v2 )
{
2012-11-26 18:58:24 +00:00
return ;
}
hashKey = silEdgeHash . GenerateKey ( v1 , v2 ) ;
// search for a matching other side
2012-11-28 15:47:07 +00:00
for ( i = silEdgeHash . First ( hashKey ) ; i > = 0 & & i < MAX_SIL_EDGES ; i = silEdgeHash . Next ( i ) )
{
if ( silEdges [ i ] . v1 = = v1 & & silEdges [ i ] . v2 = = v2 )
{
2012-11-26 18:58:24 +00:00
c_duplicatedEdges + + ;
// allow it to still create a new edge
continue ;
}
2012-11-28 15:47:07 +00:00
if ( silEdges [ i ] . v2 = = v1 & & silEdges [ i ] . v1 = = v2 )
{
if ( silEdges [ i ] . p2 ! = numPlanes )
{
2012-11-26 18:58:24 +00:00
c_tripledEdges + + ;
// allow it to still create a new edge
continue ;
}
// this is a matching back side
silEdges [ i ] . p2 = planeNum ;
return ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// define the new edge
silEdgeHash . Add ( hashKey , silEdges . Num ( ) ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
silEdge_t silEdge ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
silEdge . p1 = planeNum ;
silEdge . p2 = numPlanes ;
silEdge . v1 = v1 ;
silEdge . v2 = v2 ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
silEdges . Append ( silEdge ) ;
}
/*
= = = = = = = = = = = = = = = = =
SilEdgeSort
= = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
static int SilEdgeSort ( const void * a , const void * b )
{
if ( ( ( silEdge_t * ) a ) - > p1 < ( ( silEdge_t * ) b ) - > p1 )
{
2012-11-26 18:58:24 +00:00
return - 1 ;
}
2012-11-28 15:47:07 +00:00
if ( ( ( silEdge_t * ) a ) - > p1 > ( ( silEdge_t * ) b ) - > p1 )
{
2012-11-26 18:58:24 +00:00
return 1 ;
}
2012-11-28 15:47:07 +00:00
if ( ( ( silEdge_t * ) a ) - > p2 < ( ( silEdge_t * ) b ) - > p2 )
{
2012-11-26 18:58:24 +00:00
return - 1 ;
}
2012-11-28 15:47:07 +00:00
if ( ( ( silEdge_t * ) a ) - > p2 > ( ( silEdge_t * ) b ) - > p2 )
{
2012-11-26 18:58:24 +00:00
return 1 ;
}
return 0 ;
}
/*
= = = = = = = = = = = = = = = = =
R_IdentifySilEdges
If the surface will not deform , coplanar edges ( polygon interiors )
can never create silhouette plains , and can be omited
= = = = = = = = = = = = = = = = =
*/
int c_coplanarSilEdges ;
int c_totalSilEdges ;
2012-11-28 15:47:07 +00:00
void R_IdentifySilEdges ( srfTriangles_t * tri , bool omitCoplanarEdges )
{
2012-11-26 18:58:24 +00:00
int i ;
int shared , single ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
omitCoplanarEdges = false ; // optimization doesn't work for some reason
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
static const int SILEDGE_HASH_SIZE = 1024 ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
const int numTris = tri - > numIndexes / 3 ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
idList < silEdge_t > silEdges ( MAX_SIL_EDGES ) ;
idHashIndex silEdgeHash ( SILEDGE_HASH_SIZE , MAX_SIL_EDGES ) ;
int numPlanes = numTris ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
silEdgeHash . Clear ( ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
c_duplicatedEdges = 0 ;
c_tripledEdges = 0 ;
2012-11-28 15:47:07 +00:00
for ( i = 0 ; i < numTris ; i + + )
{
2012-11-26 18:58:24 +00:00
int i1 , i2 , i3 ;
2012-11-28 15:47:07 +00:00
i1 = tri - > silIndexes [ i * 3 + 0 ] ;
i2 = tri - > silIndexes [ i * 3 + 1 ] ;
i3 = tri - > silIndexes [ i * 3 + 2 ] ;
2012-11-26 18:58:24 +00:00
// create the edges
R_DefineEdge ( i1 , i2 , i , numPlanes , silEdges , silEdgeHash ) ;
R_DefineEdge ( i2 , i3 , i , numPlanes , silEdges , silEdgeHash ) ;
R_DefineEdge ( i3 , i1 , i , numPlanes , silEdges , silEdgeHash ) ;
}
2012-11-28 15:47:07 +00:00
if ( c_duplicatedEdges | | c_tripledEdges )
{
2012-11-26 18:58:24 +00:00
common - > DWarning ( " %i duplicated edge directions, %i tripled edges " , c_duplicatedEdges , c_tripledEdges ) ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// if we know that the vertexes aren't going
// to deform, we can remove interior triangulation edges
// on otherwise planar polygons.
// I earlier believed that I could also remove concave
// edges, because they are never silhouettes in the conventional sense,
// but they are still needed to balance out all the true sil edges
// for the shadow algorithm to function
int c_coplanarCulled ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
c_coplanarCulled = 0 ;
2012-11-28 15:47:07 +00:00
if ( omitCoplanarEdges )
{
for ( i = 0 ; i < silEdges . Num ( ) ; i + + )
{
2012-11-26 18:58:24 +00:00
int i1 , i2 , i3 ;
idPlane plane ;
int base ;
int j ;
float d ;
2012-11-28 15:47:07 +00:00
if ( silEdges [ i ] . p2 = = numPlanes ) // the fake dangling edge
{
2012-11-26 18:58:24 +00:00
continue ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
base = silEdges [ i ] . p1 * 3 ;
i1 = tri - > silIndexes [ base + 0 ] ;
i2 = tri - > silIndexes [ base + 1 ] ;
i3 = tri - > silIndexes [ base + 2 ] ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
plane . FromPoints ( tri - > verts [ i1 ] . xyz , tri - > verts [ i2 ] . xyz , tri - > verts [ i3 ] . xyz ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// check to see if points of second triangle are not coplanar
base = silEdges [ i ] . p2 * 3 ;
2012-11-28 15:47:07 +00:00
for ( j = 0 ; j < 3 ; j + + )
{
2012-11-26 18:58:24 +00:00
i1 = tri - > silIndexes [ base + j ] ;
d = plane . Distance ( tri - > verts [ i1 ] . xyz ) ;
2012-11-28 15:47:07 +00:00
if ( d ! = 0 ) // even a small epsilon causes problems
{
2012-11-26 18:58:24 +00:00
break ;
}
}
2012-11-28 15:47:07 +00:00
if ( j = = 3 )
{
2012-11-26 18:58:24 +00:00
// we can cull this sil edge
2012-11-28 15:47:07 +00:00
memmove ( & silEdges [ i ] , & silEdges [ i + 1 ] , ( silEdges . Num ( ) - i - 1 ) * sizeof ( silEdges [ i ] ) ) ;
2012-11-26 18:58:24 +00:00
c_coplanarCulled + + ;
silEdges . SetNum ( silEdges . Num ( ) - 1 ) ;
i - - ;
}
}
2012-11-28 15:47:07 +00:00
if ( c_coplanarCulled )
{
2012-11-26 18:58:24 +00:00
c_coplanarSilEdges + = c_coplanarCulled ;
// common->Printf( "%i of %i sil edges coplanar culled\n", c_coplanarCulled,
// c_coplanarCulled + numSilEdges );
}
}
c_totalSilEdges + = silEdges . Num ( ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// sort the sil edges based on plane number
qsort ( silEdges . Ptr ( ) , silEdges . Num ( ) , sizeof ( silEdges [ 0 ] ) , SilEdgeSort ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// count up the distribution.
// a perfectly built model should only have shared
// edges, but most models will have some interpenetration
// and dangling edges
shared = 0 ;
single = 0 ;
2012-11-28 15:47:07 +00:00
for ( i = 0 ; i < silEdges . Num ( ) ; i + + )
{
if ( silEdges [ i ] . p2 = = numPlanes )
{
2012-11-26 18:58:24 +00:00
single + + ;
2012-11-28 15:47:07 +00:00
}
else
{
2012-11-26 18:58:24 +00:00
shared + + ;
}
}
2012-11-28 15:47:07 +00:00
if ( ! single )
{
2012-11-26 18:58:24 +00:00
tri - > perfectHull = true ;
2012-11-28 15:47:07 +00:00
}
else
{
2012-11-26 18:58:24 +00:00
tri - > perfectHull = false ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
tri - > numSilEdges = silEdges . Num ( ) ;
R_AllocStaticTriSurfSilEdges ( tri , silEdges . Num ( ) ) ;
memcpy ( tri - > silEdges , silEdges . Ptr ( ) , silEdges . Num ( ) * sizeof ( tri - > silEdges [ 0 ] ) ) ;
}
/*
= = = = = = = = = = = = = = =
R_FaceNegativePolarity
Returns true if the texture polarity of the face is negative , false if it is positive or zero
= = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
static bool R_FaceNegativePolarity ( const srfTriangles_t * tri , int firstIndex )
{
const idDrawVert * a = tri - > verts + tri - > indexes [ firstIndex + 0 ] ;
const idDrawVert * b = tri - > verts + tri - > indexes [ firstIndex + 1 ] ;
const idDrawVert * c = tri - > verts + tri - > indexes [ firstIndex + 2 ] ;
2012-11-26 18:58:24 +00:00
const idVec2 aST = a - > GetTexCoord ( ) ;
const idVec2 bST = b - > GetTexCoord ( ) ;
const idVec2 cST = c - > GetTexCoord ( ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
float d0 [ 5 ] ;
d0 [ 3 ] = bST [ 0 ] - aST [ 0 ] ;
d0 [ 4 ] = bST [ 1 ] - aST [ 1 ] ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
float d1 [ 5 ] ;
d1 [ 3 ] = cST [ 0 ] - aST [ 0 ] ;
d1 [ 4 ] = cST [ 1 ] - aST [ 1 ] ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
const float area = d0 [ 3 ] * d1 [ 4 ] - d0 [ 4 ] * d1 [ 3 ] ;
2012-11-28 15:47:07 +00:00
if ( area > = 0 )
{
2012-11-26 18:58:24 +00:00
return false ;
}
return true ;
}
/*
= = = = = = = = = = = = = = = = = = =
R_DuplicateMirroredVertexes
Modifies the surface to bust apart any verts that are shared by both positive and
negative texture polarities , so tangent space smoothing at the vertex doesn ' t
degenerate .
This will create some identical vertexes ( which will eventually get different tangent
vectors ) , so never optimize the resulting mesh , or it will get the mirrored edges back .
Reallocates tri - > verts and changes tri - > indexes in place
Silindexes are unchanged by this .
sets mirroredVerts and mirroredVerts [ ]
= = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
struct tangentVert_t
{
2012-11-26 18:58:24 +00:00
bool polarityUsed [ 2 ] ;
int negativeRemap ;
} ;
2012-11-28 15:47:07 +00:00
static void R_DuplicateMirroredVertexes ( srfTriangles_t * tri )
{
tangentVert_t * vert ;
2012-11-26 18:58:24 +00:00
int i , j ;
int totalVerts ;
int numMirror ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
idTempArray < tangentVert_t > tverts ( tri - > numVerts ) ;
tverts . Zero ( ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// determine texture polarity of each surface
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// mark each vert with the polarities it uses
2012-11-28 15:47:07 +00:00
for ( i = 0 ; i < tri - > numIndexes ; i + = 3 )
{
2012-11-26 18:58:24 +00:00
int polarity = R_FaceNegativePolarity ( tri , i ) ;
2012-11-28 15:47:07 +00:00
for ( j = 0 ; j < 3 ; j + + )
{
tverts [ tri - > indexes [ i + j ] ] . polarityUsed [ polarity ] = true ;
2012-11-26 18:58:24 +00:00
}
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// now create new vertex indices as needed
totalVerts = tri - > numVerts ;
2012-11-28 15:47:07 +00:00
for ( i = 0 ; i < tri - > numVerts ; i + + )
{
2012-11-26 18:58:24 +00:00
vert = & tverts [ i ] ;
2012-11-28 15:47:07 +00:00
if ( vert - > polarityUsed [ 0 ] & & vert - > polarityUsed [ 1 ] )
{
2012-11-26 18:58:24 +00:00
vert - > negativeRemap = totalVerts ;
totalVerts + + ;
}
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
tri - > numMirroredVerts = totalVerts - tri - > numVerts ;
2012-11-28 15:47:07 +00:00
if ( tri - > numMirroredVerts = = 0 )
{
2012-11-26 18:58:24 +00:00
tri - > mirroredVerts = NULL ;
return ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// now create the new list
R_AllocStaticTriSurfMirroredVerts ( tri , tri - > numMirroredVerts ) ;
R_ResizeStaticTriSurfVerts ( tri , totalVerts ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// create the duplicates
numMirror = 0 ;
2012-11-28 15:47:07 +00:00
for ( i = 0 ; i < tri - > numVerts ; i + + )
{
2012-11-26 18:58:24 +00:00
j = tverts [ i ] . negativeRemap ;
2012-11-28 15:47:07 +00:00
if ( j )
{
2012-11-26 18:58:24 +00:00
tri - > verts [ j ] = tri - > verts [ i ] ;
tri - > mirroredVerts [ numMirror ] = i ;
numMirror + + ;
}
}
tri - > numVerts = totalVerts ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// change the indexes
2012-11-28 15:47:07 +00:00
for ( i = 0 ; i < tri - > numIndexes ; i + + )
{
if ( tverts [ tri - > indexes [ i ] ] . negativeRemap & & R_FaceNegativePolarity ( tri , 3 * ( i / 3 ) ) )
{
2012-11-26 18:58:24 +00:00
tri - > indexes [ i ] = tverts [ tri - > indexes [ i ] ] . negativeRemap ;
}
}
}
/*
= = = = = = = = = = = =
R_DeriveNormalsAndTangents
Derives the normal and orthogonal tangent vectors for the triangle vertices .
For each vertex the normal and tangent vectors are derived from all triangles
using the vertex which results in smooth tangents across the mesh .
= = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void R_DeriveNormalsAndTangents ( srfTriangles_t * tri )
{
2012-11-26 18:58:24 +00:00
idTempArray < idVec3 > vertexNormals ( tri - > numVerts ) ;
idTempArray < idVec3 > vertexTangents ( tri - > numVerts ) ;
idTempArray < idVec3 > vertexBitangents ( tri - > numVerts ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
vertexNormals . Zero ( ) ;
vertexTangents . Zero ( ) ;
vertexBitangents . Zero ( ) ;
2012-11-28 15:47:07 +00:00
for ( int i = 0 ; i < tri - > numIndexes ; i + = 3 )
{
2012-11-26 18:58:24 +00:00
const int v0 = tri - > indexes [ i + 0 ] ;
const int v1 = tri - > indexes [ i + 1 ] ;
const int v2 = tri - > indexes [ i + 2 ] ;
2012-11-28 15:47:07 +00:00
const idDrawVert * a = tri - > verts + v0 ;
const idDrawVert * b = tri - > verts + v1 ;
const idDrawVert * c = tri - > verts + v2 ;
2012-11-26 18:58:24 +00:00
const idVec2 aST = a - > GetTexCoord ( ) ;
const idVec2 bST = b - > GetTexCoord ( ) ;
const idVec2 cST = c - > GetTexCoord ( ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
float d0 [ 5 ] ;
d0 [ 0 ] = b - > xyz [ 0 ] - a - > xyz [ 0 ] ;
d0 [ 1 ] = b - > xyz [ 1 ] - a - > xyz [ 1 ] ;
d0 [ 2 ] = b - > xyz [ 2 ] - a - > xyz [ 2 ] ;
d0 [ 3 ] = bST [ 0 ] - aST [ 0 ] ;
d0 [ 4 ] = bST [ 1 ] - aST [ 1 ] ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
float d1 [ 5 ] ;
d1 [ 0 ] = c - > xyz [ 0 ] - a - > xyz [ 0 ] ;
d1 [ 1 ] = c - > xyz [ 1 ] - a - > xyz [ 1 ] ;
d1 [ 2 ] = c - > xyz [ 2 ] - a - > xyz [ 2 ] ;
d1 [ 3 ] = cST [ 0 ] - aST [ 0 ] ;
d1 [ 4 ] = cST [ 1 ] - aST [ 1 ] ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
idVec3 normal ;
normal [ 0 ] = d1 [ 1 ] * d0 [ 2 ] - d1 [ 2 ] * d0 [ 1 ] ;
normal [ 1 ] = d1 [ 2 ] * d0 [ 0 ] - d1 [ 0 ] * d0 [ 2 ] ;
normal [ 2 ] = d1 [ 0 ] * d0 [ 1 ] - d1 [ 1 ] * d0 [ 0 ] ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
const float f0 = idMath : : InvSqrt ( normal . x * normal . x + normal . y * normal . y + normal . z * normal . z ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
normal . x * = f0 ;
normal . y * = f0 ;
normal . z * = f0 ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// area sign bit
const float area = d0 [ 3 ] * d1 [ 4 ] - d0 [ 4 ] * d1 [ 3 ] ;
2012-11-28 15:47:07 +00:00
unsigned int signBit = ( * ( unsigned int * ) & area ) & ( 1 < < 31 ) ;
2012-11-26 18:58:24 +00:00
idVec3 tangent ;
tangent [ 0 ] = d0 [ 0 ] * d1 [ 4 ] - d0 [ 4 ] * d1 [ 0 ] ;
tangent [ 1 ] = d0 [ 1 ] * d1 [ 4 ] - d0 [ 4 ] * d1 [ 1 ] ;
tangent [ 2 ] = d0 [ 2 ] * d1 [ 4 ] - d0 [ 4 ] * d1 [ 2 ] ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
const float f1 = idMath : : InvSqrt ( tangent . x * tangent . x + tangent . y * tangent . y + tangent . z * tangent . z ) ;
2012-11-28 15:47:07 +00:00
* ( unsigned int * ) & f1 ^ = signBit ;
2012-11-26 18:58:24 +00:00
tangent . x * = f1 ;
tangent . y * = f1 ;
tangent . z * = f1 ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
idVec3 bitangent ;
bitangent [ 0 ] = d0 [ 3 ] * d1 [ 0 ] - d0 [ 0 ] * d1 [ 3 ] ;
bitangent [ 1 ] = d0 [ 3 ] * d1 [ 1 ] - d0 [ 1 ] * d1 [ 3 ] ;
bitangent [ 2 ] = d0 [ 3 ] * d1 [ 2 ] - d0 [ 2 ] * d1 [ 3 ] ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
const float f2 = idMath : : InvSqrt ( bitangent . x * bitangent . x + bitangent . y * bitangent . y + bitangent . z * bitangent . z ) ;
2012-11-28 15:47:07 +00:00
* ( unsigned int * ) & f2 ^ = signBit ;
2012-11-26 18:58:24 +00:00
bitangent . x * = f2 ;
bitangent . y * = f2 ;
bitangent . z * = f2 ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
vertexNormals [ v0 ] + = normal ;
vertexTangents [ v0 ] + = tangent ;
vertexBitangents [ v0 ] + = bitangent ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
vertexNormals [ v1 ] + = normal ;
vertexTangents [ v1 ] + = tangent ;
vertexBitangents [ v1 ] + = bitangent ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
vertexNormals [ v2 ] + = normal ;
vertexTangents [ v2 ] + = tangent ;
vertexBitangents [ v2 ] + = bitangent ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// add the normal of a duplicated vertex to the normal of the first vertex with the same XYZ
2012-11-28 15:47:07 +00:00
for ( int i = 0 ; i < tri - > numDupVerts ; i + + )
{
vertexNormals [ tri - > dupVerts [ i * 2 + 0 ] ] + = vertexNormals [ tri - > dupVerts [ i * 2 + 1 ] ] ;
2012-11-26 18:58:24 +00:00
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// copy vertex normals to duplicated vertices
2012-11-28 15:47:07 +00:00
for ( int i = 0 ; i < tri - > numDupVerts ; i + + )
{
vertexNormals [ tri - > dupVerts [ i * 2 + 1 ] ] = vertexNormals [ tri - > dupVerts [ i * 2 + 0 ] ] ;
2012-11-26 18:58:24 +00:00
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// Project the summed vectors onto the normal plane and normalize.
// The tangent vectors will not necessarily be orthogonal to each
// other, but they will be orthogonal to the surface normal.
2012-11-28 15:47:07 +00:00
for ( int i = 0 ; i < tri - > numVerts ; i + + )
{
2012-11-26 18:58:24 +00:00
const float normalScale = idMath : : InvSqrt ( vertexNormals [ i ] . x * vertexNormals [ i ] . x + vertexNormals [ i ] . y * vertexNormals [ i ] . y + vertexNormals [ i ] . z * vertexNormals [ i ] . z ) ;
vertexNormals [ i ] . x * = normalScale ;
vertexNormals [ i ] . y * = normalScale ;
vertexNormals [ i ] . z * = normalScale ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
vertexTangents [ i ] - = ( vertexTangents [ i ] * vertexNormals [ i ] ) * vertexNormals [ i ] ;
vertexBitangents [ i ] - = ( vertexBitangents [ i ] * vertexNormals [ i ] ) * vertexNormals [ i ] ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
const float tangentScale = idMath : : InvSqrt ( vertexTangents [ i ] . x * vertexTangents [ i ] . x + vertexTangents [ i ] . y * vertexTangents [ i ] . y + vertexTangents [ i ] . z * vertexTangents [ i ] . z ) ;
vertexTangents [ i ] . x * = tangentScale ;
vertexTangents [ i ] . y * = tangentScale ;
vertexTangents [ i ] . z * = tangentScale ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
const float bitangentScale = idMath : : InvSqrt ( vertexBitangents [ i ] . x * vertexBitangents [ i ] . x + vertexBitangents [ i ] . y * vertexBitangents [ i ] . y + vertexBitangents [ i ] . z * vertexBitangents [ i ] . z ) ;
vertexBitangents [ i ] . x * = bitangentScale ;
vertexBitangents [ i ] . y * = bitangentScale ;
vertexBitangents [ i ] . z * = bitangentScale ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// compress the normals and tangents
2012-11-28 15:47:07 +00:00
for ( int i = 0 ; i < tri - > numVerts ; i + + )
{
2012-11-26 18:58:24 +00:00
tri - > verts [ i ] . SetNormal ( vertexNormals [ i ] ) ;
tri - > verts [ i ] . SetTangent ( vertexTangents [ i ] ) ;
tri - > verts [ i ] . SetBiTangent ( vertexBitangents [ i ] ) ;
}
}
/*
= = = = = = = = = = = =
R_DeriveUnsmoothedNormalsAndTangents
= = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void R_DeriveUnsmoothedNormalsAndTangents ( srfTriangles_t * tri )
{
for ( int i = 0 ; i < tri - > numVerts ; i + + )
{
2012-11-26 18:58:24 +00:00
float d0 , d1 , d2 , d3 , d4 ;
float d5 , d6 , d7 , d8 , d9 ;
float s0 , s1 , s2 ;
float n0 , n1 , n2 ;
float t0 , t1 , t2 ;
float t3 , t4 , t5 ;
2012-11-28 15:47:07 +00:00
const dominantTri_t & dt = tri - > dominantTris [ i ] ;
idDrawVert * a = tri - > verts + i ;
idDrawVert * b = tri - > verts + dt . v2 ;
idDrawVert * c = tri - > verts + dt . v3 ;
2012-11-26 18:58:24 +00:00
const idVec2 aST = a - > GetTexCoord ( ) ;
const idVec2 bST = b - > GetTexCoord ( ) ;
const idVec2 cST = c - > GetTexCoord ( ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
d0 = b - > xyz [ 0 ] - a - > xyz [ 0 ] ;
d1 = b - > xyz [ 1 ] - a - > xyz [ 1 ] ;
d2 = b - > xyz [ 2 ] - a - > xyz [ 2 ] ;
d3 = bST [ 0 ] - aST [ 0 ] ;
d4 = bST [ 1 ] - aST [ 1 ] ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
d5 = c - > xyz [ 0 ] - a - > xyz [ 0 ] ;
d6 = c - > xyz [ 1 ] - a - > xyz [ 1 ] ;
d7 = c - > xyz [ 2 ] - a - > xyz [ 2 ] ;
d8 = cST [ 0 ] - aST [ 0 ] ;
d9 = cST [ 1 ] - aST [ 1 ] ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
s0 = dt . normalizationScale [ 0 ] ;
s1 = dt . normalizationScale [ 1 ] ;
s2 = dt . normalizationScale [ 2 ] ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
n0 = s2 * ( d6 * d2 - d7 * d1 ) ;
n1 = s2 * ( d7 * d0 - d5 * d2 ) ;
n2 = s2 * ( d5 * d1 - d6 * d0 ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
t0 = s0 * ( d0 * d9 - d4 * d5 ) ;
t1 = s0 * ( d1 * d9 - d4 * d6 ) ;
t2 = s0 * ( d2 * d9 - d4 * d7 ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
# ifndef DERIVE_UNSMOOTHED_BITANGENT
t3 = s1 * ( d3 * d5 - d0 * d8 ) ;
t4 = s1 * ( d3 * d6 - d1 * d8 ) ;
t5 = s1 * ( d3 * d7 - d2 * d8 ) ;
# else
t3 = s1 * ( n2 * t1 - n1 * t2 ) ;
t4 = s1 * ( n0 * t2 - n2 * t0 ) ;
t5 = s1 * ( n1 * t0 - n0 * t1 ) ;
# endif
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
a - > SetNormal ( n0 , n1 , n2 ) ;
a - > SetTangent ( t0 , t1 , t2 ) ;
a - > SetBiTangent ( t3 , t4 , t5 ) ;
}
}
/*
= = = = = = = = = = = = = = = = = = = = =
R_CreateVertexNormals
Averages together the contributions of all faces that are
used by a vertex , creating drawVert - > normal
= = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void R_CreateVertexNormals ( srfTriangles_t * tri )
{
if ( tri - > silIndexes = = NULL )
{
2012-11-26 18:58:24 +00:00
R_CreateSilIndexes ( tri ) ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
idTempArray < idVec3 > vertexNormals ( tri - > numVerts ) ;
vertexNormals . Zero ( ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
assert ( tri - > silIndexes ! = NULL ) ;
2012-11-28 15:47:07 +00:00
for ( int i = 0 ; i < tri - > numIndexes ; i + = 3 )
{
2012-11-26 18:58:24 +00:00
const int i0 = tri - > silIndexes [ i + 0 ] ;
const int i1 = tri - > silIndexes [ i + 1 ] ;
const int i2 = tri - > silIndexes [ i + 2 ] ;
2012-11-28 15:47:07 +00:00
const idDrawVert & v0 = tri - > verts [ i0 ] ;
const idDrawVert & v1 = tri - > verts [ i1 ] ;
const idDrawVert & v2 = tri - > verts [ i2 ] ;
2012-11-26 18:58:24 +00:00
const idPlane plane ( v0 . xyz , v1 . xyz , v2 . xyz ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
vertexNormals [ i0 ] + = plane . Normal ( ) ;
vertexNormals [ i1 ] + = plane . Normal ( ) ;
vertexNormals [ i2 ] + = plane . Normal ( ) ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// replicate from silIndexes to all indexes
2012-11-28 15:47:07 +00:00
for ( int i = 0 ; i < tri - > numIndexes ; i + + )
{
2012-11-26 18:58:24 +00:00
vertexNormals [ tri - > indexes [ i ] ] = vertexNormals [ tri - > silIndexes [ i ] ] ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// normalize
2012-11-28 15:47:07 +00:00
for ( int i = 0 ; i < tri - > numVerts ; i + + )
{
2012-11-26 18:58:24 +00:00
vertexNormals [ i ] . Normalize ( ) ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// compress the normals
2012-11-28 15:47:07 +00:00
for ( int i = 0 ; i < tri - > numVerts ; i + + )
{
2012-11-26 18:58:24 +00:00
tri - > verts [ i ] . SetNormal ( vertexNormals [ i ] ) ;
}
}
/*
= = = = = = = = = = = = = = = = =
R_DeriveTangentsWithoutNormals
Build texture space tangents for bump mapping
If a surface is deformed , this must be recalculated
This assumes that any mirrored vertexes have already been duplicated , so
any shared vertexes will have the tangent spaces smoothed across .
Texture wrapping slightly complicates this , but as long as the normals
are shared , and the tangent vectors are projected onto the normals , the
separate vertexes should wind up with identical tangent spaces .
mirroring a normalmap WILL cause a slightly visible seam unless the normals
are completely flat around the edge ' s full bilerp support .
Vertexes which are smooth shaded must have their tangent vectors
in the same plane , which will allow a seamless
rendering as long as the normal map is even on both sides of the
seam .
A smooth shaded surface may have multiple tangent vectors at a vertex
due to texture seams or mirroring , but it should only have a single
normal vector .
Each triangle has a pair of tangent vectors in it ' s plane
Should we consider having vertexes point at shared tangent spaces
to save space or speed transforms ?
this version only handles bilateral symetry
= = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void R_DeriveTangentsWithoutNormals ( srfTriangles_t * tri )
{
2012-11-26 18:58:24 +00:00
idTempArray < idVec3 > triangleTangents ( tri - > numIndexes / 3 ) ;
idTempArray < idVec3 > triangleBitangents ( tri - > numIndexes / 3 ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
//
// calculate tangent vectors for each face in isolation
//
int c_positive = 0 ;
int c_negative = 0 ;
int c_textureDegenerateFaces = 0 ;
2012-11-28 15:47:07 +00:00
for ( int i = 0 ; i < tri - > numIndexes ; i + = 3 )
{
2012-11-26 18:58:24 +00:00
idVec3 temp ;
2012-11-28 15:47:07 +00:00
idDrawVert * a = tri - > verts + tri - > indexes [ i + 0 ] ;
idDrawVert * b = tri - > verts + tri - > indexes [ i + 1 ] ;
idDrawVert * c = tri - > verts + tri - > indexes [ i + 2 ] ;
2012-11-26 18:58:24 +00:00
const idVec2 aST = a - > GetTexCoord ( ) ;
const idVec2 bST = b - > GetTexCoord ( ) ;
const idVec2 cST = c - > GetTexCoord ( ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
float d0 [ 5 ] ;
d0 [ 0 ] = b - > xyz [ 0 ] - a - > xyz [ 0 ] ;
d0 [ 1 ] = b - > xyz [ 1 ] - a - > xyz [ 1 ] ;
d0 [ 2 ] = b - > xyz [ 2 ] - a - > xyz [ 2 ] ;
d0 [ 3 ] = bST [ 0 ] - aST [ 0 ] ;
d0 [ 4 ] = bST [ 1 ] - aST [ 1 ] ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
float d1 [ 5 ] ;
d1 [ 0 ] = c - > xyz [ 0 ] - a - > xyz [ 0 ] ;
d1 [ 1 ] = c - > xyz [ 1 ] - a - > xyz [ 1 ] ;
d1 [ 2 ] = c - > xyz [ 2 ] - a - > xyz [ 2 ] ;
d1 [ 3 ] = cST [ 0 ] - aST [ 0 ] ;
d1 [ 4 ] = cST [ 1 ] - aST [ 1 ] ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
const float area = d0 [ 3 ] * d1 [ 4 ] - d0 [ 4 ] * d1 [ 3 ] ;
2012-11-28 15:47:07 +00:00
if ( fabs ( area ) < 1e-20 f )
{
2012-11-26 18:58:24 +00:00
triangleTangents [ i / 3 ] . Zero ( ) ;
triangleBitangents [ i / 3 ] . Zero ( ) ;
c_textureDegenerateFaces + + ;
continue ;
}
2012-11-28 15:47:07 +00:00
if ( area > 0.0f )
{
2012-11-26 18:58:24 +00:00
c_positive + + ;
2012-11-28 15:47:07 +00:00
}
else
{
2012-11-26 18:58:24 +00:00
c_negative + + ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
# ifdef USE_INVA
float inva = ( area < 0.0f ) ? - 1.0f : 1.0f ; // was = 1.0f / area;
2012-11-28 15:47:07 +00:00
temp [ 0 ] = ( d0 [ 0 ] * d1 [ 4 ] - d0 [ 4 ] * d1 [ 0 ] ) * inva ;
temp [ 1 ] = ( d0 [ 1 ] * d1 [ 4 ] - d0 [ 4 ] * d1 [ 1 ] ) * inva ;
temp [ 2 ] = ( d0 [ 2 ] * d1 [ 4 ] - d0 [ 4 ] * d1 [ 2 ] ) * inva ;
2012-11-26 18:58:24 +00:00
temp . Normalize ( ) ;
triangleTangents [ i / 3 ] = temp ;
2012-11-28 15:47:07 +00:00
temp [ 0 ] = ( d0 [ 3 ] * d1 [ 0 ] - d0 [ 0 ] * d1 [ 3 ] ) * inva ;
temp [ 1 ] = ( d0 [ 3 ] * d1 [ 1 ] - d0 [ 1 ] * d1 [ 3 ] ) * inva ;
temp [ 2 ] = ( d0 [ 3 ] * d1 [ 2 ] - d0 [ 2 ] * d1 [ 3 ] ) * inva ;
2012-11-26 18:58:24 +00:00
temp . Normalize ( ) ;
triangleBitangents [ i / 3 ] = temp ;
# else
2012-11-28 15:47:07 +00:00
temp [ 0 ] = ( d0 [ 0 ] * d1 [ 4 ] - d0 [ 4 ] * d1 [ 0 ] ) ;
temp [ 1 ] = ( d0 [ 1 ] * d1 [ 4 ] - d0 [ 4 ] * d1 [ 1 ] ) ;
temp [ 2 ] = ( d0 [ 2 ] * d1 [ 4 ] - d0 [ 4 ] * d1 [ 2 ] ) ;
2012-11-26 18:58:24 +00:00
temp . Normalize ( ) ;
triangleTangents [ i / 3 ] = temp ;
2012-11-28 15:47:07 +00:00
temp [ 0 ] = ( d0 [ 3 ] * d1 [ 0 ] - d0 [ 0 ] * d1 [ 3 ] ) ;
temp [ 1 ] = ( d0 [ 3 ] * d1 [ 1 ] - d0 [ 1 ] * d1 [ 3 ] ) ;
temp [ 2 ] = ( d0 [ 3 ] * d1 [ 2 ] - d0 [ 2 ] * d1 [ 3 ] ) ;
2012-11-26 18:58:24 +00:00
temp . Normalize ( ) ;
triangleBitangents [ i / 3 ] = temp ;
# endif
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
idTempArray < idVec3 > vertexTangents ( tri - > numVerts ) ;
idTempArray < idVec3 > vertexBitangents ( tri - > numVerts ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// clear the tangents
2012-11-28 15:47:07 +00:00
for ( int i = 0 ; i < tri - > numVerts ; + + i )
{
2012-11-26 18:58:24 +00:00
vertexTangents [ i ] . Zero ( ) ;
vertexBitangents [ i ] . Zero ( ) ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// sum up the neighbors
2012-11-28 15:47:07 +00:00
for ( int i = 0 ; i < tri - > numIndexes ; i + = 3 )
{
2012-11-26 18:58:24 +00:00
// for each vertex on this face
2012-11-28 15:47:07 +00:00
for ( int j = 0 ; j < 3 ; j + + )
{
vertexTangents [ tri - > indexes [ i + j ] ] + = triangleTangents [ i / 3 ] ;
vertexBitangents [ tri - > indexes [ i + j ] ] + = triangleBitangents [ i / 3 ] ;
2012-11-26 18:58:24 +00:00
}
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// Project the summed vectors onto the normal plane and normalize.
// The tangent vectors will not necessarily be orthogonal to each
// other, but they will be orthogonal to the surface normal.
2012-11-28 15:47:07 +00:00
for ( int i = 0 ; i < tri - > numVerts ; i + + )
{
2012-11-26 18:58:24 +00:00
idVec3 normal = tri - > verts [ i ] . GetNormal ( ) ;
normal . Normalize ( ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
vertexTangents [ i ] - = ( vertexTangents [ i ] * normal ) * normal ;
vertexTangents [ i ] . Normalize ( ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
vertexBitangents [ i ] - = ( vertexBitangents [ i ] * normal ) * normal ;
vertexBitangents [ i ] . Normalize ( ) ;
}
2012-11-28 15:47:07 +00:00
for ( int i = 0 ; i < tri - > numVerts ; i + + )
{
2012-11-26 18:58:24 +00:00
tri - > verts [ i ] . SetTangent ( vertexTangents [ i ] ) ;
tri - > verts [ i ] . SetBiTangent ( vertexBitangents [ i ] ) ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
tri - > tangentsCalculated = true ;
}
/*
= = = = = = = = = = = = = = = = = = =
R_BuildDominantTris
Find the largest triangle that uses each vertex
= = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
typedef struct
{
2012-11-26 18:58:24 +00:00
int vertexNum ;
int faceNum ;
} indexSort_t ;
2012-11-28 15:47:07 +00:00
static int IndexSort ( const void * a , const void * b )
{
if ( ( ( indexSort_t * ) a ) - > vertexNum < ( ( indexSort_t * ) b ) - > vertexNum )
{
2012-11-26 18:58:24 +00:00
return - 1 ;
}
2012-11-28 15:47:07 +00:00
if ( ( ( indexSort_t * ) a ) - > vertexNum > ( ( indexSort_t * ) b ) - > vertexNum )
{
2012-11-26 18:58:24 +00:00
return 1 ;
}
return 0 ;
}
2012-11-28 15:47:07 +00:00
void R_BuildDominantTris ( srfTriangles_t * tri )
{
2012-11-26 18:58:24 +00:00
int i , j ;
2012-11-28 15:47:07 +00:00
dominantTri_t * dt ;
2012-11-26 18:58:24 +00:00
const int numIndexes = tri - > numIndexes ;
2012-11-28 15:47:07 +00:00
indexSort_t * ind = ( indexSort_t * ) R_StaticAlloc ( numIndexes * sizeof ( indexSort_t ) ) ;
if ( ind = = NULL )
{
2012-11-26 18:58:24 +00:00
idLib : : Error ( " Couldn't allocate index sort array " ) ;
return ;
}
2012-11-28 15:47:07 +00:00
for ( i = 0 ; i < tri - > numIndexes ; i + + )
{
2012-11-26 18:58:24 +00:00
ind [ i ] . vertexNum = tri - > indexes [ i ] ;
ind [ i ] . faceNum = i / 3 ;
}
qsort ( ind , tri - > numIndexes , sizeof ( * ind ) , IndexSort ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
R_AllocStaticTriSurfDominantTris ( tri , tri - > numVerts ) ;
dt = tri - > dominantTris ;
memset ( dt , 0 , tri - > numVerts * sizeof ( dt [ 0 ] ) ) ;
2012-11-28 15:47:07 +00:00
for ( i = 0 ; i < numIndexes ; i + = j )
{
2012-11-26 18:58:24 +00:00
float maxArea = 0 ;
# pragma warning( disable: 6385 ) // This is simply to get pass a false defect for /analyze -- if you can figure out a better way, please let Shawn know...
int vertNum = ind [ i ] . vertexNum ;
# pragma warning( default: 6385 )
2012-11-28 15:47:07 +00:00
for ( j = 0 ; i + j < tri - > numIndexes & & ind [ i + j ] . vertexNum = = vertNum ; j + + )
{
2012-11-26 18:58:24 +00:00
float d0 [ 5 ] , d1 [ 5 ] ;
2012-11-28 15:47:07 +00:00
idDrawVert * a , * b , * c ;
2012-11-26 18:58:24 +00:00
idVec3 normal , tangent , bitangent ;
2012-11-28 15:47:07 +00:00
int i1 = tri - > indexes [ ind [ i + j ] . faceNum * 3 + 0 ] ;
int i2 = tri - > indexes [ ind [ i + j ] . faceNum * 3 + 1 ] ;
int i3 = tri - > indexes [ ind [ i + j ] . faceNum * 3 + 2 ] ;
2012-11-26 18:58:24 +00:00
a = tri - > verts + i1 ;
b = tri - > verts + i2 ;
c = tri - > verts + i3 ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
const idVec2 aST = a - > GetTexCoord ( ) ;
const idVec2 bST = b - > GetTexCoord ( ) ;
const idVec2 cST = c - > GetTexCoord ( ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
d0 [ 0 ] = b - > xyz [ 0 ] - a - > xyz [ 0 ] ;
d0 [ 1 ] = b - > xyz [ 1 ] - a - > xyz [ 1 ] ;
d0 [ 2 ] = b - > xyz [ 2 ] - a - > xyz [ 2 ] ;
d0 [ 3 ] = bST [ 0 ] - aST [ 0 ] ;
d0 [ 4 ] = bST [ 1 ] - aST [ 1 ] ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
d1 [ 0 ] = c - > xyz [ 0 ] - a - > xyz [ 0 ] ;
d1 [ 1 ] = c - > xyz [ 1 ] - a - > xyz [ 1 ] ;
d1 [ 2 ] = c - > xyz [ 2 ] - a - > xyz [ 2 ] ;
d1 [ 3 ] = cST [ 0 ] - aST [ 0 ] ;
d1 [ 4 ] = cST [ 1 ] - aST [ 1 ] ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
normal [ 0 ] = ( d1 [ 1 ] * d0 [ 2 ] - d1 [ 2 ] * d0 [ 1 ] ) ;
normal [ 1 ] = ( d1 [ 2 ] * d0 [ 0 ] - d1 [ 0 ] * d0 [ 2 ] ) ;
normal [ 2 ] = ( d1 [ 0 ] * d0 [ 1 ] - d1 [ 1 ] * d0 [ 0 ] ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
float area = normal . Length ( ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// if this is smaller than what we already have, skip it
2012-11-28 15:47:07 +00:00
if ( area < maxArea )
{
2012-11-26 18:58:24 +00:00
continue ;
}
maxArea = area ;
2012-11-28 15:47:07 +00:00
if ( i1 = = vertNum )
{
2012-11-26 18:58:24 +00:00
dt [ vertNum ] . v2 = i2 ;
dt [ vertNum ] . v3 = i3 ;
2012-11-28 15:47:07 +00:00
}
else if ( i2 = = vertNum )
{
2012-11-26 18:58:24 +00:00
dt [ vertNum ] . v2 = i3 ;
dt [ vertNum ] . v3 = i1 ;
2012-11-28 15:47:07 +00:00
}
else
{
2012-11-26 18:58:24 +00:00
dt [ vertNum ] . v2 = i1 ;
dt [ vertNum ] . v3 = i2 ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
float len = area ;
2012-11-28 15:47:07 +00:00
if ( len < 0.001f )
{
2012-11-26 18:58:24 +00:00
len = 0.001f ;
}
dt [ vertNum ] . normalizationScale [ 2 ] = 1.0f / len ; // normal
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// texture area
area = d0 [ 3 ] * d1 [ 4 ] - d0 [ 4 ] * d1 [ 3 ] ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
tangent [ 0 ] = ( d0 [ 0 ] * d1 [ 4 ] - d0 [ 4 ] * d1 [ 0 ] ) ;
tangent [ 1 ] = ( d0 [ 1 ] * d1 [ 4 ] - d0 [ 4 ] * d1 [ 1 ] ) ;
tangent [ 2 ] = ( d0 [ 2 ] * d1 [ 4 ] - d0 [ 4 ] * d1 [ 2 ] ) ;
len = tangent . Length ( ) ;
2012-11-28 15:47:07 +00:00
if ( len < 0.001f )
{
2012-11-26 18:58:24 +00:00
len = 0.001f ;
}
dt [ vertNum ] . normalizationScale [ 0 ] = ( area > 0 ? 1 : - 1 ) / len ; // tangents[0]
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
bitangent [ 0 ] = ( d0 [ 3 ] * d1 [ 0 ] - d0 [ 0 ] * d1 [ 3 ] ) ;
bitangent [ 1 ] = ( d0 [ 3 ] * d1 [ 1 ] - d0 [ 1 ] * d1 [ 3 ] ) ;
bitangent [ 2 ] = ( d0 [ 3 ] * d1 [ 2 ] - d0 [ 2 ] * d1 [ 3 ] ) ;
len = bitangent . Length ( ) ;
2012-11-28 15:47:07 +00:00
if ( len < 0.001f )
{
2012-11-26 18:58:24 +00:00
len = 0.001f ;
}
# ifdef DERIVE_UNSMOOTHED_BITANGENT
dt [ vertNum ] . normalizationScale [ 1 ] = ( area > 0 ? 1 : - 1 ) ;
# else
dt [ vertNum ] . normalizationScale [ 1 ] = ( area > 0 ? 1 : - 1 ) / len ; // tangents[1]
# endif
}
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
R_StaticFree ( ind ) ;
}
/*
= = = = = = = = = = = = = = = = = =
R_DeriveTangents
This is called once for static surfaces , and every frame for deforming surfaces
Builds tangents , normals , and face planes
= = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void R_DeriveTangents ( srfTriangles_t * tri )
{
if ( tri - > tangentsCalculated )
{
2012-11-26 18:58:24 +00:00
return ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
tr . pc . c_tangentIndexes + = tri - > numIndexes ;
2012-11-28 15:47:07 +00:00
if ( tri - > dominantTris ! = NULL )
{
2012-11-26 18:58:24 +00:00
R_DeriveUnsmoothedNormalsAndTangents ( tri ) ;
2012-11-28 15:47:07 +00:00
}
else
{
2012-11-26 18:58:24 +00:00
R_DeriveNormalsAndTangents ( tri ) ;
}
tri - > tangentsCalculated = true ;
}
/*
= = = = = = = = = = = = = = = = =
R_RemoveDuplicatedTriangles
silIndexes must have already been calculated
silIndexes are used instead of indexes , because duplicated
triangles could have different texture coordinates .
= = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void R_RemoveDuplicatedTriangles ( srfTriangles_t * tri )
{
2012-11-26 18:58:24 +00:00
int c_removed ;
int i , j , r ;
int a , b , c ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
c_removed = 0 ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// check for completely duplicated triangles
// any rotation of the triangle is still the same, but a mirroring
// is considered different
2012-11-28 15:47:07 +00:00
for ( i = 0 ; i < tri - > numIndexes ; i + = 3 )
{
for ( r = 0 ; r < 3 ; r + + )
{
a = tri - > silIndexes [ i + r ] ;
b = tri - > silIndexes [ i + ( r + 1 ) % 3 ] ;
c = tri - > silIndexes [ i + ( r + 2 ) % 3 ] ;
for ( j = i + 3 ; j < tri - > numIndexes ; j + = 3 )
{
if ( tri - > silIndexes [ j ] = = a & & tri - > silIndexes [ j + 1 ] = = b & & tri - > silIndexes [ j + 2 ] = = c )
{
2012-11-26 18:58:24 +00:00
c_removed + + ;
memmove ( tri - > indexes + j , tri - > indexes + j + 3 , ( tri - > numIndexes - j - 3 ) * sizeof ( tri - > indexes [ 0 ] ) ) ;
memmove ( tri - > silIndexes + j , tri - > silIndexes + j + 3 , ( tri - > numIndexes - j - 3 ) * sizeof ( tri - > silIndexes [ 0 ] ) ) ;
tri - > numIndexes - = 3 ;
j - = 3 ;
}
}
}
}
2012-11-28 15:47:07 +00:00
if ( c_removed )
{
2012-11-26 18:58:24 +00:00
common - > Printf ( " removed %i duplicated triangles \n " , c_removed ) ;
}
}
/*
= = = = = = = = = = = = = = = = =
R_RemoveDegenerateTriangles
silIndexes must have already been calculated
= = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void R_RemoveDegenerateTriangles ( srfTriangles_t * tri )
{
2012-11-26 18:58:24 +00:00
int c_removed ;
int i ;
int a , b , c ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
assert ( tri - > silIndexes ! = NULL ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// check for completely degenerate triangles
c_removed = 0 ;
2012-11-28 15:47:07 +00:00
for ( i = 0 ; i < tri - > numIndexes ; i + = 3 )
{
2012-11-26 18:58:24 +00:00
a = tri - > silIndexes [ i ] ;
2012-11-28 15:47:07 +00:00
b = tri - > silIndexes [ i + 1 ] ;
c = tri - > silIndexes [ i + 2 ] ;
if ( a = = b | | a = = c | | b = = c )
{
2012-11-26 18:58:24 +00:00
c_removed + + ;
memmove ( tri - > indexes + i , tri - > indexes + i + 3 , ( tri - > numIndexes - i - 3 ) * sizeof ( tri - > indexes [ 0 ] ) ) ;
memmove ( tri - > silIndexes + i , tri - > silIndexes + i + 3 , ( tri - > numIndexes - i - 3 ) * sizeof ( tri - > silIndexes [ 0 ] ) ) ;
tri - > numIndexes - = 3 ;
i - = 3 ;
}
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// this doesn't free the memory used by the unused verts
2012-11-28 15:47:07 +00:00
if ( c_removed )
{
2012-11-26 18:58:24 +00:00
common - > Printf ( " removed %i degenerate triangles \n " , c_removed ) ;
}
}
/*
= = = = = = = = = = = = = = = = =
R_TestDegenerateTextureSpace
= = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void R_TestDegenerateTextureSpace ( srfTriangles_t * tri )
{
2012-11-26 18:58:24 +00:00
int c_degenerate ;
int i ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// check for triangles with a degenerate texture space
c_degenerate = 0 ;
2012-11-28 15:47:07 +00:00
for ( i = 0 ; i < tri - > numIndexes ; i + = 3 )
{
const idDrawVert & a = tri - > verts [ tri - > indexes [ i + 0 ] ] ;
const idDrawVert & b = tri - > verts [ tri - > indexes [ i + 1 ] ] ;
const idDrawVert & c = tri - > verts [ tri - > indexes [ i + 2 ] ] ;
2013-06-01 13:13:00 +00:00
// RB: compare texcoords instead of pointers
if ( a . GetTexCoord ( ) = = b . GetTexCoord ( ) | | b . GetTexCoord ( ) = = c . GetTexCoord ( ) | | c . GetTexCoord ( ) = = a . GetTexCoord ( ) )
2012-11-28 15:47:07 +00:00
{
2012-11-26 18:58:24 +00:00
c_degenerate + + ;
}
2013-06-01 13:13:00 +00:00
// RB end
2012-11-26 18:58:24 +00:00
}
2012-11-28 15:47:07 +00:00
if ( c_degenerate )
{
2012-11-26 18:58:24 +00:00
// common->Printf( "%d triangles with a degenerate texture space\n", c_degenerate );
}
}
/*
= = = = = = = = = = = = = = = = =
R_RemoveUnusedVerts
= = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void R_RemoveUnusedVerts ( srfTriangles_t * tri )
{
2012-11-26 18:58:24 +00:00
int i ;
2012-11-28 15:47:07 +00:00
int * mark ;
2012-11-26 18:58:24 +00:00
int index ;
int used ;
2012-11-28 15:47:07 +00:00
mark = ( int * ) R_ClearedStaticAlloc ( tri - > numVerts * sizeof ( * mark ) ) ;
for ( i = 0 ; i < tri - > numIndexes ; i + + )
{
2012-11-26 18:58:24 +00:00
index = tri - > indexes [ i ] ;
2012-11-28 15:47:07 +00:00
if ( index < 0 | | index > = tri - > numVerts )
{
2012-11-26 18:58:24 +00:00
common - > Error ( " R_RemoveUnusedVerts: bad index " ) ;
}
mark [ index ] = 1 ;
2012-11-28 15:47:07 +00:00
if ( tri - > silIndexes )
{
2012-11-26 18:58:24 +00:00
index = tri - > silIndexes [ i ] ;
2012-11-28 15:47:07 +00:00
if ( index < 0 | | index > = tri - > numVerts )
{
2012-11-26 18:58:24 +00:00
common - > Error ( " R_RemoveUnusedVerts: bad index " ) ;
}
mark [ index ] = 1 ;
}
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
used = 0 ;
2012-11-28 15:47:07 +00:00
for ( i = 0 ; i < tri - > numVerts ; i + + )
{
if ( ! mark [ i ] )
{
2012-11-26 18:58:24 +00:00
continue ;
}
mark [ i ] = used + 1 ;
used + + ;
}
2012-11-28 15:47:07 +00:00
if ( used ! = tri - > numVerts )
{
for ( i = 0 ; i < tri - > numIndexes ; i + + )
{
2012-11-26 18:58:24 +00:00
tri - > indexes [ i ] = mark [ tri - > indexes [ i ] ] - 1 ;
2012-11-28 15:47:07 +00:00
if ( tri - > silIndexes )
{
2012-11-26 18:58:24 +00:00
tri - > silIndexes [ i ] = mark [ tri - > silIndexes [ i ] ] - 1 ;
}
}
tri - > numVerts = used ;
2012-11-28 15:47:07 +00:00
for ( i = 0 ; i < tri - > numVerts ; i + + )
{
2012-11-26 18:58:24 +00:00
index = mark [ i ] ;
2012-11-28 15:47:07 +00:00
if ( ! index )
{
2012-11-26 18:58:24 +00:00
continue ;
}
tri - > verts [ index - 1 ] = tri - > verts [ i ] ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// this doesn't realloc the arrays to save the memory used by the unused verts
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
R_StaticFree ( mark ) ;
}
/*
= = = = = = = = = = = = = = = = =
R_MergeSurfaceList
Only deals with vertexes and indexes , not silhouettes , planes , etc .
Does NOT perform a cleanup triangles , so there may be duplicated verts in the result .
= = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
srfTriangles_t * R_MergeSurfaceList ( const srfTriangles_t * * surfaces , int numSurfaces )
{
srfTriangles_t * newTri ;
const srfTriangles_t * tri ;
2012-11-26 18:58:24 +00:00
int i , j ;
int totalVerts ;
int totalIndexes ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
totalVerts = 0 ;
totalIndexes = 0 ;
2012-11-28 15:47:07 +00:00
for ( i = 0 ; i < numSurfaces ; i + + )
{
2012-11-26 18:58:24 +00:00
totalVerts + = surfaces [ i ] - > numVerts ;
totalIndexes + = surfaces [ i ] - > numIndexes ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
newTri = R_AllocStaticTriSurf ( ) ;
newTri - > numVerts = totalVerts ;
newTri - > numIndexes = totalIndexes ;
R_AllocStaticTriSurfVerts ( newTri , newTri - > numVerts ) ;
R_AllocStaticTriSurfIndexes ( newTri , newTri - > numIndexes ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
totalVerts = 0 ;
totalIndexes = 0 ;
2012-11-28 15:47:07 +00:00
for ( i = 0 ; i < numSurfaces ; i + + )
{
2012-11-26 18:58:24 +00:00
tri = surfaces [ i ] ;
memcpy ( newTri - > verts + totalVerts , tri - > verts , tri - > numVerts * sizeof ( * tri - > verts ) ) ;
2012-11-28 15:47:07 +00:00
for ( j = 0 ; j < tri - > numIndexes ; j + + )
{
2012-11-26 18:58:24 +00:00
newTri - > indexes [ totalIndexes + j ] = totalVerts + tri - > indexes [ j ] ;
}
totalVerts + = tri - > numVerts ;
totalIndexes + = tri - > numIndexes ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
return newTri ;
}
/*
= = = = = = = = = = = = = = = = =
R_MergeTriangles
Only deals with vertexes and indexes , not silhouettes , planes , etc .
Does NOT perform a cleanup triangles , so there may be duplicated verts in the result .
= = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
srfTriangles_t * R_MergeTriangles ( const srfTriangles_t * tri1 , const srfTriangles_t * tri2 )
{
const srfTriangles_t * tris [ 2 ] ;
2012-11-26 18:58:24 +00:00
tris [ 0 ] = tri1 ;
tris [ 1 ] = tri2 ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
return R_MergeSurfaceList ( tris , 2 ) ;
}
/*
= = = = = = = = = = = = = = = = =
R_ReverseTriangles
Lit two sided surfaces need to have the triangles actually duplicated ,
they can ' t just turn on two sided lighting , because the normal and tangents
are wrong on the other sides .
This should be called before R_CleanupTriangles
= = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void R_ReverseTriangles ( srfTriangles_t * tri )
{
2012-11-26 18:58:24 +00:00
int i ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// flip the normal on each vertex
// If the surface is going to have generated normals, this won't matter,
// but if it has explicit normals, this will keep it on the correct side
2012-11-28 15:47:07 +00:00
for ( i = 0 ; i < tri - > numVerts ; i + + )
{
2012-11-26 18:58:24 +00:00
tri - > verts [ i ] . SetNormal ( vec3_origin - tri - > verts [ i ] . GetNormal ( ) ) ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// flip the index order to make them back sided
2012-11-28 15:47:07 +00:00
for ( i = 0 ; i < tri - > numIndexes ; i + = 3 )
{
2012-11-26 18:58:24 +00:00
triIndex_t temp ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
temp = tri - > indexes [ i + 0 ] ;
tri - > indexes [ i + 0 ] = tri - > indexes [ i + 1 ] ;
tri - > indexes [ i + 1 ] = temp ;
}
}
/*
= = = = = = = = = = = = = = = = =
R_CleanupTriangles
FIXME : allow createFlat and createSmooth normals , as well as explicit
= = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void R_CleanupTriangles ( srfTriangles_t * tri , bool createNormals , bool identifySilEdges , bool useUnsmoothedTangents )
{
2012-11-26 18:58:24 +00:00
R_RangeCheckIndexes ( tri ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
R_CreateSilIndexes ( tri ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// R_RemoveDuplicatedTriangles( tri ); // this may remove valid overlapped transparent triangles
R_RemoveDegenerateTriangles ( tri ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
R_TestDegenerateTextureSpace ( tri ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// R_RemoveUnusedVerts( tri );
2012-11-28 15:47:07 +00:00
if ( identifySilEdges )
{
2012-11-26 18:58:24 +00:00
R_IdentifySilEdges ( tri , true ) ; // assume it is non-deformable, and omit coplanar edges
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// bust vertexes that share a mirrored edge into separate vertexes
R_DuplicateMirroredVertexes ( tri ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
R_CreateDupVerts ( tri ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
R_BoundTriSurf ( tri ) ;
2012-11-28 15:47:07 +00:00
if ( useUnsmoothedTangents )
{
2012-11-26 18:58:24 +00:00
R_BuildDominantTris ( tri ) ;
R_DeriveTangents ( tri ) ;
2012-11-28 15:47:07 +00:00
}
else if ( ! createNormals )
{
2012-11-26 18:58:24 +00:00
R_DeriveTangentsWithoutNormals ( tri ) ;
2012-11-28 15:47:07 +00:00
}
else
{
2012-11-26 18:58:24 +00:00
R_DeriveTangents ( tri ) ;
}
}
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
DEFORMED SURFACES
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
/*
= = = = = = = = = = = = = = = = = = =
R_BuildDeformInfo
= = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
deformInfo_t * R_BuildDeformInfo ( int numVerts , const idDrawVert * verts , int numIndexes , const int * indexes ,
bool useUnsmoothedTangents )
{
2012-11-26 18:58:24 +00:00
srfTriangles_t tri ;
memset ( & tri , 0 , sizeof ( srfTriangles_t ) ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
tri . numVerts = numVerts ;
R_AllocStaticTriSurfVerts ( & tri , tri . numVerts ) ;
SIMDProcessor - > Memcpy ( tri . verts , verts , tri . numVerts * sizeof ( tri . verts [ 0 ] ) ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
tri . numIndexes = numIndexes ;
R_AllocStaticTriSurfIndexes ( & tri , tri . numIndexes ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// don't memcpy, so we can change the index type from int to short without changing the interface
2012-11-28 15:47:07 +00:00
for ( int i = 0 ; i < tri . numIndexes ; i + + )
{
2012-11-26 18:58:24 +00:00
tri . indexes [ i ] = indexes [ i ] ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
R_RangeCheckIndexes ( & tri ) ;
R_CreateSilIndexes ( & tri ) ;
R_IdentifySilEdges ( & tri , false ) ; // we cannot remove coplanar edges, because they can deform to silhouettes
R_DuplicateMirroredVertexes ( & tri ) ; // split mirror points into multiple points
R_CreateDupVerts ( & tri ) ;
2012-11-28 15:47:07 +00:00
if ( useUnsmoothedTangents )
{
2012-11-26 18:58:24 +00:00
R_BuildDominantTris ( & tri ) ;
}
R_DeriveTangents ( & tri ) ;
2012-11-28 15:47:07 +00:00
deformInfo_t * deform = ( deformInfo_t * ) R_ClearedStaticAlloc ( sizeof ( * deform ) ) ;
2012-11-26 18:58:24 +00:00
deform - > numSourceVerts = numVerts ;
deform - > numOutputVerts = tri . numVerts ;
deform - > verts = tri . verts ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
deform - > numIndexes = numIndexes ;
deform - > indexes = tri . indexes ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
deform - > silIndexes = tri . silIndexes ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
deform - > numSilEdges = tri . numSilEdges ;
deform - > silEdges = tri . silEdges ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
deform - > numMirroredVerts = tri . numMirroredVerts ;
deform - > mirroredVerts = tri . mirroredVerts ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
deform - > numDupVerts = tri . numDupVerts ;
deform - > dupVerts = tri . dupVerts ;
2012-11-28 15:47:07 +00:00
if ( tri . dominantTris ! = NULL )
{
2012-11-26 18:58:24 +00:00
Mem_Free ( tri . dominantTris ) ;
tri . dominantTris = NULL ;
}
2012-11-28 15:47:07 +00:00
idShadowVertSkinned * shadowVerts = ( idShadowVertSkinned * ) Mem_Alloc16 ( ALIGN ( deform - > numOutputVerts * 2 * sizeof ( idShadowVertSkinned ) , 16 ) , TAG_MODEL ) ;
2012-11-26 18:58:24 +00:00
idShadowVertSkinned : : CreateShadowCache ( shadowVerts , deform - > verts , deform - > numOutputVerts ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
deform - > staticAmbientCache = vertexCache . AllocStaticVertex ( deform - > verts , ALIGN ( deform - > numOutputVerts * sizeof ( idDrawVert ) , VERTEX_CACHE_ALIGN ) ) ;
deform - > staticIndexCache = vertexCache . AllocStaticIndex ( deform - > indexes , ALIGN ( deform - > numIndexes * sizeof ( triIndex_t ) , INDEX_CACHE_ALIGN ) ) ;
deform - > staticShadowCache = vertexCache . AllocStaticVertex ( shadowVerts , ALIGN ( deform - > numOutputVerts * 2 * sizeof ( idShadowVertSkinned ) , VERTEX_CACHE_ALIGN ) ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
Mem_Free ( shadowVerts ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
return deform ;
}
/*
= = = = = = = = = = = = = = = = = = =
R_FreeDeformInfo
= = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void R_FreeDeformInfo ( deformInfo_t * deformInfo )
{
if ( deformInfo - > verts ! = NULL )
{
2012-11-26 18:58:24 +00:00
Mem_Free ( deformInfo - > verts ) ;
}
2012-11-28 15:47:07 +00:00
if ( deformInfo - > indexes ! = NULL )
{
2012-11-26 18:58:24 +00:00
Mem_Free ( deformInfo - > indexes ) ;
}
2012-11-28 15:47:07 +00:00
if ( deformInfo - > silIndexes ! = NULL )
{
2012-11-26 18:58:24 +00:00
Mem_Free ( deformInfo - > silIndexes ) ;
}
2012-11-28 15:47:07 +00:00
if ( deformInfo - > silEdges ! = NULL )
{
2012-11-26 18:58:24 +00:00
Mem_Free ( deformInfo - > silEdges ) ;
}
2012-11-28 15:47:07 +00:00
if ( deformInfo - > mirroredVerts ! = NULL )
{
2012-11-26 18:58:24 +00:00
Mem_Free ( deformInfo - > mirroredVerts ) ;
}
2012-11-28 15:47:07 +00:00
if ( deformInfo - > dupVerts ! = NULL )
{
2012-11-26 18:58:24 +00:00
Mem_Free ( deformInfo - > dupVerts ) ;
}
R_StaticFree ( deformInfo ) ;
}
/*
= = = = = = = = = = = = = = = = = = =
R_DeformInfoMemoryUsed
= = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
int R_DeformInfoMemoryUsed ( deformInfo_t * deformInfo )
{
2012-11-26 18:58:24 +00:00
int total = 0 ;
2012-11-28 15:47:07 +00:00
if ( deformInfo - > verts ! = NULL )
{
2012-11-26 18:58:24 +00:00
total + = deformInfo - > numOutputVerts * sizeof ( deformInfo - > verts [ 0 ] ) ;
}
2012-11-28 15:47:07 +00:00
if ( deformInfo - > indexes ! = NULL )
{
2012-11-26 18:58:24 +00:00
total + = deformInfo - > numIndexes * sizeof ( deformInfo - > indexes [ 0 ] ) ;
}
2012-11-28 15:47:07 +00:00
if ( deformInfo - > mirroredVerts ! = NULL )
{
2012-11-26 18:58:24 +00:00
total + = deformInfo - > numMirroredVerts * sizeof ( deformInfo - > mirroredVerts [ 0 ] ) ;
}
2012-11-28 15:47:07 +00:00
if ( deformInfo - > dupVerts ! = NULL )
{
2012-11-26 18:58:24 +00:00
total + = deformInfo - > numDupVerts * sizeof ( deformInfo - > dupVerts [ 0 ] ) ;
}
2012-11-28 15:47:07 +00:00
if ( deformInfo - > silIndexes ! = NULL )
{
2012-11-26 18:58:24 +00:00
total + = deformInfo - > numIndexes * sizeof ( deformInfo - > silIndexes [ 0 ] ) ;
}
2012-11-28 15:47:07 +00:00
if ( deformInfo - > silEdges ! = NULL )
{
2012-11-26 18:58:24 +00:00
total + = deformInfo - > numSilEdges * sizeof ( deformInfo - > silEdges [ 0 ] ) ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
total + = sizeof ( * deformInfo ) ;
return total ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
VERTEX / INDEX CACHING
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
/*
= = = = = = = = = = = = = = = = = = =
R_InitDrawSurfFromTri
= = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void R_InitDrawSurfFromTri ( drawSurf_t & ds , srfTriangles_t & tri )
{
if ( tri . numIndexes = = 0 )
{
2012-11-26 18:58:24 +00:00
ds . numIndexes = 0 ;
return ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// copy verts and indexes to this frame's hardware memory if they aren't already there
//
// deformed surfaces will not have any vertices but the ambient cache will have already
// been created for them.
2012-11-28 15:47:07 +00:00
if ( ( tri . verts = = NULL ) & & ! tri . referencedIndexes )
{
2012-11-26 18:58:24 +00:00
// pre-generated shadow models will not have any verts, just shadowVerts
tri . ambientCache = 0 ;
2012-11-28 15:47:07 +00:00
}
else if ( ! vertexCache . CacheIsCurrent ( tri . ambientCache ) )
{
2012-11-26 18:58:24 +00:00
tri . ambientCache = vertexCache . AllocVertex ( tri . verts , ALIGN ( tri . numVerts * sizeof ( tri . verts [ 0 ] ) , VERTEX_CACHE_ALIGN ) ) ;
}
2012-11-28 15:47:07 +00:00
if ( ! vertexCache . CacheIsCurrent ( tri . indexCache ) )
{
2012-11-26 18:58:24 +00:00
tri . indexCache = vertexCache . AllocIndex ( tri . indexes , ALIGN ( tri . numIndexes * sizeof ( tri . indexes [ 0 ] ) , INDEX_CACHE_ALIGN ) ) ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
ds . numIndexes = tri . numIndexes ;
ds . ambientCache = tri . ambientCache ;
ds . indexCache = tri . indexCache ;
ds . shadowCache = tri . shadowCache ;
ds . jointCache = 0 ;
}
/*
= = = = = = = = = = = = = = = = = = =
R_CreateStaticBuffersForTri
For static surfaces , the indexes , ambient , and shadow buffers can be pre - created at load
time , rather than being re - created each frame in the frame temporary buffers .
= = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void R_CreateStaticBuffersForTri ( srfTriangles_t & tri )
{
2012-11-26 18:58:24 +00:00
tri . indexCache = 0 ;
tri . ambientCache = 0 ;
tri . shadowCache = 0 ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// index cache
2012-11-28 15:47:07 +00:00
if ( tri . indexes ! = NULL )
{
2012-11-26 18:58:24 +00:00
tri . indexCache = vertexCache . AllocStaticIndex ( tri . indexes , ALIGN ( tri . numIndexes * sizeof ( tri . indexes [ 0 ] ) , INDEX_CACHE_ALIGN ) ) ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// vertex cache
2012-11-28 15:47:07 +00:00
if ( tri . verts ! = NULL )
{
2012-11-26 18:58:24 +00:00
tri . ambientCache = vertexCache . AllocStaticVertex ( tri . verts , ALIGN ( tri . numVerts * sizeof ( tri . verts [ 0 ] ) , VERTEX_CACHE_ALIGN ) ) ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// shadow cache
2012-11-28 15:47:07 +00:00
if ( tri . preLightShadowVertexes ! = NULL )
{
2012-11-26 18:58:24 +00:00
// this should only be true for the _prelight<NAME> pre-calculated shadow volumes
assert ( tri . verts = = NULL ) ; // pre-light shadow volume surfaces don't have ambient vertices
const int shadowSize = ALIGN ( tri . numVerts * 2 * sizeof ( idShadowVert ) , VERTEX_CACHE_ALIGN ) ;
tri . shadowCache = vertexCache . AllocStaticVertex ( tri . preLightShadowVertexes , shadowSize ) ;
2012-11-28 15:47:07 +00:00
}
else if ( tri . verts ! = NULL )
{
2012-11-26 18:58:24 +00:00
// the shadowVerts for normal models include all the xyz values duplicated
// for a W of 1 (near cap) and a W of 0 (end cap, projected to infinity)
const int shadowSize = ALIGN ( tri . numVerts * 2 * sizeof ( idShadowVert ) , VERTEX_CACHE_ALIGN ) ;
2012-11-28 15:47:07 +00:00
if ( tri . staticShadowVertexes = = NULL )
{
tri . staticShadowVertexes = ( idShadowVert * ) Mem_Alloc16 ( shadowSize , TAG_TEMP ) ;
2012-11-26 18:58:24 +00:00
idShadowVert : : CreateShadowCache ( tri . staticShadowVertexes , tri . verts , tri . numVerts ) ;
}
tri . shadowCache = vertexCache . AllocStaticVertex ( tri . staticShadowVertexes , shadowSize ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
# if !defined( KEEP_INTERACTION_CPU_DATA )
Mem_Free ( tri . staticShadowVertexes ) ;
tri . staticShadowVertexes = NULL ;
# endif
}
}