📄 faces.cpp
字号:
int c_nodefaces;
static void SubdivideFaceBySubdivSize( face_t *f, float subdivsize );
void SubdivideFaceBySubdivSize( face_t *f );
/*
============
FaceFromPortal
============
*/
extern int FindOrCreateTexInfo( const texinfo_t &searchTexInfo );
face_t *FaceFromPortal (portal_t *p, int pside)
{
face_t *f;
side_t *side;
int deltaContents;
// portal does not bridge different visible contents
side = p->side;
if (!side)
return NULL;
// allocate a new face
f = AllocFace();
// save the original "side" from the map brush -- portal->side
// see FindPortalSide(...)
f->originalface = side;
//
// save material info
//
f->texinfo = side->texinfo;
f->dispinfo = -1; // all faces with displacement info are created elsewhere
f->smoothingGroups = side->smoothingGroups;
// save plane info
f->planenum = (side->planenum & ~1) | pside;
// save portal info
f->portal = p;
deltaContents = VisibleContents(p->nodes[!pside]->contents^p->nodes[pside]->contents);
// don't show insides of windows or grates
if ( ((p->nodes[pside]->contents & CONTENTS_WINDOW) && deltaContents == CONTENTS_WINDOW) ||
((p->nodes[pside]->contents & CONTENTS_GRATE) && deltaContents == CONTENTS_GRATE) )
{
FreeFace( f );
return NULL;
}
// If it's the underside of water, we need to figure out what material to use, etc.
if( ( p->nodes[pside]->contents & CONTENTS_WATER ) && deltaContents == CONTENTS_WATER )
{
#if 0
FreeFace( f );
return NULL;
#endif
// garymcthack - stick in another function
texinfo_t *pTexInfo = &texinfo[f->texinfo];
dtexdata_t *pTexData = GetTexData( pTexInfo->texdata );
MaterialSystemMaterial_t matID =
FindOriginalMaterial( TexDataStringTable_GetString( pTexData->nameStringTableID ), NULL, true );
const char *bottomMatName = GetMaterialVar( matID, "$bottommaterial" );
if( !bottomMatName )
{
const char *pMaterialName = TexDataStringTable_GetString( pTexData->nameStringTableID );
if( !Q_stristr( pMaterialName, "nodraw" ) )
{
Warning("error: material %s doesn't have a $bottommaterial\n",
pMaterialName );
}
FreeFace( f );
return NULL;
}
texinfo_t newTexInfo;
newTexInfo.flags = pTexInfo->flags;
int j, k;
for (j=0 ; j<2 ; j++)
{
for (k=0 ; k<4 ; k++)
{
newTexInfo.textureVecsTexelsPerWorldUnits[j][k] = pTexInfo->textureVecsTexelsPerWorldUnits[j][k];
newTexInfo.lightmapVecsLuxelsPerWorldUnits[j][k] = pTexInfo->lightmapVecsLuxelsPerWorldUnits[j][k];
}
}
newTexInfo.texdata = FindTexData( bottomMatName );
f->texinfo = FindOrCreateTexInfo( newTexInfo );
}
//
// generate the winding for the face and save face contents
//
if( pside )
{
f->w = ReverseWinding(p->winding);
f->contents = p->nodes[1]->contents;
}
else
{
f->w = CopyWinding(p->winding);
f->contents = p->nodes[0]->contents;
}
f->numPrims = 0;
f->firstPrimID = 0;
// return the created face
return f;
}
/*
===============
MakeFaces_r
If a portal will make a visible face,
mark the side that originally created it
solid / empty : solid
solid / water : solid
water / empty : water
water / water : none
===============
*/
void MakeFaces_r (node_t *node)
{
portal_t *p;
int s;
// recurse down to leafs
if (node->planenum != PLANENUM_LEAF)
{
MakeFaces_r (node->children[0]);
MakeFaces_r (node->children[1]);
// merge together all visible faces on the node
if (!nomerge)
MergeFaceList(&node->faces);
if (!nosubdiv)
SubdivideFaceList(&node->faces);
return;
}
// solid leafs never have visible faces
if (node->contents & CONTENTS_SOLID)
return;
// see which portals are valid
for (p=node->portals ; p ; p = p->next[s])
{
s = (p->nodes[1] == node);
p->face[s] = FaceFromPortal (p, s);
if (p->face[s])
{
c_nodefaces++;
p->face[s]->next = p->onnode->faces;
p->onnode->faces = p->face[s];
}
}
}
typedef winding_t *pwinding_t;
static void PrintWinding( winding_t *w )
{
int i;
Msg( "\t---\n" );
for( i = 0; i < w->numpoints; i++ )
{
Msg( "\t%f %f %f\n", w->p[i].x, w->p[i].y, w->p[i].z );
}
}
//-----------------------------------------------------------------------------
// Purpose: Adds a winding to the current list of primverts
// Input : *w - the winding
// *pIndices - The output indices
// vertStart - the starting vert index
// vertCount - current count
// Output : int - output count including new verts from this winding
//-----------------------------------------------------------------------------
int AddWindingToPrimverts( const winding_t *w, unsigned short *pIndices, int vertStart, int vertCount )
{
for( int i = 0; i < w->numpoints; i++ )
{
int j;
for( j = vertStart; j < vertStart + vertCount; j++ )
{
Vector tmp = g_primverts[j].pos - w->p[i];
if( tmp.LengthSqr() < POINT_EPSILON*POINT_EPSILON )
{
pIndices[i] = j;
break;
}
}
if ( j >= vertStart + vertCount )
{
pIndices[i] = j;
g_primverts[j].pos = w->p[i];
vertCount++;
g_numprimverts++;
if ( g_numprimverts > MAX_MAP_PRIMVERTS )
{
Error( "Exceeded max water verts.\nIncrease surface subdivision size or lower your subdivision size in vmt files! (%d>%d)\n",
( int )g_numprimverts, ( int )MAX_MAP_PRIMVERTS );
}
}
}
return vertCount;
}
#pragma optimize( "g", off )
#define USE_TRISTRIPS
// UNDONE: Should split this function into subdivide and primitive building parts
// UNDONE: We should try building strips of shared verts for all water faces in a leaf
// since those will be drawn concurrently anyway. It should be more efficient.
static void SubdivideFaceBySubdivSize( face_t *f, float subdivsize )
{
// garymcthack - REFACTOR ME!!!
vec_t dummy;
Vector hackNormal;
WindingPlane( f->w, hackNormal, &dummy );
// HACK - only subdivide stuff that is facing up or down (for water)
if( fabs(hackNormal[2]) < .9f )
{
return;
}
// Get the extents of the surface.
// garymcthack - this assumes a surface of constant z for now (for water). . can generalize later.
subdivsize = ( int )subdivsize;
winding_t *w;
w = CopyWinding( f->w );
Vector min, max;
WindingBounds( w, min, max );
#if 0
Msg( "START WINDING: \n" );
PrintWinding( w );
#endif
int xStart, yStart, xEnd, yEnd, xSteps, ySteps;
xStart = ( int )subdivsize * ( int )( ( min[0] - subdivsize ) / subdivsize );
xEnd = ( int )subdivsize * ( int )( ( max[0] + subdivsize ) / subdivsize );
yStart = ( int )subdivsize * ( int )( ( min[1] - subdivsize ) / subdivsize );
yEnd = ( int )subdivsize * ( int )( ( max[1] + subdivsize ) / subdivsize );
xSteps = ( xEnd - xStart ) / subdivsize;
ySteps = ( yEnd - yStart ) / subdivsize;
int x, y;
int xi, yi;
winding_t **windings = ( winding_t ** )new pwinding_t[xSteps * ySteps];
memset( windings, 0, sizeof( winding_t * ) * xSteps * ySteps );
int numWindings = 0;
for( yi = 0, y = yStart; y < yEnd; y += ( int )subdivsize, yi++ )
{
for( xi = 0, x = xStart; x < xEnd; x += ( int )subdivsize, xi++ )
{
winding_t *tempWinding, *frontWinding, *backWinding;
float planeDist;
Vector normal;
normal.Init( 1.0f, 0.0f, 0.0f );
planeDist = ( float )x;
tempWinding = CopyWinding( w );
ClipWindingEpsilon( tempWinding, normal, planeDist, ON_EPSILON,
&frontWinding, &backWinding );
if( tempWinding )
{
FreeWinding( tempWinding );
}
if( backWinding )
{
FreeWinding( backWinding );
}
if( !frontWinding )
{
continue;
}
tempWinding = frontWinding;
normal.Init( -1.0f, 0.0f, 0.0f );
planeDist = -( float )( x + subdivsize );
ClipWindingEpsilon( tempWinding, normal, planeDist, ON_EPSILON,
&frontWinding, &backWinding );
if( tempWinding )
{
FreeWinding( tempWinding );
}
if( backWinding )
{
FreeWinding( backWinding );
}
if( !frontWinding )
{
continue;
}
tempWinding = frontWinding;
normal.Init( 0.0f, 1.0f, 0.0f );
planeDist = ( float )y;
ClipWindingEpsilon( tempWinding, normal, planeDist, ON_EPSILON,
&frontWinding, &backWinding );
if( tempWinding )
{
FreeWinding( tempWinding );
}
if( backWinding )
{
FreeWinding( backWinding );
}
if( !frontWinding )
{
continue;
}
tempWinding = frontWinding;
normal.Init( 0.0f, -1.0f, 0.0f );
planeDist = -( float )( y + subdivsize );
ClipWindingEpsilon( tempWinding, normal, planeDist, ON_EPSILON,
&frontWinding, &backWinding );
if( tempWinding )
{
FreeWinding( tempWinding );
}
if( backWinding )
{
FreeWinding( backWinding );
}
if( !frontWinding )
{
continue;
}
#if 0
Msg( "output winding:\n" );
PrintWinding( frontWinding );
#endif
if( frontWinding )
{
windings[xi + yi * xSteps] = frontWinding;
}
}
}
FreeWinding( w );
dprimitive_t &newPrim = g_primitives[g_numprimitives];
f->firstPrimID = g_numprimitives;
f->numPrims = 1;
newPrim.firstIndex = g_numprimindices;
newPrim.firstVert = g_numprimverts;
newPrim.indexCount = 0;
newPrim.vertCount = 0;
#ifdef USE_TRISTRIPS
newPrim.type = PRIM_TRISTRIP;
#else
newPrim.type = PRIM_TRILIST;
#endif
CUtlVector<WORD> triListIndices;
int i;
for( i = 0; i < xSteps * ySteps; i++ )
{
if( !windings[i] )
{
continue;
}
unsigned short *pIndices =
( unsigned short * )_alloca( windings[i]->numpoints * sizeof( unsigned short ) );
// find indices for the verts.
newPrim.vertCount = AddWindingToPrimverts( windings[i], pIndices, newPrim.firstVert, newPrim.vertCount );
// Now that we have indices for the verts, fan-tesselate the polygon and spit out tris.
for( int j = 0; j < windings[i]->numpoints - 2; j++ )
{
triListIndices.AddToTail( pIndices[0] );
triListIndices.AddToTail( pIndices[j+1] );
triListIndices.AddToTail( pIndices[j+2] );
}
}
delete [] windings;
// We've already updated the verts and have a trilist. . let's strip it!
if( !triListIndices.Size() )
{
return;
}
#ifdef USE_TRISTRIPS
int numTristripIndices;
WORD *pStripIndices = NULL;
Stripify( triListIndices.Size() / 3, triListIndices.Base(), &numTristripIndices,
&pStripIndices );
assert( pStripIndices );
// FIXME: Should also call ComputeVertexPermutation and reorder the verts.
for( i = 0; i < numTristripIndices; i++ )
{
assert( pStripIndices[i] >= newPrim.firstVert &&
pStripIndices[i] < newPrim.firstVert + newPrim.vertCount );
g_primindices[newPrim.firstIndex + newPrim.indexCount] = pStripIndices[i];
newPrim.indexCount++;
g_numprimindices++;
if( g_numprimindices > MAX_MAP_PRIMINDICES )
{
Error( "Exceeded max water indicies.\nIncrease surface subdivision size! (%d>%d)\n", g_numprimindices, MAX_MAP_PRIMINDICES );
}
}
delete [] pStripIndices;
#else
for( i = 0; i < triListIndices.Size(); i++ )
{
g_primindices[newPrim.firstIndex + newPrim.indexCount] = triListIndices[i];
newPrim.indexCount++;
g_numprimindices++;
if( g_numprimindices > MAX_MAP_PRIMINDICES )
{
Error( "Exceeded max water indicies.\nIncrease surface subdivision size! (%d>%d)\n", g_numprimindices, MAX_MAP_PRIMINDICES );
}
}
#endif
g_numprimitives++; // don't increment until we get here and are sure that we have a primitive.
if( g_numprimitives > MAX_MAP_PRIMITIVES )
{
Error( "Exceeded max water primitives.\nIncrease surface subdivision size! (%d>%d)\n", ( int )g_numprimitives, ( int )MAX_MAP_PRIMITIVES );
}
}
void SubdivideFaceBySubdivSize( face_t *f )
{
if( f->numpoints == 0 )
{
return;
}
// see if the face needs to be subdivided.
texinfo_t *pTexInfo = &texinfo[f->texinfo];
dtexdata_t *pTexData = GetTexData( pTexInfo->texdata );
bool bFound;
const char *pMaterialName = TexDataStringTable_GetString( pTexData->nameStringTableID );
MaterialSystemMaterial_t matID =
FindOriginalMaterial( pMaterialName, &bFound, false );
if( !bFound )
{
return;
}
const char *subdivsizeString = GetMaterialVar( matID, "$subdivsize" );
if( subdivsizeString )
{
float subdivSize = atof( subdivsizeString );
if( subdivSize > 0.0f )
{
SubdivideFaceBySubdivSize( f, subdivSize );
}
}
}
void SplitSubdividedFaces_Node_r( node_t *node )
{
if (node->planenum == PLANENUM_LEAF)
{
return;
}
face_t *f;
for( f = node->faces; f ;f = f->next )
{
SubdivideFaceBySubdivSize( f );
}
//
// recursively output the other nodes
//
SplitSubdividedFaces_Node_r( node->children[0] );
SplitSubdividedFaces_Node_r( node->children[1] );
}
void SplitSubdividedFaces( face_t *pLeafFaceList, node_t *headnode )
{
// deal with leaf faces.
face_t *f = pLeafFaceList;
while ( f )
{
SubdivideFaceBySubdivSize( f );
f = f->next;
}
// deal with node faces.
SplitSubdividedFaces_Node_r( headnode );
}
#pragma optimize( "", on )
/*
============
MakeFaces
============
*/
void MakeFaces (node_t *node)
{
qprintf ("--- MakeFaces ---\n");
c_merge = 0;
c_subdivide = 0;
c_nodefaces = 0;
MakeFaces_r (node);
qprintf ("%5i makefaces\n", c_nodefaces);
qprintf ("%5i merged\n", c_merge);
qprintf ("%5i subdivided\n", c_subdivide);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -