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.

718 lines
19 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $Workfile: $
  6. // $Date: $
  7. // $NoKeywords: $
  8. //=============================================================================//
  9. #include <stdafx.h>
  10. #include "UtlLinkedList.h"
  11. //#include "DispManager.h"
  12. #include "MapFace.h"
  13. #include "MapDisp.h"
  14. #include "DispSubdiv.h"
  15. #include "History.h"
  16. #include "tier0/minidump.h"
  17. // memdbgon must be the last include file in a .cpp file!!!
  18. #include <tier0/memdbgon.h>
  19. //=============================================================================
  20. //
  21. // Global Displacement Manager
  22. //
  23. class CEditDispMgr : public IEditDispMgr
  24. {
  25. public: // functions
  26. CEditDispMgr();
  27. virtual ~CEditDispMgr();
  28. EditDispHandle_t Create( void );
  29. void Destroy( EditDispHandle_t handle );
  30. CMapDisp *GetDisp( EditDispHandle_t handle );
  31. private: // variables
  32. CUtlLinkedList<CMapDisp, EditDispHandle_t> m_AllocList;
  33. };
  34. //-----------------------------------------------------------------------------
  35. // Purpose:
  36. //-----------------------------------------------------------------------------
  37. IEditDispMgr* EditDispMgr( void )
  38. {
  39. static CEditDispMgr s_EditDispMgr;
  40. return &s_EditDispMgr;
  41. }
  42. //-----------------------------------------------------------------------------
  43. // Purpose:
  44. //-----------------------------------------------------------------------------
  45. CEditDispMgr::CEditDispMgr()
  46. {
  47. }
  48. //-----------------------------------------------------------------------------
  49. // Purpose:
  50. //-----------------------------------------------------------------------------
  51. CEditDispMgr::~CEditDispMgr()
  52. {
  53. m_AllocList.Purge();
  54. }
  55. //-----------------------------------------------------------------------------
  56. // Purpose:
  57. //-----------------------------------------------------------------------------
  58. EditDispHandle_t CEditDispMgr::Create( void )
  59. {
  60. EditDispHandle_t handle = m_AllocList.AddToTail();
  61. if( handle != EDITDISPHANDLE_INVALID )
  62. {
  63. CMapDisp *pDisp = &m_AllocList.Element( handle );
  64. pDisp->SetEditHandle( handle );
  65. }
  66. return handle;
  67. }
  68. //-----------------------------------------------------------------------------
  69. // Purpose:
  70. //-----------------------------------------------------------------------------
  71. void CEditDispMgr::Destroy( EditDispHandle_t handle )
  72. {
  73. if ( m_AllocList.IsValidIndex( handle ) )
  74. {
  75. m_AllocList.Remove( handle );
  76. }
  77. else
  78. {
  79. static bool bNoToAll = false;
  80. if ( !bNoToAll )
  81. {
  82. int result = AfxMessageBox(
  83. "CEditDispMgr::Destroy - invalid handle.\n"
  84. "Write minidump?\n",
  85. MB_YESNO );
  86. if ( result == IDYES )
  87. {
  88. // Generate a minidump.
  89. WriteMiniDump();
  90. }
  91. else
  92. {
  93. bNoToAll = true;
  94. }
  95. }
  96. }
  97. }
  98. //-----------------------------------------------------------------------------
  99. // Purpose:
  100. //-----------------------------------------------------------------------------
  101. CMapDisp *CEditDispMgr::GetDisp( EditDispHandle_t handle )
  102. {
  103. if( m_AllocList.IsValidIndex( handle ) )
  104. {
  105. return &m_AllocList.Element( handle );
  106. }
  107. return NULL;
  108. }
  109. //=============================================================================
  110. //
  111. // World Displacement Manager(s)
  112. //
  113. class CWorldEditDispMgr : public IWorldEditDispMgr
  114. {
  115. public: // functions
  116. // construction/deconstruction
  117. CWorldEditDispMgr();
  118. virtual ~CWorldEditDispMgr();
  119. // world list functionals
  120. int WorldCount( void );
  121. CMapDisp *GetFromWorld( int iWorldList );
  122. CMapDisp *GetFromWorld( EditDispHandle_t handle );
  123. void AddToWorld( EditDispHandle_t handle );
  124. void RemoveFromWorld( EditDispHandle_t handle );
  125. void FindWorldNeighbors( EditDispHandle_t handle );
  126. // selection list functions
  127. int SelectCount( void );
  128. void SelectClear( void );
  129. CMapDisp *GetFromSelect( int iSelectList );
  130. void AddToSelect( EditDispHandle_t handle );
  131. void RemoveFromSelect( EditDispHandle_t handle );
  132. bool IsInSelect( EditDispHandle_t handle );
  133. void CatmullClarkSubdivide( void );
  134. void PreUndo( const char *pszMarkName );
  135. void Undo( EditDispHandle_t handle, bool bAddNeighbors );
  136. void PostUndo( void );
  137. virtual int NumSharedPoints( CMapDisp *pDisp, CMapDisp *pNeighborDisp, int *edge1, int *edge2 );
  138. private: // functions
  139. void TestNeighbors( CMapDisp *pDisp, CMapDisp *pNeighborDisp );
  140. int GetCornerIndex( int index );
  141. int GetEdgeIndex( int *edge );
  142. bool IsInKeptList( CMapClass *pObject );
  143. private: // variables
  144. CUtlVector<EditDispHandle_t> m_WorldList;
  145. CUtlVector<EditDispHandle_t> m_SelectList;
  146. IEditDispSubdivMesh *m_pSubdivMesh; // pointer to the subdivision mesh
  147. CUtlVector<CMapClass*> m_aKeptList;
  148. };
  149. //-----------------------------------------------------------------------------
  150. // Purpose:
  151. //-----------------------------------------------------------------------------
  152. IWorldEditDispMgr *CreateWorldEditDispMgr( void )
  153. {
  154. return new CWorldEditDispMgr;
  155. }
  156. //-----------------------------------------------------------------------------
  157. // Purpose:
  158. //-----------------------------------------------------------------------------
  159. void DestroyWorldEditDispMgr( IWorldEditDispMgr **pDispMgr )
  160. {
  161. if( *pDispMgr )
  162. {
  163. delete *pDispMgr;
  164. *pDispMgr = NULL;
  165. }
  166. }
  167. //-----------------------------------------------------------------------------
  168. // Purpose:
  169. //-----------------------------------------------------------------------------
  170. CWorldEditDispMgr::CWorldEditDispMgr()
  171. {
  172. // allocate the subdivision mesh
  173. m_pSubdivMesh = CreateEditDispSubdivMesh();
  174. }
  175. //-----------------------------------------------------------------------------
  176. // Purpose:
  177. //-----------------------------------------------------------------------------
  178. CWorldEditDispMgr::~CWorldEditDispMgr()
  179. {
  180. // clear the displacement manager lists
  181. m_WorldList.Purge();
  182. m_SelectList.Purge();
  183. // de-allocate the subdivision mesh
  184. DestroyEditDispSubdivMesh( &m_pSubdivMesh );
  185. m_aKeptList.Purge();
  186. }
  187. //-----------------------------------------------------------------------------
  188. // Purpose:
  189. //-----------------------------------------------------------------------------
  190. int CWorldEditDispMgr::WorldCount( void )
  191. {
  192. return m_WorldList.Count();
  193. }
  194. //-----------------------------------------------------------------------------
  195. // Purpose:
  196. //-----------------------------------------------------------------------------
  197. CMapDisp *CWorldEditDispMgr::GetFromWorld( int iWorldList )
  198. {
  199. // no assert because the .Element( ) takes care of that!
  200. EditDispHandle_t handle = m_WorldList.Element( iWorldList );
  201. return EditDispMgr()->GetDisp( handle );
  202. }
  203. //-----------------------------------------------------------------------------
  204. // Purpose:
  205. //-----------------------------------------------------------------------------
  206. CMapDisp *CWorldEditDispMgr::GetFromWorld( EditDispHandle_t handle )
  207. {
  208. int ndx = m_WorldList.Find( handle );
  209. if( ndx != -1 )
  210. {
  211. return EditDispMgr()->GetDisp( handle );
  212. }
  213. return NULL;
  214. }
  215. //-----------------------------------------------------------------------------
  216. // Purpose:
  217. //-----------------------------------------------------------------------------
  218. void CWorldEditDispMgr::AddToWorld( EditDispHandle_t handle )
  219. {
  220. int ndx = m_WorldList.Find( handle );
  221. if( ndx == -1 )
  222. {
  223. ndx = m_WorldList.AddToTail();
  224. m_WorldList[ndx] = handle;
  225. }
  226. // Update itself when it gets added to the world.
  227. CMapDisp *pDisp = EditDispMgr()->GetDisp( handle );
  228. if ( pDisp )
  229. {
  230. pDisp->UpdateData();
  231. }
  232. }
  233. //-----------------------------------------------------------------------------
  234. // Purpose:
  235. //-----------------------------------------------------------------------------
  236. void CWorldEditDispMgr::RemoveFromWorld( EditDispHandle_t handle )
  237. {
  238. int ndx = m_WorldList.Find( handle );
  239. if( ndx != -1 )
  240. {
  241. m_WorldList.Remove( ndx );
  242. }
  243. }
  244. //-----------------------------------------------------------------------------
  245. // Purpose:
  246. // NOTE: this will be in the common code soon!!!!!!!!!
  247. //-----------------------------------------------------------------------------
  248. void CWorldEditDispMgr::FindWorldNeighbors( EditDispHandle_t handle )
  249. {
  250. // get the current displacement
  251. CMapDisp *pDisp = GetFromWorld( handle );
  252. if( !pDisp )
  253. return;
  254. //
  255. // compare against all of the displacements in the world
  256. //
  257. int count = WorldCount();
  258. for( int ndx = 0; ndx < count; ndx++ )
  259. {
  260. // get the potential neighbor surface
  261. CMapDisp *pNeighborDisp = GetFromWorld( ndx );
  262. // check for valid neighbor and don't compare against self
  263. if( !pNeighborDisp || ( pNeighborDisp == pDisp ) )
  264. continue;
  265. // displacements at different resolutions are not considered neighbors
  266. // regardless of edge connectivity
  267. if( pDisp->GetPower() != pNeighborDisp->GetPower() )
  268. continue;
  269. // test for neighboring edge/corner properties
  270. TestNeighbors( pDisp, pNeighborDisp );
  271. }
  272. }
  273. //-----------------------------------------------------------------------------
  274. //-----------------------------------------------------------------------------
  275. void CWorldEditDispMgr::TestNeighbors( CMapDisp *pDisp, CMapDisp *pNeighborDisp )
  276. {
  277. //
  278. // find the number of shared points between the two displacements (corners, edges)
  279. // NOTE: should use only 2, but face may be right on top of one another
  280. //
  281. int edge1[4], edge2[4];
  282. int sharedPointCount = NumSharedPoints( pDisp, pNeighborDisp, edge1, edge2 );
  283. //
  284. // set the neighboring info
  285. //
  286. if( sharedPointCount == 1 )
  287. {
  288. int cornerIndex = GetCornerIndex( edge1[0] );
  289. int neighborCornerIndex = GetCornerIndex( edge2[0] );
  290. if ( ( cornerIndex != -1 ) && ( neighborCornerIndex != -1 ) )
  291. {
  292. CMapFace *pNeighborFace = ( CMapFace* )pNeighborDisp->GetParent();
  293. pDisp->AddCornerNeighbor( cornerIndex, pNeighborFace->GetDisp(), neighborCornerIndex );
  294. }
  295. }
  296. else if( sharedPointCount == 2 )
  297. {
  298. //
  299. // get edge indices
  300. //
  301. int edgeIndex = GetEdgeIndex( edge1 );
  302. int neighborEdgeIndex = GetEdgeIndex( edge2 );
  303. if ( ( edgeIndex != -1 ) && ( neighborEdgeIndex != -1 ) )
  304. {
  305. CMapFace *pNeighborFace = ( CMapFace* )pNeighborDisp->GetParent();
  306. pDisp->SetEdgeNeighbor( edgeIndex, pNeighborFace->GetDisp(), neighborEdgeIndex );
  307. }
  308. }
  309. }
  310. //-----------------------------------------------------------------------------
  311. //-----------------------------------------------------------------------------
  312. bool ComparePoints( const Vector& v1, const Vector& v2, float tolerance )
  313. {
  314. for( int axis = 0; axis < 3; axis++ )
  315. {
  316. if( fabs( v1[axis] - v2[axis] ) > tolerance )
  317. return false;
  318. }
  319. return true;
  320. }
  321. //-----------------------------------------------------------------------------
  322. //-----------------------------------------------------------------------------
  323. int CWorldEditDispMgr::NumSharedPoints( CMapDisp *pDisp, CMapDisp *pNeighborDisp,
  324. int *edge1, int *edge2 )
  325. {
  326. int ptCount = 0;
  327. for( int i = 0; i < 4; i++ )
  328. {
  329. int j;
  330. for( j = 0; j < 4; j++ )
  331. {
  332. Vector pt1, pt2;
  333. pDisp->GetSurfPoint( i, pt1 );
  334. pNeighborDisp->GetSurfPoint( j, pt2 );
  335. if( ComparePoints( pt1, pt2, 0.01f ) )
  336. break;
  337. }
  338. if( j == 4 )
  339. continue;
  340. edge1[ptCount] = i;
  341. edge2[ptCount] = j;
  342. ptCount++;
  343. }
  344. return ptCount;
  345. }
  346. //-----------------------------------------------------------------------------
  347. // Purpose:
  348. //-----------------------------------------------------------------------------
  349. int CWorldEditDispMgr::GetCornerIndex( int index )
  350. {
  351. switch( index )
  352. {
  353. case 0: return 0;
  354. case 1: return 2;
  355. case 2: return 3;
  356. case 3: return 1;
  357. default: return -1;
  358. }
  359. }
  360. //-----------------------------------------------------------------------------
  361. // Purpose:
  362. //-----------------------------------------------------------------------------
  363. int CWorldEditDispMgr::GetEdgeIndex( int *edge )
  364. {
  365. if( ( edge[0] == 0 && edge[1] == 1 ) || ( edge[0] == 1 && edge[1] == 0 ) )
  366. return 0;
  367. if( ( edge[0] == 1 && edge[1] == 2 ) || ( edge[0] == 2 && edge[1] == 1 ) )
  368. return 1;
  369. if( ( edge[0] == 2 && edge[1] == 3 ) || ( edge[0] == 3 && edge[1] == 2 ) )
  370. return 2;
  371. if( ( edge[0] == 3 && edge[1] == 0 ) || ( edge[0] == 0 && edge[1] == 3 ) )
  372. return 3;
  373. return -1;
  374. }
  375. //-----------------------------------------------------------------------------
  376. // Purpose:
  377. //-----------------------------------------------------------------------------
  378. int CWorldEditDispMgr::SelectCount( void )
  379. {
  380. return m_SelectList.Count();
  381. }
  382. //-----------------------------------------------------------------------------
  383. // Purpose:
  384. //-----------------------------------------------------------------------------
  385. void CWorldEditDispMgr::SelectClear( void )
  386. {
  387. m_SelectList.RemoveAll();
  388. }
  389. //-----------------------------------------------------------------------------
  390. // Purpose:
  391. //-----------------------------------------------------------------------------
  392. CMapDisp *CWorldEditDispMgr::GetFromSelect( int iSelectList )
  393. {
  394. // no assert because the .Element( ) takes care of that!
  395. EditDispHandle_t handle = m_SelectList.Element( iSelectList );
  396. return EditDispMgr()->GetDisp( handle );
  397. }
  398. //-----------------------------------------------------------------------------
  399. // Purpose:
  400. //-----------------------------------------------------------------------------
  401. void CWorldEditDispMgr::AddToSelect( EditDispHandle_t handle )
  402. {
  403. int ndx = m_SelectList.Find( handle );
  404. if( ndx == -1 )
  405. {
  406. ndx = m_SelectList.AddToTail();
  407. m_SelectList[ndx] = handle;
  408. }
  409. }
  410. //-----------------------------------------------------------------------------
  411. // Purpose:
  412. //-----------------------------------------------------------------------------
  413. void CWorldEditDispMgr::RemoveFromSelect( EditDispHandle_t handle )
  414. {
  415. int ndx = m_SelectList.Find( handle );
  416. if( ndx != -1 )
  417. {
  418. m_SelectList.Remove( handle );
  419. }
  420. }
  421. //-----------------------------------------------------------------------------
  422. // Purpose:
  423. //-----------------------------------------------------------------------------
  424. bool CWorldEditDispMgr::IsInSelect( EditDispHandle_t handle )
  425. {
  426. int ndx = m_SelectList.Find( handle );
  427. return ( ndx != -1 );
  428. }
  429. //-----------------------------------------------------------------------------
  430. // Purpose:
  431. //-----------------------------------------------------------------------------
  432. void CWorldEditDispMgr::CatmullClarkSubdivide( void )
  433. {
  434. // change the mouse to hourglass, so level designers know something is
  435. // happening
  436. HCURSOR oldCursor = SetCursor( LoadCursor( NULL, IDC_WAIT ) );
  437. //
  438. // add all of the displacements in the selection list into the UNDO
  439. // system
  440. //
  441. PreUndo( "Subdivision" );
  442. int selectCount = m_SelectList.Count();
  443. for( int ndxSelect = 0; ndxSelect < selectCount; ndxSelect++ )
  444. {
  445. // get the current displacement surface
  446. CMapDisp *pDisp = GetFromSelect( ndxSelect );
  447. if( pDisp )
  448. {
  449. Undo( pDisp->GetEditHandle(), false );
  450. }
  451. }
  452. PostUndo();
  453. // initialize the subdivision mesh
  454. m_pSubdivMesh->Init();
  455. //
  456. // add all of the displacements in the selection list into the
  457. // subdivision mesh
  458. //
  459. for( int ndxSelect = 0; ndxSelect < selectCount; ndxSelect++ )
  460. {
  461. // get the current displacement surface
  462. CMapDisp *pDisp = GetFromSelect( ndxSelect );
  463. if( pDisp )
  464. {
  465. m_pSubdivMesh->AddDispTo( pDisp );
  466. }
  467. }
  468. // subdivision
  469. m_pSubdivMesh->DoCatmullClarkSubdivision();
  470. //
  471. // get back subdivided data for all displacement surfaces in the
  472. // selection list
  473. //
  474. for( int ndxSelect = 0; ndxSelect < selectCount; ndxSelect++ )
  475. {
  476. // get the current displacement surface
  477. CMapDisp *pDisp = GetFromSelect( ndxSelect );
  478. if( pDisp )
  479. {
  480. m_pSubdivMesh->GetDispFrom( pDisp );
  481. }
  482. }
  483. m_pSubdivMesh->Shutdown();
  484. // set the cursor back
  485. SetCursor( oldCursor );
  486. }
  487. //-----------------------------------------------------------------------------
  488. // Purpose:
  489. //-----------------------------------------------------------------------------
  490. bool CWorldEditDispMgr::IsInKeptList( CMapClass *pObject )
  491. {
  492. if ( m_aKeptList.Find( pObject ) == -1 )
  493. return false;
  494. return true;
  495. }
  496. //-----------------------------------------------------------------------------
  497. // Purpose:
  498. //-----------------------------------------------------------------------------
  499. void CWorldEditDispMgr::PreUndo( const char *pszMarkName )
  500. {
  501. GetHistory()->MarkUndoPosition( NULL, pszMarkName );
  502. }
  503. //-----------------------------------------------------------------------------
  504. // Purpose:
  505. //-----------------------------------------------------------------------------
  506. void CWorldEditDispMgr::Undo( EditDispHandle_t hDisp, bool bAddNeighbors )
  507. {
  508. // Check the handle.
  509. Assert( hDisp != EDITDISPHANDLE_INVALID );
  510. if( hDisp == EDITDISPHANDLE_INVALID )
  511. return;
  512. // Get the map class object that contains the displacement surface.
  513. CMapDisp *pDisp = EditDispMgr()->GetDisp( hDisp );
  514. if ( !pDisp )
  515. return;
  516. CMapFace *pFace = ( CMapFace* )pDisp->GetParent();
  517. CMapSolid *pSolid = ( CMapSolid* )pFace->GetParent();
  518. CMapClass *pObject = ( CMapClass* )pSolid;
  519. if ( !pObject )
  520. return;
  521. // Keep the map class object for undo.
  522. if ( !IsInKeptList( pObject ) )
  523. {
  524. m_aKeptList.AddToTail( pObject );
  525. GetHistory()->Keep( pObject );
  526. }
  527. // Keep the map class (displacement parent) neighbor objects for undo.
  528. if ( bAddNeighbors )
  529. {
  530. int nNeighborOrient;
  531. EditDispHandle_t hNeighbor;
  532. for ( int iNeighbor = 0; iNeighbor < 4; ++iNeighbor )
  533. {
  534. pDisp = EditDispMgr()->GetDisp( hDisp );
  535. if ( pDisp )
  536. {
  537. //
  538. // Edge Neighbors.
  539. //
  540. pDisp->GetEdgeNeighbor( iNeighbor, hNeighbor, nNeighborOrient );
  541. if( hNeighbor != EDITDISPHANDLE_INVALID )
  542. {
  543. CMapDisp *pNeighborDisp = EditDispMgr()->GetDisp( hNeighbor );
  544. CMapFace *pNeighborFace = ( CMapFace* )pNeighborDisp->GetParent();
  545. CMapSolid *pNeighborSolid = ( CMapSolid* )pNeighborFace->GetParent();
  546. CMapClass *pNeighborObject = ( CMapClass* )pNeighborSolid;
  547. if ( !IsInKeptList( pNeighborObject ) )
  548. {
  549. m_aKeptList.AddToTail( pNeighborObject );
  550. GetHistory()->Keep( pNeighborObject );
  551. }
  552. }
  553. }
  554. pDisp = EditDispMgr()->GetDisp( hDisp );
  555. if ( pDisp )
  556. {
  557. //
  558. // Corner Neighbors.
  559. //
  560. int nCornerCount = pDisp->GetCornerNeighborCount( iNeighbor );
  561. for( int iCorner = 0; iCorner < nCornerCount; ++iCorner )
  562. {
  563. pDisp = EditDispMgr()->GetDisp( hDisp );
  564. if ( pDisp )
  565. {
  566. pDisp->GetCornerNeighbor( iNeighbor, iCorner, hNeighbor, nNeighborOrient );
  567. CMapDisp *pNeighborDisp = EditDispMgr()->GetDisp( hNeighbor );
  568. if ( pNeighborDisp )
  569. {
  570. CMapFace *pNeighborFace = ( CMapFace* )pNeighborDisp->GetParent();
  571. CMapSolid *pNeighborSolid = ( CMapSolid* )pNeighborFace->GetParent();
  572. CMapClass *pNeighborObject = ( CMapClass* )pNeighborSolid;
  573. if ( !IsInKeptList( pNeighborObject ) )
  574. {
  575. m_aKeptList.AddToTail( pNeighborObject );
  576. GetHistory()->Keep( pNeighborObject );
  577. }
  578. }
  579. }
  580. }
  581. }
  582. }
  583. }
  584. }
  585. //-----------------------------------------------------------------------------
  586. // Purpose:
  587. //-----------------------------------------------------------------------------
  588. void CWorldEditDispMgr::PostUndo( void )
  589. {
  590. // Clear the kept list.
  591. m_aKeptList.RemoveAll();
  592. }