Team Fortress 2 Source Code as on 22/4/2020
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

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================//
  7. #ifndef DISP_TESSELATE_H
  8. #define DISP_TESSELATE_H
  9. #ifdef _WIN32
  10. #pragma once
  11. #endif
  12. #include "disp_powerinfo.h"
  13. inline int InternalVertIndex( const CPowerInfo *pInfo, const CVertIndex &vert )
  14. {
  15. return vert.y * pInfo->m_SideLength + vert.x;
  16. }
  17. template< class TesselateHelper >
  18. inline void InternalEndTriangle(
  19. TesselateHelper *pHelper,
  20. CVertIndex const &nodeIndex,
  21. int &iCurTriVert )
  22. {
  23. // End our current triangle here.
  24. Assert( iCurTriVert == 2 );
  25. // Finish the triangle.
  26. pHelper->m_TempIndices[2] = (unsigned short)InternalVertIndex( pHelper->m_pPowerInfo, nodeIndex );
  27. pHelper->EndTriangle();
  28. // Add on the last vertex to join to the next triangle.
  29. pHelper->m_TempIndices[0] = pHelper->m_TempIndices[1];
  30. iCurTriVert = 1;
  31. }
  32. //-----------------------------------------------------------------------------
  33. // Tesselates a single node, doesn't deal with hierarchy
  34. //-----------------------------------------------------------------------------
  35. template< class TesselateHelper >
  36. inline void TesselateDisplacementNode(
  37. TesselateHelper *pHelper,
  38. CVertIndex const &nodeIndex,
  39. int iLevel,
  40. int *pActiveChildren )
  41. {
  42. int iPower = pHelper->m_pPowerInfo->m_Power - iLevel;
  43. int vertInc = 1 << (iPower - 1);
  44. CTesselateWinding *pWinding = &g_TWinding;
  45. // Starting at the bottom-left, wind clockwise picking up vertices and
  46. // generating triangles.
  47. int iCurTriVert = 0;
  48. for( int iVert=0; iVert < pWinding->m_nVerts; iVert++ )
  49. {
  50. CVertIndex sideVert = BuildOffsetVertIndex( nodeIndex, pWinding->m_Verts[iVert].m_Index, vertInc );
  51. int iVertNode = pWinding->m_Verts[iVert].m_iNode;
  52. bool bNode = (iVertNode != -1) && pActiveChildren[iVertNode];
  53. if( bNode )
  54. {
  55. if( iCurTriVert == 2 )
  56. InternalEndTriangle( pHelper, nodeIndex, iCurTriVert );
  57. iCurTriVert = 0;
  58. }
  59. else
  60. {
  61. int iVertBit = InternalVertIndex( pHelper->m_pPowerInfo, sideVert );
  62. if( pHelper->m_pActiveVerts[iVertBit>>5] & (1 << (iVertBit & 31)) )
  63. {
  64. // Ok, add a vert here.
  65. pHelper->m_TempIndices[iCurTriVert] = (unsigned short)InternalVertIndex( pHelper->m_pPowerInfo, sideVert );
  66. iCurTriVert++;
  67. if( iCurTriVert == 2 )
  68. InternalEndTriangle( pHelper, nodeIndex, iCurTriVert );
  69. }
  70. }
  71. }
  72. }
  73. //-----------------------------------------------------------------------------
  74. // Tesselates in a *breadth first* fashion
  75. //-----------------------------------------------------------------------------
  76. template< class T >
  77. inline void TesselateDisplacement_R(
  78. T *pHelper,
  79. const CVertIndex &nodeIndex,
  80. int iNodeBitIndex,
  81. int iLevel
  82. )
  83. {
  84. // Here's the node info for our current node
  85. Assert( iNodeBitIndex < pHelper->m_pPowerInfo->m_NodeCount );
  86. DispNodeInfo_t& nodeInfo = pHelper->GetNodeInfo( iNodeBitIndex );
  87. // Store off the current number of indices
  88. int oldIndexCount = pHelper->m_nIndices;
  89. // Go through each quadrant. If there is an active child node, recurse down.
  90. int bActiveChildren[4];
  91. if( iLevel >= pHelper->m_pPowerInfo->m_Power - 1 )
  92. {
  93. // This node has no children.
  94. bActiveChildren[0] = bActiveChildren[1] = bActiveChildren[2] = bActiveChildren[3] = false;
  95. }
  96. else
  97. {
  98. int iNodeIndex = InternalVertIndex( pHelper->m_pPowerInfo, nodeIndex );
  99. int iChildNodeBit = iNodeBitIndex + 1;
  100. for( int iChild=0; iChild < 4; iChild++ )
  101. {
  102. CVertIndex const &childNode = pHelper->m_pPowerInfo->m_pChildVerts[iNodeIndex].m_Verts[iChild];
  103. // Make sure we really can tesselate here (a smaller neighbor displacement could
  104. // have inactivated certain edge verts.
  105. int iVertBit = InternalVertIndex( pHelper->m_pPowerInfo, childNode );
  106. bActiveChildren[iChild] = ( pHelper->m_pActiveVerts[iVertBit>>5] & (1 << (iVertBit & 31)) );
  107. if( bActiveChildren[iChild] )
  108. {
  109. TesselateDisplacement_R( pHelper, childNode, iChildNodeBit, iLevel+1 );
  110. }
  111. else
  112. {
  113. // Make sure the triangle counts are cleared on this one because it may visit this
  114. // node in GenerateDecalFragments_R if nodeInfo's CHILDREN_HAVE_TRIANGLES flag is set.
  115. DispNodeInfo_t &childInfo = pHelper->GetNodeInfo( iChildNodeBit );
  116. childInfo.m_Count = 0;
  117. childInfo.m_Flags = 0;
  118. }
  119. iChildNodeBit += pHelper->m_pPowerInfo->m_NodeIndexIncrements[iLevel];
  120. }
  121. }
  122. // Set the child field
  123. if ( pHelper->m_nIndices != oldIndexCount )
  124. {
  125. nodeInfo.m_Flags = DispNodeInfo_t::CHILDREN_HAVE_TRIANGLES;
  126. oldIndexCount = pHelper->m_nIndices;
  127. }
  128. else
  129. {
  130. nodeInfo.m_Flags = 0;
  131. }
  132. // Now tesselate the node itself...
  133. TesselateDisplacementNode( pHelper, nodeIndex, iLevel, bActiveChildren );
  134. // Now that we've tesselated, figure out how many indices we've added at this node
  135. nodeInfo.m_Count = pHelper->m_nIndices - oldIndexCount;
  136. nodeInfo.m_FirstTesselationIndex = oldIndexCount;
  137. Assert( nodeInfo.m_Count % 3 == 0 );
  138. }
  139. class CBaseTesselateHelper
  140. {
  141. public:
  142. // Functions your derived class must implement:
  143. // void EndTriangle(); // (the 3 indices are in m_TempIndices).
  144. // DispNodeInfo_t& GetNodeInfo( int iNodeBit );
  145. // Set these before calling TesselateDisplacement.
  146. uint32 *m_pActiveVerts; // These bits control the tesselation.
  147. const CPowerInfo *m_pPowerInfo; // Lots of precalculated data about a displacement this size.
  148. // Used internally by TesselateDisplacement.
  149. int m_nIndices; // After calling TesselateDisplacement, this is set to the # of indices generated.
  150. unsigned short m_TempIndices[6];
  151. };
  152. // This interface is shared betwixt VBSP and the engine. VBSP uses it to build the
  153. // physics mesh and the engine uses it to render.
  154. //
  155. // To use this function, derive a class from CBaseTesselateHelper that supports the TesselateHelper functions.
  156. template< class TesselateHelper >
  157. inline void TesselateDisplacement( TesselateHelper *pHelper )
  158. {
  159. pHelper->m_nIndices = 0;
  160. TesselateDisplacement_R<TesselateHelper>(
  161. pHelper,
  162. pHelper->m_pPowerInfo->m_RootNode,
  163. 0, // node bit indexing CDispDecal::m_NodeIntersects
  164. 0 );
  165. }
  166. #endif // DISP_TESSELATE_H