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.
719 lines
19 KiB
719 lines
19 KiB
5 years ago
|
//========= 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();
|
||
|
}
|