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.

480 lines
13 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Implementation of CDmMeshComp - CDmeMesh computation class
  4. //
  5. //=============================================================================
  6. // Valve includes
  7. #include "movieobjects/dmmeshcomp.h"
  8. #include "movieobjects/dmefaceset.h"
  9. #include "movieobjects/dmemesh.h"
  10. #include "movieobjects/dmevertexdata.h"
  11. // memdbgon must be the last include file in a .cpp file!!!
  12. #include "tier0/memdbgon.h"
  13. //=============================================================================
  14. //
  15. //=============================================================================
  16. CDmMeshComp::CDmMeshComp( CDmeMesh *pMesh, CDmeVertexData *pPassedBase )
  17. : m_pMesh( pMesh )
  18. , m_pBase( NULL )
  19. {
  20. m_pBase = pPassedBase ? pPassedBase : pMesh->GetCurrentBaseState();
  21. if ( !m_pBase )
  22. return;
  23. const FieldIndex_t pIndex( m_pBase->FindFieldIndex( CDmeVertexData::FIELD_POSITION ) );
  24. if ( pIndex < 0 )
  25. return;
  26. const CUtlVector< Vector > &pPositionData( m_pBase->GetPositionData() );
  27. const CUtlVector<int> &pPositionIndices( m_pBase->GetVertexIndexData( CDmeVertexData::FIELD_POSITION ) );
  28. const int nVertices( pPositionData.Count() );
  29. if ( nVertices <= 0 )
  30. return;
  31. // Create vertices
  32. // TODO: check for duplicates in pPositionData - that would break this algorithm
  33. m_verts.EnsureCapacity( nVertices );
  34. for ( int i = 0; i < nVertices; ++i )
  35. {
  36. const CUtlVector< int > &vertexIndices = m_pBase->FindVertexIndicesFromDataIndex( CDmeVertexData::FIELD_POSITION, i );
  37. m_verts.AddToTail( new CVert( i, &vertexIndices, &pPositionData[ i ] ) );
  38. }
  39. // Create edges and faces
  40. const int nFaceSets( pMesh->FaceSetCount() );
  41. for ( int i = 0; i < nFaceSets; ++i )
  42. {
  43. CDmeFaceSet *pFaceSet( pMesh->GetFaceSet( i ) );
  44. const int nIndices( pFaceSet->NumIndices() );
  45. if ( nIndices < 4 ) // At least a triangle and a -1
  46. continue;
  47. m_faces.EnsureCapacity( m_faces.Count() + nIndices / 4 ); // # new faces <= nIndices/4 (tri + -1)
  48. m_edges.EnsureCapacity( m_edges.Count() + nIndices / 2 ); // # new edges <= 2*new faces
  49. int facePosIndex( -1 );
  50. int edgePosIndex0( -1 );
  51. int edgePosIndex1( -1 );
  52. CUtlVector< CVert * > verts;
  53. CUtlVector< CEdge * > edges;
  54. CUtlVector< bool > edgeReverseMap;
  55. bool bReverse = false;
  56. for ( int j( 0 ); j < nIndices; ++j )
  57. {
  58. const int faceVertexIndex( pFaceSet->GetIndex( j ) );
  59. if ( faceVertexIndex < 0 )
  60. {
  61. // End of face
  62. edgePosIndex0 = edgePosIndex1;
  63. edgePosIndex1 = facePosIndex;
  64. Assert( edgePosIndex0 >= 0 );
  65. Assert( edgePosIndex1 >= 0 );
  66. edges.AddToTail( FindOrCreateEdge( edgePosIndex0, edgePosIndex1, &bReverse ) );
  67. edgeReverseMap.AddToTail( bReverse );
  68. CreateFace( verts, edges, edgeReverseMap );
  69. facePosIndex = -1;
  70. verts.RemoveAll();
  71. edges.RemoveAll();
  72. edgeReverseMap.RemoveAll();
  73. continue;
  74. }
  75. if ( facePosIndex < 0 )
  76. {
  77. // First vertex
  78. facePosIndex = pPositionIndices[ faceVertexIndex ];
  79. edgePosIndex1 = facePosIndex;
  80. verts.AddToTail( m_verts[ edgePosIndex1 ] );
  81. continue;
  82. }
  83. // 2nd through last vertex
  84. edgePosIndex0 = edgePosIndex1;
  85. edgePosIndex1 = pPositionIndices[ faceVertexIndex ];
  86. verts.AddToTail( m_verts[ edgePosIndex1 ] );
  87. Assert( edgePosIndex0 >= 0 );
  88. Assert( edgePosIndex1 >= 0 );
  89. edges.AddToTail( FindOrCreateEdge( edgePosIndex0, edgePosIndex1, &bReverse ) );
  90. edgeReverseMap.AddToTail( bReverse );
  91. }
  92. }
  93. }
  94. //-----------------------------------------------------------------------------
  95. //
  96. //-----------------------------------------------------------------------------
  97. CDmMeshComp::~CDmMeshComp()
  98. {
  99. m_verts.PurgeAndDeleteElements();
  100. m_edges.PurgeAndDeleteElements();
  101. }
  102. //-----------------------------------------------------------------------------
  103. //
  104. //-----------------------------------------------------------------------------
  105. CDmMeshComp::CVert::CVert( int nPositionIndex, const CUtlVector< int > *pVertexIndices, const Vector *pPosition )
  106. : m_positionIndex( nPositionIndex )
  107. , m_pVertexIndices( pVertexIndices )
  108. , m_pPosition( pPosition )
  109. , m_edges( 8, 8 )
  110. {
  111. }
  112. //-----------------------------------------------------------------------------
  113. //
  114. //-----------------------------------------------------------------------------
  115. CDmMeshComp::CVert::CVert( const CVert &src )
  116. : m_positionIndex( src.m_positionIndex )
  117. , m_pVertexIndices( src.m_pVertexIndices )
  118. , m_pPosition( src.m_pPosition )
  119. , m_edges( 8, 8 )
  120. {
  121. m_edges.AddMultipleToTail( src.m_edges.Count(), src.m_edges.Base() );
  122. }
  123. //-----------------------------------------------------------------------------
  124. //
  125. //-----------------------------------------------------------------------------
  126. int CDmMeshComp::CVert::PositionIndex() const
  127. {
  128. return m_positionIndex;
  129. }
  130. //-----------------------------------------------------------------------------
  131. //
  132. //-----------------------------------------------------------------------------
  133. const Vector *CDmMeshComp::CVert::Position() const
  134. {
  135. return m_pPosition;
  136. }
  137. //-----------------------------------------------------------------------------
  138. //
  139. //-----------------------------------------------------------------------------
  140. const CUtlVector< int > *CDmMeshComp::CVert::VertexIndices() const
  141. {
  142. return m_pVertexIndices;
  143. }
  144. //-----------------------------------------------------------------------------
  145. //
  146. //-----------------------------------------------------------------------------
  147. bool CDmMeshComp::CVert::operator==( const CVert &rhs ) const
  148. {
  149. return ( m_pPosition->DistToSqr( *rhs.m_pPosition ) < FLT_EPSILON );
  150. }
  151. //-----------------------------------------------------------------------------
  152. //
  153. //-----------------------------------------------------------------------------
  154. CDmMeshComp::CEdge::CEdge()
  155. : m_pVert0( NULL )
  156. , m_pVert1( NULL )
  157. , m_faceCount( 0 )
  158. {
  159. }
  160. //-----------------------------------------------------------------------------
  161. // Returns the vertex position index given the edge relative vertex index
  162. //-----------------------------------------------------------------------------
  163. int CDmMeshComp::CEdge::GetVertPositionIndex( int edgeRelativeVertexIndex ) const
  164. {
  165. if ( edgeRelativeVertexIndex == 0 && m_pVert0 )
  166. return m_pVert0->PositionIndex();
  167. if ( edgeRelativeVertexIndex == 1 && m_pVert1 )
  168. return m_pVert1->PositionIndex();
  169. return -1;
  170. }
  171. //-----------------------------------------------------------------------------
  172. //
  173. //-----------------------------------------------------------------------------
  174. CDmMeshComp::CVert *CDmMeshComp::CEdge::GetVert( int edgeRelativeVertexIndex ) const
  175. {
  176. if ( edgeRelativeVertexIndex == 0 )
  177. return m_pVert0;
  178. if ( edgeRelativeVertexIndex == 1 )
  179. return m_pVert1;
  180. return NULL;
  181. }
  182. //-----------------------------------------------------------------------------
  183. // Returns true if the edge starts and stops at the same position in space
  184. // The order of the vertices is not checked
  185. //-----------------------------------------------------------------------------
  186. bool CDmMeshComp::CEdge::operator==( const CEdge &rhs ) const
  187. {
  188. return (
  189. ( *m_pVert0 == *rhs.m_pVert0 && *m_pVert1 == *rhs.m_pVert1 ) ||
  190. ( *m_pVert0 == *rhs.m_pVert1 && *m_pVert1 == *rhs.m_pVert0 ) );
  191. }
  192. //-----------------------------------------------------------------------------
  193. //
  194. //-----------------------------------------------------------------------------
  195. Vector CDmMeshComp::CEdge::EdgeVector() const
  196. {
  197. if ( m_pVert0 && m_pVert1 )
  198. return *m_pVert1->Position() - *m_pVert0->Position();
  199. return vec3_origin;
  200. }
  201. //-----------------------------------------------------------------------------
  202. // Finds or Creates an edge... Can still return NULL if vertices do not exist
  203. //-----------------------------------------------------------------------------
  204. CDmMeshComp::CEdge *CDmMeshComp::FindOrCreateEdge( int vIndex0, int vIndex1, bool *pReverse /* = NULL */ )
  205. {
  206. CEdge *pEdge = FindEdge( vIndex0, vIndex1, pReverse );
  207. if ( pEdge )
  208. return pEdge;
  209. CVert *pVert0 = m_verts[ vIndex0 ];
  210. if ( pVert0 == NULL )
  211. return NULL;
  212. CVert *pVert1 = m_verts[ vIndex1 ];
  213. if ( pVert1 == NULL )
  214. return NULL;
  215. pEdge = m_edges[ m_edges.AddToTail( new CEdge() ) ];
  216. pEdge->m_pVert0 = pVert0;
  217. pEdge->m_pVert1 = pVert1;
  218. pVert0->m_edges.AddToTail( pEdge );
  219. if ( vIndex0 != vIndex1 )
  220. pVert1->m_edges.AddToTail( pEdge );
  221. if ( pReverse )
  222. {
  223. *pReverse = false;
  224. }
  225. return pEdge;
  226. }
  227. //-----------------------------------------------------------------------------
  228. // Returns the edge between vIndex0 & vIndex1 (or vice versa), NULL if not found
  229. //-----------------------------------------------------------------------------
  230. CDmMeshComp::CEdge *CDmMeshComp::FindEdge( int vIndex0, int vIndex1, bool *pReverse /* = NULL */ )
  231. {
  232. CUtlVector< CEdge * > &edges = m_verts[ vIndex0 ]->m_edges;
  233. for ( int i = 0; i < edges.Count(); i++ )
  234. {
  235. CEdge *e = edges[ i ];
  236. if ( e->GetVertPositionIndex( 0 ) == vIndex0 && e->GetVertPositionIndex( 1 ) == vIndex1 )
  237. {
  238. if ( pReverse )
  239. {
  240. *pReverse = false;
  241. }
  242. return e;
  243. }
  244. if ( e->GetVertPositionIndex( 1 ) == vIndex0 && e->GetVertPositionIndex( 0 ) == vIndex1 )
  245. {
  246. if ( pReverse )
  247. {
  248. *pReverse = true;
  249. }
  250. return e;
  251. }
  252. }
  253. return NULL;
  254. }
  255. //-----------------------------------------------------------------------------
  256. //
  257. //-----------------------------------------------------------------------------
  258. CDmMeshComp::CFace *CDmMeshComp::CreateFace( const CUtlVector< CVert * > &verts, const CUtlVector< CEdge * > &edges, const CUtlVector< bool > &edgeReverseMap )
  259. {
  260. CFace *pFace = &m_faces[ m_faces.AddToTail() ];
  261. pFace->m_verts.RemoveAll();
  262. pFace->m_verts.AddVectorToTail( verts );
  263. pFace->m_edges.RemoveAll();
  264. pFace->m_edges.AddVectorToTail( edges );
  265. pFace->m_edgeReverseMap.RemoveAll();
  266. pFace->m_edgeReverseMap.AddVectorToTail( edgeReverseMap );
  267. for ( int nEdgeIndex = edges.Count() - 1; nEdgeIndex >= 0; --nEdgeIndex )
  268. {
  269. edges[ nEdgeIndex ]->m_faceCount += 1;
  270. }
  271. return pFace;
  272. }
  273. //-----------------------------------------------------------------------------
  274. //
  275. //-----------------------------------------------------------------------------
  276. int CDmMeshComp::FindFacesWithVert( int vIndex, CUtlVector< CFace * > &faces )
  277. {
  278. // TODO: optimize this by adding a vector of face pointers to each vertex
  279. faces.RemoveAll();
  280. for ( int fi( m_faces.Head() ); fi != m_faces.InvalidIndex(); fi = m_faces.Next( fi ) )
  281. {
  282. CFace &face( m_faces[ fi ] );
  283. for ( int i = 0; i < face.m_verts.Count(); ++i )
  284. {
  285. if ( face.m_verts[ i ]->PositionIndex() == vIndex )
  286. {
  287. faces.AddToTail( &face );
  288. break;
  289. }
  290. }
  291. }
  292. return faces.Count();
  293. }
  294. //-----------------------------------------------------------------------------
  295. //
  296. //-----------------------------------------------------------------------------
  297. int CDmMeshComp::FindNeighbouringVerts( int vIndex, CUtlVector< CVert * > &verts )
  298. {
  299. verts.RemoveAll();
  300. const CUtlVector< CEdge * > & edges = m_verts[ vIndex ]->m_edges;
  301. for ( int i = 0; i < edges.Count(); ++i )
  302. {
  303. CEdge *e = edges[ i ];
  304. if ( e->GetVertPositionIndex( 0 ) == vIndex )
  305. {
  306. verts.AddToTail( e->GetVert( 1 ) );
  307. }
  308. else
  309. {
  310. verts.AddToTail( e->GetVert( 0 ) );
  311. }
  312. }
  313. return verts.Count();
  314. }
  315. //-----------------------------------------------------------------------------
  316. // Find all edges that are only used by 1 face
  317. //-----------------------------------------------------------------------------
  318. int CDmMeshComp::GetBorderEdges( CUtlVector< CUtlVector< CEdge * > > &borderEdgesList )
  319. {
  320. // TODO: optimize this by stepping from edge to edge to build chains, using CVert::m_edges
  321. int retVal = 0;
  322. borderEdgesList.RemoveAll();
  323. bool connected;
  324. for ( int ei = 0; ei < m_edges.Count(); ei++ )
  325. {
  326. CEdge *pEdge = m_edges[ ei ];
  327. if ( pEdge->IsBorderEdge() )
  328. {
  329. ++retVal;
  330. connected = false;
  331. for ( int i = borderEdgesList.Count() - 1; !connected && i >= 0; --i )
  332. {
  333. CUtlVector< CEdge * > &borderEdges = borderEdgesList[ i ];
  334. for ( int j = borderEdges.Count() - 1; j >= 0; --j )
  335. {
  336. if ( borderEdges[ j ]->ConnectedTo( pEdge ) )
  337. {
  338. borderEdges.AddToTail( pEdge );
  339. connected = true;
  340. break;
  341. }
  342. }
  343. }
  344. if ( !connected )
  345. {
  346. CUtlVector< CEdge * > &borderEdges = borderEdgesList[ borderEdgesList.AddToTail() ];
  347. borderEdges.AddToTail( pEdge );
  348. }
  349. }
  350. }
  351. // Shrink the borderEdgesList to minimum number required
  352. bool anyConnected = false;
  353. do
  354. {
  355. anyConnected = false;
  356. for ( int i = borderEdgesList.Count() - 1; i >= 0; --i )
  357. {
  358. CUtlVector< CEdge * > &srcBorderEdges = borderEdgesList[ i ];
  359. for ( int j = srcBorderEdges.Count() - 1; j >= 0; --j )
  360. {
  361. CEdge *pSrcEdge = srcBorderEdges[ j ];
  362. connected = false;
  363. for ( int k = 0; !connected && k < i; ++k )
  364. {
  365. CUtlVector< CEdge * > &dstBorderEdges = borderEdgesList[ k ];
  366. for ( int l = dstBorderEdges.Count() - 1; l >= 0; --l )
  367. {
  368. if ( dstBorderEdges[ l ]->ConnectedTo( pSrcEdge ) )
  369. {
  370. connected = true;
  371. anyConnected = true;
  372. dstBorderEdges.AddToTail( pSrcEdge );
  373. srcBorderEdges.Remove( j );
  374. break;
  375. }
  376. }
  377. }
  378. }
  379. if ( srcBorderEdges.Count() == 0 )
  380. {
  381. borderEdgesList.Remove( i );
  382. }
  383. }
  384. } while( anyConnected );
  385. return retVal;
  386. }