summaryrefslogtreecommitdiff
path: root/hammer/dispmanager.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'hammer/dispmanager.cpp')
-rw-r--r--hammer/dispmanager.cpp718
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();
+}