⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 faces.cpp

📁 hl2 source code. Do not use it illegal.
💻 CPP
📖 第 1 页 / 共 3 页
字号:

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 + -