You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
206 lines
6.0 KiB
206 lines
6.0 KiB
//========= Copyright Valve Corporation, All rights reserved. ============// |
|
// |
|
// Purpose: |
|
// |
|
// $NoKeywords: $ |
|
//=============================================================================// |
|
|
|
#ifndef DISP_TESSELATE_H |
|
#define DISP_TESSELATE_H |
|
#ifdef _WIN32 |
|
#pragma once |
|
#endif |
|
|
|
|
|
#include "disp_powerinfo.h" |
|
|
|
|
|
inline int InternalVertIndex( const CPowerInfo *pInfo, const CVertIndex &vert ) |
|
{ |
|
return vert.y * pInfo->m_SideLength + vert.x; |
|
} |
|
|
|
|
|
template< class TesselateHelper > |
|
inline void InternalEndTriangle( |
|
TesselateHelper *pHelper, |
|
CVertIndex const &nodeIndex, |
|
int &iCurTriVert ) |
|
{ |
|
// End our current triangle here. |
|
Assert( iCurTriVert == 2 ); |
|
|
|
// Finish the triangle. |
|
pHelper->m_TempIndices[2] = (unsigned short)InternalVertIndex( pHelper->m_pPowerInfo, nodeIndex ); |
|
|
|
pHelper->EndTriangle(); |
|
|
|
// Add on the last vertex to join to the next triangle. |
|
pHelper->m_TempIndices[0] = pHelper->m_TempIndices[1]; |
|
iCurTriVert = 1; |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Tesselates a single node, doesn't deal with hierarchy |
|
//----------------------------------------------------------------------------- |
|
template< class TesselateHelper > |
|
inline void TesselateDisplacementNode( |
|
TesselateHelper *pHelper, |
|
CVertIndex const &nodeIndex, |
|
int iLevel, |
|
int *pActiveChildren ) |
|
{ |
|
int iPower = pHelper->m_pPowerInfo->m_Power - iLevel; |
|
int vertInc = 1 << (iPower - 1); |
|
|
|
CTesselateWinding *pWinding = &g_TWinding; |
|
|
|
// Starting at the bottom-left, wind clockwise picking up vertices and |
|
// generating triangles. |
|
int iCurTriVert = 0; |
|
for( int iVert=0; iVert < pWinding->m_nVerts; iVert++ ) |
|
{ |
|
CVertIndex sideVert = BuildOffsetVertIndex( nodeIndex, pWinding->m_Verts[iVert].m_Index, vertInc ); |
|
|
|
int iVertNode = pWinding->m_Verts[iVert].m_iNode; |
|
bool bNode = (iVertNode != -1) && pActiveChildren[iVertNode]; |
|
if( bNode ) |
|
{ |
|
if( iCurTriVert == 2 ) |
|
InternalEndTriangle( pHelper, nodeIndex, iCurTriVert ); |
|
|
|
iCurTriVert = 0; |
|
} |
|
else |
|
{ |
|
int iVertBit = InternalVertIndex( pHelper->m_pPowerInfo, sideVert ); |
|
if( pHelper->m_pActiveVerts[iVertBit>>5] & (1 << (iVertBit & 31)) ) |
|
{ |
|
// Ok, add a vert here. |
|
pHelper->m_TempIndices[iCurTriVert] = (unsigned short)InternalVertIndex( pHelper->m_pPowerInfo, sideVert ); |
|
iCurTriVert++; |
|
if( iCurTriVert == 2 ) |
|
InternalEndTriangle( pHelper, nodeIndex, iCurTriVert ); |
|
} |
|
} |
|
} |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Tesselates in a *breadth first* fashion |
|
//----------------------------------------------------------------------------- |
|
template< class T > |
|
inline void TesselateDisplacement_R( |
|
T *pHelper, |
|
const CVertIndex &nodeIndex, |
|
int iNodeBitIndex, |
|
int iLevel |
|
) |
|
{ |
|
// Here's the node info for our current node |
|
Assert( iNodeBitIndex < pHelper->m_pPowerInfo->m_NodeCount ); |
|
DispNodeInfo_t& nodeInfo = pHelper->GetNodeInfo( iNodeBitIndex ); |
|
|
|
// Store off the current number of indices |
|
int oldIndexCount = pHelper->m_nIndices; |
|
|
|
// Go through each quadrant. If there is an active child node, recurse down. |
|
int bActiveChildren[4]; |
|
if( iLevel >= pHelper->m_pPowerInfo->m_Power - 1 ) |
|
{ |
|
// This node has no children. |
|
bActiveChildren[0] = bActiveChildren[1] = bActiveChildren[2] = bActiveChildren[3] = false; |
|
} |
|
else |
|
{ |
|
int iNodeIndex = InternalVertIndex( pHelper->m_pPowerInfo, nodeIndex ); |
|
|
|
int iChildNodeBit = iNodeBitIndex + 1; |
|
for( int iChild=0; iChild < 4; iChild++ ) |
|
{ |
|
CVertIndex const &childNode = pHelper->m_pPowerInfo->m_pChildVerts[iNodeIndex].m_Verts[iChild]; |
|
|
|
// Make sure we really can tesselate here (a smaller neighbor displacement could |
|
// have inactivated certain edge verts. |
|
int iVertBit = InternalVertIndex( pHelper->m_pPowerInfo, childNode ); |
|
bActiveChildren[iChild] = ( pHelper->m_pActiveVerts[iVertBit>>5] & (1 << (iVertBit & 31)) ); |
|
|
|
if( bActiveChildren[iChild] ) |
|
{ |
|
TesselateDisplacement_R( pHelper, childNode, iChildNodeBit, iLevel+1 ); |
|
} |
|
else |
|
{ |
|
// Make sure the triangle counts are cleared on this one because it may visit this |
|
// node in GenerateDecalFragments_R if nodeInfo's CHILDREN_HAVE_TRIANGLES flag is set. |
|
DispNodeInfo_t &childInfo = pHelper->GetNodeInfo( iChildNodeBit ); |
|
childInfo.m_Count = 0; |
|
childInfo.m_Flags = 0; |
|
} |
|
|
|
iChildNodeBit += pHelper->m_pPowerInfo->m_NodeIndexIncrements[iLevel]; |
|
} |
|
} |
|
|
|
// Set the child field |
|
if ( pHelper->m_nIndices != oldIndexCount ) |
|
{ |
|
nodeInfo.m_Flags = DispNodeInfo_t::CHILDREN_HAVE_TRIANGLES; |
|
oldIndexCount = pHelper->m_nIndices; |
|
} |
|
else |
|
{ |
|
nodeInfo.m_Flags = 0; |
|
} |
|
|
|
// Now tesselate the node itself... |
|
TesselateDisplacementNode( pHelper, nodeIndex, iLevel, bActiveChildren ); |
|
|
|
// Now that we've tesselated, figure out how many indices we've added at this node |
|
nodeInfo.m_Count = pHelper->m_nIndices - oldIndexCount; |
|
nodeInfo.m_FirstTesselationIndex = oldIndexCount; |
|
Assert( nodeInfo.m_Count % 3 == 0 ); |
|
} |
|
|
|
|
|
class CBaseTesselateHelper |
|
{ |
|
public: |
|
|
|
// Functions your derived class must implement: |
|
// void EndTriangle(); // (the 3 indices are in m_TempIndices). |
|
// DispNodeInfo_t& GetNodeInfo( int iNodeBit ); |
|
|
|
|
|
// Set these before calling TesselateDisplacement. |
|
uint32 *m_pActiveVerts; // These bits control the tesselation. |
|
const CPowerInfo *m_pPowerInfo; // Lots of precalculated data about a displacement this size. |
|
|
|
|
|
// Used internally by TesselateDisplacement. |
|
int m_nIndices; // After calling TesselateDisplacement, this is set to the # of indices generated. |
|
unsigned short m_TempIndices[6]; |
|
}; |
|
|
|
|
|
|
|
// This interface is shared betwixt VBSP and the engine. VBSP uses it to build the |
|
// physics mesh and the engine uses it to render. |
|
// |
|
// To use this function, derive a class from CBaseTesselateHelper that supports the TesselateHelper functions. |
|
template< class TesselateHelper > |
|
inline void TesselateDisplacement( TesselateHelper *pHelper ) |
|
{ |
|
pHelper->m_nIndices = 0; |
|
|
|
TesselateDisplacement_R<TesselateHelper>( |
|
pHelper, |
|
pHelper->m_pPowerInfo->m_RootNode, |
|
0, // node bit indexing CDispDecal::m_NodeIntersects |
|
0 ); |
|
} |
|
|
|
|
|
#endif // DISP_TESSELATE_H
|
|
|