diff options
Diffstat (limited to 'hammer/dispmanager.cpp')
| -rw-r--r-- | hammer/dispmanager.cpp | 718 |
1 files changed, 718 insertions, 0 deletions
diff --git a/hammer/dispmanager.cpp b/hammer/dispmanager.cpp new file mode 100644 index 0000000..01e530d --- /dev/null +++ b/hammer/dispmanager.cpp @@ -0,0 +1,718 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $Workfile: $ +// $Date: $ +// $NoKeywords: $ +//=============================================================================// + +#include <stdafx.h> +#include "UtlLinkedList.h" +//#include "DispManager.h" +#include "MapFace.h" +#include "MapDisp.h" +#include "DispSubdiv.h" +#include "History.h" +#include "tier0/minidump.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include <tier0/memdbgon.h> + +//============================================================================= +// +// Global Displacement Manager +// +class CEditDispMgr : public IEditDispMgr +{ +public: // functions + + CEditDispMgr(); + virtual ~CEditDispMgr(); + + EditDispHandle_t Create( void ); + void Destroy( EditDispHandle_t handle ); + + CMapDisp *GetDisp( EditDispHandle_t handle ); + +private: // variables + + CUtlLinkedList<CMapDisp, EditDispHandle_t> m_AllocList; +}; + + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +IEditDispMgr* EditDispMgr( void ) +{ + static CEditDispMgr s_EditDispMgr; + return &s_EditDispMgr; +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +CEditDispMgr::CEditDispMgr() +{ +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +CEditDispMgr::~CEditDispMgr() +{ + m_AllocList.Purge(); +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +EditDispHandle_t CEditDispMgr::Create( void ) +{ + EditDispHandle_t handle = m_AllocList.AddToTail(); + if( handle != EDITDISPHANDLE_INVALID ) + { + CMapDisp *pDisp = &m_AllocList.Element( handle ); + pDisp->SetEditHandle( handle ); + } + + return handle; +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CEditDispMgr::Destroy( EditDispHandle_t handle ) +{ + if ( m_AllocList.IsValidIndex( handle ) ) + { + m_AllocList.Remove( handle ); + } + else + { + static bool bNoToAll = false; + if ( !bNoToAll ) + { + int result = AfxMessageBox( + "CEditDispMgr::Destroy - invalid handle.\n" + "Write minidump?\n", + MB_YESNO ); + + if ( result == IDYES ) + { + // Generate a minidump. + WriteMiniDump(); + } + else + { + bNoToAll = true; + } + } + } +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +CMapDisp *CEditDispMgr::GetDisp( EditDispHandle_t handle ) +{ + if( m_AllocList.IsValidIndex( handle ) ) + { + return &m_AllocList.Element( handle ); + } + + return NULL; +} + + +//============================================================================= +// +// World Displacement Manager(s) +// +class CWorldEditDispMgr : public IWorldEditDispMgr +{ +public: // functions + + // construction/deconstruction + CWorldEditDispMgr(); + virtual ~CWorldEditDispMgr(); + + // world list functionals + int WorldCount( void ); + CMapDisp *GetFromWorld( int iWorldList ); + CMapDisp *GetFromWorld( EditDispHandle_t handle ); + + void AddToWorld( EditDispHandle_t handle ); + void RemoveFromWorld( EditDispHandle_t handle ); + + void FindWorldNeighbors( EditDispHandle_t handle ); + + // selection list functions + int SelectCount( void ); + void SelectClear( void ); + CMapDisp *GetFromSelect( int iSelectList ); + + void AddToSelect( EditDispHandle_t handle ); + void RemoveFromSelect( EditDispHandle_t handle ); + bool IsInSelect( EditDispHandle_t handle ); + + void CatmullClarkSubdivide( void ); + + void PreUndo( const char *pszMarkName ); + void Undo( EditDispHandle_t handle, bool bAddNeighbors ); + void PostUndo( void ); + + virtual int NumSharedPoints( CMapDisp *pDisp, CMapDisp *pNeighborDisp, int *edge1, int *edge2 ); + +private: // functions + + void TestNeighbors( CMapDisp *pDisp, CMapDisp *pNeighborDisp ); + int GetCornerIndex( int index ); + int GetEdgeIndex( int *edge ); + + bool IsInKeptList( CMapClass *pObject ); + +private: // variables + + CUtlVector<EditDispHandle_t> m_WorldList; + CUtlVector<EditDispHandle_t> m_SelectList; + + IEditDispSubdivMesh *m_pSubdivMesh; // pointer to the subdivision mesh + + CUtlVector<CMapClass*> m_aKeptList; +}; + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +IWorldEditDispMgr *CreateWorldEditDispMgr( void ) +{ + return new CWorldEditDispMgr; +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void DestroyWorldEditDispMgr( IWorldEditDispMgr **pDispMgr ) +{ + if( *pDispMgr ) + { + delete *pDispMgr; + *pDispMgr = NULL; + } +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +CWorldEditDispMgr::CWorldEditDispMgr() +{ + // allocate the subdivision mesh + m_pSubdivMesh = CreateEditDispSubdivMesh(); +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +CWorldEditDispMgr::~CWorldEditDispMgr() +{ + // clear the displacement manager lists + m_WorldList.Purge(); + m_SelectList.Purge(); + + // de-allocate the subdivision mesh + DestroyEditDispSubdivMesh( &m_pSubdivMesh ); + + m_aKeptList.Purge(); +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +int CWorldEditDispMgr::WorldCount( void ) +{ + return m_WorldList.Count(); +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +CMapDisp *CWorldEditDispMgr::GetFromWorld( int iWorldList ) +{ + // no assert because the .Element( ) takes care of that! + EditDispHandle_t handle = m_WorldList.Element( iWorldList ); + return EditDispMgr()->GetDisp( handle ); +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +CMapDisp *CWorldEditDispMgr::GetFromWorld( EditDispHandle_t handle ) +{ + int ndx = m_WorldList.Find( handle ); + if( ndx != -1 ) + { + return EditDispMgr()->GetDisp( handle ); + } + + return NULL; +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CWorldEditDispMgr::AddToWorld( EditDispHandle_t handle ) +{ + int ndx = m_WorldList.Find( handle ); + if( ndx == -1 ) + { + ndx = m_WorldList.AddToTail(); + m_WorldList[ndx] = handle; + } + + // Update itself when it gets added to the world. + CMapDisp *pDisp = EditDispMgr()->GetDisp( handle ); + if ( pDisp ) + { + pDisp->UpdateData(); + } +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CWorldEditDispMgr::RemoveFromWorld( EditDispHandle_t handle ) +{ + int ndx = m_WorldList.Find( handle ); + if( ndx != -1 ) + { + m_WorldList.Remove( ndx ); + } +} + + +//----------------------------------------------------------------------------- +// Purpose: +// NOTE: this will be in the common code soon!!!!!!!!! +//----------------------------------------------------------------------------- +void CWorldEditDispMgr::FindWorldNeighbors( EditDispHandle_t handle ) +{ + // get the current displacement + CMapDisp *pDisp = GetFromWorld( handle ); + if( !pDisp ) + return; + + // + // compare against all of the displacements in the world + // + int count = WorldCount(); + for( int ndx = 0; ndx < count; ndx++ ) + { + // get the potential neighbor surface + CMapDisp *pNeighborDisp = GetFromWorld( ndx ); + + // check for valid neighbor and don't compare against self + if( !pNeighborDisp || ( pNeighborDisp == pDisp ) ) + continue; + + // displacements at different resolutions are not considered neighbors + // regardless of edge connectivity + if( pDisp->GetPower() != pNeighborDisp->GetPower() ) + continue; + + // test for neighboring edge/corner properties + TestNeighbors( pDisp, pNeighborDisp ); + } +} + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +void CWorldEditDispMgr::TestNeighbors( CMapDisp *pDisp, CMapDisp *pNeighborDisp ) +{ + // + // find the number of shared points between the two displacements (corners, edges) + // NOTE: should use only 2, but face may be right on top of one another + // + int edge1[4], edge2[4]; + int sharedPointCount = NumSharedPoints( pDisp, pNeighborDisp, edge1, edge2 ); + + // + // set the neighboring info + // + if( sharedPointCount == 1 ) + { + int cornerIndex = GetCornerIndex( edge1[0] ); + int neighborCornerIndex = GetCornerIndex( edge2[0] ); + + if ( ( cornerIndex != -1 ) && ( neighborCornerIndex != -1 ) ) + { + CMapFace *pNeighborFace = ( CMapFace* )pNeighborDisp->GetParent(); + pDisp->AddCornerNeighbor( cornerIndex, pNeighborFace->GetDisp(), neighborCornerIndex ); + } + } + else if( sharedPointCount == 2 ) + { + // + // get edge indices + // + int edgeIndex = GetEdgeIndex( edge1 ); + int neighborEdgeIndex = GetEdgeIndex( edge2 ); + + if ( ( edgeIndex != -1 ) && ( neighborEdgeIndex != -1 ) ) + { + CMapFace *pNeighborFace = ( CMapFace* )pNeighborDisp->GetParent(); + pDisp->SetEdgeNeighbor( edgeIndex, pNeighborFace->GetDisp(), neighborEdgeIndex ); + } + } +} + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +bool ComparePoints( const Vector& v1, const Vector& v2, float tolerance ) +{ + for( int axis = 0; axis < 3; axis++ ) + { + if( fabs( v1[axis] - v2[axis] ) > tolerance ) + return false; + } + + return true; +} + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +int CWorldEditDispMgr::NumSharedPoints( CMapDisp *pDisp, CMapDisp *pNeighborDisp, + int *edge1, int *edge2 ) +{ + int ptCount = 0; + + for( int i = 0; i < 4; i++ ) + { + int j; + for( j = 0; j < 4; j++ ) + { + Vector pt1, pt2; + pDisp->GetSurfPoint( i, pt1 ); + pNeighborDisp->GetSurfPoint( j, pt2 ); + if( ComparePoints( pt1, pt2, 0.01f ) ) + break; + } + + if( j == 4 ) + continue; + + edge1[ptCount] = i; + edge2[ptCount] = j; + ptCount++; + } + + return ptCount; +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +int CWorldEditDispMgr::GetCornerIndex( int index ) +{ + switch( index ) + { + case 0: return 0; + case 1: return 2; + case 2: return 3; + case 3: return 1; + default: return -1; + } +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +int CWorldEditDispMgr::GetEdgeIndex( int *edge ) +{ + if( ( edge[0] == 0 && edge[1] == 1 ) || ( edge[0] == 1 && edge[1] == 0 ) ) + return 0; + + if( ( edge[0] == 1 && edge[1] == 2 ) || ( edge[0] == 2 && edge[1] == 1 ) ) + return 1; + + if( ( edge[0] == 2 && edge[1] == 3 ) || ( edge[0] == 3 && edge[1] == 2 ) ) + return 2; + + if( ( edge[0] == 3 && edge[1] == 0 ) || ( edge[0] == 0 && edge[1] == 3 ) ) + return 3; + + return -1; +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +int CWorldEditDispMgr::SelectCount( void ) +{ + return m_SelectList.Count(); +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CWorldEditDispMgr::SelectClear( void ) +{ + m_SelectList.RemoveAll(); +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +CMapDisp *CWorldEditDispMgr::GetFromSelect( int iSelectList ) +{ + // no assert because the .Element( ) takes care of that! + EditDispHandle_t handle = m_SelectList.Element( iSelectList ); + return EditDispMgr()->GetDisp( handle ); +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CWorldEditDispMgr::AddToSelect( EditDispHandle_t handle ) +{ + int ndx = m_SelectList.Find( handle ); + if( ndx == -1 ) + { + ndx = m_SelectList.AddToTail(); + m_SelectList[ndx] = handle; + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CWorldEditDispMgr::RemoveFromSelect( EditDispHandle_t handle ) +{ + int ndx = m_SelectList.Find( handle ); + if( ndx != -1 ) + { + m_SelectList.Remove( handle ); + } +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +bool CWorldEditDispMgr::IsInSelect( EditDispHandle_t handle ) +{ + int ndx = m_SelectList.Find( handle ); + return ( ndx != -1 ); +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CWorldEditDispMgr::CatmullClarkSubdivide( void ) +{ + // change the mouse to hourglass, so level designers know something is + // happening + HCURSOR oldCursor = SetCursor( LoadCursor( NULL, IDC_WAIT ) ); + + // + // add all of the displacements in the selection list into the UNDO + // system + // + PreUndo( "Subdivision" ); + + int selectCount = m_SelectList.Count(); + for( int ndxSelect = 0; ndxSelect < selectCount; ndxSelect++ ) + { + // get the current displacement surface + CMapDisp *pDisp = GetFromSelect( ndxSelect ); + if( pDisp ) + { + Undo( pDisp->GetEditHandle(), false ); + } + } + + PostUndo(); + + // initialize the subdivision mesh + m_pSubdivMesh->Init(); + + // + // add all of the displacements in the selection list into the + // subdivision mesh + // + for( int ndxSelect = 0; ndxSelect < selectCount; ndxSelect++ ) + { + // get the current displacement surface + CMapDisp *pDisp = GetFromSelect( ndxSelect ); + if( pDisp ) + { + m_pSubdivMesh->AddDispTo( pDisp ); + } + } + + // subdivision + m_pSubdivMesh->DoCatmullClarkSubdivision(); + + // + // get back subdivided data for all displacement surfaces in the + // selection list + // + for( int ndxSelect = 0; ndxSelect < selectCount; ndxSelect++ ) + { + // get the current displacement surface + CMapDisp *pDisp = GetFromSelect( ndxSelect ); + if( pDisp ) + { + m_pSubdivMesh->GetDispFrom( pDisp ); + } + } + + m_pSubdivMesh->Shutdown(); + + // set the cursor back + SetCursor( oldCursor ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +bool CWorldEditDispMgr::IsInKeptList( CMapClass *pObject ) +{ + if ( m_aKeptList.Find( pObject ) == -1 ) + return false; + + return true; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CWorldEditDispMgr::PreUndo( const char *pszMarkName ) +{ + GetHistory()->MarkUndoPosition( NULL, pszMarkName ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CWorldEditDispMgr::Undo( EditDispHandle_t hDisp, bool bAddNeighbors ) +{ + // Check the handle. + Assert( hDisp != EDITDISPHANDLE_INVALID ); + if( hDisp == EDITDISPHANDLE_INVALID ) + return; + + // Get the map class object that contains the displacement surface. + CMapDisp *pDisp = EditDispMgr()->GetDisp( hDisp ); + if ( !pDisp ) + return; + + CMapFace *pFace = ( CMapFace* )pDisp->GetParent(); + CMapSolid *pSolid = ( CMapSolid* )pFace->GetParent(); + CMapClass *pObject = ( CMapClass* )pSolid; + if ( !pObject ) + return; + + // Keep the map class object for undo. + if ( !IsInKeptList( pObject ) ) + { + m_aKeptList.AddToTail( pObject ); + GetHistory()->Keep( pObject ); + } + + // Keep the map class (displacement parent) neighbor objects for undo. + if ( bAddNeighbors ) + { + int nNeighborOrient; + EditDispHandle_t hNeighbor; + + for ( int iNeighbor = 0; iNeighbor < 4; ++iNeighbor ) + { + pDisp = EditDispMgr()->GetDisp( hDisp ); + if ( pDisp ) + { + // + // Edge Neighbors. + // + pDisp->GetEdgeNeighbor( iNeighbor, hNeighbor, nNeighborOrient ); + if( hNeighbor != EDITDISPHANDLE_INVALID ) + { + CMapDisp *pNeighborDisp = EditDispMgr()->GetDisp( hNeighbor ); + CMapFace *pNeighborFace = ( CMapFace* )pNeighborDisp->GetParent(); + CMapSolid *pNeighborSolid = ( CMapSolid* )pNeighborFace->GetParent(); + CMapClass *pNeighborObject = ( CMapClass* )pNeighborSolid; + if ( !IsInKeptList( pNeighborObject ) ) + { + m_aKeptList.AddToTail( pNeighborObject ); + GetHistory()->Keep( pNeighborObject ); + } + } + } + + pDisp = EditDispMgr()->GetDisp( hDisp ); + if ( pDisp ) + { + // + // Corner Neighbors. + // + int nCornerCount = pDisp->GetCornerNeighborCount( iNeighbor ); + for( int iCorner = 0; iCorner < nCornerCount; ++iCorner ) + { + pDisp = EditDispMgr()->GetDisp( hDisp ); + if ( pDisp ) + { + pDisp->GetCornerNeighbor( iNeighbor, iCorner, hNeighbor, nNeighborOrient ); + + CMapDisp *pNeighborDisp = EditDispMgr()->GetDisp( hNeighbor ); + if ( pNeighborDisp ) + { + CMapFace *pNeighborFace = ( CMapFace* )pNeighborDisp->GetParent(); + CMapSolid *pNeighborSolid = ( CMapSolid* )pNeighborFace->GetParent(); + CMapClass *pNeighborObject = ( CMapClass* )pNeighborSolid; + if ( !IsInKeptList( pNeighborObject ) ) + { + m_aKeptList.AddToTail( pNeighborObject ); + GetHistory()->Keep( pNeighborObject ); + } + } + } + } + } + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CWorldEditDispMgr::PostUndo( void ) +{ + // Clear the kept list. + m_aKeptList.RemoveAll(); +} |