1
This commit is contained in:
206
public/disp_tesselate.h
Normal file
206
public/disp_tesselate.h
Normal file
@ -0,0 +1,206 @@
|
||||
//========= 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
|
Reference in New Issue
Block a user