diff options
Diffstat (limited to 'public/disp_tesselate.h')
| -rw-r--r-- | public/disp_tesselate.h | 206 |
1 files changed, 206 insertions, 0 deletions
diff --git a/public/disp_tesselate.h b/public/disp_tesselate.h new file mode 100644 index 0000000..d2d3caf --- /dev/null +++ b/public/disp_tesselate.h @@ -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 |