summaryrefslogtreecommitdiff
path: root/public/disp_tesselate.h
diff options
context:
space:
mode:
Diffstat (limited to 'public/disp_tesselate.h')
-rw-r--r--public/disp_tesselate.h206
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