initial
This commit is contained in:
151
hammer/AnchorMgr.cpp
Normal file
151
hammer/AnchorMgr.cpp
Normal file
@@ -0,0 +1,151 @@
|
||||
//====== Copyright © 1996-2005, Valve Corporation, All rights reserved. =======
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "AnchorMgr.h"
|
||||
|
||||
|
||||
static int ProcessAnchorHorz( int originalCoord, int originalParentSize[2], EAnchorHorz eAnchor, int parentWidth, int parentHeight )
|
||||
{
|
||||
if ( eAnchor == k_eAnchorLeft )
|
||||
return originalCoord;
|
||||
else
|
||||
return parentWidth - (originalParentSize[0] - originalCoord);
|
||||
}
|
||||
|
||||
static int ProcessAnchorVert( int originalCoord, int originalParentSize[2], EAnchorVert eAnchor, int parentWidth, int parentHeight )
|
||||
{
|
||||
if ( eAnchor == k_eAnchorTop )
|
||||
return originalCoord;
|
||||
else
|
||||
return parentHeight - (originalParentSize[1] - originalCoord);
|
||||
}
|
||||
|
||||
|
||||
CAnchorDef::CAnchorDef( int dlgItemID, ESimpleAnchor eSimpleAnchor )
|
||||
{
|
||||
Init( NULL, dlgItemID, eSimpleAnchor );
|
||||
}
|
||||
|
||||
CAnchorDef::CAnchorDef( int dlgItemID, EAnchorHorz eLeftSide, EAnchorVert eTopSide, EAnchorHorz eRightSide, EAnchorVert eBottomSide )
|
||||
{
|
||||
Init( NULL, dlgItemID, eLeftSide, eTopSide, eRightSide, eBottomSide );
|
||||
}
|
||||
|
||||
CAnchorDef::CAnchorDef( HWND hWnd, ESimpleAnchor eSimpleAnchor )
|
||||
{
|
||||
Init( hWnd, -1, eSimpleAnchor );
|
||||
}
|
||||
|
||||
CAnchorDef::CAnchorDef( HWND hWnd, EAnchorHorz eLeftSide, EAnchorVert eTopSide, EAnchorHorz eRightSide, EAnchorVert eBottomSide )
|
||||
{
|
||||
Init( hWnd, -1, eLeftSide, eTopSide, eRightSide, eBottomSide );
|
||||
}
|
||||
|
||||
void CAnchorDef::Init( HWND hWnd, int dlgItemID, ESimpleAnchor eSimpleAnchor )
|
||||
{
|
||||
if ( eSimpleAnchor == k_eSimpleAnchorBottomRight )
|
||||
{
|
||||
Init( hWnd, dlgItemID, k_eAnchorRight, k_eAnchorBottom, k_eAnchorRight, k_eAnchorBottom );
|
||||
}
|
||||
else if ( eSimpleAnchor == k_eSimpleAnchorAllSides )
|
||||
{
|
||||
Init( hWnd, dlgItemID, k_eAnchorLeft, k_eAnchorTop, k_eAnchorRight, k_eAnchorBottom );
|
||||
}
|
||||
else if ( eSimpleAnchor == k_eSimpleAnchorStretchRight )
|
||||
{
|
||||
Init( hWnd, dlgItemID, k_eAnchorLeft, k_eAnchorTop, k_eAnchorRight, k_eAnchorTop );
|
||||
}
|
||||
else if ( eSimpleAnchor == k_eSimpleAnchorRightSide )
|
||||
{
|
||||
Init( hWnd, dlgItemID, k_eAnchorRight, k_eAnchorTop, k_eAnchorRight, k_eAnchorTop );
|
||||
}
|
||||
else if ( eSimpleAnchor == k_eSimpleAnchorBottomSide )
|
||||
{
|
||||
Init( hWnd, dlgItemID, k_eAnchorLeft, k_eAnchorBottom, k_eAnchorLeft, k_eAnchorBottom );
|
||||
}
|
||||
}
|
||||
|
||||
void CAnchorDef::Init( HWND hWnd, int dlgItemID, EAnchorHorz eLeftSide, EAnchorVert eTopSide, EAnchorHorz eRightSide, EAnchorVert eBottomSide )
|
||||
{
|
||||
m_hInputWnd = hWnd;
|
||||
m_DlgItemID = dlgItemID;
|
||||
m_AnchorLeft = eLeftSide;
|
||||
m_AnchorTop = eTopSide;
|
||||
m_AnchorRight = eRightSide;
|
||||
m_AnchorBottom = eBottomSide;
|
||||
}
|
||||
|
||||
|
||||
CAnchorMgr::CAnchorMgr()
|
||||
{
|
||||
}
|
||||
|
||||
void CAnchorMgr::Init( HWND hParentWnd, CAnchorDef *pAnchors, int nAnchors )
|
||||
{
|
||||
m_Anchors.CopyArray( pAnchors, nAnchors );
|
||||
|
||||
m_hParentWnd = hParentWnd;
|
||||
|
||||
// Figure out the main window's size.
|
||||
RECT rcParent, rcItem;
|
||||
GetWindowRect( m_hParentWnd, &rcParent );
|
||||
m_OriginalParentSize[0] = rcParent.right - rcParent.left;
|
||||
m_OriginalParentSize[1] = rcParent.bottom - rcParent.top;
|
||||
|
||||
// Get all the subitem positions.
|
||||
for ( int i=0; i < m_Anchors.Count(); i++ )
|
||||
{
|
||||
CAnchorDef *pAnchor = &m_Anchors[i];
|
||||
|
||||
if ( pAnchor->m_hInputWnd )
|
||||
pAnchor->m_hWnd = pAnchor->m_hInputWnd;
|
||||
else
|
||||
pAnchor->m_hWnd = GetDlgItem( m_hParentWnd, pAnchor->m_DlgItemID );
|
||||
|
||||
if ( !pAnchor->m_hWnd )
|
||||
continue;
|
||||
|
||||
GetWindowRect( pAnchor->m_hWnd, &rcItem );
|
||||
POINT ptTopLeft;
|
||||
ptTopLeft.x = rcItem.left;
|
||||
ptTopLeft.y = rcItem.top;
|
||||
ScreenToClient( m_hParentWnd, &ptTopLeft );
|
||||
|
||||
pAnchor->m_OriginalPos[0] = ptTopLeft.x;
|
||||
pAnchor->m_OriginalPos[1] = ptTopLeft.y;
|
||||
pAnchor->m_OriginalPos[2] = ptTopLeft.x + (rcItem.right - rcItem.left);
|
||||
pAnchor->m_OriginalPos[3] = ptTopLeft.y + (rcItem.bottom - rcItem.top);
|
||||
}
|
||||
}
|
||||
|
||||
void CAnchorMgr::OnSize()
|
||||
{
|
||||
// Get the new size.
|
||||
int width, height;
|
||||
RECT rcParent;
|
||||
GetWindowRect( m_hParentWnd, &rcParent );
|
||||
width = rcParent.right - rcParent.left;
|
||||
height = rcParent.bottom - rcParent.top;
|
||||
|
||||
// Move each item.
|
||||
for ( int i=0; i < m_Anchors.Count(); i++ )
|
||||
{
|
||||
CAnchorDef *pAnchor = &m_Anchors[i];
|
||||
if ( !pAnchor->m_hWnd )
|
||||
continue;
|
||||
|
||||
RECT rcNew;
|
||||
rcNew.left = ProcessAnchorHorz( pAnchor->m_OriginalPos[0], m_OriginalParentSize, pAnchor->m_AnchorLeft, width, height );
|
||||
rcNew.right = ProcessAnchorHorz( pAnchor->m_OriginalPos[2], m_OriginalParentSize, pAnchor->m_AnchorRight, width, height );
|
||||
rcNew.top = ProcessAnchorVert( pAnchor->m_OriginalPos[1], m_OriginalParentSize, pAnchor->m_AnchorTop, width, height );
|
||||
rcNew.bottom = ProcessAnchorVert( pAnchor->m_OriginalPos[3], m_OriginalParentSize, pAnchor->m_AnchorBottom, width, height );
|
||||
|
||||
SetWindowPos( pAnchor->m_hWnd, NULL, rcNew.left, rcNew.top, rcNew.right-rcNew.left, rcNew.bottom-rcNew.top, SWP_NOZORDER );
|
||||
InvalidateRect( pAnchor->m_hWnd, NULL, false );
|
||||
}
|
||||
}
|
||||
|
||||
86
hammer/AnchorMgr.h
Normal file
86
hammer/AnchorMgr.h
Normal file
@@ -0,0 +1,86 @@
|
||||
//====== Copyright © 1996-2005, Valve Corporation, All rights reserved. =======
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
#ifndef ANCHORMGR_H
|
||||
#define ANCHORMGR_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include "tier1/utlvector.h"
|
||||
|
||||
|
||||
enum ESimpleAnchor
|
||||
{
|
||||
k_eSimpleAnchorAllSides,
|
||||
k_eSimpleAnchorBottomRight, // The whole control follows the bottom right.
|
||||
k_eSimpleAnchorStretchRight, // Only grow in width.
|
||||
k_eSimpleAnchorRightSide,
|
||||
k_eSimpleAnchorBottomSide
|
||||
};
|
||||
enum EAnchorHorz
|
||||
{
|
||||
k_eAnchorLeft, // Anchor this side of the control to the left of its parent window.
|
||||
k_eAnchorRight // Anchor this side of the control to the right of its parent window.
|
||||
};
|
||||
enum EAnchorVert
|
||||
{
|
||||
k_eAnchorTop, // Anchor this side of the control to the top of its parent window.
|
||||
k_eAnchorBottom // Anchor this side of the control to the bottom of its parent window.
|
||||
};
|
||||
|
||||
class CAnchorDef
|
||||
{
|
||||
public:
|
||||
friend class CAnchorMgr;
|
||||
|
||||
// You can use the first constructor for simple cases.
|
||||
CAnchorDef() {}
|
||||
CAnchorDef( int dlgItemID, ESimpleAnchor eSimpleAnchor );
|
||||
CAnchorDef( HWND hWnd, ESimpleAnchor eSimpleAnchor );
|
||||
|
||||
CAnchorDef( int dlgItemID, EAnchorHorz eLeftSide=k_eAnchorLeft, EAnchorVert eTopSide=k_eAnchorTop, EAnchorHorz eRightSide=k_eAnchorRight, EAnchorVert eBottomSide=k_eAnchorBottom );
|
||||
CAnchorDef( HWND hWnd, EAnchorHorz eLeftSide=k_eAnchorLeft, EAnchorVert eTopSide=k_eAnchorTop, EAnchorHorz eRightSide=k_eAnchorRight, EAnchorVert eBottomSide=k_eAnchorBottom );
|
||||
|
||||
// Only one of hWnd or dlgItemID should be set.
|
||||
void Init( HWND hWnd, int dlgItemID, ESimpleAnchor eSimpleAnchor );
|
||||
void Init( HWND hWnd, int dlgItemID, EAnchorHorz eLeftSide, EAnchorVert eTopSide, EAnchorHorz eRightSide, EAnchorVert eBottomSide );
|
||||
|
||||
public:
|
||||
int m_DlgItemID;
|
||||
HWND m_hInputWnd; // Either this or m_DlgItemID is set.
|
||||
EAnchorHorz m_AnchorLeft, m_AnchorRight;
|
||||
EAnchorVert m_AnchorTop, m_AnchorBottom;
|
||||
|
||||
private:
|
||||
int m_OriginalPos[4]; // left, top, right, bottom
|
||||
HWND m_hWnd;
|
||||
};
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: This class helps a resizable window resize and move its controls
|
||||
// whenever the window is resized. First, you call Init() to tell it how
|
||||
// you want all the child windows anchored, then just call OnSize() whenever
|
||||
// the parent window is sized.
|
||||
//-----------------------------------------------------------------------------
|
||||
class CAnchorMgr
|
||||
{
|
||||
public:
|
||||
CAnchorMgr();
|
||||
void Init( HWND hParentWnd, CAnchorMgr::CAnchorDef *pAnchors, int nAnchors );
|
||||
|
||||
// Call this when the parent window's size changes and it'll resize all the subcontrols.
|
||||
void OnSize();
|
||||
|
||||
private:
|
||||
CUtlVector<CAnchorMgr::CAnchorDef> m_Anchors;
|
||||
HWND m_hParentWnd;
|
||||
int m_OriginalParentSize[2]; // wide, tall
|
||||
};
|
||||
|
||||
|
||||
#endif // ANCHORMGR_H
|
||||
1234
hammer/DispShore.cpp
Normal file
1234
hammer/DispShore.cpp
Normal file
File diff suppressed because it is too large
Load Diff
79
hammer/DispShore.h
Normal file
79
hammer/DispShore.h
Normal file
@@ -0,0 +1,79 @@
|
||||
//========= Copyright © 1996-2004, Valve LLC, All rights reserved. ============
|
||||
//
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
#ifndef DISPSHORE_H
|
||||
#define DISPSHORE_H
|
||||
#pragma once
|
||||
|
||||
#include "MapHelper.h"
|
||||
#include "MapFace.h"
|
||||
#include "MapOverlay.h"
|
||||
#include "MapOverlayTrans.h"
|
||||
|
||||
class CHelperInfo;
|
||||
class CMapEntity;
|
||||
|
||||
struct ShoreFaceData_t
|
||||
{
|
||||
CMapFace *m_pFaces[4]; // The hammer faces the points reside on.
|
||||
Vector m_vecPoints[4]; // The shore face points.
|
||||
Vector2D m_vecTexCoords[4]; // The shore texture coordinates.
|
||||
bool m_bAdjWinding;
|
||||
};
|
||||
|
||||
struct ShoreSegment_t
|
||||
{
|
||||
Vector m_vecPoints[2]; // Shore segment points.
|
||||
Vector m_vecNormals[2]; // Shore segment normals.
|
||||
Vector2D m_vecTexCoords[4]; // Shore segment texture coordinates.
|
||||
|
||||
EditDispHandle_t m_hDisp; // Displacement the shore segment was created from.
|
||||
float m_flWaterZ;
|
||||
|
||||
ShoreFaceData_t m_WorldFace;
|
||||
ShoreFaceData_t m_WaterFace;
|
||||
|
||||
// ?
|
||||
Vector m_vecCenter;
|
||||
unsigned int m_iStartPoint;
|
||||
bool m_bTouch;
|
||||
bool m_bCreated;
|
||||
};
|
||||
|
||||
struct Shoreline_t
|
||||
{
|
||||
int m_nShorelineId;
|
||||
CUtlVector<ShoreSegment_t> m_aSegments; // List of shore segments making up the shore line.
|
||||
CUtlVector<int> m_aSortedSegments; // List of shore segments sorted (for connectivity).
|
||||
CUtlVector<CMapOverlay> m_aOverlays;
|
||||
float m_flLength; // Total length of the shore line.
|
||||
ShoreEntityData_t m_ShoreData;
|
||||
|
||||
Shoreline_t();
|
||||
~Shoreline_t();
|
||||
void AddSegment( Vector &vecPoint0, Vector &vecPoint1, Vector &vecNormal, float flWaterZ, CMapFace *pWaterFace, EditDispHandle_t hDisp );
|
||||
};
|
||||
|
||||
class IDispShoreManager
|
||||
{
|
||||
public:
|
||||
|
||||
virtual bool Init( void ) = 0;
|
||||
virtual void Shutdown( void ) = 0;
|
||||
|
||||
// Shoreline management.
|
||||
virtual int GetShorelineCount( void ) = 0;
|
||||
virtual Shoreline_t *GetShoreline( int nShorelineId ) = 0;
|
||||
virtual void AddShoreline( int nShorelineId ) = 0;
|
||||
virtual void RemoveShoreline( int nShorelineId ) = 0;
|
||||
virtual void BuildShoreline( int nShorelineId, CUtlVector<CMapFace*> &aFaces, CUtlVector<CMapFace*> &aWaterFaces ) = 0;
|
||||
|
||||
virtual void Draw( CRender3D *pRender ) = 0;
|
||||
virtual void DebugDraw( CRender3D *pRender ) = 0;
|
||||
};
|
||||
|
||||
IDispShoreManager *GetShoreManager( void );
|
||||
|
||||
#endif // DISPSHORE_H
|
||||
161
hammer/FileChangeWatcher.cpp
Normal file
161
hammer/FileChangeWatcher.cpp
Normal file
@@ -0,0 +1,161 @@
|
||||
//====== Copyright © 1996-2005, Valve Corporation, All rights reserved. =======
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "FileChangeWatcher.h"
|
||||
#include "tier1/utldict.h"
|
||||
#include "filesystem_tools.h"
|
||||
#include "vstdlib/vstrtools.h"
|
||||
|
||||
|
||||
CFileChangeWatcher::CFileChangeWatcher()
|
||||
{
|
||||
m_pCallbacks = NULL;
|
||||
}
|
||||
|
||||
CFileChangeWatcher::~CFileChangeWatcher()
|
||||
{
|
||||
Term();
|
||||
}
|
||||
|
||||
void CFileChangeWatcher::Init( ICallbacks *pCallbacks )
|
||||
{
|
||||
Term();
|
||||
m_pCallbacks = pCallbacks;
|
||||
}
|
||||
|
||||
bool CFileChangeWatcher::AddDirectory( const char *pSearchPathBase, const char *pDirName, bool bRecursive )
|
||||
{
|
||||
char fullDirName[MAX_PATH];
|
||||
V_ComposeFileName( pSearchPathBase, pDirName, fullDirName, sizeof( fullDirName ) );
|
||||
|
||||
HANDLE hDir = CreateFile( fullDirName, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS|FILE_FLAG_OVERLAPPED, NULL );
|
||||
if ( hDir == INVALID_HANDLE_VALUE )
|
||||
{
|
||||
Warning( "CFileChangeWatcher::AddDirectory - can't get a handle to directory %s.\n", pDirName );
|
||||
return false;
|
||||
}
|
||||
|
||||
// Call this once to start the ball rolling.. Next time we call it, it'll tell us the changes that
|
||||
// have happened since this call.
|
||||
CDirWatch *pDirWatch = new CDirWatch;
|
||||
V_strncpy( pDirWatch->m_SearchPathBase, pSearchPathBase, sizeof( pDirWatch->m_SearchPathBase ) );
|
||||
V_strncpy( pDirWatch->m_DirName, pDirName, sizeof( pDirWatch->m_DirName ) );
|
||||
V_strncpy( pDirWatch->m_FullDirName, fullDirName, sizeof( pDirWatch->m_FullDirName ) );
|
||||
pDirWatch->m_hDir = hDir;
|
||||
pDirWatch->m_hEvent = CreateEvent( NULL, false, false, NULL );
|
||||
memset( &pDirWatch->m_Overlapped, 0, sizeof( pDirWatch->m_Overlapped ) );
|
||||
pDirWatch->m_Overlapped.hEvent = pDirWatch->m_hEvent;
|
||||
if ( !CallReadDirectoryChanges( pDirWatch ) )
|
||||
{
|
||||
CloseHandle( pDirWatch->m_hEvent );
|
||||
CloseHandle( pDirWatch->m_hDir );
|
||||
delete pDirWatch;
|
||||
return false;
|
||||
}
|
||||
|
||||
m_DirWatches.AddToTail( pDirWatch );
|
||||
return true;
|
||||
}
|
||||
|
||||
void CFileChangeWatcher::Term()
|
||||
{
|
||||
for ( int i=0; i < m_DirWatches.Count(); i++ )
|
||||
{
|
||||
CloseHandle( m_DirWatches[i]->m_hDir );
|
||||
CloseHandle( m_DirWatches[i]->m_hEvent );
|
||||
}
|
||||
m_DirWatches.PurgeAndDeleteElements();
|
||||
m_pCallbacks = NULL;
|
||||
}
|
||||
|
||||
int CFileChangeWatcher::Update()
|
||||
{
|
||||
CUtlDict< int, int > queuedChanges;
|
||||
int nTotalChanges = 0;
|
||||
|
||||
// Check each CDirWatch.
|
||||
int i = 0;
|
||||
while ( i < m_DirWatches.Count() )
|
||||
{
|
||||
CDirWatch *pDirWatch = m_DirWatches[i];
|
||||
|
||||
DWORD dwBytes = 0;
|
||||
if ( GetOverlappedResult( pDirWatch->m_hDir, &pDirWatch->m_Overlapped, &dwBytes, FALSE ) )
|
||||
{
|
||||
// Read through the notifications.
|
||||
int nBytesLeft = (int)dwBytes;
|
||||
char *pCurPos = pDirWatch->m_Buffer;
|
||||
while ( nBytesLeft >= sizeof( FILE_NOTIFY_INFORMATION ) )
|
||||
{
|
||||
FILE_NOTIFY_INFORMATION *pNotify = (FILE_NOTIFY_INFORMATION*)pCurPos;
|
||||
|
||||
if ( m_pCallbacks )
|
||||
{
|
||||
// Figure out what happened to this file.
|
||||
WCHAR nullTerminated[2048];
|
||||
int nBytesToCopy = min( pNotify->FileNameLength, 2047 );
|
||||
memcpy( nullTerminated, pNotify->FileName, nBytesToCopy );
|
||||
nullTerminated[nBytesToCopy/2] = 0;
|
||||
char ansiFilename[1024];
|
||||
V_UnicodeToUTF8( nullTerminated, ansiFilename, sizeof( ansiFilename ) );
|
||||
|
||||
// Now add it to the queue. We use this queue because sometimes Windows will give us multiple
|
||||
// of the same modified notification back to back, and we want to reduce redundant calls.
|
||||
int iExisting = queuedChanges.Find( ansiFilename );
|
||||
if ( iExisting == queuedChanges.InvalidIndex() )
|
||||
{
|
||||
iExisting = queuedChanges.Insert( ansiFilename, 0 );
|
||||
++nTotalChanges;
|
||||
}
|
||||
}
|
||||
|
||||
if ( pNotify->NextEntryOffset == 0 )
|
||||
break;
|
||||
|
||||
pCurPos += pNotify->NextEntryOffset;
|
||||
nBytesLeft -= (int)pNotify->NextEntryOffset;
|
||||
}
|
||||
|
||||
CallReadDirectoryChanges( pDirWatch );
|
||||
continue; // Check again because sometimes it queues up duplicate notifications.
|
||||
}
|
||||
|
||||
// Process all the entries in the queue.
|
||||
for ( int iQueuedChange=queuedChanges.First(); iQueuedChange != queuedChanges.InvalidIndex(); iQueuedChange=queuedChanges.Next( iQueuedChange ) )
|
||||
{
|
||||
SendNotification( pDirWatch, queuedChanges.GetElementName( iQueuedChange ) );
|
||||
}
|
||||
queuedChanges.Purge();
|
||||
++i;
|
||||
}
|
||||
|
||||
return nTotalChanges;
|
||||
}
|
||||
|
||||
void CFileChangeWatcher::SendNotification( CFileChangeWatcher::CDirWatch *pDirWatch, const char *pRelativeFilename )
|
||||
{
|
||||
// Use this for full filenames although you don't strictly need it..
|
||||
char fullFilename[MAX_PATH];
|
||||
V_ComposeFileName( pDirWatch->m_FullDirName, pRelativeFilename, fullFilename, sizeof( fullFilename ) );
|
||||
|
||||
m_pCallbacks->OnFileChange( pRelativeFilename, fullFilename );
|
||||
}
|
||||
|
||||
BOOL CFileChangeWatcher::CallReadDirectoryChanges( CFileChangeWatcher::CDirWatch *pDirWatch )
|
||||
{
|
||||
return ReadDirectoryChangesW( pDirWatch->m_hDir,
|
||||
pDirWatch->m_Buffer,
|
||||
sizeof( pDirWatch->m_Buffer ),
|
||||
true,
|
||||
FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_SIZE | FILE_NOTIFY_CHANGE_LAST_WRITE,
|
||||
NULL,
|
||||
&pDirWatch->m_Overlapped,
|
||||
NULL );
|
||||
}
|
||||
|
||||
|
||||
|
||||
70
hammer/FileChangeWatcher.h
Normal file
70
hammer/FileChangeWatcher.h
Normal file
@@ -0,0 +1,70 @@
|
||||
//====== Copyright © 1996-2005, Valve Corporation, All rights reserved. =======
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
#ifndef FILECHANGEWATCHER_H
|
||||
#define FILECHANGEWATCHER_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
|
||||
#include "tier1/utlvector.h"
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: This class provides notifications of changes in directories.
|
||||
// Call AddDirectory to tell it which directories to watch, then
|
||||
// call Update() periodically to check for updates.
|
||||
//-----------------------------------------------------------------------------
|
||||
class CFileChangeWatcher
|
||||
{
|
||||
public:
|
||||
class ICallbacks
|
||||
{
|
||||
public:
|
||||
// Note: this is called if the file is added, removed, or modified. It's up to the app to figure out
|
||||
// what it wants to do with the change.
|
||||
virtual void OnFileChange( const char *pRelativeFilename, const char *pFullFilename ) = 0;
|
||||
};
|
||||
|
||||
|
||||
CFileChangeWatcher();
|
||||
~CFileChangeWatcher();
|
||||
|
||||
void Init( ICallbacks *pCallbacks );
|
||||
|
||||
// pSearchPathBase would be like "c:\valve\hl2" and pDirName would be like "materials".
|
||||
bool AddDirectory( const char *pSearchPathBase, const char *pDirName, bool bRecursive );
|
||||
void Term();
|
||||
|
||||
// Call this periodically to update. It'll call your ICallbacks functions for anything it finds.
|
||||
// Returns the number of updates it got.
|
||||
int Update();
|
||||
|
||||
private:
|
||||
class CDirWatch
|
||||
{
|
||||
public:
|
||||
char m_SearchPathBase[MAX_PATH];
|
||||
char m_DirName[MAX_PATH];
|
||||
char m_FullDirName[MAX_PATH];
|
||||
OVERLAPPED m_Overlapped;
|
||||
HANDLE m_hEvent;
|
||||
HANDLE m_hDir; // Created with CreateFile.
|
||||
char m_Buffer[1024 * 16];
|
||||
};
|
||||
|
||||
void SendNotification( CFileChangeWatcher::CDirWatch *pDirWatch, const char *pRelativeFilename );
|
||||
BOOL CallReadDirectoryChanges( CFileChangeWatcher::CDirWatch *pDirWatch );
|
||||
|
||||
private:
|
||||
// Override these.
|
||||
CUtlVector<CDirWatch*> m_DirWatches;
|
||||
ICallbacks *m_pCallbacks;
|
||||
};
|
||||
|
||||
|
||||
#endif // FILECHANGEWATCHER_H
|
||||
876
hammer/FilteredComboBox.cpp
Normal file
876
hammer/FilteredComboBox.cpp
Normal file
@@ -0,0 +1,876 @@
|
||||
|
||||
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ====
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "FilteredComboBox.h"
|
||||
|
||||
|
||||
BEGIN_MESSAGE_MAP(CFilteredComboBox, CComboBox)
|
||||
//{{AFX_MSG_MAP(CFilteredComboBox)
|
||||
ON_CONTROL_REFLECT_EX(CBN_SELCHANGE, OnSelChange)
|
||||
ON_CONTROL_REFLECT_EX(CBN_EDITCHANGE, OnEditChange)
|
||||
ON_CONTROL_REFLECT_EX(CBN_CLOSEUP, OnCloseUp)
|
||||
ON_CONTROL_REFLECT_EX(CBN_DROPDOWN, OnDropDown)
|
||||
ON_CONTROL_REFLECT_EX(CBN_SELENDOK, OnSelEndOK)
|
||||
ON_WM_CTLCOLOR()
|
||||
//}}AFX_MSG_MAP
|
||||
END_MESSAGE_MAP()
|
||||
|
||||
|
||||
static const char *s_pStringToMatch = NULL;
|
||||
static int s_iStringToMatchLen;
|
||||
|
||||
|
||||
// This can help debug events in the combo box.
|
||||
static int g_iFunctionMarkerEvent = 1;
|
||||
class CFunctionMarker
|
||||
{
|
||||
public:
|
||||
CFunctionMarker( const char *p )
|
||||
{
|
||||
#if 0
|
||||
m_iEvent = g_iFunctionMarkerEvent++;
|
||||
|
||||
char str[512];
|
||||
Q_snprintf( str, sizeof( str ), "enter %d: %s\n", m_iEvent, p );
|
||||
OutputDebugString( str );
|
||||
m_p = p;
|
||||
#endif
|
||||
}
|
||||
|
||||
~CFunctionMarker()
|
||||
{
|
||||
#if 0
|
||||
char str[512];
|
||||
Q_snprintf( str, sizeof( str ), "exit %d: %s\n", m_iEvent, m_p );
|
||||
OutputDebugString( str );
|
||||
#endif
|
||||
}
|
||||
const char *m_p;
|
||||
int m_iEvent;
|
||||
};
|
||||
|
||||
// ------------------------------------------------------------------------------------------------------------ //
|
||||
// CFilteredComboBox implementation.
|
||||
// ------------------------------------------------------------------------------------------------------------ //
|
||||
CFilteredComboBox::CFilteredComboBox( CFilteredComboBox::ICallbacks *pCallbacks )
|
||||
: m_pCallbacks( pCallbacks )
|
||||
{
|
||||
m_hQueuedFont = NULL;
|
||||
m_bInSelChange = false;
|
||||
m_bNotifyParent = true;
|
||||
m_dwTextColor = RGB(0, 0, 0);
|
||||
m_bOnlyProvideSuggestions = true;
|
||||
m_hEditControlFont = NULL;
|
||||
m_bInEnterKeyPressedHandler = false;
|
||||
}
|
||||
|
||||
|
||||
void CFilteredComboBox::SetSuggestions( CUtlVector<CString> &suggestions, int flags )
|
||||
{
|
||||
CreateFonts();
|
||||
|
||||
// Verify some of the window styles. This class requires these, and it doesn't get a change to set them
|
||||
// unless you call Create on it.
|
||||
// If we use owner draw variable, we get the bug described here: http://support.microsoft.com/kb/813791.
|
||||
Assert( GetStyle() & CBS_OWNERDRAWFIXED );
|
||||
Assert( GetStyle() & CBS_HASSTRINGS );
|
||||
Assert( !( GetStyle() & CBS_SORT ) );
|
||||
|
||||
// Copy the list.
|
||||
m_Suggestions = suggestions;
|
||||
|
||||
CString str;
|
||||
GetWindowText( str );
|
||||
DWORD sel = GetEditSel();
|
||||
|
||||
FillDropdownList( NULL, false );
|
||||
|
||||
// Force it to provide the first one if they only want suggestions and the current text in there is not valid.
|
||||
bool bSelectFirst = ((flags & SETSUGGESTIONS_SELECTFIRST) != 0);
|
||||
bool bCallback = ((flags & SETSUGGESTIONS_CALLBACK) != 0);
|
||||
bool bForceFirst = (m_bOnlyProvideSuggestions && FindSuggestion( str ) == -1);
|
||||
if ( bSelectFirst || bForceFirst )
|
||||
{
|
||||
SetCurSel( 0 );
|
||||
|
||||
if ( GetCount() > 0 )
|
||||
{
|
||||
CString str;
|
||||
GetLBText( 0, str );
|
||||
if ( bCallback )
|
||||
DoTextChangedCallback( str );
|
||||
}
|
||||
else
|
||||
{
|
||||
m_LastTextChangedValue = "";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
SetWindowText( str );
|
||||
SetEditSel( LOWORD( sel ), HIWORD( sel ) );
|
||||
if ( bCallback )
|
||||
DoTextChangedCallback( str );
|
||||
}
|
||||
|
||||
SetRedraw( true );
|
||||
Invalidate();
|
||||
}
|
||||
|
||||
|
||||
void CFilteredComboBox::AddSuggestion( const CString &suggestion )
|
||||
{
|
||||
if ( FindSuggestion( suggestion ) == -1 )
|
||||
m_Suggestions.AddToTail( suggestion );
|
||||
}
|
||||
|
||||
|
||||
void CFilteredComboBox::Clear()
|
||||
{
|
||||
m_Suggestions.Purge();
|
||||
SetWindowText( "" );
|
||||
m_LastTextChangedValue = "";
|
||||
}
|
||||
|
||||
|
||||
void CFilteredComboBox::ForceEditControlText( const char *pStr )
|
||||
{
|
||||
SetWindowText( pStr );
|
||||
}
|
||||
|
||||
|
||||
void CFilteredComboBox::SelectItem( const char *pStr )
|
||||
{
|
||||
if ( !pStr )
|
||||
{
|
||||
SetEditControlText( "" );
|
||||
return;
|
||||
}
|
||||
|
||||
// See if we already have this item selected. If so, don't do anything.
|
||||
int iCurSel = GetCurSel();
|
||||
if ( iCurSel != CB_ERR )
|
||||
{
|
||||
CString str;
|
||||
GetLBText( iCurSel, str );
|
||||
if ( Q_stricmp( pStr, str ) == 0 )
|
||||
{
|
||||
// Make sure the edit control has the right text in there. If they called ForceEditControlText,
|
||||
// then it might not.
|
||||
CString str;
|
||||
GetWindowText( str );
|
||||
if ( Q_stricmp( str, pStr ) != 0 )
|
||||
{
|
||||
SetWindowText( pStr );
|
||||
}
|
||||
|
||||
m_LastTextChangedValue = pStr;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if ( m_bOnlyProvideSuggestions && FindSuggestion( pStr ) == -1 )
|
||||
{
|
||||
// This item doesn't match any suggestion. We can get rid of this assert
|
||||
// if it becomes a nuissance, but for now it's good to note that this
|
||||
// is a weird situation.
|
||||
Assert( false );
|
||||
SetEditControlText( pStr );
|
||||
return;
|
||||
}
|
||||
|
||||
FillDropdownList( pStr );
|
||||
}
|
||||
|
||||
|
||||
CString CFilteredComboBox::GetCurrentItem()
|
||||
{
|
||||
return m_LastTextChangedValue;
|
||||
}
|
||||
|
||||
|
||||
void CFilteredComboBox::SetEditControlFont( HFONT hFont )
|
||||
{
|
||||
if ( !hFont )
|
||||
return;
|
||||
|
||||
if ( m_bInSelChange )
|
||||
{
|
||||
m_hQueuedFont = hFont;
|
||||
return;
|
||||
}
|
||||
|
||||
CString str;
|
||||
GetWindowText( str );
|
||||
DWORD sel = GetEditSel();
|
||||
|
||||
InternalSetEditControlFont( hFont, str, sel );
|
||||
}
|
||||
|
||||
|
||||
void CFilteredComboBox::InternalSetEditControlFont( HFONT hFont, const char *pEditText, DWORD sel )
|
||||
{
|
||||
if ( hFont != m_hEditControlFont )
|
||||
{
|
||||
CFunctionMarker marker( "InternalSetEditControlFont" );
|
||||
|
||||
// Don't let it mess with everything here.
|
||||
SetRedraw( false );
|
||||
|
||||
CRect rcMyRect;
|
||||
GetWindowRect( rcMyRect );
|
||||
CWnd *pParent = GetParent();
|
||||
if ( pParent )
|
||||
pParent->ScreenToClient( &rcMyRect );
|
||||
|
||||
BOOL bWasDropped = GetDroppedState();
|
||||
|
||||
|
||||
m_hEditControlFont = hFont;
|
||||
SetFont( CFont::FromHandle( m_hEditControlFont ), false );
|
||||
|
||||
|
||||
SetWindowText( pEditText );
|
||||
SetEditSel( LOWORD( sel ), HIWORD( sel ) );
|
||||
|
||||
if ( pParent )
|
||||
MoveWindow( rcMyRect );
|
||||
|
||||
if ( bWasDropped )
|
||||
ShowDropDown( true );
|
||||
|
||||
|
||||
SetRedraw( true );
|
||||
Invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
HFONT CFilteredComboBox::GetEditControlFont() const
|
||||
{
|
||||
return m_hEditControlFont;
|
||||
}
|
||||
|
||||
|
||||
void CFilteredComboBox::SetEditControlTextColor(COLORREF dwColor)
|
||||
{
|
||||
m_dwTextColor = dwColor;
|
||||
}
|
||||
|
||||
|
||||
COLORREF CFilteredComboBox::GetEditControlTextColor() const
|
||||
{
|
||||
return m_dwTextColor;
|
||||
}
|
||||
|
||||
|
||||
void CFilteredComboBox::SetEditControlText( const char *pText )
|
||||
{
|
||||
SetWindowText( pText );
|
||||
}
|
||||
|
||||
|
||||
CString CFilteredComboBox::GetEditControlText() const
|
||||
{
|
||||
CString ret;
|
||||
GetWindowText( ret );
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool CFilteredComboBox::IsWindowEnabled() const
|
||||
{
|
||||
return (BaseClass::IsWindowEnabled() == TRUE);
|
||||
}
|
||||
|
||||
|
||||
void CFilteredComboBox::EnableWindow( bool bEnable )
|
||||
{
|
||||
BaseClass::EnableWindow( bEnable );
|
||||
}
|
||||
|
||||
|
||||
void CFilteredComboBox::SetOnlyProvideSuggestions( bool bOnlyProvideSuggestions )
|
||||
{
|
||||
m_bOnlyProvideSuggestions = bOnlyProvideSuggestions;
|
||||
}
|
||||
|
||||
|
||||
void CFilteredComboBox::FillDropdownList( const char *pInitialSel, bool bEnableRedraw )
|
||||
{
|
||||
CFunctionMarker marker( "FillDropdownList" );
|
||||
|
||||
SetRedraw( FALSE );
|
||||
ResetContent();
|
||||
|
||||
// Fill the box with the initial set of values.
|
||||
CUtlVector<CString> items;
|
||||
GetItemsMatchingString( "", items );
|
||||
|
||||
for ( int i=0; i < items.Count(); i++ )
|
||||
AddString( items[i] );
|
||||
|
||||
if ( pInitialSel )
|
||||
{
|
||||
CString str = pInitialSel;
|
||||
if ( m_bOnlyProvideSuggestions )
|
||||
{
|
||||
str = GetBestSuggestion( pInitialSel );
|
||||
if ( !InternalSelectItemByName( pInitialSel) )
|
||||
{
|
||||
Assert( false );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Make sure we're putting the item they requested in there.
|
||||
if ( !InternalSelectItemByName( str ) )
|
||||
{
|
||||
// Add the typed text to the combobox here otherwise it'll select the nearest match when they drop it down with the mouse.
|
||||
AddString( str );
|
||||
InternalSelectItemByName( str );
|
||||
}
|
||||
}
|
||||
|
||||
DoTextChangedCallback( str );
|
||||
}
|
||||
|
||||
if ( bEnableRedraw )
|
||||
{
|
||||
SetRedraw( TRUE );
|
||||
Invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
LRESULT CFilteredComboBox::DefWindowProc(
|
||||
UINT message,
|
||||
WPARAM wParam,
|
||||
LPARAM lParam
|
||||
)
|
||||
{
|
||||
// We handle the enter key specifically because the default combo box behavior is to
|
||||
// reset the text and all this stuff we don't want.
|
||||
if ( message == WM_KEYDOWN )
|
||||
{
|
||||
if ( wParam == '\r' )
|
||||
{
|
||||
OnEnterKeyPressed( NULL );
|
||||
return 0;
|
||||
}
|
||||
else if ( wParam == 27 )
|
||||
{
|
||||
// Escape..
|
||||
OnEscapeKeyPressed();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return BaseClass::DefWindowProc( message, wParam, lParam );
|
||||
}
|
||||
|
||||
|
||||
BOOL CFilteredComboBox::PreCreateWindow( CREATESTRUCT& cs )
|
||||
{
|
||||
// We need these styles in order for owner draw to work.
|
||||
// If we use CBS_OWNERDRAWVARIABLE, then we run into this bug: http://support.microsoft.com/kb/813791.
|
||||
cs.style |= CBS_OWNERDRAWFIXED | CBS_HASSTRINGS;
|
||||
cs.style &= ~CBS_SORT;
|
||||
return BaseClass::PreCreateWindow( cs );
|
||||
}
|
||||
|
||||
void CFilteredComboBox::OnEnterKeyPressed( const char *pForceText )
|
||||
{
|
||||
if ( m_bInEnterKeyPressedHandler )
|
||||
return;
|
||||
|
||||
CFunctionMarker marker( "OnEnterKeyPressed" );
|
||||
|
||||
m_bInEnterKeyPressedHandler = true;
|
||||
|
||||
// Must do this before ShowDropDown because that will change these variables underneath us.
|
||||
CString szTypedText;
|
||||
DWORD sel;
|
||||
if ( pForceText )
|
||||
{
|
||||
szTypedText = pForceText;
|
||||
sel = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
GetWindowText( szTypedText );
|
||||
sel = GetEditSel();
|
||||
}
|
||||
|
||||
CRect rcMyRect;
|
||||
GetWindowRect( rcMyRect );
|
||||
CWnd *pParent = GetParent();
|
||||
if ( pParent )
|
||||
pParent->ScreenToClient( &rcMyRect );
|
||||
|
||||
SetRedraw( false );
|
||||
ShowDropDown( FALSE );
|
||||
|
||||
// They can get into here a variety of ways. Editing followed by enter. Editing+arrow keys, followed by enter, etc.
|
||||
if ( m_bOnlyProvideSuggestions )
|
||||
{
|
||||
CString str;
|
||||
if ( FindSuggestion( szTypedText ) == -1 && m_pCallbacks->OnUnknownEntry( szTypedText ) )
|
||||
{
|
||||
// They want us to KEEP this unknown entry, so add it to our list and select it.
|
||||
m_Suggestions.AddToTail( szTypedText );
|
||||
str = szTypedText;
|
||||
}
|
||||
else
|
||||
{
|
||||
// They returned false, so do the default behavior: go to the best match we can find.
|
||||
str = GetBestSuggestion( szTypedText );
|
||||
}
|
||||
|
||||
DoTextChangedCallback( str );
|
||||
FillDropdownList( str, false );
|
||||
|
||||
if ( GetCurSel() == CB_ERR )
|
||||
SetCurSel( 0 );
|
||||
}
|
||||
else
|
||||
{
|
||||
FillDropdownList( szTypedText, false );
|
||||
SetWindowText( szTypedText );
|
||||
SetEditSel( LOWORD(sel), HIWORD(sel) );
|
||||
}
|
||||
|
||||
// Restore our window if necessary.
|
||||
if ( pParent )
|
||||
MoveWindow( &rcMyRect );
|
||||
SetRedraw( true );
|
||||
Invalidate();
|
||||
|
||||
DoTextChangedCallback( GetEditControlText() );
|
||||
m_bInEnterKeyPressedHandler = false;
|
||||
}
|
||||
|
||||
|
||||
void CFilteredComboBox::OnEscapeKeyPressed()
|
||||
{
|
||||
// Fill it with everything and force it to select whatever we last selected.
|
||||
m_bInEnterKeyPressedHandler = true;
|
||||
ShowDropDown( FALSE );
|
||||
m_bInEnterKeyPressedHandler = false;
|
||||
|
||||
FillDropdownList( m_LastTextChangedValue, true );
|
||||
}
|
||||
|
||||
|
||||
BOOL CFilteredComboBox::OnDropDown()
|
||||
{
|
||||
CFunctionMarker marker( "OnDropDown" );
|
||||
// This is necessary to keep the cursor from disappearing.
|
||||
SendMessage( WM_SETCURSOR, 0, 0 );
|
||||
return !m_bNotifyParent;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Attaches this object to the given dialog item.
|
||||
//-----------------------------------------------------------------------------
|
||||
void CFilteredComboBox::SubclassDlgItem(UINT nID, CWnd *pParent)
|
||||
{
|
||||
//
|
||||
// Disable parent notifications for CControlBar-derived classes. This is
|
||||
// necessary because these classes result in multiple message reflections
|
||||
// unless we return TRUE from our message handler.
|
||||
//
|
||||
if (pParent->IsKindOf(RUNTIME_CLASS(CControlBar)))
|
||||
{
|
||||
m_bNotifyParent = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_bNotifyParent = true;
|
||||
}
|
||||
|
||||
BaseClass::SubclassDlgItem(nID, pParent);
|
||||
}
|
||||
|
||||
BOOL CFilteredComboBox::OnSelChange()
|
||||
{
|
||||
if ( !m_bInSelChange )
|
||||
{
|
||||
CFunctionMarker marker( "OnSelChange" );
|
||||
|
||||
CString strOriginalText;
|
||||
GetWindowText( strOriginalText );
|
||||
DWORD dwOriginalEditSel = GetEditSel();
|
||||
|
||||
|
||||
m_bInSelChange = true;
|
||||
|
||||
int iSel = GetCurSel();
|
||||
if ( iSel != CB_ERR )
|
||||
{
|
||||
CString str;
|
||||
GetLBText( iSel, str );
|
||||
strOriginalText = str;
|
||||
DoTextChangedCallback( str );
|
||||
}
|
||||
|
||||
m_bInSelChange = false;
|
||||
|
||||
if ( m_hQueuedFont )
|
||||
{
|
||||
HFONT hFont = m_hQueuedFont;
|
||||
m_hQueuedFont = NULL;
|
||||
m_bInSelChange = false;
|
||||
InternalSetEditControlFont( hFont, strOriginalText, dwOriginalEditSel );
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Despite MSDN's lies, returning FALSE here allows the parent
|
||||
// window to hook the notification message as well, not TRUE.
|
||||
//
|
||||
return !m_bNotifyParent;
|
||||
}
|
||||
|
||||
BOOL CFilteredComboBox::OnCloseUp()
|
||||
{
|
||||
if ( !m_bInEnterKeyPressedHandler )
|
||||
{
|
||||
CFunctionMarker marker( "OnCloseUp" );
|
||||
|
||||
CString str;
|
||||
if ( GetCurSel() == CB_ERR || GetCount() == 0 )
|
||||
str = m_LastTextChangedValue;
|
||||
else
|
||||
GetLBText( GetCurSel(), str );
|
||||
OnEnterKeyPressed( str );
|
||||
}
|
||||
|
||||
//
|
||||
// Despite MSDN's lies, returning FALSE here allows the parent
|
||||
// window to hook the notification message as well, not TRUE.
|
||||
//
|
||||
return !m_bNotifyParent;
|
||||
}
|
||||
|
||||
BOOL CFilteredComboBox::OnSelEndOK()
|
||||
{
|
||||
//
|
||||
// Despite MSDN's lies, returning FALSE here allows the parent
|
||||
// window to hook the notification message as well, not TRUE.
|
||||
//
|
||||
return !m_bNotifyParent;
|
||||
}
|
||||
|
||||
BOOL CFilteredComboBox::OnEditChange()
|
||||
{
|
||||
CFunctionMarker marker( "OnEditChange" );
|
||||
|
||||
// Remember the text in the edit control because we're going to slam the
|
||||
// contents of the list and we'll want to put the text back in.
|
||||
CString szTypedText;
|
||||
DWORD dwEditSel;
|
||||
GetWindowText( szTypedText );
|
||||
dwEditSel = GetEditSel();
|
||||
|
||||
// Show all the matching autosuggestions.
|
||||
CUtlVector<CString> items;
|
||||
GetItemsMatchingString( szTypedText, items );
|
||||
|
||||
SetRedraw( FALSE );
|
||||
ResetContent();
|
||||
|
||||
for ( int i=0; i < items.Count(); i++ )
|
||||
{
|
||||
AddString( items[i] );
|
||||
}
|
||||
|
||||
// Add the typed text to the combobox here otherwise it'll select the nearest match when they drop it down with the mouse.
|
||||
if ( !m_bOnlyProvideSuggestions && FindSuggestion( szTypedText ) == -1 )
|
||||
AddString( szTypedText );
|
||||
|
||||
// Note: for arcane and unspeakable MFC reasons, the placement of this call is VERY sensitive.
|
||||
// For example, if CTargetNameComboBox changes from a bold font to a normal font, then if this
|
||||
// call comes before ResetContent(), it will resize the dropdown listbox to a small size and not
|
||||
// size it back until it is cloesd and opened again.
|
||||
ShowDropDown();
|
||||
|
||||
SetRedraw( TRUE );
|
||||
Invalidate();
|
||||
|
||||
// Possibly tell the app about this change.
|
||||
if ( m_bOnlyProvideSuggestions )
|
||||
{
|
||||
if ( FindSuggestion( szTypedText ) != -1 )
|
||||
DoTextChangedCallback( szTypedText );
|
||||
}
|
||||
else
|
||||
{
|
||||
DoTextChangedCallback( szTypedText );
|
||||
}
|
||||
|
||||
// Put the text BACK in there.
|
||||
SetWindowText( szTypedText );
|
||||
SetEditSel( LOWORD( dwEditSel ), HIWORD( dwEditSel ) );
|
||||
|
||||
//
|
||||
// Despite MSDN's lies, returning FALSE here allows the parent
|
||||
// window to hook the notification message as well, not TRUE.
|
||||
//
|
||||
return !m_bNotifyParent;
|
||||
}
|
||||
|
||||
int CFilteredComboBox::FindSuggestion( const char *pTest ) const
|
||||
{
|
||||
for ( int i=0; i < m_Suggestions.Count(); i++ )
|
||||
{
|
||||
if ( Q_stricmp( m_Suggestions[i], pTest ) == 0 )
|
||||
return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
CString CFilteredComboBox::GetBestSuggestion( const char *pTest )
|
||||
{
|
||||
// If it's an exact match, use that.
|
||||
if ( FindSuggestion( pTest ) != -1 )
|
||||
return pTest;
|
||||
|
||||
// Look for the first autocomplete suggestion.
|
||||
CUtlVector<CString> matches;
|
||||
GetItemsMatchingString( pTest, matches );
|
||||
if ( matches.Count() > 0 )
|
||||
return matches[0];
|
||||
|
||||
// Ok, fall back to the last known good one.
|
||||
return m_LastTextChangedValue;
|
||||
}
|
||||
|
||||
|
||||
CFont& CFilteredComboBox::GetNormalFont()
|
||||
{
|
||||
CreateFonts();
|
||||
return m_NormalFont;
|
||||
}
|
||||
|
||||
|
||||
void CFilteredComboBox::GetItemsMatchingString( const char *pStringToMatch, CUtlVector<CString> &matchingItems )
|
||||
{
|
||||
for ( int i=0; i < m_Suggestions.Count(); i++ )
|
||||
{
|
||||
if ( MatchString( pStringToMatch, m_Suggestions[i] ) )
|
||||
matchingItems.AddToTail( m_Suggestions[i] );
|
||||
}
|
||||
|
||||
s_pStringToMatch = pStringToMatch;
|
||||
s_iStringToMatchLen = V_strlen( pStringToMatch );
|
||||
matchingItems.Sort( &CFilteredComboBox::SortFn );
|
||||
s_pStringToMatch = NULL;
|
||||
}
|
||||
|
||||
|
||||
int CFilteredComboBox::SortFn( const CString *pItem1, const CString *pItem2 )
|
||||
{
|
||||
// If one of them matches the prefix we're looking at, then that one should be listed first.
|
||||
// Otherwise, just do an alphabetical sort.
|
||||
bool bPrefixMatch1=false, bPrefixMatch2=false;
|
||||
if ( s_pStringToMatch )
|
||||
{
|
||||
bPrefixMatch1 = ( V_strnistr( *pItem1, s_pStringToMatch, s_iStringToMatchLen ) != NULL );
|
||||
bPrefixMatch2 = ( V_strnistr( *pItem2, s_pStringToMatch, s_iStringToMatchLen ) != NULL );
|
||||
}
|
||||
|
||||
if ( bPrefixMatch1 == bPrefixMatch2 )
|
||||
{
|
||||
return Q_stricmp( *pItem1, *pItem2 );
|
||||
}
|
||||
else
|
||||
{
|
||||
return bPrefixMatch1 ? -1 : 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool CFilteredComboBox::MatchString( const char *pStringToMatchStart, const char *pTestStringStart )
|
||||
{
|
||||
if ( !pStringToMatchStart || pStringToMatchStart[0] == 0 )
|
||||
return true;
|
||||
|
||||
while ( *pTestStringStart )
|
||||
{
|
||||
const char *pStringToMatch = pStringToMatchStart;
|
||||
const char *pTestString = pTestStringStart;
|
||||
|
||||
while ( 1 )
|
||||
{
|
||||
// Skip underscores in both strings.
|
||||
while ( *pStringToMatch == '_' )
|
||||
++pStringToMatch;
|
||||
|
||||
while ( *pTestString == '_' )
|
||||
++pTestString;
|
||||
|
||||
// If we're at the end of pStringToMatch with no mismatch, then treat this as a prefix match.
|
||||
// If we're at the end of pTestString, but pStringToMatch has more to go, then it's not a match.
|
||||
if ( *pStringToMatch == 0 )
|
||||
return true;
|
||||
else if ( *pTestString == 0 )
|
||||
break;
|
||||
|
||||
// Match this character.
|
||||
if ( toupper( *pStringToMatch ) != toupper( *pTestString ) )
|
||||
break;
|
||||
|
||||
++pStringToMatch;
|
||||
++pTestString;
|
||||
}
|
||||
|
||||
++pTestStringStart;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Called before painting to override default colors.
|
||||
// Input : pDC - DEvice context being painted into.
|
||||
// pWnd - Control asking for color.
|
||||
// nCtlColor - Type of control asking for color.
|
||||
// Output : Returns the handle of a brush to use as the background color.
|
||||
//-----------------------------------------------------------------------------
|
||||
HBRUSH CFilteredComboBox::OnCtlColor(CDC *pDC, CWnd *pWnd, UINT nCtlColor)
|
||||
{
|
||||
HBRUSH hBrush = CComboBox::OnCtlColor(pDC, pWnd, nCtlColor);
|
||||
|
||||
if (nCtlColor == CTLCOLOR_EDIT)
|
||||
{
|
||||
pDC->SetTextColor(m_dwTextColor);
|
||||
}
|
||||
|
||||
return(hBrush);
|
||||
}
|
||||
|
||||
|
||||
void CFilteredComboBox::DoTextChangedCallback( const char *pText )
|
||||
{
|
||||
// Sometimes it'll call here from a few places in a row. Only pass the result
|
||||
// to the owner once.
|
||||
if ( Q_stricmp( pText, m_LastTextChangedValue ) == 0 )
|
||||
return;
|
||||
|
||||
m_LastTextChangedValue = pText;
|
||||
m_pCallbacks->OnTextChanged( pText );
|
||||
}
|
||||
|
||||
|
||||
void CFilteredComboBox::CreateFonts()
|
||||
{
|
||||
//
|
||||
// Create a normal and bold font.
|
||||
//
|
||||
if (!m_NormalFont.m_hObject)
|
||||
{
|
||||
CFont *pFont = GetFont();
|
||||
if (pFont)
|
||||
{
|
||||
LOGFONT LogFont;
|
||||
pFont->GetLogFont(&LogFont);
|
||||
m_NormalFont.CreateFontIndirect(&LogFont);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void CFilteredComboBox::MeasureItem(LPMEASUREITEMSTRUCT pStruct)
|
||||
{
|
||||
HFONT hFont;
|
||||
CFont *pFont = GetFont();
|
||||
if ( pFont )
|
||||
hFont = *pFont;
|
||||
else
|
||||
hFont = (HFONT)GetStockObject( DEFAULT_GUI_FONT );
|
||||
|
||||
CFont *pActualFont = CFont::FromHandle( hFont );
|
||||
if ( pActualFont )
|
||||
{
|
||||
LOGFONT logFont;
|
||||
pActualFont->GetLogFont( &logFont );
|
||||
pStruct->itemHeight = abs( logFont.lfHeight ) + 5;
|
||||
}
|
||||
else
|
||||
{
|
||||
pStruct->itemHeight = 16;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void CFilteredComboBox::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
|
||||
{
|
||||
if ( GetCount() == 0 )
|
||||
return;
|
||||
|
||||
CString str;
|
||||
GetLBText( lpDrawItemStruct->itemID, str );
|
||||
|
||||
CDC dc;
|
||||
dc.Attach( lpDrawItemStruct->hDC );
|
||||
|
||||
// Save these values to restore them when done drawing.
|
||||
COLORREF crOldTextColor = dc.GetTextColor();
|
||||
COLORREF crOldBkColor = dc.GetBkColor();
|
||||
|
||||
// If this item is selected, set the background color
|
||||
// and the text color to appropriate values. Erase
|
||||
// the rect by filling it with the background color.
|
||||
if ( (lpDrawItemStruct->itemAction | ODA_SELECT) && (lpDrawItemStruct->itemState & ODS_SELECTED) )
|
||||
{
|
||||
dc.SetTextColor( ::GetSysColor(COLOR_HIGHLIGHTTEXT) );
|
||||
dc.SetBkColor( ::GetSysColor(COLOR_HIGHLIGHT) );
|
||||
dc.FillSolidRect( &lpDrawItemStruct->rcItem, ::GetSysColor(COLOR_HIGHLIGHT) );
|
||||
}
|
||||
else
|
||||
{
|
||||
dc.FillSolidRect(&lpDrawItemStruct->rcItem, crOldBkColor);
|
||||
}
|
||||
|
||||
CFont *pOldFont = dc.SelectObject( &m_NormalFont );
|
||||
|
||||
// Draw the text.
|
||||
RECT rcDraw = lpDrawItemStruct->rcItem;
|
||||
rcDraw.left += 1;
|
||||
dc.DrawText( str, -1, &rcDraw, DT_LEFT|DT_SINGLELINE|DT_VCENTER );
|
||||
|
||||
// Restore stuff.
|
||||
dc.SelectObject( pOldFont );
|
||||
dc.SetTextColor(crOldTextColor);
|
||||
dc.SetBkColor(crOldBkColor);
|
||||
|
||||
dc.Detach();
|
||||
}
|
||||
|
||||
|
||||
bool CFilteredComboBox::InternalSelectItemByName( const char *pName )
|
||||
{
|
||||
int i = FindStringExact( -1, pName );
|
||||
if ( i == CB_ERR )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
SetCurSel( i );
|
||||
|
||||
CString str;
|
||||
GetWindowText( str );
|
||||
if ( Q_stricmp( str, pName ) != 0 )
|
||||
SetWindowText( pName );
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
206
hammer/FilteredComboBox.h
Normal file
206
hammer/FilteredComboBox.h
Normal file
@@ -0,0 +1,206 @@
|
||||
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef FILTERED_COMBO_BOX_H
|
||||
#define FILTERED_COMBO_BOX_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
|
||||
#include "utlvector.h"
|
||||
|
||||
|
||||
#pragma warning( disable: 4355 )
|
||||
|
||||
// Flags for the SetSuggestions call.
|
||||
#define SETSUGGESTIONS_SELECTFIRST 0x0001 // Select the first item in the list.
|
||||
#define SETSUGGESTIONS_CALLBACK 0x0002 // Calls OnTextChanged for whatever it winds up selecting.
|
||||
|
||||
// CFilteredComboBox is a glorified EDIT control.
|
||||
// The user can type stuff into the edit control, and it will provide autocomplete suggestions
|
||||
// in its combo box. The user of this class provides those suggestions.
|
||||
//
|
||||
// To use this class:
|
||||
//
|
||||
// 1. Implement CFilteredComboBox::ICallbacks
|
||||
// 2. Call SetSuggestions to set the list of autocomplete suggestions.
|
||||
// 3. Call SetOnlyProvideSuggestions to tell it how to behave.
|
||||
//
|
||||
// NOTE: Use CComboBox functions with caution! You could screw up the CFilteredComboBox's operation.
|
||||
class CFilteredComboBox : public CComboBox
|
||||
{
|
||||
typedef CComboBox BaseClass;
|
||||
|
||||
public:
|
||||
|
||||
// Implement this to get updates about the state.
|
||||
class ICallbacks
|
||||
{
|
||||
public:
|
||||
// Called when the text in the box changes.
|
||||
virtual void OnTextChanged( const char *pText ) = 0;
|
||||
|
||||
// This is sort of a backdoor for "only provide suggestions" mode. Normally, it'll only call
|
||||
// OnTextChanged with entries that are in the suggestions list. But, it will call OnUnknownEntry
|
||||
// if they type in something that's not in your suggestion list first. If you return TRUE, it
|
||||
// will add that entry to the suggestions list. If you return FALSE (the default behavior),
|
||||
// it will find the closest match to what the user typed and use that.
|
||||
virtual bool OnUnknownEntry( const char *pText ) { return false; }
|
||||
};
|
||||
|
||||
|
||||
CFilteredComboBox( CFilteredComboBox::ICallbacks *pCallbacks );
|
||||
|
||||
|
||||
// The main functions to operate the filtered combo box are here.
|
||||
|
||||
// This is the list of strings that is filtered into the dropdown combo box.
|
||||
// flags is a combination of the SETSUGGESTIONS_ flags.
|
||||
void SetSuggestions( CUtlVector<CString> &suggestions, int flags=SETSUGGESTIONS_SELECTFIRST|SETSUGGESTIONS_CALLBACK );
|
||||
|
||||
// Add a single suggestion (if it's unique).
|
||||
void AddSuggestion( const CString &suggestion );
|
||||
|
||||
// This clears all items from the combo and its textbox.
|
||||
void Clear();
|
||||
|
||||
// This will force the edit control text. It won't call OnTextChanged.
|
||||
void ForceEditControlText( const char *pStr );
|
||||
|
||||
// This sets the main mode that the box runs in.
|
||||
//
|
||||
// If you pass true, then it will only ever call ICallbacks::OnTextChanged with values that are in your suggestions,
|
||||
// and it does its best to autocomplete to those suggestions (so if the user types a partial string and closes
|
||||
// the box, it will find the first possible substring match OR it will revert to the last valid suggestion it was on).
|
||||
//
|
||||
// If you pass false, then it will call OnTextChanged for anything that gets entered into the textbox. This is used
|
||||
// for the entity properties targetname box, and the entity name changes right along as you type.
|
||||
// When the user presses enter, it does NOT automatically select the first suggestion. They have to use the arrow keys for that.
|
||||
void SetOnlyProvideSuggestions( bool bOnlyProvideSuggestions );
|
||||
|
||||
|
||||
// These provide access to special behavior like font and color.
|
||||
|
||||
// Puts this string in the edit control and selects it in the combo box.
|
||||
void SelectItem( const char *pStr );
|
||||
|
||||
// Returns the same value as the last call to OnTextChanged().
|
||||
CString GetCurrentItem();
|
||||
|
||||
// Get/set the font in the edit control.
|
||||
void SetEditControlFont( HFONT hFont );
|
||||
HFONT GetEditControlFont() const;
|
||||
|
||||
// Get/set the color that the edit text is drawn in.
|
||||
void SetEditControlTextColor( COLORREF clr );
|
||||
COLORREF GetEditControlTextColor() const;
|
||||
|
||||
|
||||
// General windows functions.
|
||||
|
||||
// Enable/disable the window.
|
||||
bool IsWindowEnabled() const;
|
||||
void EnableWindow( bool bEnable );
|
||||
|
||||
|
||||
// Helper functions.
|
||||
public:
|
||||
|
||||
// This takes the string the user has entered (pStringToMatch passed into GetItemsMatchingString)
|
||||
// and returns true if pTestString matches it. It ignores underscores in both strings.
|
||||
bool MatchString( const char *pStringToMatch, const char *pTestString );
|
||||
|
||||
// Does this string match one of the suggestions?
|
||||
// Returns the suggestion index or -1.
|
||||
int FindSuggestion( const char *pTest ) const;
|
||||
|
||||
// Returns the closest-matching suggestion (the first one that would appear
|
||||
// in the autocomplete list) or the last known good suggestion.
|
||||
CString GetBestSuggestion( const char *pTest );
|
||||
|
||||
void SubclassDlgItem(UINT nID, CWnd *pParent);
|
||||
|
||||
|
||||
protected:
|
||||
|
||||
// Get the base font it's using.
|
||||
CFont& GetNormalFont();
|
||||
|
||||
// Get/set the text in the edit control.
|
||||
void SetEditControlText( const char *pText );
|
||||
CString GetEditControlText() const;
|
||||
|
||||
DECLARE_MESSAGE_MAP()
|
||||
|
||||
bool m_bNotifyParent; // Whether we allow our parent to hook our notification messages.
|
||||
// This is necessary because CControlBar-derived classes result in multiple
|
||||
// message reflections unless we disable parent notification.
|
||||
|
||||
protected:
|
||||
|
||||
// Put all suggestions into the dropdown list.
|
||||
void FillDropdownList( const char *pInitialSel, bool bEnableRedraw=true );
|
||||
|
||||
// CBN_ notification handlers.
|
||||
virtual BOOL PreCreateWindow( CREATESTRUCT& cs );
|
||||
BOOL OnDropDown();
|
||||
BOOL OnSelEndOK();
|
||||
BOOL OnCloseUp();
|
||||
BOOL OnSelChange();
|
||||
virtual BOOL OnEditChange();
|
||||
afx_msg HBRUSH OnCtlColor(CDC *pDC, CWnd *pWnd, UINT nCtlColor);
|
||||
|
||||
void OnEnterKeyPressed( const char *pForceText );
|
||||
void OnEscapeKeyPressed();
|
||||
|
||||
void DoTextChangedCallback( const char *pText );
|
||||
|
||||
// Gets the items matching the string and sorts the list alphabetically.
|
||||
virtual void GetItemsMatchingString( const char *pStringToMatch, CUtlVector<CString> &matchingItems );
|
||||
static int SortFn( const CString *pItem1, const CString *pItem2 );
|
||||
|
||||
virtual LRESULT DefWindowProc(
|
||||
UINT message,
|
||||
WPARAM wParam,
|
||||
LPARAM lParam );
|
||||
|
||||
// Overrides for owner draw.
|
||||
virtual void MeasureItem(LPMEASUREITEMSTRUCT pStruct);
|
||||
virtual void DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct);
|
||||
|
||||
private:
|
||||
|
||||
void InternalSetEditControlFont( HFONT hFont, const char *pEditText, DWORD sel );
|
||||
void CreateFonts();
|
||||
bool InternalSelectItemByName( const char *pName );
|
||||
|
||||
|
||||
private:
|
||||
|
||||
CUtlVector<CString> m_Suggestions;
|
||||
HFONT m_hEditControlFont;
|
||||
|
||||
CFont m_NormalFont;
|
||||
|
||||
CFilteredComboBox::ICallbacks *m_pCallbacks;
|
||||
bool m_bWasEditing;
|
||||
DWORD m_dwTextColor;
|
||||
|
||||
bool m_bOnlyProvideSuggestions;
|
||||
bool m_bInEnterKeyPressedHandler;
|
||||
|
||||
HFONT m_hQueuedFont;
|
||||
bool m_bInSelChange;
|
||||
|
||||
// We go back here if they type text that we can't give a suggestion on and press enter (or lose focus).
|
||||
CString m_LastTextChangedValue;
|
||||
};
|
||||
|
||||
|
||||
#endif // FILTERED_COMBO_BOX_H
|
||||
|
||||
|
||||
141
hammer/HammerScene.cpp
Normal file
141
hammer/HammerScene.cpp
Normal file
@@ -0,0 +1,141 @@
|
||||
//====== Copyright © 1996-2005, Valve Corporation, All rights reserved. =======
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "scriplib.h"
|
||||
#include "choreoscene.h"
|
||||
#include "iscenetokenprocessor.h"
|
||||
#include "filesystem_tools.h"
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Helper to scene module for parsing the .vcd file
|
||||
//-----------------------------------------------------------------------------
|
||||
class CSceneTokenProcessor : public ISceneTokenProcessor
|
||||
{
|
||||
public:
|
||||
const char *CurrentToken( void );
|
||||
bool GetToken( bool crossline );
|
||||
bool TokenAvailable( void );
|
||||
void Error( const char *fmt, ... );
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Output : const
|
||||
//-----------------------------------------------------------------------------
|
||||
const char *CSceneTokenProcessor::CurrentToken( void )
|
||||
{
|
||||
return token;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : crossline -
|
||||
// Output : Returns true on success, false on failure.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CSceneTokenProcessor::GetToken( bool crossline )
|
||||
{
|
||||
return ::GetToken( crossline ) ? true : false;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Output : Returns true on success, false on failure.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CSceneTokenProcessor::TokenAvailable( void )
|
||||
{
|
||||
return ::TokenAvailable() ? true : false;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : *fmt -
|
||||
// ... -
|
||||
//-----------------------------------------------------------------------------
|
||||
void CSceneTokenProcessor::Error( const char *fmt, ... )
|
||||
{
|
||||
char string[ 2048 ];
|
||||
va_list argptr;
|
||||
va_start( argptr, fmt );
|
||||
vsprintf( string, fmt, argptr );
|
||||
va_end( argptr );
|
||||
|
||||
Warning( "%s", string );
|
||||
}
|
||||
|
||||
static CSceneTokenProcessor g_TokenProcessor;
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Normally implemented in cmdlib.cpp but we don't want that in Hammer.
|
||||
//-----------------------------------------------------------------------------
|
||||
char *ExpandPath (char *path)
|
||||
{
|
||||
static char fullpath[ 512 ];
|
||||
g_pFullFileSystem->RelativePathToFullPath( path, "GAME", fullpath, sizeof( fullpath ) );
|
||||
return fullpath;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Normally implemented in cmdlib.cpp but we don't want that in Hammer.
|
||||
//-----------------------------------------------------------------------------
|
||||
int LoadFile( const char *filename, void **bufferptr )
|
||||
{
|
||||
FileHandle_t f = g_pFullFileSystem->Open( filename, "rb" );
|
||||
if ( FILESYSTEM_INVALID_HANDLE != f )
|
||||
{
|
||||
int length = g_pFullFileSystem->Size( f );
|
||||
void *buffer = malloc (length+1);
|
||||
((char *)buffer)[length] = 0;
|
||||
g_pFullFileSystem->Read( buffer, length, f );
|
||||
g_pFullFileSystem->Close (f);
|
||||
*bufferptr = buffer;
|
||||
return length;
|
||||
}
|
||||
else
|
||||
{
|
||||
*bufferptr = NULL;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
CChoreoScene* HammerLoadScene( const char *pFilename )
|
||||
{
|
||||
if ( g_pFullFileSystem->FileExists( pFilename ) )
|
||||
{
|
||||
LoadScriptFile( (char*)pFilename );
|
||||
CChoreoScene *scene = ChoreoLoadScene( pFilename, NULL, &g_TokenProcessor, Msg );
|
||||
return scene;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
bool GetFirstSoundInScene( const char *pSceneFilename, char *pSoundName, int soundNameLen )
|
||||
{
|
||||
CChoreoScene *pScene = HammerLoadScene( pSceneFilename );
|
||||
if ( !pScene )
|
||||
return false;
|
||||
|
||||
for ( int i = 0; i < pScene->GetNumEvents(); i++ )
|
||||
{
|
||||
CChoreoEvent *e = pScene->GetEvent( i );
|
||||
if ( !e || e->GetType() != CChoreoEvent::SPEAK )
|
||||
continue;
|
||||
|
||||
const char *pParameters = e->GetParameters();
|
||||
V_strncpy( pSoundName, pParameters, soundNameLen );
|
||||
delete pScene;
|
||||
return true;
|
||||
}
|
||||
|
||||
delete pScene;
|
||||
return false;
|
||||
}
|
||||
24
hammer/HammerScene.h
Normal file
24
hammer/HammerScene.h
Normal file
@@ -0,0 +1,24 @@
|
||||
//====== Copyright © 1996-2005, Valve Corporation, All rights reserved. =======
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
#ifndef HAMMERSCENE_H
|
||||
#define HAMMERSCENE_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
|
||||
class CChoreoScene;
|
||||
|
||||
|
||||
// Load the specified vcd file.
|
||||
CChoreoScene* HammerLoadScene( const char *pFilename );
|
||||
|
||||
// Load the VCD file and get the first sound in it.
|
||||
bool GetFirstSoundInScene( const char *pSceneFilename, char *pSoundName, int soundNameLen );
|
||||
|
||||
|
||||
#endif // HAMMERSCENE_H
|
||||
205
hammer/HammerVGui.cpp
Normal file
205
hammer/HammerVGui.cpp
Normal file
@@ -0,0 +1,205 @@
|
||||
#include "stdafx.h"
|
||||
#include "hammer.h"
|
||||
#include "hammervgui.h"
|
||||
#include <vgui/IVGui.h>
|
||||
#include <vgui/ISurface.h>
|
||||
#include <vgui/ISystem.h>
|
||||
#include "vgui/IInput.h"
|
||||
#include "vgui_controls/EditablePanel.h"
|
||||
#include <VGuiMatSurface/IMatSystemSurface.h>
|
||||
#include <matsys_controls/matsyscontrols.h>
|
||||
#include "material.h"
|
||||
#include "vgui_controls/AnimationController.h"
|
||||
#include "inputsystem/iinputsystem.h"
|
||||
#include "VGuiWnd.h"
|
||||
#include "toolutils/enginetools_int.h"
|
||||
#include "toolframework/ienginetool.h"
|
||||
#include "inputsystem/iinputstacksystem.h"
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: singleton accessor
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
// This window doesn't do anything other than tell CMatSystemSurface::CalculateMouseVisible to deem the mouse visible.
|
||||
class CDummyPopupPanel : public vgui::Panel
|
||||
{
|
||||
public:
|
||||
virtual void PaintBackground() {}
|
||||
virtual void Paint() {}
|
||||
};
|
||||
|
||||
static CHammerVGui s_HammerVGui;
|
||||
|
||||
CHammerVGui *HammerVGui()
|
||||
{
|
||||
return &s_HammerVGui;
|
||||
}
|
||||
|
||||
CHammerVGui::CHammerVGui(void)
|
||||
{
|
||||
m_pActiveWindow = NULL;
|
||||
m_hMainWindow = NULL;
|
||||
m_pDummyPopup = NULL;
|
||||
m_bCurrentDialogIsModal = false;
|
||||
m_hHammerScheme = NULL;
|
||||
m_hVguiInputContext = INPUT_CONTEXT_HANDLE_INVALID;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Setup the base vgui panels
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CHammerVGui::Init( HWND hWindow )
|
||||
{
|
||||
m_hMainWindow = hWindow;
|
||||
if ( !APP()->IsFoundryMode() ) // We don't need to init most stuff in Foundry mode because the engine has already done it.
|
||||
{
|
||||
// initialize vgui_control interfaces
|
||||
if (!vgui::VGui_InitInterfacesList( "HAMMER", &g_Factory, 1 ))
|
||||
return false;
|
||||
|
||||
if ( !vgui::VGui_InitMatSysInterfacesList( "HAMMER", &g_Factory, 1 ) )
|
||||
return false;
|
||||
|
||||
if ( !g_pMatSystemSurface )
|
||||
return false;
|
||||
|
||||
// configuration settings
|
||||
vgui::system()->SetUserConfigFile("hammer.vdf", "EXECUTABLE_PATH");
|
||||
|
||||
// Are we trapping input?
|
||||
g_pMatSystemSurface->EnableWindowsMessages( true );
|
||||
}
|
||||
|
||||
m_hVguiInputContext = g_pInputStackSystem->PushInputContext();
|
||||
g_pMatSystemSurface->SetInputContext( m_hVguiInputContext );
|
||||
|
||||
// Need to be able to play sounds through vgui
|
||||
// g_pMatSystemSurface->InstallPlaySoundFunc( VGui_PlaySound );
|
||||
|
||||
// load scheme
|
||||
m_hHammerScheme = vgui::scheme()->LoadSchemeFromFile("//PLATFORM/Resource/SourceScheme.res", "Hammer");
|
||||
if ( !m_hHammerScheme )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( !APP()->IsFoundryMode() ) // We don't need to init most stuff in Foundry mode because the engine has already done it.
|
||||
{
|
||||
// Start the App running
|
||||
vgui::ivgui()->Start();
|
||||
vgui::ivgui()->SetSleep(false);
|
||||
|
||||
// Create a popup window. This window doesn't do anything other than tell CMatSystemSurface::CalculateMouseVisible to deem the mouse visible.
|
||||
m_pDummyPopup = new CDummyPopupPanel;
|
||||
m_pDummyPopup->MakePopup( false, true );
|
||||
m_pDummyPopup->SetVisible( true );
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CHammerVGui::SetFocus( CVGuiWnd *pVGuiWnd )
|
||||
{
|
||||
if ( pVGuiWnd == m_pActiveWindow )
|
||||
return;
|
||||
|
||||
g_pInputSystem->PollInputState();
|
||||
vgui::ivgui()->RunFrame();
|
||||
|
||||
g_pMatSystemSurface->SetAppDrivesInput( true );
|
||||
g_pInputSystem->DetachFromWindow( );
|
||||
|
||||
// Disable mouse input on the previous panel so it doesn't get input the engine should get.
|
||||
if ( m_pActiveWindow && m_pActiveWindow->GetMainPanel() )
|
||||
{
|
||||
m_pActiveWindow->GetMainPanel()->SetMouseInputEnabled( false );
|
||||
}
|
||||
|
||||
if ( pVGuiWnd )
|
||||
{
|
||||
m_pActiveWindow = pVGuiWnd;
|
||||
m_bCurrentDialogIsModal = m_pActiveWindow->IsModal();
|
||||
|
||||
Assert( pVGuiWnd->GetMainPanel() != NULL );
|
||||
if ( pVGuiWnd->GetMainPanel() )
|
||||
pVGuiWnd->GetMainPanel()->SetMouseInputEnabled( true );
|
||||
|
||||
g_pInputSystem->AttachToWindow( pVGuiWnd->GetParentWnd()->GetSafeHwnd() );
|
||||
g_pMatSystemSurface->SetAppDrivesInput( !m_bCurrentDialogIsModal );
|
||||
vgui::ivgui()->ActivateContext( pVGuiWnd->GetVGuiContext() );
|
||||
|
||||
// If this is a modal VGuiWnd (like the model browser), don't let the engine's message loop get called at all
|
||||
// or else it'll screw up stuff - it'll give focus to other CVGuiWnds and the engine might drive
|
||||
// some vgui stuff instead of the VGuiWnd message loop (in CVGuiWnd::WindowProcVGui).
|
||||
if ( pVGuiWnd->IsModal() && enginetools )
|
||||
::EnableWindow( (HWND)enginetools->GetEngineHwnd(), false );
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( enginetools )
|
||||
{
|
||||
// We can't call m_pActiveWindow->IsModal here because it might be in its destructor (as with the model browser)
|
||||
// and it's a virtual function.
|
||||
if ( m_bCurrentDialogIsModal )
|
||||
::EnableWindow( (HWND)enginetools->GetEngineHwnd(), true );
|
||||
|
||||
g_pInputSystem->AttachToWindow( enginetools->GetEngineHwnd() );
|
||||
g_pMatSystemSurface->SetAppDrivesInput( true );
|
||||
}
|
||||
|
||||
m_pActiveWindow = NULL;
|
||||
vgui::ivgui()->ActivateContext( vgui::DEFAULT_VGUI_CONTEXT );
|
||||
}
|
||||
}
|
||||
|
||||
bool CHammerVGui::HasFocus( CVGuiWnd *pWnd )
|
||||
{
|
||||
return m_pActiveWindow == pWnd;
|
||||
}
|
||||
|
||||
void CHammerVGui::Simulate()
|
||||
{
|
||||
// VPROF( "CHammerVGui::Simulate" );
|
||||
|
||||
if ( !IsInitialized() )
|
||||
return;
|
||||
|
||||
g_pInputSystem->PollInputState();
|
||||
vgui::ivgui()->RunFrame();
|
||||
|
||||
// run vgui animations
|
||||
vgui::GetAnimationController()->UpdateAnimations( vgui::system()->GetCurrentTime() );
|
||||
}
|
||||
|
||||
void CHammerVGui::Shutdown()
|
||||
{
|
||||
// Give panels a chance to settle so things
|
||||
// Marked for deletion will actually get deleted
|
||||
|
||||
if ( !IsInitialized() )
|
||||
return;
|
||||
|
||||
if ( m_pDummyPopup )
|
||||
{
|
||||
delete m_pDummyPopup;
|
||||
m_pDummyPopup = NULL;
|
||||
}
|
||||
|
||||
if ( m_hVguiInputContext != INPUT_CONTEXT_HANDLE_INVALID )
|
||||
{
|
||||
g_pMatSystemSurface->SetInputContext( NULL );
|
||||
g_pInputStackSystem->PopInputContext();
|
||||
m_hVguiInputContext = INPUT_CONTEXT_HANDLE_INVALID;
|
||||
}
|
||||
|
||||
g_pInputSystem->PollInputState();
|
||||
vgui::ivgui()->RunFrame();
|
||||
|
||||
// stop the App running
|
||||
vgui::ivgui()->Stop();
|
||||
}
|
||||
|
||||
CHammerVGui::~CHammerVGui(void)
|
||||
{
|
||||
}
|
||||
56
hammer/HammerVGui.h
Normal file
56
hammer/HammerVGui.h
Normal file
@@ -0,0 +1,56 @@
|
||||
//===== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======//
|
||||
//
|
||||
// Purpose: Implements all the functions exported by the GameUI dll
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//===========================================================================//
|
||||
|
||||
#ifdef COMPILER_MSVC
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include "vgui/vgui.h"
|
||||
#include "tier3/tier3.h"
|
||||
|
||||
namespace vgui
|
||||
{
|
||||
class Panel;
|
||||
}
|
||||
|
||||
class IMatSystemSurface;
|
||||
class CVGuiWnd;
|
||||
FORWARD_DECLARE_HANDLE( InputContextHandle_t );
|
||||
|
||||
|
||||
class CHammerVGui
|
||||
{
|
||||
public:
|
||||
CHammerVGui(void);
|
||||
~CHammerVGui(void);
|
||||
|
||||
bool Init( HWND hWindow );
|
||||
void Simulate();
|
||||
void Shutdown();
|
||||
|
||||
bool HasFocus( CVGuiWnd *pWnd );
|
||||
void SetFocus( CVGuiWnd *pWnd );
|
||||
|
||||
bool IsInitialized() { return m_hMainWindow != NULL; };
|
||||
|
||||
vgui::HScheme GetHammerScheme() { return m_hHammerScheme; }
|
||||
|
||||
|
||||
protected:
|
||||
|
||||
CVGuiWnd *m_pActiveWindow; // the VGUI window that has the focus
|
||||
bool m_bCurrentDialogIsModal; // m_pActiveWindow->IsModal()
|
||||
|
||||
HWND m_hMainWindow;
|
||||
vgui::Panel *m_pDummyPopup;
|
||||
|
||||
vgui::HScheme m_hHammerScheme;
|
||||
|
||||
InputContextHandle_t m_hVguiInputContext;
|
||||
};
|
||||
|
||||
CHammerVGui *HammerVGui();
|
||||
451
hammer/MapAxisHandle.cpp
Normal file
451
hammer/MapAxisHandle.cpp
Normal file
@@ -0,0 +1,451 @@
|
||||
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: A helper that represents the axis of rotation for a rotating entity.
|
||||
// When selected, it exposes handles for the endpoints of the axis.
|
||||
//
|
||||
// It writes the axis as a keyvalue of the form:
|
||||
//
|
||||
// "x0 y0 z0, x1 y1 z1"
|
||||
//
|
||||
//=============================================================================//
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "Box3D.h"
|
||||
#include "GlobalFunctions.h"
|
||||
#include "fgdlib/HelperInfo.h"
|
||||
#include "materialsystem/IMaterialSystem.h"
|
||||
#include "materialsystem/IMesh.h"
|
||||
#include "MainFrm.h" // For refreshing the object properties dialog
|
||||
#include "MapDoc.h"
|
||||
#include "MapAxisHandle.h"
|
||||
#include "MapPointHandle.h"
|
||||
#include "MapView2D.h"
|
||||
#include "Material.h"
|
||||
#include "Options.h"
|
||||
#include "Render2D.h"
|
||||
#include "Render3D.h"
|
||||
#include "ToolManager.h"
|
||||
#include "ToolAxisHandle.h"
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include <tier0/memdbgon.h>
|
||||
|
||||
|
||||
IMPLEMENT_MAPCLASS(CMapAxisHandle);
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Factory function. Used for creating a CMapAxisHandle from a set
|
||||
// of string parameters from the FGD file.
|
||||
// Input : pInfo - Pointer to helper info class which gives us information
|
||||
// about how to create the class.
|
||||
// Output : Returns a pointer to the class, NULL if an error occurs.
|
||||
//-----------------------------------------------------------------------------
|
||||
CMapClass *CMapAxisHandle::Create(CHelperInfo *pHelperInfo, CMapEntity *pParent)
|
||||
{
|
||||
static char *pszDefaultKeyName = "axis";
|
||||
|
||||
const char *pszKey = pHelperInfo->GetParameter(0);
|
||||
if (pszKey == NULL)
|
||||
{
|
||||
pszKey = pszDefaultKeyName;
|
||||
}
|
||||
|
||||
CMapAxisHandle *pBox = new CMapAxisHandle(pszKey);
|
||||
pBox->SetRenderColor(255, 255, 255);
|
||||
return(pBox);
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : pfMins -
|
||||
// pfMaxs -
|
||||
//-----------------------------------------------------------------------------
|
||||
CMapAxisHandle::CMapAxisHandle(void)
|
||||
{
|
||||
Initialize();
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : pfMins -
|
||||
// pfMaxs -
|
||||
//-----------------------------------------------------------------------------
|
||||
CMapAxisHandle::CMapAxisHandle(const char *pszKey)
|
||||
{
|
||||
Initialize();
|
||||
strcpy(m_szKeyName, pszKey);
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CMapAxisHandle::Initialize(void)
|
||||
{
|
||||
m_szKeyName[0] = '\0';
|
||||
|
||||
r = 255;
|
||||
g = 255;
|
||||
b = 255;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
CMapAxisHandle::~CMapAxisHandle(void)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : bFullUpdate -
|
||||
//-----------------------------------------------------------------------------
|
||||
void CMapAxisHandle::CalcBounds(BOOL bFullUpdate)
|
||||
{
|
||||
CMapClass::CalcBounds(bFullUpdate);
|
||||
|
||||
//
|
||||
// We don't affect our parent's 2D render bounds.
|
||||
//
|
||||
m_Render2DBox.ResetBounds();
|
||||
|
||||
//
|
||||
// Calculate 3D culling box.
|
||||
//
|
||||
m_CullBox.ResetBounds();
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
m_Point[i].CalcBounds(bFullUpdate);
|
||||
|
||||
Vector vecMins;
|
||||
Vector vecMaxs;
|
||||
m_Point[i].GetCullBox(vecMins, vecMaxs);
|
||||
m_CullBox.UpdateBounds(vecMins, vecMaxs);
|
||||
}
|
||||
m_BoundingBox = m_CullBox;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Output : CMapClass
|
||||
//-----------------------------------------------------------------------------
|
||||
CMapClass *CMapAxisHandle::Copy(bool bUpdateDependencies)
|
||||
{
|
||||
CMapAxisHandle *pCopy = new CMapAxisHandle;
|
||||
|
||||
if (pCopy != NULL)
|
||||
{
|
||||
pCopy->CopyFrom(this, bUpdateDependencies);
|
||||
}
|
||||
|
||||
return(pCopy);
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : pObject -
|
||||
// Output : CMapClass
|
||||
//-----------------------------------------------------------------------------
|
||||
CMapClass *CMapAxisHandle::CopyFrom(CMapClass *pObject, bool bUpdateDependencies)
|
||||
{
|
||||
Assert(pObject->IsMapClass(MAPCLASS_TYPE(CMapAxisHandle)));
|
||||
CMapAxisHandle *pFrom = (CMapAxisHandle *)pObject;
|
||||
|
||||
CMapClass::CopyFrom(pObject, bUpdateDependencies);
|
||||
|
||||
m_Point[0].CopyFrom(&pFrom->m_Point[0], bUpdateDependencies);
|
||||
m_Point[1].CopyFrom(&pFrom->m_Point[1], bUpdateDependencies);
|
||||
|
||||
strcpy(m_szKeyName, pFrom->m_szKeyName);
|
||||
|
||||
return(this);
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Gets the tool object for a given context data from HitTest2D.
|
||||
//-----------------------------------------------------------------------------
|
||||
CBaseTool *CMapAxisHandle::GetToolObject(int nHitData, bool bAttachObject)
|
||||
{
|
||||
// FIXME: ideally, we could use CToolPointHandle here, because all it does is move
|
||||
// points around, but that would require some way for the CMapAxisHandle to know
|
||||
// when the CMapPointHandle's position changes. This way the CToolAxisHandle can
|
||||
// handle the notification. In general, we need a better system for building complex
|
||||
// objects from simple ones and handling changes to the simple objects in the complex one.
|
||||
//
|
||||
// If we DID use a CToolPointHandle, we'd need to reconcile the status bar updates that
|
||||
// are done in OnMouseMove2D, because points and axes cause different status bar text
|
||||
// to be displayed as they are dragged around.
|
||||
CToolAxisHandle *pTool = (CToolAxisHandle *)ToolManager()->GetToolForID(TOOL_AXIS_HANDLE);
|
||||
|
||||
if ( bAttachObject )
|
||||
{
|
||||
pTool->Attach(this, nHitData);
|
||||
}
|
||||
|
||||
return pTool;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : pView -
|
||||
// point -
|
||||
// nData -
|
||||
// Output : Returns true on success, false on failure.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CMapAxisHandle::HitTest2D(CMapView2D *pView, const Vector2D &point, HitInfo_t &HitData)
|
||||
{
|
||||
if ( IsVisible() )
|
||||
{
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
if ( m_Point[i].HitTest2D(pView, point, HitData) )
|
||||
{
|
||||
HitData.pObject = this;
|
||||
HitData.uData = i;
|
||||
HitData.nDepth = 0; // map helpers have no real depth
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : pRender -
|
||||
//-----------------------------------------------------------------------------
|
||||
void CMapAxisHandle::Render2D(CRender2D *pRender)
|
||||
{
|
||||
SelectionState_t eState = GetSelectionState();
|
||||
if (eState == SELECT_NONE)
|
||||
return;
|
||||
|
||||
m_Point[0].Render2D(pRender);
|
||||
m_Point[1].Render2D(pRender);
|
||||
|
||||
if (eState == SELECT_MODIFY)
|
||||
{
|
||||
pRender->PushRenderMode( RENDER_MODE_DOTTED );
|
||||
pRender->SetDrawColor( GetRValue(Options.colors.clrSelection), GetGValue(Options.colors.clrSelection), GetBValue(Options.colors.clrSelection) );
|
||||
}
|
||||
else
|
||||
{
|
||||
pRender->PushRenderMode( RENDER_MODE_FLAT );
|
||||
pRender->SetDrawColor( GetRValue(Options.colors.clrToolHandle), GetGValue(Options.colors.clrToolHandle), GetBValue(Options.colors.clrToolHandle) );
|
||||
}
|
||||
|
||||
Vector vecOrigin1;
|
||||
Vector vecOrigin2;
|
||||
m_Point[0].GetOrigin(vecOrigin1);
|
||||
m_Point[1].GetOrigin(vecOrigin2);
|
||||
|
||||
pRender->DrawLine(vecOrigin1, vecOrigin2);
|
||||
|
||||
pRender->PopRenderMode();
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : pRender -
|
||||
//-----------------------------------------------------------------------------
|
||||
void CMapAxisHandle::Render3D(CRender3D *pRender)
|
||||
{
|
||||
if (GetSelectionState() != SELECT_NONE)
|
||||
{
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
m_Point[i].Render3D(pRender);
|
||||
}
|
||||
|
||||
Vector vec1;
|
||||
Vector vec2;
|
||||
m_Point[0].GetOrigin(vec1);
|
||||
m_Point[1].GetOrigin(vec2);
|
||||
|
||||
pRender->SetDrawColor( 255, 255, 255 );
|
||||
pRender->DrawLine(vec1, vec2);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
int CMapAxisHandle::SerializeRMF(std::fstream &File, BOOL bRMF)
|
||||
{
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
int CMapAxisHandle::SerializeMAP(std::fstream &File, BOOL bRMF)
|
||||
{
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Overridden to chain down to our endpoints, which are not children.
|
||||
//-----------------------------------------------------------------------------
|
||||
void CMapAxisHandle::SetOrigin(Vector &vecOrigin)
|
||||
{
|
||||
BaseClass::SetOrigin(vecOrigin);
|
||||
|
||||
m_Point[0].SetOrigin(vecOrigin);
|
||||
m_Point[1].SetOrigin(vecOrigin);
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Overridden to chain down to our endpoints, which are not children.
|
||||
//-----------------------------------------------------------------------------
|
||||
SelectionState_t CMapAxisHandle::SetSelectionState(SelectionState_t eSelectionState)
|
||||
{
|
||||
SelectionState_t eState = BaseClass::SetSelectionState(eSelectionState);
|
||||
|
||||
m_Point[0].SetSelectionState(eSelectionState);
|
||||
m_Point[1].SetSelectionState(eSelectionState);
|
||||
|
||||
return eState;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Special version of set SelectionState to set the state in only one
|
||||
// endpoint handle for dragging that handle.
|
||||
//-----------------------------------------------------------------------------
|
||||
SelectionState_t CMapAxisHandle::SetSelectionState(SelectionState_t eSelectionState, int nHandle)
|
||||
{
|
||||
SelectionState_t eState = BaseClass::SetSelectionState(eSelectionState);
|
||||
m_Point[nHandle].SetSelectionState(eSelectionState);
|
||||
return eState;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Overridden because origin helpers don't take the color of their
|
||||
// parent entity.
|
||||
// Input : red, green, blue -
|
||||
//-----------------------------------------------------------------------------
|
||||
void CMapAxisHandle::SetRenderColor(unsigned char red, unsigned char green, unsigned char blue)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Overridden because origin helpers don't take the color of their
|
||||
// parent entity.
|
||||
// Input : red, green, blue -
|
||||
//-----------------------------------------------------------------------------
|
||||
void CMapAxisHandle::SetRenderColor(color32 rgbColor)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : szKey -
|
||||
// szValue -
|
||||
//-----------------------------------------------------------------------------
|
||||
void CMapAxisHandle::OnParentKeyChanged(const char *szKey, const char *szValue)
|
||||
{
|
||||
if (!stricmp(szKey, m_szKeyName))
|
||||
{
|
||||
Vector vecOrigin1;
|
||||
Vector vecOrigin2;
|
||||
|
||||
sscanf(szValue, "%f %f %f, %f %f %f", &vecOrigin1.x, &vecOrigin1.y, &vecOrigin1.z, &vecOrigin2.x, &vecOrigin2.y, &vecOrigin2.z);
|
||||
|
||||
m_Point[0].SetOrigin(vecOrigin1);
|
||||
m_Point[1].SetOrigin(vecOrigin2);
|
||||
|
||||
CalcBounds();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Called by the axis tool to update the position of the endpoint.
|
||||
//-----------------------------------------------------------------------------
|
||||
void CMapAxisHandle::UpdateEndPoint(Vector &vecPos, int nPointIndex)
|
||||
{
|
||||
m_Point[nPointIndex].m_Origin = vecPos;
|
||||
CalcBounds();
|
||||
UpdateParentKey();
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Overridden to transform our endpoints.
|
||||
//-----------------------------------------------------------------------------
|
||||
void CMapAxisHandle::DoTransform(const VMatrix &matrix)
|
||||
{
|
||||
BaseClass::DoTransform(matrix);
|
||||
|
||||
m_Point[0].Transform(matrix);
|
||||
m_Point[1].Transform(matrix);
|
||||
|
||||
UpdateParentKey();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CMapAxisHandle::UpdateParentKey(void)
|
||||
{
|
||||
if (m_szKeyName[0])
|
||||
{
|
||||
CMapEntity *pEntity = dynamic_cast <CMapEntity *> (m_pParent);
|
||||
if (pEntity != NULL)
|
||||
{
|
||||
Vector vecOrigin1;
|
||||
Vector vecOrigin2;
|
||||
m_Point[0].GetOrigin(vecOrigin1);
|
||||
m_Point[1].GetOrigin(vecOrigin2);
|
||||
|
||||
CalcBounds();
|
||||
|
||||
char szValue[KEYVALUE_MAX_VALUE_LENGTH];
|
||||
sprintf(szValue, "%g %g %g, %g %g %g", (double)vecOrigin1.x, (double)vecOrigin1.y, (double)vecOrigin1.z, (double)vecOrigin2.x, (double)vecOrigin2.y, (double)vecOrigin2.z);
|
||||
pEntity->NotifyChildKeyChanged(this, m_szKeyName, szValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Sets the keyvalue in our parent when we are added to the world.
|
||||
// Input : pWorld -
|
||||
//-----------------------------------------------------------------------------
|
||||
void CMapAxisHandle::OnAddToWorld(CMapWorld *pWorld)
|
||||
{
|
||||
BaseClass::OnAddToWorld(pWorld);
|
||||
UpdateParentKey();
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Sets the keyvalue in our parent after the map is loaded.
|
||||
// Input : pWorld -
|
||||
//-----------------------------------------------------------------------------
|
||||
void CMapAxisHandle::PostloadWorld(CMapWorld *pWorld)
|
||||
{
|
||||
BaseClass::PostloadWorld(pWorld);
|
||||
UpdateParentKey();
|
||||
}
|
||||
|
||||
129
hammer/MapAxisHandle.h
Normal file
129
hammer/MapAxisHandle.h
Normal file
@@ -0,0 +1,129 @@
|
||||
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef MAPAXISHANDLE_H
|
||||
#define MAPAXISHANDLE_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include "MapClass.h"
|
||||
#include "MapPointHandle.h"
|
||||
#include "ToolInterface.h"
|
||||
#include "MapPointHandle.h"
|
||||
#include "mapview.h"
|
||||
|
||||
|
||||
class CHelperInfo;
|
||||
class CRender2D;
|
||||
class CRender3D;
|
||||
class CToolAxisHandle;
|
||||
|
||||
|
||||
#define MAX_KEYNAME_SIZE 32
|
||||
|
||||
|
||||
class CMapAxisHandle : public CMapHelper
|
||||
{
|
||||
friend CToolAxisHandle;
|
||||
|
||||
public:
|
||||
|
||||
DECLARE_MAPCLASS(CMapAxisHandle, CMapHelper)
|
||||
|
||||
//
|
||||
// Factory for building from a list of string parameters.
|
||||
//
|
||||
static CMapClass *Create(CHelperInfo *pInfo, CMapEntity *pParent);
|
||||
|
||||
//
|
||||
// Construction/destruction:
|
||||
//
|
||||
CMapAxisHandle();
|
||||
CMapAxisHandle(const char *pszKey);
|
||||
~CMapAxisHandle();
|
||||
|
||||
inline void GetEndPoint(Vector &vecPos, int nPointIndex);
|
||||
void UpdateEndPoint(Vector &vecPos, int nPointIndex);
|
||||
inline int GetEndPointRadius();
|
||||
|
||||
//
|
||||
// CMapClass implementation.
|
||||
//
|
||||
void CalcBounds(BOOL bFullUpdate = FALSE);
|
||||
|
||||
virtual CMapClass *Copy(bool bUpdateDependencies);
|
||||
virtual CMapClass *CopyFrom(CMapClass *pFrom, bool bUpdateDependencies);
|
||||
|
||||
virtual void Render2D(CRender2D *pRender);
|
||||
|
||||
virtual int SerializeRMF(std::fstream &File, BOOL bRMF);
|
||||
virtual int SerializeMAP(std::fstream &File, BOOL bRMF);
|
||||
|
||||
// Overridden to chain down to our endpoints, which are not children.
|
||||
void SetOrigin(Vector &vecOrigin);
|
||||
|
||||
// Overridden to chain down to our endpoints, which are not children.
|
||||
virtual SelectionState_t SetSelectionState(SelectionState_t eSelectionState);
|
||||
|
||||
// Overridden because axis helpers don't take the color of their parent entity.
|
||||
virtual void SetRenderColor(unsigned char red, unsigned char green, unsigned char blue);
|
||||
virtual void SetRenderColor(color32 rgbColor);
|
||||
|
||||
virtual bool HitTest2D(CMapView2D *pView, const Vector2D &point, HitInfo_t &HitData);
|
||||
virtual CBaseTool *GetToolObject(int nHitData, bool bAttachObject);
|
||||
|
||||
virtual bool IsVisualElement(void) { return(false); } // Only visible if our parent is selected.
|
||||
virtual bool IsClutter(void) const { return true; }
|
||||
virtual bool CanBeCulledByCordon() const { return false; } // We don't hide unless our parent hides.
|
||||
|
||||
virtual const char* GetDescription() { return("Axis helper"); }
|
||||
|
||||
virtual void OnAddToWorld(CMapWorld *pWorld);
|
||||
virtual void OnParentKeyChanged(const char *key, const char *value);
|
||||
|
||||
virtual void PostloadWorld(CMapWorld *pWorld);
|
||||
|
||||
virtual void Render3D(CRender3D *pRender);
|
||||
|
||||
protected:
|
||||
|
||||
SelectionState_t SetSelectionState(SelectionState_t eSelectionState, int nHandle);
|
||||
|
||||
void UpdateParentKey(void);
|
||||
|
||||
// Overriden to transform our endpoints, which are not children.
|
||||
virtual void DoTransform(const VMatrix &matrix);
|
||||
|
||||
void Initialize(void);
|
||||
|
||||
CMapPointHandle m_Point[2]; // The two endpoints of the axis.
|
||||
|
||||
char m_szKeyName[MAX_KEYNAME_SIZE];
|
||||
};
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Returns the position of the given endpoint.
|
||||
// Input : vecPos - Receives the position.
|
||||
// nPointIndex - Endpoint index [0,1].
|
||||
//-----------------------------------------------------------------------------
|
||||
inline void CMapAxisHandle::GetEndPoint(Vector &vecPos, int nPointIndex)
|
||||
{
|
||||
m_Point[nPointIndex].GetOrigin(vecPos);
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Returns the radius to use in rendering the endpoints.
|
||||
//-----------------------------------------------------------------------------
|
||||
inline int CMapAxisHandle::GetEndPointRadius()
|
||||
{
|
||||
return m_Point[0].GetRadius();
|
||||
}
|
||||
|
||||
|
||||
#endif // MAPAXISHANDLE_H
|
||||
171
hammer/MapDiffDlg.cpp
Normal file
171
hammer/MapDiffDlg.cpp
Normal file
@@ -0,0 +1,171 @@
|
||||
// MapDiffDlg.cpp : implementation file
|
||||
//
|
||||
#include "stdafx.h"
|
||||
#include "GlobalFunctions.h"
|
||||
#include "History.h"
|
||||
#include "MainFrm.h"
|
||||
#include "MapDiffDlg.h"
|
||||
#include "MapDoc.h"
|
||||
#include "MapEntity.h"
|
||||
#include "MapSolid.h"
|
||||
#include "MapView2D.h"
|
||||
#include "MapWorld.h"
|
||||
#include "ObjectProperties.h" // For ObjectProperties::RefreshData
|
||||
#include "Options.h"
|
||||
#include "ToolManager.h"
|
||||
#include "VisGroup.h"
|
||||
#include "hammer.h"
|
||||
#include "MapOverlay.h"
|
||||
#include "GameConfig.h"
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include <tier0/memdbgon.h>
|
||||
#include ".\mapdiffdlg.h"
|
||||
|
||||
CMapDiffDlg *s_pDlg = NULL;
|
||||
CMapDoc *s_pCurrentMap = NULL;
|
||||
|
||||
// MapDiffDlg dialog
|
||||
|
||||
CMapDiffDlg::CMapDiffDlg(CWnd* pParent )
|
||||
: CDialog(CMapDiffDlg::IDD, pParent)
|
||||
{
|
||||
m_bCheckSimilar = true;
|
||||
}
|
||||
|
||||
void CMapDiffDlg::DoDataExchange(CDataExchange* pDX)
|
||||
{
|
||||
CDialog::DoDataExchange(pDX);
|
||||
|
||||
DDX_Check(pDX, IDC_SIMILARCHECK, m_bCheckSimilar);
|
||||
DDX_Control(pDX, IDC_MAPNAME, m_mapName);
|
||||
}
|
||||
|
||||
|
||||
BEGIN_MESSAGE_MAP(CMapDiffDlg, CDialog)
|
||||
ON_BN_CLICKED(IDC_SIMILARCHECK, OnBnClickedSimilarcheck)
|
||||
ON_BN_CLICKED(IDC_MAPBROWSE, OnBnClickedMapbrowse)
|
||||
ON_BN_CLICKED(IDOK, OnBnClickedOk)
|
||||
ON_BN_CLICKED(IDCANCEL, OnBnClickedCancel)
|
||||
ON_WM_DESTROY()
|
||||
END_MESSAGE_MAP()
|
||||
|
||||
void CMapDiffDlg::MapDiff(CWnd *pwndParent, CMapDoc *pCurrentMapDoc)
|
||||
{
|
||||
if (!s_pDlg)
|
||||
{
|
||||
s_pDlg = new CMapDiffDlg;
|
||||
s_pDlg->Create(IDD, pwndParent);
|
||||
s_pDlg->ShowWindow(SW_SHOW);
|
||||
s_pCurrentMap = pCurrentMapDoc;
|
||||
}
|
||||
}
|
||||
|
||||
// MapDiffDlg message handlers
|
||||
|
||||
void CMapDiffDlg::OnBnClickedSimilarcheck()
|
||||
{
|
||||
// TODO: Add your control notification handler code here
|
||||
m_bCheckSimilar = !m_bCheckSimilar;
|
||||
}
|
||||
|
||||
void CMapDiffDlg::OnBnClickedMapbrowse()
|
||||
{
|
||||
CString m_pszFilename;
|
||||
|
||||
// TODO: Add your control notification handler code here
|
||||
static char szInitialDir[MAX_PATH] = "";
|
||||
if (szInitialDir[0] == '\0')
|
||||
{
|
||||
strcpy(szInitialDir, g_pGameConfig->szMapDir);
|
||||
}
|
||||
|
||||
// TODO: need to prevent (or handle) opening VMF files when using old map file formats
|
||||
CFileDialog dlg(TRUE, NULL, NULL, OFN_LONGNAMES | OFN_HIDEREADONLY | OFN_NOCHANGEDIR, "Valve Map Files (*.vmf)|*.vmf|Valve Map Files Autosaves (*.vmf_autosave)|*.vmf_autosave|Worldcraft RMFs (*.rmf)|*.rmf|Worldcraft Maps (*.map)|*.map||");
|
||||
dlg.m_ofn.lpstrInitialDir = szInitialDir;
|
||||
int iRvl = dlg.DoModal();
|
||||
|
||||
if (iRvl == IDCANCEL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
// Get the directory they browsed to for next time.
|
||||
//
|
||||
m_pszFilename = dlg.GetPathName();
|
||||
m_mapName.SetWindowText( m_pszFilename );
|
||||
}
|
||||
|
||||
void CMapDiffDlg::OnBnClickedOk()
|
||||
{
|
||||
// TODO: Add your control notification handler code here
|
||||
OnOK();
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CMapDiffDlg::OnOK()
|
||||
{
|
||||
CString strFilename;
|
||||
m_mapName.GetWindowText( strFilename );
|
||||
CHammer *pApp = (CHammer*) AfxGetApp();
|
||||
CMapDoc *pDoc = (CMapDoc*) pApp->pMapDocTemplate->OpenDocumentFile( strFilename );
|
||||
CUtlVector <int> IDList;
|
||||
|
||||
const CMapObjectList *pChildren = pDoc->GetMapWorld()->GetChildren();
|
||||
|
||||
FOR_EACH_OBJ( *pChildren, pos )
|
||||
{
|
||||
int nID = pChildren->Element(pos)->GetID();
|
||||
IDList.AddToTail( nID );
|
||||
}
|
||||
|
||||
pDoc->OnCloseDocument();
|
||||
|
||||
CVisGroup *resultsVisGroup = NULL;
|
||||
pChildren = s_pCurrentMap->GetMapWorld()->GetChildren();
|
||||
int nTotalSimilarities = 0;
|
||||
if ( m_bCheckSimilar )
|
||||
{
|
||||
FOR_EACH_OBJ( *pChildren, pos )
|
||||
{
|
||||
CMapClass *pChild = (CUtlReference< CMapClass >)pChildren->Element(pos) ;
|
||||
int ID = pChild->GetID();
|
||||
if ( IDList.Find( ID ) != -1 )
|
||||
{
|
||||
if ( resultsVisGroup == NULL )
|
||||
{
|
||||
resultsVisGroup = s_pCurrentMap->VisGroups_AddGroup( "Similar" );
|
||||
nTotalSimilarities++;
|
||||
}
|
||||
pChild->AddVisGroup( resultsVisGroup );
|
||||
}
|
||||
}
|
||||
}
|
||||
if ( nTotalSimilarities > 0 )
|
||||
{
|
||||
GetMainWnd()->MessageBox( "Similarities were found and placed into the \"Similar\" visgroup.", "Map Similarities Found", MB_OK | MB_ICONEXCLAMATION);
|
||||
}
|
||||
s_pCurrentMap->VisGroups_UpdateAll();
|
||||
DestroyWindow();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Called when our window is being destroyed.
|
||||
//-----------------------------------------------------------------------------
|
||||
void CMapDiffDlg::OnDestroy()
|
||||
{
|
||||
delete this;
|
||||
s_pDlg = NULL;
|
||||
s_pCurrentMap = NULL;
|
||||
}
|
||||
|
||||
|
||||
void CMapDiffDlg::OnBnClickedCancel()
|
||||
{
|
||||
// TODO: Add your control notification handler code here
|
||||
DestroyWindow();
|
||||
}
|
||||
41
hammer/MapDiffDlg.h
Normal file
41
hammer/MapDiffDlg.h
Normal file
@@ -0,0 +1,41 @@
|
||||
|
||||
#ifndef MAPDIFFDLG_H
|
||||
#define MAPDIFFDLG_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include "mapdoc.h"
|
||||
|
||||
// MapDiffDlg dialog
|
||||
|
||||
class CMapDiffDlg : public CDialog
|
||||
{
|
||||
public:
|
||||
static void MapDiff(CWnd *pwndParent, CMapDoc *p_CurrentMap);
|
||||
|
||||
private:
|
||||
|
||||
CMapDiffDlg(CWnd* pParent = NULL); // standard constructor
|
||||
enum { IDD = IDD_DIFFMAP };
|
||||
|
||||
BOOL m_bCheckSimilar;
|
||||
CEdit m_mapName;
|
||||
|
||||
|
||||
protected:
|
||||
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
|
||||
|
||||
virtual void OnOK();
|
||||
afx_msg void OnDestroy();
|
||||
|
||||
|
||||
DECLARE_MESSAGE_MAP()
|
||||
public:
|
||||
afx_msg void OnBnClickedSimilarcheck();
|
||||
afx_msg void OnBnClickedMapbrowse();
|
||||
afx_msg void OnBnClickedOk();
|
||||
afx_msg void OnBnClickedCancel();
|
||||
};
|
||||
|
||||
#endif //MAPDIFFDLG_H
|
||||
36
hammer/MapHelper.h
Normal file
36
hammer/MapHelper.h
Normal file
@@ -0,0 +1,36 @@
|
||||
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: Defines a base class for all helper objects. Helper objects are
|
||||
// subordinate to their entity parents, and provide services such as
|
||||
// enhanced presentation and manipulation of keyvalues for their parent
|
||||
// entity.
|
||||
//
|
||||
// Like all children, helpers are transformed with their parent.
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef MAPHELPER_H
|
||||
#define MAPHELPER_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
|
||||
#include "MapClass.h"
|
||||
|
||||
|
||||
class CMapHelper : public CMapClass
|
||||
{
|
||||
public:
|
||||
|
||||
//
|
||||
// Serialization.
|
||||
//
|
||||
virtual bool ShouldSerialize(void) { return(false); }
|
||||
|
||||
virtual CMapClass *PrepareSelection(SelectMode_t eSelectMode);
|
||||
};
|
||||
|
||||
|
||||
#endif // MAPHELPER_H
|
||||
310
hammer/ModelBrowser.cpp
Normal file
310
hammer/ModelBrowser.cpp
Normal file
@@ -0,0 +1,310 @@
|
||||
// ModelBrowser.cpp : implementation file
|
||||
//
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "ModelBrowser.h"
|
||||
#include "matsys_controls/mdlpicker.h"
|
||||
#include "matsys_controls/baseassetpicker.h"
|
||||
#include "matsys_controls/matsyscontrols.h"
|
||||
#include "vgui_controls/TextEntry.h"
|
||||
#include "vgui_controls/Splitter.h"
|
||||
#include "vgui_controls/Button.h"
|
||||
#include "KeyValues.h"
|
||||
#include "vgui/KeyCode.h"
|
||||
#include "texturesystem.h"
|
||||
#include "HammerVGui.h"
|
||||
|
||||
static LPCTSTR pszIniSection = "Model Browser";
|
||||
|
||||
// CModelBrowser dialog
|
||||
|
||||
|
||||
class CModelBrowserPanel : public vgui::EditablePanel
|
||||
{
|
||||
public:
|
||||
CModelBrowserPanel( CModelBrowser *pBrowser, const char *panelName, vgui::HScheme hScheme ) :
|
||||
vgui::EditablePanel( NULL, panelName, hScheme )
|
||||
{
|
||||
m_pBrowser = pBrowser;
|
||||
}
|
||||
|
||||
virtual void OnSizeChanged(int newWide, int newTall)
|
||||
{
|
||||
// call Panel and not EditablePanel OnSizeChanged.
|
||||
Panel::OnSizeChanged(newWide, newTall);
|
||||
}
|
||||
|
||||
virtual void OnCommand( const char *pCommand )
|
||||
{
|
||||
if ( Q_strcmp( pCommand, "OK" ) == 0 )
|
||||
{
|
||||
m_pBrowser->EndDialog( IDOK );
|
||||
}
|
||||
else if ( Q_strcmp( pCommand, "Cancel" ) == 0 )
|
||||
{
|
||||
m_pBrowser->EndDialog( IDCANCEL );
|
||||
}
|
||||
}
|
||||
|
||||
virtual void OnKeyCodeTyped(vgui::KeyCode code)
|
||||
{
|
||||
vgui::EditablePanel::OnKeyCodeTyped( code );
|
||||
|
||||
if ( code == KEY_ENTER )
|
||||
{
|
||||
m_pBrowser->EndDialog( IDOK );
|
||||
}
|
||||
else if ( code == KEY_ESCAPE )
|
||||
{
|
||||
m_pBrowser->EndDialog( IDCANCEL );
|
||||
}
|
||||
}
|
||||
|
||||
virtual void OnMessage(const KeyValues *params, vgui::VPANEL ifromPanel)
|
||||
{
|
||||
vgui::EditablePanel::OnMessage( params, ifromPanel );
|
||||
|
||||
if ( Q_strcmp( params->GetName(), "MDLPreviewChanged" ) == 0 )
|
||||
{
|
||||
m_pBrowser->UpdateStatusLine();
|
||||
}
|
||||
else if ( Q_stricmp( params->GetName(), "AssetPickerFind" ) == 0 )
|
||||
{
|
||||
m_pBrowser->EndDialog( ID_FIND_ASSET );
|
||||
}
|
||||
}
|
||||
|
||||
CModelBrowser *m_pBrowser;
|
||||
};
|
||||
|
||||
IMPLEMENT_DYNAMIC(CModelBrowser, CDialog)
|
||||
CModelBrowser::CModelBrowser(CWnd* pParent /*=NULL*/)
|
||||
: CDialog(CModelBrowser::IDD, pParent)
|
||||
{
|
||||
m_pPicker = new CMDLPicker( NULL );
|
||||
m_pStatusLine = new vgui::TextEntry( NULL, "StatusLine" );
|
||||
|
||||
m_pButtonOK = new vgui::Button( NULL, "OpenButton", "OK" );
|
||||
m_pButtonCancel = new vgui::Button( NULL, "CancelButton", "Cancel" );
|
||||
}
|
||||
|
||||
CModelBrowser::~CModelBrowser()
|
||||
{
|
||||
delete m_pPicker;
|
||||
delete m_pStatusLine;
|
||||
delete m_pButtonOK;
|
||||
delete m_pButtonCancel;
|
||||
}
|
||||
|
||||
void CModelBrowser::SetUsedModelList( CUtlVector<AssetUsageInfo_t> &usedModels )
|
||||
{
|
||||
m_pPicker->SetUsedAssetList( usedModels );
|
||||
}
|
||||
|
||||
void CModelBrowser::SetModelName( const char *pModelName )
|
||||
{
|
||||
char pszTempModelName[255];
|
||||
strcpy( pszTempModelName, pModelName );
|
||||
|
||||
char * pszSelectedModel = strchr( pszTempModelName, '/' );
|
||||
if( pszSelectedModel)
|
||||
{
|
||||
pszSelectedModel += 1;
|
||||
Q_FixSlashes( pszSelectedModel, '\\' );
|
||||
}
|
||||
|
||||
m_pPicker->SelectMDL( pModelName );
|
||||
m_pPicker->SetInitialSelection( pszSelectedModel );
|
||||
|
||||
m_pStatusLine->SetText( pModelName );
|
||||
}
|
||||
|
||||
void CModelBrowser::GetModelName( char *pModelName, int length )
|
||||
{
|
||||
m_pPicker->GetSelectedMDLName( pModelName, length );
|
||||
|
||||
Q_FixSlashes( pModelName, '/' );
|
||||
}
|
||||
|
||||
void CModelBrowser::GetSkin( int &nSkin )
|
||||
{
|
||||
nSkin = m_pPicker->GetSelectedSkin();
|
||||
}
|
||||
|
||||
void CModelBrowser::SetSkin( int nSkin )
|
||||
{
|
||||
m_pPicker->SelectSkin( nSkin );
|
||||
}
|
||||
|
||||
void CModelBrowser::UpdateStatusLine()
|
||||
{
|
||||
char szModel[1024];
|
||||
|
||||
m_pPicker->GetSelectedMDLName( szModel, sizeof(szModel) );
|
||||
|
||||
m_pStatusLine->SetText( szModel );
|
||||
|
||||
/* MDLHandle_t hMDL = vgui::MDLCache()->FindMDL( szModel );
|
||||
|
||||
studiohdr_t *hdr = vgui::MDLCache()->GetStudioHdr( hMDL );
|
||||
|
||||
vgui::MDLCache()->Release( hMDL ); */
|
||||
}
|
||||
|
||||
void CModelBrowser::SaveLoadSettings( bool bSave )
|
||||
{
|
||||
CString str;
|
||||
CRect rect;
|
||||
CWinApp *pApp = AfxGetApp();
|
||||
|
||||
if ( bSave )
|
||||
{
|
||||
GetWindowRect(rect);
|
||||
str.Format("%d %d %d %d", rect.left, rect.top, rect.right, rect.bottom);
|
||||
pApp->WriteProfileString(pszIniSection, "Position", str);
|
||||
pApp->WriteProfileString(pszIniSection, "Filter", m_pPicker->GetFilter() );
|
||||
}
|
||||
else
|
||||
{
|
||||
str = pApp->GetProfileString(pszIniSection, "Position");
|
||||
|
||||
if (!str.IsEmpty())
|
||||
{
|
||||
sscanf(str, "%d %d %d %d", &rect.left, &rect.top, &rect.right, &rect.bottom);
|
||||
MoveWindow(rect.left, rect.top, rect.right-rect.left, rect.bottom-rect.top, FALSE);
|
||||
Resize();
|
||||
}
|
||||
|
||||
str = pApp->GetProfileString(pszIniSection, "Filter");
|
||||
|
||||
if (!str.IsEmpty())
|
||||
{
|
||||
m_pPicker->SetFilter( str );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void CModelBrowser::DoDataExchange(CDataExchange* pDX)
|
||||
{
|
||||
CDialog::DoDataExchange(pDX);
|
||||
}
|
||||
|
||||
void CModelBrowser::Resize()
|
||||
{
|
||||
// reposition controls
|
||||
CRect rect;
|
||||
GetClientRect(&rect);
|
||||
|
||||
m_VGuiWindow.MoveWindow( rect );
|
||||
|
||||
m_pPicker->SetBounds( 0,0, rect.Width(), rect.Height() - 32 );
|
||||
m_pButtonCancel->SetPos( 8, rect.Height() - 30 );
|
||||
m_pButtonOK->SetPos( 84, rect.Height() - 30 );
|
||||
m_pStatusLine->SetBounds( 160, rect.Height() - 30, max( 100, rect.Width() - 166 ), 24 );
|
||||
}
|
||||
|
||||
void CModelBrowser::OnSize(UINT nType, int cx, int cy)
|
||||
{
|
||||
if (nType == SIZE_MINIMIZED || !IsWindow(m_VGuiWindow.m_hWnd) )
|
||||
{
|
||||
CDialog::OnSize(nType, cx, cy);
|
||||
return;
|
||||
}
|
||||
|
||||
Resize();
|
||||
|
||||
CDialog::OnSize(nType, cx, cy);
|
||||
}
|
||||
|
||||
|
||||
BEGIN_MESSAGE_MAP(CModelBrowser, CDialog)
|
||||
ON_WM_SIZE()
|
||||
ON_WM_DESTROY()
|
||||
ON_WM_ERASEBKGND()
|
||||
END_MESSAGE_MAP()
|
||||
|
||||
BOOL CModelBrowser::PreTranslateMessage( MSG* pMsg )
|
||||
{
|
||||
// don't filter dialog message
|
||||
return CWnd::PreTranslateMessage( pMsg );
|
||||
}
|
||||
|
||||
BOOL CModelBrowser::OnInitDialog()
|
||||
{
|
||||
CDialog::OnInitDialog();
|
||||
|
||||
m_VGuiWindow.Create( NULL, _T("ModelViewer"), WS_VISIBLE|WS_CHILD, CRect(0,0,100,100), this, 1001);
|
||||
|
||||
vgui::EditablePanel *pMainPanel = new CModelBrowserPanel( this, "ModelBrowerPanel", HammerVGui()->GetHammerScheme() );
|
||||
|
||||
m_VGuiWindow.SetParentWindow( &m_VGuiWindow );
|
||||
m_VGuiWindow.SetMainPanel( pMainPanel );
|
||||
pMainPanel->MakePopup( false, false );
|
||||
m_VGuiWindow.SetRepaintInterval( 75 );
|
||||
|
||||
m_pPicker->SetParent( pMainPanel );
|
||||
m_pPicker->AddActionSignalTarget( pMainPanel );
|
||||
|
||||
m_pButtonOK->SetParent( pMainPanel );
|
||||
m_pButtonOK->AddActionSignalTarget( pMainPanel );
|
||||
m_pButtonOK->SetCommand( "OK" );
|
||||
|
||||
m_pButtonCancel->SetParent( pMainPanel );
|
||||
m_pButtonCancel->AddActionSignalTarget( pMainPanel );
|
||||
m_pButtonCancel->SetCommand( "Cancel" );
|
||||
|
||||
m_pStatusLine->SetParent( pMainPanel );
|
||||
m_pStatusLine->SetEditable( false );
|
||||
|
||||
SaveLoadSettings( false ); // load
|
||||
|
||||
m_pPicker->Activate();
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void CModelBrowser::OnDestroy()
|
||||
{
|
||||
SaveLoadSettings( true ); // save
|
||||
|
||||
// model browser destoys our default cube map, reload it
|
||||
g_Textures.RebindDefaultCubeMap();
|
||||
|
||||
CDialog::OnDestroy();
|
||||
}
|
||||
|
||||
void CModelBrowser::Show()
|
||||
{
|
||||
if (m_pPicker)
|
||||
{
|
||||
m_pPicker->SetVisible( true );
|
||||
}
|
||||
if (m_pStatusLine)
|
||||
m_pStatusLine->SetVisible( true );
|
||||
if (m_pButtonOK)
|
||||
m_pButtonOK->SetVisible( true );
|
||||
if (m_pButtonCancel)
|
||||
m_pButtonCancel->SetVisible( true );
|
||||
|
||||
}
|
||||
void CModelBrowser::Hide()
|
||||
{
|
||||
if (m_pPicker)
|
||||
m_pPicker->SetVisible( false );
|
||||
|
||||
if (m_pStatusLine)
|
||||
m_pStatusLine->SetVisible( false );
|
||||
|
||||
if (m_pButtonOK)
|
||||
m_pButtonOK->SetVisible( false );
|
||||
|
||||
if (m_pButtonCancel)
|
||||
m_pButtonCancel->SetVisible( false );
|
||||
}
|
||||
|
||||
BOOL CModelBrowser::OnEraseBkgnd(CDC* pDC)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
69
hammer/ModelBrowser.h
Normal file
69
hammer/ModelBrowser.h
Normal file
@@ -0,0 +1,69 @@
|
||||
#pragma once
|
||||
|
||||
#include "resource.h"
|
||||
#include "utlvector.h"
|
||||
#include "VGuiWnd.h"
|
||||
#include "matsys_controls\baseassetpicker.h"
|
||||
|
||||
|
||||
namespace vgui
|
||||
{
|
||||
class TextEntry;
|
||||
class Splitter;
|
||||
class Button;
|
||||
}
|
||||
|
||||
class CModelBrowserPanel;
|
||||
class CMDLPicker;
|
||||
|
||||
|
||||
#define ID_FIND_ASSET 100
|
||||
|
||||
|
||||
class CModelBrowser : public CDialog
|
||||
{
|
||||
DECLARE_DYNAMIC(CModelBrowser)
|
||||
|
||||
public:
|
||||
CModelBrowser(CWnd* pParent = NULL); // standard constructor
|
||||
virtual ~CModelBrowser();
|
||||
|
||||
void SetUsedModelList( CUtlVector<AssetUsageInfo_t> &usedModels );
|
||||
|
||||
void SetModelName( const char *pModelName );
|
||||
void GetModelName( char *pModelName, int length );
|
||||
void GetSkin( int &nSkin );
|
||||
void SetSkin( int nSkin );
|
||||
|
||||
// Dialog Data
|
||||
enum { IDD = IDD_MODEL_BROWSER };
|
||||
|
||||
protected:
|
||||
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
|
||||
virtual BOOL PreTranslateMessage( MSG* pMsg );
|
||||
|
||||
|
||||
DECLARE_MESSAGE_MAP()
|
||||
|
||||
public:
|
||||
afx_msg void OnSize(UINT nType, int cx, int cy);
|
||||
afx_msg void OnDestroy();
|
||||
afx_msg BOOL OnEraseBkgnd(CDC* pDC);
|
||||
|
||||
virtual BOOL OnInitDialog();
|
||||
|
||||
void UpdateStatusLine();
|
||||
void SaveLoadSettings( bool bSave );
|
||||
void Resize( void );
|
||||
|
||||
CVGuiPanelWnd m_VGuiWindow;
|
||||
|
||||
CMDLPicker *m_pPicker;
|
||||
vgui::Button *m_pButtonOK;
|
||||
vgui::Button *m_pButtonCancel;
|
||||
vgui::TextEntry *m_pStatusLine;
|
||||
|
||||
void Show();
|
||||
void Hide();
|
||||
|
||||
};
|
||||
176
hammer/NewVisGroupDlg.cpp
Normal file
176
hammer/NewVisGroupDlg.cpp
Normal file
@@ -0,0 +1,176 @@
|
||||
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: A dialog that is invoked when a new visgroup is created.
|
||||
// It lets the user pick an existing visgroup or create a new one.
|
||||
//
|
||||
//=============================================================================//
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "MapDoc.h"
|
||||
#include "NewVisGroupDlg.h"
|
||||
#include "hammer.h"
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include <tier0/memdbgon.h>
|
||||
|
||||
|
||||
static const unsigned int g_uSelChangeMsg = ::RegisterWindowMessage(GROUPLIST_MSG_SEL_CHANGE);
|
||||
static BOOL s_bLastHideObjects = TRUE;
|
||||
|
||||
|
||||
BEGIN_MESSAGE_MAP(CNewVisGroupDlg, CDialog)
|
||||
//{{AFX_MSG_MAP(CNewVisGroupDlg)
|
||||
ON_REGISTERED_MESSAGE(g_uSelChangeMsg, OnSelChangeGroupList)
|
||||
ON_COMMAND(IDC_PLACE_IN_EXISTING_VISGROUP, OnPlaceInExistingVisGroup)
|
||||
ON_COMMAND(IDC_CREATE_NEW_VISGROUP, OnCreateNewVisGroup)
|
||||
//}}AFX_MSG_MAP
|
||||
END_MESSAGE_MAP()
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : pParent -
|
||||
//-----------------------------------------------------------------------------
|
||||
CNewVisGroupDlg::CNewVisGroupDlg(CString &str, CWnd *pParent)
|
||||
: CDialog(CNewVisGroupDlg::IDD, pParent)
|
||||
{
|
||||
m_pPickedVisGroup = NULL;
|
||||
|
||||
//{{AFX_DATA_INIT(CNewVisGroupDlg)
|
||||
m_strName = str;
|
||||
//}}AFX_DATA_INIT
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : pDX -
|
||||
//-----------------------------------------------------------------------------
|
||||
void CNewVisGroupDlg::DoDataExchange(CDataExchange* pDX)
|
||||
{
|
||||
CDialog::DoDataExchange(pDX);
|
||||
//{{AFX_DATA_MAP(CNewVisGroupDlg)
|
||||
DDX_Check(pDX, IDC_REMOVE_FROM_ALL, m_bRemoveFromOtherGroups);
|
||||
DDX_Check(pDX, IDC_HIDE_OBJECTS, m_bHideObjects);
|
||||
DDX_Text(pDX, IDC_VISGROUP_NAME, m_strName);
|
||||
//}}AFX_DATA_MAP
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
BOOL CNewVisGroupDlg::OnInitDialog(void)
|
||||
{
|
||||
m_bHideObjects = s_bLastHideObjects;
|
||||
|
||||
CDialog::OnInitDialog();
|
||||
|
||||
CButton *pButton = (CButton *)GetDlgItem(IDC_CREATE_NEW_VISGROUP);
|
||||
pButton->SetCheck(1);
|
||||
|
||||
m_cGroupList.SubclassDlgItem(IDC_GROUP_LIST, this);
|
||||
UpdateGroupList();
|
||||
|
||||
CEdit *pEdit = (CEdit *)GetDlgItem(IDC_GROUP_LIST);
|
||||
pEdit->EnableWindow(FALSE);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Returns the visgroup name that was entered in the dialog.
|
||||
//-----------------------------------------------------------------------------
|
||||
void CNewVisGroupDlg::GetName(CString &str)
|
||||
{
|
||||
str = m_strName;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CNewVisGroupDlg::OnOK()
|
||||
{
|
||||
CDialog::OnOK();
|
||||
s_bLastHideObjects = m_bHideObjects;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Switches the mode of the dialog to pick an existing visgroup rather than
|
||||
// create a new one.
|
||||
//-----------------------------------------------------------------------------
|
||||
void CNewVisGroupDlg::OnPlaceInExistingVisGroup()
|
||||
{
|
||||
CEdit *pEdit = (CEdit *)GetDlgItem(IDC_VISGROUP_NAME);
|
||||
pEdit->EnableWindow(FALSE);
|
||||
|
||||
pEdit = (CEdit *)GetDlgItem(IDC_GROUP_LIST);
|
||||
pEdit->EnableWindow(TRUE);
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Switches the mode of the dialog to create a new visgroup rather than
|
||||
// pick an existing one.
|
||||
//-----------------------------------------------------------------------------
|
||||
void CNewVisGroupDlg::OnCreateNewVisGroup()
|
||||
{
|
||||
CEdit *pEdit = (CEdit *)GetDlgItem(IDC_VISGROUP_NAME);
|
||||
pEdit->EnableWindow(TRUE);
|
||||
|
||||
pEdit = (CEdit *)GetDlgItem(IDC_GROUP_LIST);
|
||||
pEdit->EnableWindow(FALSE);
|
||||
|
||||
m_pPickedVisGroup = NULL;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Handles selection change in the visgroup list.
|
||||
//-----------------------------------------------------------------------------
|
||||
LRESULT CNewVisGroupDlg::OnSelChangeGroupList(WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
m_pPickedVisGroup = m_cGroupList.GetSelectedVisGroup();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CNewVisGroupDlg::UpdateGroupList(void)
|
||||
{
|
||||
m_cGroupList.SetRedraw(false);
|
||||
m_cGroupList.DeleteAllItems();
|
||||
|
||||
CMapDoc *pDoc = CMapDoc::GetActiveMapDoc();
|
||||
if (pDoc != NULL)
|
||||
{
|
||||
int nCount = pDoc->VisGroups_GetRootCount();
|
||||
for (int i = 0; i < nCount; i++)
|
||||
{
|
||||
CVisGroup *pGroup = pDoc->VisGroups_GetRootVisGroup(i);
|
||||
if (stricmp(pGroup->GetName(), "Auto") != 0)
|
||||
{
|
||||
m_cGroupList.AddVisGroup(pGroup);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m_cGroupList.ExpandAll();
|
||||
m_cGroupList.SetRedraw(true);
|
||||
m_cGroupList.Invalidate();
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
CVisGroup *CNewVisGroupDlg::GetPickedVisGroup(void)
|
||||
{
|
||||
return m_pPickedVisGroup;
|
||||
}
|
||||
|
||||
73
hammer/NewVisGroupDlg.h
Normal file
73
hammer/NewVisGroupDlg.h
Normal file
@@ -0,0 +1,73 @@
|
||||
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: A dialog that is invoked when a new visgroup is created.
|
||||
//
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef NEWVISGROUPDLG_H
|
||||
#define NEWVISGROUPDLG_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include "resource.h"
|
||||
#include "GroupList.h"
|
||||
|
||||
|
||||
class CNewVisGroupDlg : public CDialog
|
||||
{
|
||||
public:
|
||||
CNewVisGroupDlg(CString &str, CWnd *pParent = NULL);
|
||||
|
||||
void GetName(CString &str);
|
||||
CVisGroup *GetPickedVisGroup(void);
|
||||
bool GetRemoveFromOtherGroups(void);
|
||||
bool GetHideObjectsOption(void);
|
||||
|
||||
//{{AFX_DATA(CNewVisGroupDlg)
|
||||
enum { IDD = IDD_NEW_VISGROUP };
|
||||
//}}AFX_DATA
|
||||
|
||||
// ClassWizard generated virtual function overrides
|
||||
//{{AFX_VIRTUAL(CNewVisGroupDlg)
|
||||
protected:
|
||||
virtual void DoDataExchange(CDataExchange *pDX);
|
||||
virtual BOOL OnInitDialog(void);
|
||||
//}}AFX_VIRTUAL
|
||||
|
||||
protected:
|
||||
|
||||
void UpdateGroupList(void);
|
||||
|
||||
// Generated message map functions
|
||||
//{{AFX_MSG(CNewVisGroupDlg)
|
||||
virtual void OnOK();
|
||||
LRESULT OnSelChangeGroupList(WPARAM wParam, LPARAM lParam);
|
||||
void OnCreateNewVisGroup();
|
||||
void OnPlaceInExistingVisGroup();
|
||||
//}}AFX_MSG
|
||||
|
||||
CGroupList m_cGroupList;
|
||||
CVisGroup *m_pPickedVisGroup;
|
||||
BOOL m_bRemoveFromOtherGroups;
|
||||
BOOL m_bHideObjects;
|
||||
CString m_strName;
|
||||
|
||||
DECLARE_MESSAGE_MAP()
|
||||
};
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
inline bool CNewVisGroupDlg::GetRemoveFromOtherGroups(void)
|
||||
{
|
||||
return m_bRemoveFromOtherGroups == TRUE;
|
||||
}
|
||||
|
||||
inline bool CNewVisGroupDlg::GetHideObjectsOption()
|
||||
{
|
||||
return (m_bHideObjects != FALSE);
|
||||
}
|
||||
|
||||
#endif // NEWVISGROUPDLG_H
|
||||
342
hammer/OP_Model.cpp
Normal file
342
hammer/OP_Model.cpp
Normal file
@@ -0,0 +1,342 @@
|
||||
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ====
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "hammer.h"
|
||||
#include "MapEntity.h"
|
||||
#include "MapStudioModel.h"
|
||||
#include "OP_Model.h"
|
||||
#include "ObjectProperties.h"
|
||||
#include "mapdoc.h"
|
||||
#include "options.h"
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include <tier0/memdbgon.h>
|
||||
|
||||
|
||||
#pragma warning( disable : 4355 )
|
||||
|
||||
|
||||
IMPLEMENT_DYNCREATE(COP_Model, CObjectPage)
|
||||
|
||||
|
||||
BEGIN_MESSAGE_MAP(COP_Model, CObjectPage)
|
||||
//{{AFX_MSG_MAP(COP_Model)
|
||||
ON_WM_HSCROLL()
|
||||
//}}AFX_MSG_MAP
|
||||
END_MESSAGE_MAP()
|
||||
|
||||
|
||||
const int FRAME_SCROLLBAR_RANGE = 1000;
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
COP_Model::COP_Model() : CObjectPage(COP_Model::IDD), m_ComboSequence( this )
|
||||
{
|
||||
//{{AFX_DATA_INIT(COP_Model)
|
||||
//}}AFX_DATA_INIT
|
||||
|
||||
m_pEditObjectRuntimeClass = RUNTIME_CLASS(editCEditGameClass);
|
||||
m_ComboSequence.SetOnlyProvideSuggestions( true );
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
COP_Model::~COP_Model()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : pDX -
|
||||
//-----------------------------------------------------------------------------
|
||||
void COP_Model::DoDataExchange(CDataExchange* pDX)
|
||||
{
|
||||
CObjectPage::DoDataExchange(pDX);
|
||||
//{{AFX_DATA_MAP(COP_Model)
|
||||
DDX_Control(pDX, IDC_SEQUENCE, m_ComboSequence);
|
||||
DDX_Control(pDX, IDC_FRAME_SCROLLBAR, m_ScrollBarFrame);
|
||||
//}}AFX_DATA_MAP
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : Mode -
|
||||
// pData -
|
||||
//-----------------------------------------------------------------------------
|
||||
void COP_Model::UpdateData( int Mode, PVOID pData, bool bCanEdit )
|
||||
{
|
||||
__super::UpdateData( Mode, pData, bCanEdit );
|
||||
|
||||
if (!IsWindow(m_hWnd) || !pData)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (Mode == LoadFirstData)
|
||||
{
|
||||
m_ComboSequence.Clear();
|
||||
|
||||
CMapStudioModel *pModel = GetModelHelper();
|
||||
if ( pModel )
|
||||
{
|
||||
// If they were on a previous animation, remember it and we'll set the combo box to that after
|
||||
// we tell it the list of suggestions.
|
||||
char txt[512];
|
||||
txt[0] = 0;
|
||||
int iSequence = pModel->GetSequence();
|
||||
if ( iSequence )
|
||||
pModel->GetSequenceName( iSequence, txt );
|
||||
|
||||
// Set the list of suggestions.
|
||||
CUtlVector<CString> suggestions;
|
||||
|
||||
int nCount = pModel->GetSequenceCount();
|
||||
for ( int i = 0; i < nCount; i++ )
|
||||
{
|
||||
char szName[MAX_PATH];
|
||||
pModel->GetSequenceName(i, szName);
|
||||
suggestions.AddToTail( szName );
|
||||
}
|
||||
|
||||
m_ComboSequence.SetSuggestions( suggestions, 0 );
|
||||
m_ComboSequence.SetCurSel( iSequence );
|
||||
}
|
||||
|
||||
// Reset the scroll bar
|
||||
InitScrollRange();
|
||||
}
|
||||
else if (Mode == LoadData)
|
||||
{
|
||||
Assert(false);
|
||||
}
|
||||
|
||||
SetReadOnly( !m_bCanEdit );
|
||||
}
|
||||
|
||||
BOOL COP_Model::OnSetActive()
|
||||
{
|
||||
m_bOldAnimatedModels = Options.view3d.bAnimateModels;
|
||||
Options.view3d.bAnimateModels = true;
|
||||
|
||||
CMapStudioModel *pModel = GetModelHelper();
|
||||
if ( pModel )
|
||||
{
|
||||
m_nOldSequence = pModel->GetSequence();
|
||||
}
|
||||
|
||||
CMapDoc *pDoc = CMapDoc::GetActiveMapDoc();
|
||||
if ( pDoc )
|
||||
{
|
||||
pDoc->UpdateAllViews( MAPVIEW_UPDATE_ANIMATION|MAPVIEW_OPTIONS_CHANGED );
|
||||
}
|
||||
|
||||
return CObjectPage::OnSetActive();
|
||||
}
|
||||
|
||||
BOOL COP_Model::OnKillActive()
|
||||
{
|
||||
Options.view3d.bAnimateModels = m_bOldAnimatedModels;
|
||||
|
||||
CMapDoc *pDoc = CMapDoc::GetActiveMapDoc();
|
||||
if ( pDoc )
|
||||
{
|
||||
pDoc->UpdateAllViews( MAPVIEW_UPDATE_ANIMATION|MAPVIEW_OPTIONS_CHANGED );
|
||||
}
|
||||
|
||||
return CObjectPage::OnKillActive();
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Output : Returns true on success, false on failure.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool COP_Model::SaveData( SaveData_Reason_t reason )
|
||||
{
|
||||
if (!IsWindow(m_hWnd))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// If we've closed the dialog or changed focus, reset the model now
|
||||
if ( reason == SAVEDATA_SELECTION_CHANGED || reason == SAVEDATA_CLOSE )
|
||||
{
|
||||
CMapStudioModel *pModel = GetModelHelper();
|
||||
if (pModel != NULL)
|
||||
{
|
||||
pModel->SetSequence( m_nOldSequence );
|
||||
pModel->SetFrame( 0 );
|
||||
|
||||
CMapDoc *pDoc = CMapDoc::GetActiveMapDoc();
|
||||
if ( pDoc )
|
||||
{
|
||||
pDoc->UpdateAllViews( MAPVIEW_UPDATE_ANIMATION );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : pszClass -
|
||||
//-----------------------------------------------------------------------------
|
||||
void COP_Model::UpdateForClass(LPCTSTR pszClass)
|
||||
{
|
||||
if (!IsWindow(m_hWnd))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : flFrame -
|
||||
//-----------------------------------------------------------------------------
|
||||
void COP_Model::UpdateFrameText( int nFrame)
|
||||
{
|
||||
char szFrame[40];
|
||||
sprintf(szFrame, "%d", nFrame);
|
||||
GetDlgItem(IDC_FRAME_TEXT)->SetWindowText(szFrame);
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Output : Returns TRUE on success, FALSE on failure.
|
||||
//-----------------------------------------------------------------------------
|
||||
BOOL COP_Model::OnInitDialog()
|
||||
{
|
||||
CObjectPage::OnInitDialog();
|
||||
|
||||
InitScrollRange();
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void COP_Model::InitScrollRange( void )
|
||||
{
|
||||
// Set the frame number scrollbar range
|
||||
int nMaxRange = FRAME_SCROLLBAR_RANGE;
|
||||
CMapStudioModel *pModel = GetModelHelper();
|
||||
if (pModel != NULL)
|
||||
{
|
||||
nMaxRange = pModel->GetMaxFrame();
|
||||
}
|
||||
|
||||
// Setup the bar
|
||||
m_ScrollBarFrame.SetRange( 0, nMaxRange );
|
||||
m_ScrollBarFrame.SetPos( 0 );
|
||||
|
||||
// Start at the zeroth frame
|
||||
UpdateFrameText( 0 );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : nSBCode -
|
||||
// nPos -
|
||||
// pScrollBar -
|
||||
//-----------------------------------------------------------------------------
|
||||
void COP_Model::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar *pScrollBar)
|
||||
{
|
||||
if (pScrollBar == (CScrollBar *)&m_ScrollBarFrame)
|
||||
{
|
||||
if ( nSBCode == SB_ENDSCROLL )
|
||||
return;
|
||||
|
||||
CMapStudioModel *pModel = GetModelHelper();
|
||||
if (pModel != NULL)
|
||||
{
|
||||
pModel->SetFrame( nPos );
|
||||
UpdateFrameText( nPos );
|
||||
|
||||
Options.view3d.bAnimateModels = false; // Pause animations while we're scrubbing
|
||||
|
||||
CMapDoc *pDoc = CMapDoc::GetActiveMapDoc();
|
||||
if ( pDoc )
|
||||
{
|
||||
pDoc->UpdateAllViews( MAPVIEW_UPDATE_ANIMATION|MAPVIEW_OPTIONS_CHANGED );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CPropertyPage::OnHScroll(nSBCode, nPos, pScrollBar);
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void COP_Model::OnTextChanged( const char *pText )
|
||||
{
|
||||
CMapStudioModel *pModel = GetModelHelper();
|
||||
if (pModel != NULL)
|
||||
{
|
||||
int iSequence = pModel->GetSequenceIndex( pText );
|
||||
if ( iSequence != -1 )
|
||||
pModel->SetSequence( iSequence );
|
||||
|
||||
pModel->SetFrame( 0 );
|
||||
|
||||
InitScrollRange();
|
||||
|
||||
Options.view3d.bAnimateModels = true; // They've changed sequences, so allow animation again
|
||||
|
||||
CMapDoc *pDoc = CMapDoc::GetActiveMapDoc();
|
||||
if ( pDoc )
|
||||
{
|
||||
pDoc->UpdateAllViews( MAPVIEW_UPDATE_ANIMATION|MAPVIEW_OPTIONS_CHANGED );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
CMapStudioModel *COP_Model::GetModelHelper(void)
|
||||
{
|
||||
if ( m_pObjectList->Count() == 0 )
|
||||
return NULL;
|
||||
|
||||
CMapClass *pObject = (CUtlReference< CMapClass >)m_pObjectList->Element( 0 );
|
||||
|
||||
if (pObject != NULL)
|
||||
{
|
||||
CMapEntity *pEntity = dynamic_cast <CMapEntity *>(pObject);
|
||||
if (pEntity != NULL)
|
||||
{
|
||||
CMapStudioModel *pModel = pEntity->GetChildOfType((CMapStudioModel *)NULL);
|
||||
return pModel;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: sets the controls to be read only
|
||||
// Input : bReadOnly - indicates if the controls should be read only
|
||||
//-----------------------------------------------------------------------------
|
||||
void COP_Model::SetReadOnly( bool bReadOnly )
|
||||
{
|
||||
m_ComboSequence.EnableWindow( bReadOnly ? FALSE : TRUE );
|
||||
m_ScrollBarFrame.EnableWindow( bReadOnly ? FALSE : TRUE );
|
||||
}
|
||||
80
hammer/OP_Model.h
Normal file
80
hammer/OP_Model.h
Normal file
@@ -0,0 +1,80 @@
|
||||
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef OP_MODEL_H
|
||||
#define OP_MODEL_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include "ObjectPage.h"
|
||||
#include "FilteredComboBox.h"
|
||||
|
||||
class GDclass;
|
||||
class CMapStudioModel;
|
||||
|
||||
|
||||
class COP_Model : public CObjectPage, public CFilteredComboBox::ICallbacks
|
||||
{
|
||||
friend class CFilteredModelSequenceComboBox;
|
||||
DECLARE_DYNCREATE(COP_Model)
|
||||
|
||||
public:
|
||||
COP_Model();
|
||||
~COP_Model();
|
||||
|
||||
virtual bool SaveData( SaveData_Reason_t reason );
|
||||
virtual void UpdateData( int Mode, PVOID pData, bool bCanEdit );
|
||||
void UpdateForClass(LPCTSTR pszClass);
|
||||
|
||||
void OnSelChangeSequence( int iSequence );
|
||||
|
||||
|
||||
// Implementation of CFilteredComboBox::ICallbacks.
|
||||
|
||||
virtual void OnTextChanged( const char *pText );
|
||||
|
||||
// Variables.
|
||||
|
||||
GDclass *pObjClass;
|
||||
|
||||
//{{AFX_DATA(COP_Model)
|
||||
enum { IDD = IDD_OBJPAGE_MODEL };
|
||||
CFilteredComboBox m_ComboSequence;
|
||||
CSliderCtrl m_ScrollBarFrame;
|
||||
// DO NOT EDIT what you see in these blocks of generated code !
|
||||
//}}AFX_DATA
|
||||
|
||||
// ClassWizard generate virtual function overrides
|
||||
//{{AFX_VIRTUAL(COP_Model)
|
||||
protected:
|
||||
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
|
||||
//}}AFX_VIRTUAL
|
||||
|
||||
private:
|
||||
void SetReadOnly( bool bReadOnly );
|
||||
|
||||
protected:
|
||||
|
||||
CMapStudioModel *GetModelHelper(void);
|
||||
void UpdateFrameText(int nFrame);
|
||||
void InitScrollRange( void );
|
||||
|
||||
// Generated message map functions
|
||||
//{{AFX_MSG(COP_Model)
|
||||
virtual BOOL OnInitDialog();
|
||||
virtual BOOL OnKillActive();
|
||||
virtual BOOL OnSetActive();
|
||||
afx_msg void OnHScroll(UINT nSBCode, UINT nPos, CScrollBar *pScrollBar);
|
||||
//}}AFX_MSG
|
||||
|
||||
DECLARE_MESSAGE_MAP()
|
||||
|
||||
BOOL m_bOldAnimatedModels;
|
||||
int m_nOldSequence;
|
||||
};
|
||||
|
||||
#endif // OP_MODEL_H
|
||||
76
hammer/ObjectPage.cpp
Normal file
76
hammer/ObjectPage.cpp
Normal file
@@ -0,0 +1,76 @@
|
||||
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "hammer.h"
|
||||
#include "ObjectPage.h"
|
||||
#include "GlobalFunctions.h"
|
||||
#include "ObjectProperties.h"
|
||||
|
||||
|
||||
//
|
||||
// Used to indicate multiselect of entities with different keyvalues.
|
||||
//
|
||||
char *CObjectPage::VALUE_DIFFERENT_STRING = "(different)";
|
||||
|
||||
//
|
||||
// Set while we are changing the page layout.
|
||||
//
|
||||
BOOL CObjectPage::s_bRESTRUCTURING = FALSE;
|
||||
|
||||
|
||||
IMPLEMENT_DYNCREATE(CObjectPage, CPropertyPage)
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: stores whether or not this page can be updated
|
||||
// Input : Mode - unused
|
||||
// pData - unused
|
||||
// bCanEdit - the edit state
|
||||
//-----------------------------------------------------------------------------
|
||||
void CObjectPage::UpdateData( int Mode, PVOID pData, bool bCanEdit )
|
||||
{
|
||||
m_bCanEdit = bCanEdit;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Called when we become the active page.
|
||||
//-----------------------------------------------------------------------------
|
||||
BOOL CObjectPage::OnSetActive(void)
|
||||
{
|
||||
//VPROF_BUDGET( "CObjectPage::OnSetActive", "Object Properties" );
|
||||
|
||||
if (CObjectPage::s_bRESTRUCTURING || !GetActiveWorld())
|
||||
{
|
||||
return CPropertyPage::OnSetActive();
|
||||
}
|
||||
|
||||
CObjectProperties *pParent = (CObjectProperties *)GetParent();
|
||||
|
||||
pParent->UpdateAnchors( this );
|
||||
|
||||
if (m_bFirstTimeActive)
|
||||
{
|
||||
m_bFirstTimeActive = false;
|
||||
pParent->LoadDataForPages(pParent->GetPageIndex(this));
|
||||
}
|
||||
|
||||
return CPropertyPage::OnSetActive();
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
PVOID CObjectPage::GetEditObject()
|
||||
{
|
||||
//VPROF_BUDGET( "CObjectPage::GetEditObject", "Object Properties" );
|
||||
return ((CObjectProperties*) GetParent())->GetEditObject(GetEditObjectRuntimeClass());
|
||||
}
|
||||
|
||||
|
||||
17
hammer/PopupMenus.h
Normal file
17
hammer/PopupMenus.h
Normal file
@@ -0,0 +1,17 @@
|
||||
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef POPUPMENUS_H
|
||||
#define POPUPMENUS_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
|
||||
#define IDM_POPUP_POINT_HANDLE 7
|
||||
|
||||
|
||||
#endif // POPUPMENUS_H
|
||||
1620
hammer/Render.cpp
Normal file
1620
hammer/Render.cpp
Normal file
File diff suppressed because it is too large
Load Diff
319
hammer/Render.h
Normal file
319
hammer/Render.h
Normal file
@@ -0,0 +1,319 @@
|
||||
//===== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//===========================================================================//
|
||||
|
||||
#ifndef RENDER_H
|
||||
#define RENDER_H
|
||||
#pragma once
|
||||
|
||||
#include "Color.h"
|
||||
#include "utlstack.h"
|
||||
#include "hammer_mathlib.h"
|
||||
#include "MaterialSystem\imesh.h"
|
||||
#include "shaderapi/ishaderapi.h"
|
||||
|
||||
class IMaterial;
|
||||
struct DrawModelInfo_t;
|
||||
class CCoreDispInfo;
|
||||
class CMapView;
|
||||
class CCamera;
|
||||
class CMapAtom;
|
||||
class IEditorTexture;
|
||||
class CMapClass;
|
||||
class CMapInstance;
|
||||
|
||||
typedef unsigned short MDLHandle_t;
|
||||
|
||||
#define CAMERA_FRONT_PLANE_DISTANCE 8.0f
|
||||
#define CAMERA_HORIZONTAL_FOV 90.0f
|
||||
|
||||
//
|
||||
// Colors for selected faces and edges. Kinda hacky; should probably be elsewhere.
|
||||
//
|
||||
#define SELECT_FACE_RED 220
|
||||
#define SELECT_FACE_GREEN 0
|
||||
#define SELECT_FACE_BLUE 0
|
||||
|
||||
#define SELECT_EDGE_RED 255
|
||||
#define SELECT_EDGE_GREEN 255
|
||||
#define SELECT_EDGE_BLUE 0
|
||||
|
||||
|
||||
inline void SelectFaceColor( Color &pColor )
|
||||
{
|
||||
pColor[0] = SELECT_FACE_RED;
|
||||
pColor[1] = SELECT_FACE_GREEN;
|
||||
pColor[2] = SELECT_FACE_BLUE;
|
||||
}
|
||||
|
||||
inline void SelectEdgeColor( Color &pColor )
|
||||
{
|
||||
pColor[0] = SELECT_EDGE_RED;
|
||||
pColor[1] = SELECT_EDGE_GREEN;
|
||||
pColor[2] = SELECT_EDGE_BLUE;
|
||||
}
|
||||
|
||||
inline void InstanceColor( Color &pColor, bool bSelected )
|
||||
{
|
||||
if ( bSelected )
|
||||
{
|
||||
pColor[ 0 ] = 192;
|
||||
pColor[ 1 ] = 128;
|
||||
pColor[ 2 ] = 0;
|
||||
pColor[ 3 ] = 192;
|
||||
}
|
||||
else
|
||||
{
|
||||
pColor[ 0 ] = 128;
|
||||
pColor[ 1 ] = 128;
|
||||
pColor[ 2 ] = 0;
|
||||
pColor[ 3 ] = 192;
|
||||
}
|
||||
}
|
||||
|
||||
enum EditorRenderMode_t
|
||||
{
|
||||
RENDER_MODE_NONE = 0, // dont render anything
|
||||
RENDER_MODE_EXTERN, // other system is using material system
|
||||
RENDER_MODE_DEFAULT, // select default material
|
||||
RENDER_MODE_CURRENT, // the current render mode
|
||||
RENDER_MODE_WIREFRAME, // wire frame mode
|
||||
RENDER_MODE_FLAT, // flat solid colors
|
||||
RENDER_MODE_FLAT_NOZ, // flat solid colors, ignore Z
|
||||
RENDER_MODE_FLAT_NOCULL, // flat solid colors, no backface culling
|
||||
RENDER_MODE_DOTTED, // flat colored dotted, ignore Z
|
||||
RENDER_MODE_TRANSLUCENT_FLAT,
|
||||
RENDER_MODE_TEXTURED,
|
||||
RENDER_MODE_LIGHTMAP_GRID,
|
||||
RENDER_MODE_SELECTION_OVERLAY,
|
||||
RENDER_MODE_SMOOTHING_GROUP,
|
||||
RENDER_MODE_TEXTURED_SHADED,
|
||||
RENDER_MODE_LIGHT_PREVIEW2,
|
||||
RENDER_MODE_LIGHT_PREVIEW_RAYTRACED,
|
||||
RENDER_MODE_INSTANCE_OVERLAY,
|
||||
};
|
||||
|
||||
|
||||
enum InstanceRenderingState_t
|
||||
{
|
||||
INSTANCE_STATE_OFF, // normal rendering
|
||||
INSTANCE_STATE_ON, // will be tinted as an instance
|
||||
INSTANCE_STACE_SELECTED // will be tinted as a selected instance
|
||||
};
|
||||
|
||||
|
||||
typedef struct SInstanceState
|
||||
{
|
||||
CMapInstance *m_pInstanceClass; // the func_instance entity
|
||||
Vector m_InstanceOrigin; // the origin offset of instance rendering
|
||||
QAngle m_InstanceAngles; // the rotation of the instance rendering
|
||||
VMatrix m_InstanceMatrix; // matrix of the origin and rotation of rendering
|
||||
VMatrix m_InstanceRenderMatrix; // matrix of the current camera transform
|
||||
bool m_bIsEditable;
|
||||
CMapInstance *m_pTopInstanceClass;
|
||||
} TInstanceState;
|
||||
|
||||
|
||||
//#define STENCIL_AS_CALLS 1
|
||||
|
||||
|
||||
class CRender
|
||||
{
|
||||
public:
|
||||
CRender(void);
|
||||
virtual ~CRender(void);
|
||||
|
||||
|
||||
|
||||
enum
|
||||
{ TEXT_SINGLELINE = 0x1, // put all of the text on one line
|
||||
TEXT_MULTILINE = 0x2, // the text is written on multiple lines
|
||||
TEXT_JUSTIFY_BOTTOM = 0x4, // default
|
||||
TEXT_JUSTIFY_TOP = 0x8,
|
||||
TEXT_JUSTIFY_RIGHT = 0x10, // default
|
||||
TEXT_JUSTIFY_LEFT = 0x20,
|
||||
TEXT_JUSTIFY_HORZ_CENTER = 0x40,
|
||||
TEXT_JUSTIFY_VERT_CENTER = 0x80,
|
||||
TEXT_CLEAR_BACKGROUND = 0x100
|
||||
}; // clear the background behind the text
|
||||
|
||||
enum
|
||||
{ HANDLE_NONE = 0,
|
||||
HANDLE_SQUARE,
|
||||
HANDLE_CIRCLE,
|
||||
HANDLE_DIAMOND,
|
||||
HANDLE_CROSS
|
||||
};
|
||||
|
||||
// map view setup
|
||||
virtual bool SetView( CMapView *pView );
|
||||
|
||||
CMapView *GetView() { return m_pView; }
|
||||
CCamera *GetCamera();// { return m_pView->GetCamera(); }
|
||||
bool IsActiveView();
|
||||
|
||||
// begin/end single render frame, sets up camera etc
|
||||
virtual void StartRenderFrame( bool bRenderingOverEngine );
|
||||
virtual void EndRenderFrame();
|
||||
int GetRenderFrame() { return m_nFrameCount; }
|
||||
|
||||
// switch rendering to client space coordinates (horz,vert,ignore)
|
||||
// render is in world space mode by default
|
||||
bool BeginClientSpace(void);
|
||||
void EndClientSpace(void);
|
||||
bool IsInClientSpace() { return m_bIsClientSpace; }
|
||||
|
||||
void BeginLocalTransfrom( const VMatrix &matrix, bool MultiplyCurrent = false );
|
||||
void EndLocalTransfrom();
|
||||
bool IsInLocalTransformMode();
|
||||
void GetLocalTranform( VMatrix &matrix );
|
||||
|
||||
void SetTextColor( unsigned char r, unsigned char g, unsigned char b, unsigned char a = 255 );
|
||||
void SetDrawColor( unsigned char r, unsigned char g, unsigned char b );
|
||||
void SetDrawColor( const Color &color );
|
||||
void GetDrawColor( Color &color );
|
||||
void SetHandleColor( unsigned char r, unsigned char g, unsigned char b );
|
||||
|
||||
void SetHandleStyle( int size, int type );
|
||||
|
||||
void SetDefaultRenderMode(EditorRenderMode_t eRenderMode);
|
||||
void BindTexture(IEditorTexture *pTexture);
|
||||
void BindMaterial( IMaterial *pMaterial );
|
||||
|
||||
virtual void SetRenderMode( EditorRenderMode_t eRenderMode, bool force = false);
|
||||
inline EditorRenderMode_t GetCurrentRenderMode() { return m_eCurrentRenderMode; }
|
||||
inline EditorRenderMode_t GetDefaultRenderMode() { return m_eDefaultRenderMode; }
|
||||
|
||||
void PushRenderMode( EditorRenderMode_t eRenderMode );
|
||||
void PopRenderMode();
|
||||
|
||||
// drawing primitives
|
||||
void DrawPoint( const Vector &vPoint );
|
||||
void DrawLine( const Vector &vStart, const Vector &vEnd );
|
||||
virtual void DrawBox( const Vector &vMins, const Vector &vMaxs, bool bFill = false );
|
||||
void DrawBoxExt( const Vector &vCenter, float extend, bool bFill = false );
|
||||
void DrawSphere( const Vector &vCenter, int nRadius );
|
||||
void DrawCircle( const Vector &vCenter, const Vector &vNormal, float flRadius, int nSegments );
|
||||
void DrawPolyLine( int nPoints, const Vector *Points );
|
||||
void DrawText( const char *text, int x, int y, int nFlags ); // Uses pixel coordinates
|
||||
void DrawText( const char *text, const Vector2D &vPos, int nOffsetX, int nOffsetY, int nFlags ); // Uses "world" coordinates
|
||||
void DrawHandle( const Vector &vPoint, const Vector2D *vOffset = NULL );
|
||||
void DrawHandles( int nPoints, const Vector *Points );
|
||||
void DrawArrow( Vector const &vStart, Vector const &vEnd );
|
||||
void DrawPlane( const Vector &p0, const Vector &p1, const Vector &p2, const Vector &p3, bool bFill = false );
|
||||
|
||||
// client space helper functions:
|
||||
void DrawFilledRect( Vector2D& pt1, Vector2D& pt2, unsigned char *pColor, bool bBorder );
|
||||
|
||||
// drawing complex objects
|
||||
void DrawModel( DrawModelInfo_t* pInfo, matrix3x4_t *pBoneToWorld, const Vector &vOrigin, float fAlpha = 1, bool bWireframe = false, const Color &color = Color( 255, 255, 255, 255 ) );
|
||||
void DrawDisplacement( CCoreDispInfo *pDisp );
|
||||
void DrawCollisionModel( MDLHandle_t mdlHandle, const VMatrix &mViewMatrix );
|
||||
|
||||
|
||||
//
|
||||
// helper funtions
|
||||
//
|
||||
void TransformPoint( Vector2D &vClient, const Vector& vWorld );
|
||||
void TransformNormal( Vector2D &vClient, const Vector& vWorld );
|
||||
|
||||
void GetViewForward( Vector &ViewForward ) const;
|
||||
void GetViewRight( Vector &ViewRight ) const;
|
||||
void GetViewUp( Vector &ViewUp ) const;
|
||||
|
||||
void PrepareInstanceStencil( void );
|
||||
void DrawInstanceStencil( void );
|
||||
void PushInstanceRendering( InstanceRenderingState_t State );
|
||||
void PopInstanceRendering( void );
|
||||
void SetInstanceRendering( InstanceRenderingState_t State );
|
||||
|
||||
void SetInstanceRendering( bool InstanceRendering ) { m_bInstanceRendering = InstanceRendering; }
|
||||
virtual void PushInstanceData( CMapInstance *pInstanceClass, Vector &InstanceOrigin, QAngle &InstanceAngles );
|
||||
virtual void PopInstanceData( void );
|
||||
bool GetInstanceRendering( void ) { return m_bInstanceRendering; }
|
||||
CMapInstance *GetInstanceClass( void ) { return m_CurrentInstanceState.m_pInstanceClass; }
|
||||
void GetInstanceMatrix( VMatrix &Matrix ) { Matrix = m_CurrentInstanceState.m_InstanceMatrix; }
|
||||
Vector GetInstanceOrigin( void ) { return m_CurrentInstanceState.m_InstanceOrigin; }
|
||||
QAngle GetInstanceAngle( void ) { return m_CurrentInstanceState.m_InstanceAngles; }
|
||||
void TransformInstanceVector( Vector &In, Vector &Out ) { m_CurrentInstanceState.m_InstanceMatrix.V3Mul( In, Out ); }
|
||||
void RotateInstanceVector( Vector &In, Vector &Out ) { VectorRotate( In, m_CurrentInstanceState.m_InstanceMatrix.As3x4(), Out ); }
|
||||
void TransformInstanceAABB( Vector &InMins, Vector &InMaxs, Vector &OutMins, Vector &OutMaxs ) { TransformAABB( m_CurrentInstanceState.m_InstanceMatrix.As3x4(), InMins, InMaxs, OutMins, OutMaxs ); }
|
||||
|
||||
protected:
|
||||
|
||||
bool GetRequiredMaterial( const char *pName, IMaterial* &pMaterial );
|
||||
void UpdateStudioRenderConfig( bool bFlat, bool bWireframe );
|
||||
// client space helper functions:
|
||||
void DrawCross( Vector2D& pt1, Vector2D& pt2, unsigned char *pColor );
|
||||
void DrawCircle( Vector2D &vCenter, float fRadius, int nSegments, unsigned char *pColor );
|
||||
void DrawRect( Vector2D& pt1, Vector2D& pt2, unsigned char *pColor );
|
||||
|
||||
protected:
|
||||
CMapView *m_pView;
|
||||
unsigned long m_DefaultFont;
|
||||
bool m_bIsClientSpace;
|
||||
|
||||
bool m_bIsLocalTransform;
|
||||
CUtlVector< VMatrix > m_LocalMatrix;
|
||||
|
||||
VMatrix m_OrthoMatrix;
|
||||
|
||||
// Are we rendering on top of the engine's view? If so, we avoid certain view setup things and we avoid drawing world geometry.
|
||||
bool m_bRenderingOverEngine;
|
||||
|
||||
// Meshbuilder used for drawing
|
||||
IMesh* m_pMesh;
|
||||
CMeshBuilder meshBuilder;
|
||||
|
||||
// colors
|
||||
Color m_DrawColor; // current draw/fill color
|
||||
Color m_TextColor; // current text color
|
||||
Color m_HandleColor; // current text color
|
||||
|
||||
// handle styles
|
||||
int m_nHandleSize;
|
||||
int m_nHandleType;
|
||||
|
||||
// frame count
|
||||
int m_nFrameCount; // increases each setup camera
|
||||
bool m_bIsRendering;
|
||||
bool m_bIsRenderingIntoVGUI;
|
||||
|
||||
// materials
|
||||
IMaterial* m_pCurrentMaterial; // The currently bound material
|
||||
IMaterial* m_pBoundMaterial; // a material given from external caller
|
||||
|
||||
int m_nDecalMode; // 0 or 1
|
||||
IMaterial* m_pWireframe[2]; // default wireframe material
|
||||
IMaterial* m_pFlat[2]; // default flat material
|
||||
IMaterial* m_pDotted[2]; // default dotted material
|
||||
IMaterial* m_pFlatNoZ[2]; // default flat material, ignore Z
|
||||
IMaterial* m_pFlatNoCull[2]; // default flat material, no backface cull
|
||||
IMaterial* m_pTranslucentFlat[2]; // default translucent flat material
|
||||
IMaterial* m_pLightmapGrid[2]; // default lightmap grid material
|
||||
IMaterial* m_pSelectionOverlay[2]; // for selecting actual textures
|
||||
|
||||
// render modes
|
||||
EditorRenderMode_t m_eCurrentRenderMode; // Current render mode setting - Wireframe, flat, or textured.
|
||||
EditorRenderMode_t m_eDefaultRenderMode; // Default render mode - Wireframe, flat, or textured.
|
||||
CUtlStack<EditorRenderMode_t> m_RenderModeStack;
|
||||
|
||||
// instance
|
||||
int m_nInstanceCount; // increases each time an instance is drawn regardless of view
|
||||
bool m_bInstanceRendering; // if true, we are rendering an instance
|
||||
VMatrix m_CurrentMatrix; // matrix of the current transforms
|
||||
int m_InstanceSelectionDepth;
|
||||
TInstanceState m_CurrentInstanceState; // the current instance state ( with current transforms )
|
||||
CUtlVector< TInstanceState > m_InstanceState; // the instance state stack
|
||||
#ifndef STENCIL_AS_CALLS
|
||||
ShaderStencilState_t m_ShaderStencilState;
|
||||
#endif // STENCIL_AS_CALLS
|
||||
int m_nNumInstancesRendered; // number of instances rendered that impacted the stencil buffer
|
||||
CUtlVector< InstanceRenderingState_t > m_InstanceRenderingState; // the instance rendering state stack
|
||||
|
||||
};
|
||||
|
||||
#endif // RENDER_H
|
||||
95
hammer/RenderUtils.cpp
Normal file
95
hammer/RenderUtils.cpp
Normal file
@@ -0,0 +1,95 @@
|
||||
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "Render2D.h"
|
||||
#include "RenderUtils.h"
|
||||
#include "mapview2d.h"
|
||||
#include "toolinterface.h"
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Draws the measurements of a brush in the 2D view.
|
||||
// Input : pRender -
|
||||
// Mins -
|
||||
// Maxs -
|
||||
// nFlags -
|
||||
//-----------------------------------------------------------------------------
|
||||
void DrawBoundsText(CRender2D *pRender, const Vector &Mins, const Vector &Maxs, int nFlags)
|
||||
{
|
||||
CMapView2D *pView = (CMapView2D*) pRender->GetView();
|
||||
|
||||
// Calculate the solid's extents along our 2D view axes.
|
||||
Vector Extents = Maxs - Mins;
|
||||
Vector Center = (Mins + Maxs ) * 0.5f;
|
||||
|
||||
for ( int i=0; i<3;i++ )
|
||||
Extents[i] = fabs(Extents[i]);
|
||||
|
||||
// Transform the solids mins and maxs to 2D view space. These are used
|
||||
// for placing the text in the view.
|
||||
Vector2D projMins, projMaxs, projCenter;
|
||||
pRender->TransformPoint( projMins, Mins );
|
||||
pRender->TransformPoint( projMaxs, Maxs );
|
||||
pRender->TransformPoint( projCenter, Center );
|
||||
|
||||
if( projMins.x > projMaxs.x )
|
||||
{
|
||||
V_swap( projMins.x, projMaxs.x );
|
||||
}
|
||||
|
||||
if( projMins.y > projMaxs.y )
|
||||
{
|
||||
V_swap( projMins.y, projMaxs.y );
|
||||
}
|
||||
|
||||
//
|
||||
// display the extents of this brush
|
||||
//
|
||||
char extentText[30];
|
||||
int nTextX, nTextY;
|
||||
int nTextFlags;
|
||||
|
||||
pRender->SetTextColor( 255, 255, 255 );
|
||||
|
||||
// horz
|
||||
sprintf( extentText, "%.1f", Extents[pView->axHorz] );
|
||||
nTextFlags = CRender2D::TEXT_JUSTIFY_HORZ_CENTER;
|
||||
nTextX = projCenter.x;
|
||||
|
||||
if ( nFlags & DBT_TOP )
|
||||
{
|
||||
nTextY = projMins.y - (HANDLE_RADIUS*3);
|
||||
nTextFlags |= CRender2D::TEXT_JUSTIFY_TOP;
|
||||
}
|
||||
else
|
||||
{
|
||||
nTextY = projMaxs.y + (HANDLE_RADIUS*3);
|
||||
nTextFlags |= CRender2D::TEXT_JUSTIFY_BOTTOM;
|
||||
}
|
||||
|
||||
pRender->DrawText( extentText, nTextX, nTextY, nTextFlags );
|
||||
|
||||
// vert
|
||||
sprintf( extentText, "%.1f", Extents[pView->axVert] );
|
||||
nTextFlags = CRender2D::TEXT_JUSTIFY_VERT_CENTER;
|
||||
nTextY = projCenter.y;
|
||||
|
||||
if ( nFlags & DBT_LEFT )
|
||||
{
|
||||
nTextX = projMins.x - (HANDLE_RADIUS*3);
|
||||
nTextFlags |= CRender2D::TEXT_JUSTIFY_LEFT;
|
||||
}
|
||||
else
|
||||
{
|
||||
nTextX = projMaxs.x + (HANDLE_RADIUS*3);
|
||||
nTextFlags |= CRender2D::TEXT_JUSTIFY_RIGHT;
|
||||
}
|
||||
|
||||
pRender->DrawText( extentText, nTextX, nTextY, nTextFlags );
|
||||
}
|
||||
|
||||
|
||||
30
hammer/RenderUtils.h
Normal file
30
hammer/RenderUtils.h
Normal file
@@ -0,0 +1,30 @@
|
||||
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef RENDERUTILS_H
|
||||
#define RENDERUTILS_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
|
||||
class CRender2D;
|
||||
|
||||
//
|
||||
// Flags for DrawBoundsText
|
||||
//
|
||||
#define DBT_TOP 0x1
|
||||
#define DBT_BOTTOM 0x2
|
||||
#define DBT_LEFT 0x4
|
||||
#define DBT_RIGHT 0x8
|
||||
#define DBT_BACK 0x10
|
||||
|
||||
|
||||
void DrawBoundsText(CRender2D *pRender, const Vector &Mins, const Vector &Maxs, int nFlags);
|
||||
|
||||
|
||||
#endif // RENDERUTILS_H
|
||||
200
hammer/ScenePreviewDlg.cpp
Normal file
200
hammer/ScenePreviewDlg.cpp
Normal file
@@ -0,0 +1,200 @@
|
||||
//====== Copyright © 1996-2005, Valve Corporation, All rights reserved. =======
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "hammer.h"
|
||||
#include "ScenePreviewDlg.h"
|
||||
#include "choreoscene.h"
|
||||
#include "soundsystem.h"
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include <tier0/memdbgon.h>
|
||||
|
||||
|
||||
#define WM_SCENEPREVIEW_IDLE (WM_USER+1)
|
||||
|
||||
|
||||
BEGIN_MESSAGE_MAP(CScenePreviewDlg, CDialog)
|
||||
//{{AFX_MSG_MAP(CScenePreviewDlg)
|
||||
ON_BN_CLICKED(IDCANCEL, OnCancel)
|
||||
//}}AFX_MSG_MAP
|
||||
END_MESSAGE_MAP()
|
||||
|
||||
|
||||
CScenePreviewDlg::CScenePreviewDlg( CChoreoScene *pScene, const char *pFilename, CWnd* pParent /*=NULL*/ )
|
||||
: CDialog(CScenePreviewDlg::IDD, pParent)
|
||||
{
|
||||
//{{AFX_DATA_INIT(CScenePreviewDlg)
|
||||
m_pScene = pScene;
|
||||
m_iLastEventPlayed = -2; // Don't do anything yet.
|
||||
m_hExitThreadEvent = NULL;
|
||||
m_hIdleEventHandledEvent = NULL;
|
||||
m_hIdleThread = NULL;
|
||||
V_strncpy( m_SceneFilename, pFilename, sizeof( m_SceneFilename ) );
|
||||
}
|
||||
|
||||
|
||||
CScenePreviewDlg::~CScenePreviewDlg()
|
||||
{
|
||||
EndThread();
|
||||
delete m_pScene;
|
||||
}
|
||||
|
||||
|
||||
void CScenePreviewDlg::EndThread()
|
||||
{
|
||||
if ( m_hIdleThread )
|
||||
{
|
||||
SetEvent( m_hExitThreadEvent );
|
||||
WaitForSingleObject( m_hIdleThread, INFINITE );
|
||||
CloseHandle( m_hIdleThread );
|
||||
CloseHandle( m_hExitThreadEvent );
|
||||
CloseHandle( m_hIdleEventHandledEvent );
|
||||
m_hIdleThread = m_hExitThreadEvent = m_hIdleEventHandledEvent = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
BOOL CScenePreviewDlg::OnInitDialog()
|
||||
{
|
||||
CDialog::OnInitDialog();
|
||||
|
||||
// Setup the control showing the scene name.
|
||||
CString str;
|
||||
GetDlgItemText( IDC_SCENE_NAME, str );
|
||||
str = str + " " + m_SceneFilename;
|
||||
SetDlgItemText( IDC_SCENE_NAME, str );
|
||||
|
||||
CString strNone;
|
||||
strNone.LoadString( IDS_NONE );
|
||||
SetDlgItemText( IDC_CURRENT_SOUND, strNone );
|
||||
SetDlgItemText( IDC_NEXT_SOUND, strNone );
|
||||
|
||||
m_iLastEventPlayed = -1;
|
||||
m_flStartTime = Plat_FloatTime();
|
||||
|
||||
// Start on the first event..
|
||||
for ( int i = 0; i < m_pScene->GetNumEvents(); i++ )
|
||||
{
|
||||
CChoreoEvent *e = m_pScene->GetEvent( i );
|
||||
if ( e && e->GetType() == CChoreoEvent::SPEAK )
|
||||
{
|
||||
m_flStartTime -= e->GetStartTime();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Create our idle thread.
|
||||
m_hExitThreadEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
|
||||
m_hIdleEventHandledEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
|
||||
m_hIdleThread = CreateThread( NULL, 0, &CScenePreviewDlg::StaticIdleThread, this, 0, NULL );
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
DWORD CScenePreviewDlg::StaticIdleThread( LPVOID pParameter )
|
||||
{
|
||||
return ((CScenePreviewDlg*)pParameter)->IdleThread();
|
||||
}
|
||||
|
||||
DWORD CScenePreviewDlg::IdleThread()
|
||||
{
|
||||
HANDLE handles[2] = {m_hExitThreadEvent, m_hIdleEventHandledEvent};
|
||||
|
||||
while ( 1 )
|
||||
{
|
||||
// Send the event to the window.
|
||||
PostMessage( WM_SCENEPREVIEW_IDLE, 0, 0 );
|
||||
|
||||
DWORD ret = WaitForMultipleObjects( ARRAYSIZE( handles ), handles, false, INFINITE );
|
||||
if ( ret == WAIT_OBJECT_0 || ret == WAIT_TIMEOUT )
|
||||
return 0;
|
||||
|
||||
Sleep( 100 ); // Only handle idle 10x/sec.
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void CScenePreviewDlg::OnIdle()
|
||||
{
|
||||
double flElapsed = Plat_FloatTime() - m_flStartTime;
|
||||
|
||||
// Find the next sound to play.
|
||||
int iLastSound = -1;
|
||||
for ( int i = 0; i < m_pScene->GetNumEvents(); i++ )
|
||||
{
|
||||
CChoreoEvent *e = m_pScene->GetEvent( i );
|
||||
if ( !e || e->GetType() != CChoreoEvent::SPEAK )
|
||||
continue;
|
||||
|
||||
if ( flElapsed > e->GetStartTime() )
|
||||
iLastSound = i;
|
||||
}
|
||||
|
||||
// Is there another sound to play in here?
|
||||
if ( iLastSound >= 0 && iLastSound != m_iLastEventPlayed )
|
||||
{
|
||||
m_iLastEventPlayed = iLastSound;
|
||||
|
||||
// Play the current sound.
|
||||
CChoreoEvent *e = m_pScene->GetEvent( iLastSound );
|
||||
const char *pSoundName = e->GetParameters();
|
||||
|
||||
SoundType_t soundType;
|
||||
int nIndex;
|
||||
if ( g_Sounds.FindSoundByName( pSoundName, &soundType, &nIndex ) )
|
||||
{
|
||||
bool bRet = g_Sounds.Play( soundType, nIndex );
|
||||
|
||||
CString curSound = pSoundName;
|
||||
if ( !bRet )
|
||||
{
|
||||
CString strErrorPlaying;
|
||||
strErrorPlaying.LoadString( IDS_ERROR_PLAYING );
|
||||
curSound += " " + strErrorPlaying;
|
||||
}
|
||||
SetDlgItemText( IDC_CURRENT_SOUND, curSound );
|
||||
}
|
||||
|
||||
// Find the next sound event.
|
||||
CString str;
|
||||
str.LoadString( IDS_NONE );
|
||||
for ( int i=iLastSound+1; i < m_pScene->GetNumEvents(); i++ )
|
||||
{
|
||||
CChoreoEvent *e = m_pScene->GetEvent( i );
|
||||
if ( e && e->GetType() == CChoreoEvent::SPEAK )
|
||||
{
|
||||
str = e->GetParameters();
|
||||
break;
|
||||
}
|
||||
}
|
||||
SetDlgItemText( IDC_NEXT_SOUND, str );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
LRESULT CScenePreviewDlg::DefWindowProc( UINT message, WPARAM wParam, LPARAM lParam )
|
||||
{
|
||||
// We handle the enter key specifically because the default combo box behavior is to
|
||||
// reset the text and all this stuff we don't want.
|
||||
if ( message == WM_SCENEPREVIEW_IDLE )
|
||||
{
|
||||
OnIdle();
|
||||
SetEvent( m_hIdleEventHandledEvent );
|
||||
return 0;
|
||||
}
|
||||
|
||||
return CDialog::DefWindowProc( message, wParam, lParam );
|
||||
}
|
||||
|
||||
|
||||
void CScenePreviewDlg::OnCancel(void)
|
||||
{
|
||||
g_Sounds.StopSound();
|
||||
EndThread();
|
||||
EndDialog( 0 );
|
||||
}
|
||||
59
hammer/ScenePreviewDlg.h
Normal file
59
hammer/ScenePreviewDlg.h
Normal file
@@ -0,0 +1,59 @@
|
||||
//====== Copyright © 1996-2005, Valve Corporation, All rights reserved. =======
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
#ifndef SCENEPREVIEWDLG_H
|
||||
#define SCENEPREVIEWDLG_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
|
||||
class CChoreoScene;
|
||||
|
||||
|
||||
class CScenePreviewDlg : public CDialog
|
||||
{
|
||||
// Construction
|
||||
public:
|
||||
// Note: the dialog now owns the scene and it'll delete it when it goes away.
|
||||
CScenePreviewDlg( CChoreoScene *pScene, const char *pSceneFilename, CWnd* pParent = NULL ); // standard constructor
|
||||
virtual ~CScenePreviewDlg();
|
||||
|
||||
// Dialog Data
|
||||
//{{AFX_DATA(CSoundBrowser)
|
||||
DECLARE_MESSAGE_MAP()
|
||||
enum { IDD = IDD_SCENE_PREVIEW };
|
||||
|
||||
|
||||
protected:
|
||||
BOOL OnInitDialog();
|
||||
virtual LRESULT DefWindowProc( UINT message, WPARAM wParam, LPARAM lParam );
|
||||
virtual void OnCancel(void);
|
||||
|
||||
|
||||
private:
|
||||
static DWORD WINAPI StaticIdleThread( LPVOID pParameter );
|
||||
DWORD IdleThread();
|
||||
|
||||
void OnIdle();
|
||||
void EndThread();
|
||||
|
||||
|
||||
private:
|
||||
CChoreoScene *m_pScene;
|
||||
|
||||
HANDLE m_hExitThreadEvent;
|
||||
HANDLE m_hIdleEventHandledEvent;
|
||||
|
||||
HANDLE m_hIdleThread;
|
||||
|
||||
int m_iLastEventPlayed; // Last sound event we handled.
|
||||
double m_flStartTime; // When we started playing the scene.
|
||||
char m_SceneFilename[MAX_PATH];
|
||||
};
|
||||
|
||||
|
||||
#endif // SCENEPREVIEWDLG_H
|
||||
599
hammer/SearchReplaceDlg.cpp
Normal file
599
hammer/SearchReplaceDlg.cpp
Normal file
@@ -0,0 +1,599 @@
|
||||
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "History.h"
|
||||
#include "GlobalFunctions.h"
|
||||
#include "MapDoc.h"
|
||||
#include "MapWorld.h"
|
||||
#include "SearchReplaceDlg.h"
|
||||
#include "hammer.h"
|
||||
#include "Selection.h"
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include <tier0/memdbgon.h>
|
||||
|
||||
|
||||
//
|
||||
// Context data for a FindFirstObject/FindNextObject session.
|
||||
//
|
||||
struct FindObject_t
|
||||
{
|
||||
//
|
||||
// Where to look: in the world or in the selection set.
|
||||
//
|
||||
FindReplaceIn_t eFindIn;
|
||||
|
||||
CMapWorld *pWorld;
|
||||
EnumChildrenPos_t WorldPos; // A position in the world tree for world searches.
|
||||
|
||||
CMapObjectRefList SelectionList; // A copy of the selection list for selection only searches.
|
||||
int nSelectionIndex; // The index into the selection list for iterating the selection list.
|
||||
|
||||
//
|
||||
// What to look for.
|
||||
//
|
||||
CString strFindText;
|
||||
bool bVisiblesOnly;
|
||||
bool bCaseSensitive;
|
||||
bool bWholeWord;
|
||||
};
|
||||
|
||||
|
||||
CMapClass *FindNextObject(FindObject_t &FindObject);
|
||||
bool FindCheck(CMapClass *pObject, FindObject_t &FindObject);
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Returns true if the string matches the search criteria, false if not.
|
||||
// Input : pszString - String to check.
|
||||
// FindObject - Search criteria, including string to search for.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool MatchString(const char *pszString, FindObject_t &FindObject)
|
||||
{
|
||||
if (FindObject.bWholeWord)
|
||||
{
|
||||
if (FindObject.bCaseSensitive)
|
||||
{
|
||||
return (!strcmp(pszString, FindObject.strFindText));
|
||||
}
|
||||
|
||||
return (!stricmp(pszString, FindObject.strFindText));
|
||||
}
|
||||
|
||||
if (FindObject.bCaseSensitive)
|
||||
{
|
||||
return (strstr(pszString, FindObject.strFindText) != NULL);
|
||||
}
|
||||
|
||||
return (Q_stristr(pszString, FindObject.strFindText) != NULL);
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Returns true if the string matches the search criteria, false if not.
|
||||
// Input : pszIn -
|
||||
// pszOut - String to check.
|
||||
// FindObject - Search criteria, including string to search for.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool ReplaceString(char *pszOut, const char *pszIn, FindObject_t &FindObject, const char *pszReplace)
|
||||
{
|
||||
//
|
||||
// Whole matches are simple, just strcpy the replacement string into the out buffer.
|
||||
//
|
||||
if (FindObject.bWholeWord)
|
||||
{
|
||||
if (FindObject.bCaseSensitive && (!strcmp(pszIn, FindObject.strFindText)))
|
||||
{
|
||||
strcpy(pszOut, pszReplace);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!stricmp(pszIn, FindObject.strFindText))
|
||||
{
|
||||
strcpy(pszOut, pszReplace);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Partial matches are a little tougher.
|
||||
//
|
||||
const char *pszStart = NULL;
|
||||
if (FindObject.bCaseSensitive)
|
||||
{
|
||||
pszStart = strstr(pszIn, FindObject.strFindText);
|
||||
}
|
||||
else
|
||||
{
|
||||
pszStart = Q_stristr(pszIn, FindObject.strFindText);
|
||||
}
|
||||
|
||||
if (pszStart != NULL)
|
||||
{
|
||||
int nOffset = pszStart - pszIn;
|
||||
|
||||
strncpy(pszOut, pszIn, nOffset);
|
||||
pszOut += nOffset;
|
||||
pszIn += nOffset + strlen(FindObject.strFindText);
|
||||
|
||||
strcpy(pszOut, pszReplace);
|
||||
pszOut += strlen(pszReplace);
|
||||
|
||||
strcpy(pszOut, pszIn);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Begins a Find or Find/Replace operation.
|
||||
//-----------------------------------------------------------------------------
|
||||
CMapClass *FindFirstObject(FindObject_t &FindObject)
|
||||
{
|
||||
CMapClass *pObject = NULL;
|
||||
|
||||
if (FindObject.eFindIn == FindInWorld)
|
||||
{
|
||||
// Search the entire world.
|
||||
pObject = FindObject.pWorld->GetFirstDescendent(FindObject.WorldPos);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Search the selection only.
|
||||
if (FindObject.SelectionList.Count())
|
||||
{
|
||||
pObject = FindObject.SelectionList.Element(0);
|
||||
FindObject.nSelectionIndex = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (!pObject)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (FindCheck(pObject, FindObject))
|
||||
{
|
||||
return pObject;
|
||||
}
|
||||
|
||||
return FindNextObject(FindObject);
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : pObject -
|
||||
//-----------------------------------------------------------------------------
|
||||
CMapClass *FindNextObject(FindObject_t &FindObject)
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
CMapClass *pObject = NULL;
|
||||
if (FindObject.eFindIn == FindInWorld)
|
||||
{
|
||||
// Search the entire world.
|
||||
pObject = FindObject.pWorld->GetNextDescendent(FindObject.WorldPos);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Search the selection only.
|
||||
if (FindObject.nSelectionIndex < FindObject.SelectionList.Count())
|
||||
{
|
||||
pObject = FindObject.SelectionList.Element(FindObject.nSelectionIndex);
|
||||
FindObject.nSelectionIndex++;
|
||||
}
|
||||
}
|
||||
|
||||
if ((!pObject) || FindCheck(pObject, FindObject))
|
||||
{
|
||||
return pObject;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : pObject -
|
||||
// FindObject -
|
||||
// Output : Returns true if the object matches the search criteria, false if not.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool FindCheck(CMapClass *pObject, FindObject_t &FindObject)
|
||||
{
|
||||
CMapEntity *pEntity = dynamic_cast <CMapEntity *>(pObject);
|
||||
if (!pEntity)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (FindObject.bVisiblesOnly && !pObject->IsVisible())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
//
|
||||
// Search keyvalues.
|
||||
//
|
||||
for ( int i=pEntity->GetFirstKeyValue(); i != pEntity->GetInvalidKeyValue(); i=pEntity->GetNextKeyValue( i ) )
|
||||
{
|
||||
const char *pszValue = pEntity->GetKeyValue(i);
|
||||
if (pszValue && MatchString(pszValue, FindObject))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Search connections.
|
||||
//
|
||||
int nConnCount = pEntity->Connections_GetCount();
|
||||
for (int i = 0; i < nConnCount; i++)
|
||||
{
|
||||
CEntityConnection *pConn = pEntity->Connections_Get(i);
|
||||
if (pConn)
|
||||
{
|
||||
if (MatchString(pConn->GetTargetName(), FindObject) ||
|
||||
MatchString(pConn->GetParam(), FindObject))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : pLastFound -
|
||||
// FindObject -
|
||||
// pszReplaceText -
|
||||
// Output : Returns the number of occurrences of the find text that were replaced.
|
||||
//-----------------------------------------------------------------------------
|
||||
int FindReplace(CMapEntity *pEntity, FindObject_t &FindObject, const char *pszReplace)
|
||||
{
|
||||
int nReplacedCount = 0;
|
||||
|
||||
//
|
||||
// Replace keyvalues.
|
||||
//
|
||||
for ( int i=pEntity->GetFirstKeyValue(); i != pEntity->GetInvalidKeyValue(); i=pEntity->GetNextKeyValue( i ) )
|
||||
{
|
||||
const char *pszValue = pEntity->GetKeyValue(i);
|
||||
char szNewValue[MAX_PATH];
|
||||
if (pszValue && ReplaceString(szNewValue, pszValue, FindObject, pszReplace))
|
||||
{
|
||||
const char *pszKey = pEntity->GetKey(i);
|
||||
if (pszKey)
|
||||
{
|
||||
pEntity->SetKeyValue(pszKey, szNewValue);
|
||||
nReplacedCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Replace connections.
|
||||
//
|
||||
int nConnCount = pEntity->Connections_GetCount();
|
||||
for (int i = 0; i < nConnCount; i++)
|
||||
{
|
||||
CEntityConnection *pConn = pEntity->Connections_Get(i);
|
||||
if (pConn)
|
||||
{
|
||||
char szNewValue[MAX_PATH];
|
||||
|
||||
if (ReplaceString(szNewValue, pConn->GetTargetName(), FindObject, pszReplace))
|
||||
{
|
||||
pConn->SetTargetName(szNewValue);
|
||||
nReplacedCount++;
|
||||
}
|
||||
|
||||
if (ReplaceString(szNewValue, pConn->GetParam(), FindObject, pszReplace))
|
||||
{
|
||||
pConn->SetParam(szNewValue);
|
||||
nReplacedCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nReplacedCount;
|
||||
}
|
||||
|
||||
|
||||
BEGIN_MESSAGE_MAP(CSearchReplaceDlg, CDialog)
|
||||
//{{AFX_MSG_MAP(CSearchReplaceDlg)
|
||||
ON_WM_SHOWWINDOW()
|
||||
ON_COMMAND_EX(IDC_FIND_NEXT, OnFindReplace)
|
||||
ON_COMMAND_EX(IDC_REPLACE, OnFindReplace)
|
||||
ON_COMMAND_EX(IDC_REPLACE_ALL, OnFindReplace)
|
||||
//}}AFX_MSG_MAP
|
||||
END_MESSAGE_MAP()
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : pParent -
|
||||
//-----------------------------------------------------------------------------
|
||||
CSearchReplaceDlg::CSearchReplaceDlg(CWnd *pParent)
|
||||
: CDialog(CSearchReplaceDlg::IDD, pParent)
|
||||
{
|
||||
m_bNewSearch = true;
|
||||
|
||||
//{{AFX_DATA_INIT(CSearchReplaceDlg)
|
||||
m_bVisiblesOnly = FALSE;
|
||||
m_nFindIn = FindInWorld;
|
||||
m_bWholeWord = FALSE;
|
||||
m_bCaseSensitive = FALSE;
|
||||
//}}AFX_DATA_INIT
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Output : Returns TRUE on success, FALSE on failure.
|
||||
//-----------------------------------------------------------------------------
|
||||
BOOL CSearchReplaceDlg::Create(CWnd *pwndParent)
|
||||
{
|
||||
return CDialog::Create(CSearchReplaceDlg::IDD, pwndParent);
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : pDX -
|
||||
//-----------------------------------------------------------------------------
|
||||
void CSearchReplaceDlg::DoDataExchange(CDataExchange* pDX)
|
||||
{
|
||||
CDialog::DoDataExchange(pDX);
|
||||
|
||||
//{{AFX_DATA_MAP(CSearchReplaceDlg)
|
||||
DDX_Check(pDX, IDC_VISIBLES_ONLY, m_bVisiblesOnly);
|
||||
DDX_Check(pDX, IDC_WHOLE_WORD, m_bWholeWord);
|
||||
DDX_Check(pDX, IDC_CASE_SENSITIVE, m_bCaseSensitive);
|
||||
DDX_Text(pDX, IDC_FIND_TEXT, m_strFindText);
|
||||
DDX_Text(pDX, IDC_REPLACE_TEXT, m_strReplaceText);
|
||||
DDX_Radio(pDX, IDC_SELECTION, m_nFindIn);
|
||||
//}}AFX_DATA_MAP
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CSearchReplaceDlg::OnCancel(void)
|
||||
{
|
||||
ShowWindow(SW_HIDE);
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Fill out the find criteria from the dialog controls.
|
||||
// Input : FindObject -
|
||||
//-----------------------------------------------------------------------------
|
||||
void CSearchReplaceDlg::GetFindCriteria(FindObject_t &FindObject, CMapDoc *pDoc)
|
||||
{
|
||||
FindObject.pWorld = pDoc->GetMapWorld();
|
||||
|
||||
if (m_nFindIn == FindInSelection)
|
||||
{
|
||||
FindObject.eFindIn = FindInSelection;
|
||||
|
||||
FindObject.SelectionList.RemoveAll();
|
||||
|
||||
const CMapObjectList *pSelection = pDoc->GetSelection()->GetList();
|
||||
for (int i = 0; i < pSelection->Count(); i++)
|
||||
{
|
||||
CUtlReference< CMapClass > object = pSelection->Element(i);
|
||||
if ( object->IsGroup() )
|
||||
{
|
||||
// If it's a group, get all the entities in the group.
|
||||
const CMapObjectList *pChildren = object->GetChildren();
|
||||
FOR_EACH_OBJ( *pChildren, pos )
|
||||
{
|
||||
FindObject.SelectionList.AddToTail( pChildren->Element(pos) );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
FindObject.SelectionList.AddToTail( object );
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
FindObject.eFindIn = FindInWorld;
|
||||
}
|
||||
|
||||
FindObject.strFindText = m_strFindText;
|
||||
FindObject.bVisiblesOnly = (m_bVisiblesOnly == TRUE);
|
||||
FindObject.bWholeWord = (m_bWholeWord == TRUE);
|
||||
FindObject.bCaseSensitive = (m_bCaseSensitive == TRUE);
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Called when they hit the Find, the Replace, or the Replace All button.
|
||||
// Input : uCmd - The ID of the button the user hit, IDC_FIND_NEXT or IDC_REPLACE.
|
||||
// Output : Returns TRUE to indicate that the message was handled.
|
||||
//-----------------------------------------------------------------------------
|
||||
BOOL CSearchReplaceDlg::OnFindReplace(UINT uCmd)
|
||||
{
|
||||
CMapDoc *pDoc = CMapDoc::GetActiveMapDoc();
|
||||
if (!pDoc)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static FindObject_t FindObject;
|
||||
static CMapClass *pLastFound = NULL;
|
||||
static int nReplaceCount = 0;
|
||||
FindObject_t TempFindObject;
|
||||
|
||||
bool bDone = false;
|
||||
|
||||
UpdateData();
|
||||
GetFindCriteria(TempFindObject, pDoc);
|
||||
|
||||
if ( strcmp(TempFindObject.strFindText, FindObject.strFindText) != 0 )
|
||||
{
|
||||
m_bNewSearch = true;
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
CMapClass *pObject = NULL;
|
||||
|
||||
if (m_bNewSearch)
|
||||
{
|
||||
//
|
||||
// New search. Fetch the data from the controls.
|
||||
//
|
||||
UpdateData();
|
||||
GetFindCriteria(FindObject, pDoc);
|
||||
|
||||
//
|
||||
// We have to keep track of the last object in the iteration for replacement,
|
||||
// because replacement is done when me advance to the next object.
|
||||
//
|
||||
pLastFound = NULL;
|
||||
nReplaceCount = 0;
|
||||
|
||||
pObject = FindFirstObject(FindObject);
|
||||
}
|
||||
else
|
||||
{
|
||||
pObject = FindNextObject(FindObject);
|
||||
}
|
||||
|
||||
//
|
||||
// Replace All is undone as single operation. Mark the undo position the first time
|
||||
// we find a match during a Replace All.
|
||||
//
|
||||
if (m_bNewSearch && (uCmd == IDC_REPLACE_ALL) && pObject)
|
||||
{
|
||||
GetHistory()->MarkUndoPosition(pDoc->GetSelection()->GetList(), "Replace Text");
|
||||
}
|
||||
|
||||
//
|
||||
// If we have an object to do the replace on, do the replace.
|
||||
//
|
||||
if (pLastFound && ((uCmd == IDC_REPLACE) || (uCmd == IDC_REPLACE_ALL)))
|
||||
{
|
||||
if (uCmd == IDC_REPLACE)
|
||||
{
|
||||
// Allow for undo each time we do a Replace.
|
||||
GetHistory()->MarkUndoPosition(NULL, "Replace Text");
|
||||
}
|
||||
|
||||
//
|
||||
// Do the replace on the last matching object we found. This lets the user see what
|
||||
// object will be modified before it is done.
|
||||
//
|
||||
GetHistory()->Keep(pLastFound);
|
||||
nReplaceCount += FindReplace((CMapEntity *)pLastFound, FindObject, m_strReplaceText);
|
||||
|
||||
GetDlgItem(IDCANCEL)->SetWindowText("Close");
|
||||
}
|
||||
|
||||
if (pObject)
|
||||
{
|
||||
//
|
||||
// We found an object that satisfies our search.
|
||||
//
|
||||
if ((uCmd == IDC_FIND_NEXT) || (uCmd == IDC_REPLACE))
|
||||
{
|
||||
//
|
||||
// Highlight the match.
|
||||
//
|
||||
pDoc->SelectObject(pObject, scClear | scSelect);
|
||||
pDoc->CenterViewsOnSelection();
|
||||
}
|
||||
|
||||
//
|
||||
// Stop after one match unless we are doing a Replace All.
|
||||
//
|
||||
if (uCmd != IDC_REPLACE_ALL)
|
||||
{
|
||||
bDone = true;
|
||||
}
|
||||
|
||||
m_bNewSearch = false;
|
||||
pLastFound = pObject;
|
||||
}
|
||||
else
|
||||
{
|
||||
//
|
||||
// No more objects in the search set match our criteria.
|
||||
//
|
||||
if ((m_bNewSearch) || (uCmd != IDC_REPLACE_ALL))
|
||||
{
|
||||
CString str;
|
||||
str.Format("Finished searching for '%s'.", m_strFindText);
|
||||
MessageBox(str, "Find/Replace Text", MB_OK);
|
||||
|
||||
// TODO: put the old selection back
|
||||
}
|
||||
else if (uCmd == IDC_REPLACE_ALL)
|
||||
{
|
||||
CString str;
|
||||
str.Format("Replaced %d occurrences of the string '%s' with '%s'.", nReplaceCount, m_strFindText, m_strReplaceText);
|
||||
MessageBox(str, "Find/Replace Text", MB_OK);
|
||||
}
|
||||
|
||||
m_bNewSearch = true;
|
||||
bDone = true;
|
||||
}
|
||||
|
||||
} while (!bDone);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CSearchReplaceDlg::OnOK()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Called any time we are hidden or shown.
|
||||
// Input : bShow -
|
||||
// nStatus -
|
||||
//-----------------------------------------------------------------------------
|
||||
void CSearchReplaceDlg::OnShowWindow(BOOL bShow, UINT nStatus)
|
||||
{
|
||||
if (bShow)
|
||||
{
|
||||
m_bNewSearch = true;
|
||||
GetDlgItem(IDCANCEL)->SetWindowText("Cancel");
|
||||
|
||||
m_nFindIn = FindInWorld;
|
||||
CMapDoc *pDoc = CMapDoc::GetActiveMapDoc();
|
||||
if (pDoc)
|
||||
{
|
||||
if ( !pDoc->GetSelection()->IsEmpty() )
|
||||
{
|
||||
m_nFindIn = FindInSelection;
|
||||
}
|
||||
}
|
||||
|
||||
// Populate the controls with the current data.
|
||||
UpdateData(FALSE);
|
||||
}
|
||||
|
||||
CDialog::OnShowWindow(bShow, nStatus);
|
||||
}
|
||||
81
hammer/SearchReplaceDlg.h
Normal file
81
hammer/SearchReplaceDlg.h
Normal file
@@ -0,0 +1,81 @@
|
||||
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef SEARCHREPLACEDLG_H
|
||||
#define SEARCHREPLACEDLG_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include "resource.h"
|
||||
#include "UtlVector.h"
|
||||
#include "MapClass.h"
|
||||
|
||||
|
||||
class CMapEntity;
|
||||
|
||||
struct FindObject_t;
|
||||
|
||||
|
||||
enum FindReplaceIn_t
|
||||
{
|
||||
FindInSelection = 0,
|
||||
FindInWorld,
|
||||
};
|
||||
|
||||
|
||||
class CSearchReplaceDlg : public CDialog
|
||||
{
|
||||
// Construction
|
||||
public:
|
||||
CSearchReplaceDlg(CWnd* pParent = NULL); // standard constructor
|
||||
int Create(CWnd *pwndParent = NULL);
|
||||
|
||||
// Dialog Data
|
||||
//{{AFX_DATA(CSearchReplaceDlg)
|
||||
enum { IDD = IDD_SEARCH_REPLACE };
|
||||
CString m_strFindText;
|
||||
CString m_strReplaceText;
|
||||
BOOL m_bVisiblesOnly;
|
||||
BOOL m_bWholeWord;
|
||||
BOOL m_bCaseSensitive;
|
||||
int m_nFindIn;
|
||||
//}}AFX_DATA
|
||||
|
||||
|
||||
// Overrides
|
||||
// ClassWizard generated virtual function overrides
|
||||
//{{AFX_VIRTUAL(CSearchReplaceDlg)
|
||||
protected:
|
||||
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
|
||||
//}}AFX_VIRTUAL
|
||||
|
||||
// Implementation
|
||||
protected:
|
||||
|
||||
// Generated message map functions
|
||||
//{{AFX_MSG(CSearchReplaceDlg)
|
||||
afx_msg BOOL OnFindReplace(UINT uCmd);
|
||||
virtual void OnOK();
|
||||
virtual void OnCancel();
|
||||
virtual void OnShowWindow(BOOL bShow, UINT nStatus);
|
||||
//}}AFX_MSG
|
||||
|
||||
DECLARE_MESSAGE_MAP()
|
||||
|
||||
private:
|
||||
|
||||
void GetFindCriteria(FindObject_t &FindObject, CMapDoc *pDoc);
|
||||
|
||||
void FindFirst();
|
||||
bool FindNext(bool bReplace);
|
||||
|
||||
bool m_bNewSearch; // Set to true every time the dialog is brought up.
|
||||
};
|
||||
|
||||
|
||||
#endif // SEARCHREPLACEDLG_H
|
||||
43
hammer/SelectModeDlgBar.h
Normal file
43
hammer/SelectModeDlgBar.h
Normal file
@@ -0,0 +1,43 @@
|
||||
//========= Copyright Š 1996-2005, Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef SELECTMODEDLGBAR_H
|
||||
#define SELECTMODEDLGBAR_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
|
||||
#include "resource.h"
|
||||
#include "GroupList.h"
|
||||
#include "HammerBar.h"
|
||||
|
||||
|
||||
class CSelectModeDlgBar : public CHammerBar
|
||||
{
|
||||
public:
|
||||
BOOL Create(CWnd *pParentWnd);
|
||||
|
||||
private:
|
||||
//{{AFX_DATA(CFilterControl)
|
||||
enum { IDD = IDD_SELECT_MODE_BAR };
|
||||
//}}AFX_DATA
|
||||
|
||||
protected:
|
||||
//{{AFX_MSG(CFilterControl)
|
||||
afx_msg void OnGroups();
|
||||
afx_msg void OnObjects();
|
||||
afx_msg void OnSolids();
|
||||
afx_msg void UpdateControlGroups(CCmdUI *pCmdUI);
|
||||
afx_msg void UpdateControlObjects(CCmdUI *pCmdUI);
|
||||
afx_msg void UpdateControlSolids(CCmdUI *pCmdUI);
|
||||
//}}AFX_MSG
|
||||
|
||||
DECLARE_MESSAGE_MAP()
|
||||
};
|
||||
|
||||
#endif // SELECTMODEDLGBAR_H
|
||||
626
hammer/Selection.cpp
Normal file
626
hammer/Selection.cpp
Normal file
@@ -0,0 +1,626 @@
|
||||
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: The document. Exposes functions for object creation, deletion, and
|
||||
// manipulation. Holds the current tool. Handles GUI messages that are
|
||||
// view-independent.
|
||||
//
|
||||
//=============================================================================//
|
||||
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "Selection.h"
|
||||
#include "mapdoc.h"
|
||||
#include "MapHelper.h"
|
||||
#include "MapSolid.h"
|
||||
#include "Manifest.h"
|
||||
#include "mapdefs.h"
|
||||
#include "globalfunctions.h"
|
||||
#include "mainfrm.h"
|
||||
#include "objectproperties.h"
|
||||
|
||||
CSelection::CSelection(void)
|
||||
{
|
||||
m_pDocument = NULL;
|
||||
}
|
||||
|
||||
CSelection::~CSelection(void)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void CSelection::Init( CMapDoc *pDocument )
|
||||
{
|
||||
m_pDocument = pDocument;
|
||||
m_eSelectMode = selectGroups;
|
||||
m_SelectionList.RemoveAll();
|
||||
ClearHitList();
|
||||
|
||||
m_LastValidBounds.bmins = Vector(0, 0, 0);
|
||||
m_LastValidBounds.bmaxs = Vector(64, 64, 64);
|
||||
|
||||
UpdateSelectionBounds();
|
||||
}
|
||||
|
||||
bool CSelection::IsSelected(CMapClass *pobj)
|
||||
{
|
||||
return (m_SelectionList.Find(pobj) != m_SelectionList.InvalidIndex());
|
||||
}
|
||||
|
||||
|
||||
void CSelection::GetLastValidBounds(Vector &vecMins, Vector &vecMaxs)
|
||||
{
|
||||
vecMins = m_LastValidBounds.bmins;
|
||||
vecMaxs = m_LastValidBounds.bmaxs;
|
||||
}
|
||||
|
||||
bool CSelection::GetBounds(Vector &vecMins, Vector &vecMaxs)
|
||||
{
|
||||
if ( m_bBoundsDirty )
|
||||
UpdateSelectionBounds();
|
||||
|
||||
if ( m_SelectionList.Count() == 0)
|
||||
return false;
|
||||
|
||||
vecMins = m_Bounds.bmins;
|
||||
vecMaxs = m_Bounds.bmaxs;
|
||||
|
||||
return true;;
|
||||
}
|
||||
|
||||
bool CSelection::GetLogicalBounds(Vector2D &vecMins, Vector2D &vecMaxs)
|
||||
{
|
||||
if ( m_bBoundsDirty )
|
||||
UpdateSelectionBounds();
|
||||
|
||||
if ( m_SelectionList.Count() == 0)
|
||||
return false;
|
||||
|
||||
vecMins = m_vecLogicalMins;
|
||||
vecMaxs = m_vecLogicalMaxs;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Used for translations. Uses entity origins and brush bounds.
|
||||
// That way, when moving stuff, the entity origins will stay on the grid.
|
||||
//-----------------------------------------------------------------------------
|
||||
void CSelection::GetBoundsForTranslation( Vector &vecMins, Vector &vecMaxs )
|
||||
{
|
||||
vecMins.Init( COORD_NOTINIT, COORD_NOTINIT, 0 );
|
||||
vecMaxs.Init( -COORD_NOTINIT, -COORD_NOTINIT, 0 );
|
||||
|
||||
// If there are any solids, then only use the bounds for those. Otherwise,
|
||||
// an entity that is off the grid can pull all the solids off the grid and you never want that.
|
||||
int nSolids = 0;
|
||||
for (int i = 0; i < m_SelectionList.Count(); i++)
|
||||
{
|
||||
CMapClass *pobj = m_SelectionList[i];
|
||||
CEditGameClass *pEdit = dynamic_cast< CEditGameClass* >( pobj );
|
||||
if ( (pEdit && pEdit->IsSolidClass()) || dynamic_cast<CMapSolid *>(pobj) )
|
||||
{
|
||||
++nSolids;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < m_SelectionList.Count(); i++)
|
||||
{
|
||||
CMapClass *pobj = m_SelectionList[i];
|
||||
|
||||
// update physical bounds
|
||||
Vector mins, maxs;
|
||||
|
||||
CEditGameClass *pEdit = dynamic_cast< CEditGameClass* >( pobj );
|
||||
if ( (pEdit && pEdit->IsSolidClass()) || dynamic_cast<CMapSolid *>(pobj) )
|
||||
{
|
||||
pobj->GetRender2DBox(mins, maxs);
|
||||
}
|
||||
else if ( nSolids == 0 )
|
||||
{
|
||||
pobj->GetOrigin( mins );
|
||||
maxs = mins;
|
||||
}
|
||||
|
||||
VectorMin( mins, vecMins, vecMins );
|
||||
VectorMax( maxs, vecMaxs, vecMaxs );
|
||||
}
|
||||
}
|
||||
|
||||
void CSelection::UpdateSelectionBounds( void )
|
||||
{
|
||||
m_Bounds.ResetBounds();
|
||||
|
||||
m_vecLogicalMins[0] = m_vecLogicalMins[1] = COORD_NOTINIT;
|
||||
m_vecLogicalMaxs[0] = m_vecLogicalMaxs[1] = -COORD_NOTINIT;
|
||||
|
||||
for (int i = 0; i < m_SelectionList.Count(); i++)
|
||||
{
|
||||
CMapClass *pobj = m_SelectionList[i];
|
||||
|
||||
// update physical bounds
|
||||
Vector mins,maxs;
|
||||
pobj->GetRender2DBox(mins, maxs);
|
||||
m_Bounds.UpdateBounds(mins, maxs);
|
||||
|
||||
// update logical bounds
|
||||
Vector2D logicalMins,logicalMaxs;
|
||||
pobj->GetRenderLogicalBox( logicalMins, logicalMaxs );
|
||||
Vector2DMin( logicalMins, m_vecLogicalMins, m_vecLogicalMins );
|
||||
Vector2DMax( logicalMaxs, m_vecLogicalMaxs, m_vecLogicalMaxs );
|
||||
}
|
||||
|
||||
// remeber bounds if valid
|
||||
if ( m_Bounds.IsValidBox() )
|
||||
{
|
||||
m_LastValidBounds = m_Bounds;
|
||||
}
|
||||
|
||||
m_bBoundsDirty = false;
|
||||
}
|
||||
|
||||
bool CSelection::GetBoundsCenter(Vector &vecCenter)
|
||||
{
|
||||
if ( m_bBoundsDirty )
|
||||
UpdateSelectionBounds();
|
||||
|
||||
if ( m_SelectionList.Count() == 0 )
|
||||
return false;
|
||||
|
||||
m_Bounds.GetBoundsCenter( vecCenter );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CSelection::GetLogicalBoundsCenter( Vector2D &vecCenter )
|
||||
{
|
||||
if ( m_bBoundsDirty )
|
||||
UpdateSelectionBounds();
|
||||
|
||||
if ( m_SelectionList.Count() == 0 )
|
||||
return false;
|
||||
|
||||
vecCenter = (m_vecLogicalMins+m_vecLogicalMaxs)/2;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CSelection::IsEmpty()
|
||||
{
|
||||
return m_SelectionList.Count() == 0;
|
||||
}
|
||||
|
||||
const CMapObjectList *CSelection::GetList()
|
||||
{
|
||||
return &m_SelectionList;
|
||||
}
|
||||
|
||||
const CMapObjectList* CSelection::GetHitList()
|
||||
{
|
||||
return &m_HitList;
|
||||
}
|
||||
|
||||
int CSelection::GetCount()
|
||||
{
|
||||
return m_SelectionList.Count();
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Returns the current selection mode. The selection mode determines
|
||||
// what gets selected when the user clicks on something - the group,
|
||||
// the entity, or the solid.
|
||||
//-----------------------------------------------------------------------------
|
||||
SelectMode_t CSelection::GetMode()
|
||||
{
|
||||
return m_eSelectMode;
|
||||
}
|
||||
|
||||
void CSelection::SetSelectionState(SelectionState_t eSelectionState)
|
||||
{
|
||||
for ( int i=0; i<m_SelectionList.Count(); i++ )
|
||||
{
|
||||
CMapClass *pMapClass = (CUtlReference< CMapClass >)m_SelectionList.Element(i);
|
||||
CMapEntity *pObject = (CMapEntity *)pMapClass;
|
||||
pObject->SetSelectionState( eSelectionState );
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CSelection::IsAnEntitySelected(void)
|
||||
{
|
||||
if (m_SelectionList.Count() > 0)
|
||||
{
|
||||
int nSelCount = m_SelectionList.Count();
|
||||
for (int i = 0; i < nSelCount; i++)
|
||||
{
|
||||
CMapClass *pObject = m_SelectionList.Element(i);
|
||||
CMapEntity *pEntity = dynamic_cast <CMapEntity *> (pObject);
|
||||
if (pEntity != NULL)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Returns true if the selection is editable. Every object must be
|
||||
// individually editable for this routine to return true.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CSelection::IsEditable()
|
||||
{
|
||||
if ( m_SelectionList.Count() > 0 )
|
||||
{
|
||||
int nSelCount = m_SelectionList.Count();
|
||||
for (int i = 0; i < nSelCount; i++)
|
||||
{
|
||||
CMapClass *pObject = m_SelectionList.Element(i);
|
||||
|
||||
if ( pObject->IsEditable() == false )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Returns true if the selection is copyable. CManifestInstance classes
|
||||
// are not copyable.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CSelection::IsCopyable()
|
||||
{
|
||||
if ( m_SelectionList.Count() > 0 )
|
||||
{
|
||||
int nSelCount = m_SelectionList.Count();
|
||||
for (int i = 0; i < nSelCount; i++)
|
||||
{
|
||||
CMapClass *pObject = m_SelectionList.Element(i);
|
||||
|
||||
if ( pObject->IsMapClass( MAPCLASS_TYPE( CManifestInstance ) ) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Sets the current selection mode, which determines which objects
|
||||
// are selected when the user clicks on things.
|
||||
//-----------------------------------------------------------------------------
|
||||
void CSelection::SetMode(SelectMode_t eNewSelectMode)
|
||||
{
|
||||
SelectMode_t eOldSelectMode = m_eSelectMode;
|
||||
m_eSelectMode = eNewSelectMode;
|
||||
|
||||
if ((eOldSelectMode == selectSolids) ||
|
||||
((eOldSelectMode == selectObjects) && (eNewSelectMode == selectGroups)))
|
||||
{
|
||||
//
|
||||
// If we are going from a more specific selection mode to a less specific one,
|
||||
// clear the selection. This avoids unexpectedly selecting new things.
|
||||
//
|
||||
SelectObject(NULL, scClear|scSaveChanges);
|
||||
}
|
||||
else
|
||||
{
|
||||
//
|
||||
// Put all the children of the selected objects in a list, along with their children.
|
||||
//
|
||||
CMapObjectList NewList;
|
||||
int nSelCount = m_SelectionList.Count();
|
||||
for (int i = 0; i < nSelCount; i++)
|
||||
{
|
||||
CMapClass *pObject = m_SelectionList[i];
|
||||
AddLeavesToListCallback(pObject, &NewList);
|
||||
pObject->EnumChildren((ENUMMAPCHILDRENPROC)AddLeavesToListCallback, (DWORD)&NewList);
|
||||
}
|
||||
|
||||
SelectObject(NULL, scClear|scSaveChanges);
|
||||
|
||||
//
|
||||
// Add child objects to selection.
|
||||
//
|
||||
for (int pos=0;pos<NewList.Count();pos++)
|
||||
{
|
||||
CMapClass *pObject = NewList[pos];
|
||||
CMapClass *pSelObject = pObject->PrepareSelection(eNewSelectMode);
|
||||
if (pSelObject)
|
||||
{
|
||||
SelectObject(pSelObject, scSelect);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : *pObject -
|
||||
//-----------------------------------------------------------------------------
|
||||
void CSelection::AddHit(CMapClass *pObject)
|
||||
{
|
||||
if ( m_HitList.Find(pObject) == -1 )
|
||||
{
|
||||
m_HitList.AddToTail(pObject);
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CSelection::ClearHitList(void)
|
||||
{
|
||||
m_HitList.RemoveAll();
|
||||
m_iCurHit = -1;
|
||||
}
|
||||
|
||||
bool CSelection::RemoveAll(void)
|
||||
{
|
||||
for ( int i=0;i<m_SelectionList.Count(); i++ )
|
||||
{
|
||||
CMapClass *pObject = m_SelectionList.Element(i);
|
||||
pObject->SetSelectionState(SELECT_NONE);
|
||||
}
|
||||
|
||||
m_SelectionList.RemoveAll();
|
||||
SetBoundsDirty();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CSelection::RemoveDead(void)
|
||||
{
|
||||
bool bFoundOne = false;
|
||||
|
||||
for ( int i=m_SelectionList.Count()-1; i>=0; i-- )
|
||||
{
|
||||
CMapClass *pObject = m_SelectionList.Element(i);
|
||||
if (!pObject->GetParent())
|
||||
{
|
||||
m_SelectionList.FastRemove(i);
|
||||
pObject->SetSelectionState(SELECT_NONE);
|
||||
bFoundOne = true;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO check if we do the same as in SelectObject
|
||||
SetBoundsDirty();
|
||||
|
||||
return bFoundOne;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Removes objects that are not visible from the selection set.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CSelection::RemoveInvisibles(void)
|
||||
{
|
||||
bool bFoundOne = false;
|
||||
|
||||
for ( int i=m_SelectionList.Count()-1; i>=0; i-- )
|
||||
{
|
||||
CMapClass *pObject = m_SelectionList.Element(i);
|
||||
if ( !pObject->IsVisible() )
|
||||
{
|
||||
m_SelectionList.FastRemove(i);
|
||||
pObject->SetSelectionState(SELECT_NONE);
|
||||
bFoundOne = true;
|
||||
}
|
||||
}
|
||||
|
||||
SetBoundsDirty();
|
||||
|
||||
return bFoundOne;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : iIndex -
|
||||
// bUpdateViews -
|
||||
//-----------------------------------------------------------------------------
|
||||
void CSelection::SetCurrentHit(int iIndex, bool bCascading)
|
||||
{
|
||||
if ( m_HitList.Count() == 0)
|
||||
{
|
||||
Assert( m_iCurHit == -1);
|
||||
return;
|
||||
}
|
||||
|
||||
// save & toggle old selection off
|
||||
if (m_iCurHit != -1)
|
||||
{
|
||||
CMapClass *pObject = m_HitList[m_iCurHit];
|
||||
SelectObject(pObject, scToggle|scSaveChanges);
|
||||
}
|
||||
|
||||
if (iIndex == hitNext)
|
||||
{
|
||||
// hit next object
|
||||
m_iCurHit++;
|
||||
}
|
||||
else if (iIndex == hitPrev)
|
||||
{
|
||||
// hit prev object
|
||||
m_iCurHit--;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_iCurHit = iIndex;
|
||||
}
|
||||
|
||||
// make sure curhit is valid
|
||||
if (m_iCurHit >= m_HitList.Count())
|
||||
{
|
||||
m_iCurHit = 0;
|
||||
}
|
||||
else if (m_iCurHit < 0)
|
||||
{
|
||||
m_iCurHit = m_HitList.Count() - 1;
|
||||
}
|
||||
|
||||
CMapClass *pObject = m_HitList[m_iCurHit];
|
||||
|
||||
if ( bCascading )
|
||||
{
|
||||
// Build actual selection list based on cascading...
|
||||
CUtlRBTree< CMapClass*, unsigned short > tree( 0, 0, DefLessFunc( CMapClass* ) );
|
||||
|
||||
bool bRecursive = false; // not used yet
|
||||
m_pDocument->BuildCascadingSelectionList( pObject, tree, bRecursive );
|
||||
|
||||
CMapObjectList list;
|
||||
list.AddToTail( pObject );
|
||||
bool bRootIsSelected = IsSelected(pObject);
|
||||
bool bUniformSelectionState = true;
|
||||
|
||||
for ( unsigned short h = tree.FirstInorder(); h != tree.InvalidIndex(); h = tree.NextInorder(h) )
|
||||
{
|
||||
list.AddToTail( list[h] );
|
||||
|
||||
if ( IsSelected( list[h] ) != bRootIsSelected )
|
||||
{
|
||||
bUniformSelectionState = false;
|
||||
}
|
||||
}
|
||||
|
||||
/* Change toggle to select or unselect if we're toggling and cascading
|
||||
// but the root + children have different selection state
|
||||
if ( ( !bUniformSelectionState ) && ( cmd == scToggle ) )
|
||||
{
|
||||
cmd = bRootIsSelected ? scSelect : scUnselect;
|
||||
}*/
|
||||
|
||||
SelectObjectList( &list, scSelect );
|
||||
}
|
||||
else
|
||||
{
|
||||
SelectObject(pObject, scToggle );
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : pobj -
|
||||
// cmd -
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CSelection::SelectObject(CMapClass *pObj, int cmd)
|
||||
{
|
||||
// if no object is given we only can execute the clear command
|
||||
if ( pObj == NULL )
|
||||
{
|
||||
// check if selection is already empty
|
||||
if (m_SelectionList.Count() == 0)
|
||||
return false; // nothing to do
|
||||
|
||||
if ( cmd & scClear )
|
||||
{
|
||||
RemoveAll();
|
||||
}
|
||||
}
|
||||
else // object oriented operation
|
||||
{
|
||||
int iIndex = m_SelectionList.Find(pObj);
|
||||
bool bAlreadySelected = iIndex != -1;
|
||||
|
||||
if ( cmd & scToggle )
|
||||
{
|
||||
if ( bAlreadySelected )
|
||||
cmd |= scUnselect;
|
||||
else
|
||||
cmd |= scSelect;
|
||||
}
|
||||
|
||||
if ( cmd & scSelect )
|
||||
{
|
||||
if ( cmd & scClear )
|
||||
{
|
||||
// if we re-selected the only selected element, nothing changes
|
||||
if ( bAlreadySelected && m_SelectionList.Count() == 1 )
|
||||
return false;
|
||||
|
||||
RemoveAll();
|
||||
bAlreadySelected = false; // reset that flag
|
||||
}
|
||||
|
||||
if ( bAlreadySelected )
|
||||
return false;
|
||||
|
||||
m_SelectionList.AddToTail(pObj);
|
||||
pObj->SetSelectionState(SELECT_NORMAL);
|
||||
}
|
||||
else if ( (cmd & scUnselect) && bAlreadySelected )
|
||||
{
|
||||
// ok unselect an yet selected object
|
||||
m_SelectionList.FastRemove(iIndex);
|
||||
pObj->SetSelectionState(SELECT_NONE);
|
||||
}
|
||||
else
|
||||
{
|
||||
return false; // nothing was changed
|
||||
}
|
||||
}
|
||||
|
||||
// ok something in the selection was changed, set dirty flags
|
||||
SetBoundsDirty();
|
||||
|
||||
if ( cmd & scSaveChanges )
|
||||
{
|
||||
// changing the selection automatically saves changes made to the properties dialog
|
||||
GetMainWnd()->pObjectProperties->SaveData( SAVEDATA_SELECTION_CHANGED );
|
||||
}
|
||||
|
||||
// always mark data dirty
|
||||
GetMainWnd()->pObjectProperties->MarkDataDirty();
|
||||
|
||||
// uddate all views
|
||||
m_pDocument->UpdateAllViews( MAPVIEW_UPDATE_SELECTION );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Clears the current selection and selects everything in the given list.
|
||||
// Input : pList - Objects to select.
|
||||
//-----------------------------------------------------------------------------
|
||||
void CSelection::SelectObjectList( const CMapObjectList *pList, int cmd )
|
||||
{
|
||||
// Clear the current selection.
|
||||
|
||||
// Clear the current selection.
|
||||
if ( cmd & scSaveChanges )
|
||||
{
|
||||
GetMainWnd()->pObjectProperties->SaveData( SAVEDATA_SELECTION_CHANGED );
|
||||
cmd &= ~scSaveChanges;
|
||||
}
|
||||
|
||||
if ( cmd & scClear )
|
||||
{
|
||||
RemoveAll();
|
||||
cmd &= ~scClear;
|
||||
}
|
||||
|
||||
if ( pList != NULL )
|
||||
{
|
||||
for (int pos=0;pos<pList->Count();pos++)
|
||||
{
|
||||
CMapClass *pObject = (CUtlReference< CMapClass >)pList->Element(pos);
|
||||
CMapClass *pSelObject = pObject->PrepareSelection( m_eSelectMode );
|
||||
if (pSelObject)
|
||||
{
|
||||
SelectObject( pSelObject, cmd );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
116
hammer/Selection.h
Normal file
116
hammer/Selection.h
Normal file
@@ -0,0 +1,116 @@
|
||||
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: The document. Exposes functions for object creation, deletion, and
|
||||
// manipulation. Holds the current tool. Handles GUI messages that are
|
||||
// view-independent.
|
||||
//
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef SELECTIONMANAGER_H
|
||||
#define SELECTIONMANAGER_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include "mapclass.h"
|
||||
|
||||
class CMapDoc;
|
||||
|
||||
enum
|
||||
{
|
||||
hitFirst = 0,
|
||||
hitNext = -1,
|
||||
hitPrev = -2
|
||||
};
|
||||
|
||||
// SelectObject/SelectFace parameters:
|
||||
typedef enum
|
||||
{
|
||||
scToggle = 0x01, // toogle selection state of this object
|
||||
scSelect = 0x02, // select this object
|
||||
scUnselect = 0x04, // unselect this object
|
||||
scClear = 0x10, // Clear current before selecting
|
||||
scNoLift = 0x20, // Don't lift face attributes into Face Properties dialog dvs: lame!
|
||||
scNoApply = 0x40, // Don't apply face attributes from Face Properties dialog to selected face dvs: lame!
|
||||
scCascading = 0x80, // Select all entities attached to outputs of this entity
|
||||
scCascadingRecursive = 0x100, // Select all entities attached to outputs of this entity, recursively
|
||||
scSelectAll = 0x200,
|
||||
scSaveChanges = 0x400, // changing the selection causes changes made in the properties dialog be saved
|
||||
};
|
||||
|
||||
|
||||
class CSelection
|
||||
{
|
||||
public:
|
||||
CSelection(void);
|
||||
virtual ~CSelection(void);
|
||||
|
||||
void Init(CMapDoc *pDocument);
|
||||
|
||||
bool SelectObject(CMapClass *pobj, int cmd = scSelect);
|
||||
void SelectObjectList(const CMapObjectList *pList, int cmd = (scClear|scSelect|scSaveChanges) );
|
||||
|
||||
bool RemoveAll(); // true if any elements were removed
|
||||
bool RemoveInvisibles(); // true if any elements were removed
|
||||
bool RemoveDead(); // true if any elements were removed
|
||||
|
||||
int GetCount();
|
||||
bool IsEmpty();
|
||||
bool IsSelected(CMapClass *pObject);
|
||||
bool IsAnEntitySelected();
|
||||
bool IsEditable();
|
||||
bool IsCopyable();
|
||||
|
||||
|
||||
const CMapObjectList* GetList(void);
|
||||
CMapDoc *GetMapDoc() { return m_pDocument; }
|
||||
|
||||
// HitList feature
|
||||
const CMapObjectList* GetHitList(void);
|
||||
void ClearHitList();
|
||||
void AddHit(CMapClass *pObject);
|
||||
void SetCurrentHit(int iIndex, bool bCascading = false);
|
||||
|
||||
SelectMode_t GetMode(void);
|
||||
void SetMode(SelectMode_t eSelectMode);
|
||||
void SetSelectionState(SelectionState_t eSelectionState);
|
||||
|
||||
bool GetBounds(Vector &vecMins, Vector &vecMaxs);
|
||||
|
||||
// Used for translations. Uses entity origins and brush bounds. That way, when moving stuff,
|
||||
// the entity origins will stay on the grid.
|
||||
void GetBoundsForTranslation( Vector &vecMins, Vector &vecMaxs );
|
||||
|
||||
bool GetBoundsCenter(Vector &vecCenter);
|
||||
void GetLastValidBounds(Vector &vecMins, Vector &vecMaxs);
|
||||
bool GetLogicalBounds(Vector2D &vecMins, Vector2D &vecMaxs);
|
||||
bool GetLogicalBoundsCenter( Vector2D &vecCenter );
|
||||
|
||||
void SetBoundsDirty() {m_bBoundsDirty = true;}
|
||||
|
||||
protected:
|
||||
|
||||
void UpdateSelectionBounds();
|
||||
|
||||
CMapDoc *m_pDocument; // document this selection set belongs to
|
||||
SelectMode_t m_eSelectMode; // Controls what gets selected based on what the user clicked on.
|
||||
CMapObjectList m_SelectionList; // The list of selected objects.
|
||||
|
||||
bool m_bBoundsDirty; // recalc bounds box with next query
|
||||
|
||||
BoundBox m_Bounds; // current bounds
|
||||
BoundBox m_LastValidBounds; // last valid selection bounds
|
||||
|
||||
Vector2D m_vecLogicalMins; // Selection bounds in "logical" space
|
||||
Vector2D m_vecLogicalMaxs;
|
||||
|
||||
// Hit selection.
|
||||
CMapObjectList m_HitList; // list of 'hit' object (potential selected object)
|
||||
int m_iCurHit; // current hit or -1
|
||||
|
||||
|
||||
|
||||
|
||||
};
|
||||
|
||||
#endif // SELECTIONMANAGER_H
|
||||
416
hammer/SmoothingGroupMgr.cpp
Normal file
416
hammer/SmoothingGroupMgr.cpp
Normal file
@@ -0,0 +1,416 @@
|
||||
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================//
|
||||
|
||||
#include <stdafx.h>
|
||||
#include "smoothinggroupmgr.h"
|
||||
#include "mapface.h"
|
||||
#include "ChunkFile.h"
|
||||
|
||||
class CSmoothingGroupMgr : public ISmoothingGroupMgr
|
||||
{
|
||||
public:
|
||||
|
||||
CSmoothingGroupMgr();
|
||||
~CSmoothingGroupMgr();
|
||||
|
||||
SmoothingGroupHandle_t CreateGroup( void );
|
||||
void DestroyGroup( SmoothingGroupHandle_t hGroup );
|
||||
|
||||
bool IsGroup( SmoothingGroupHandle_t hGroup );
|
||||
|
||||
void AddFaceToGroup( SmoothingGroupHandle_t hGroup, CMapFace *pFace );
|
||||
void RemoveFaceFromGroup( SmoothingGroupHandle_t hGroup, CMapFace *pFace );
|
||||
|
||||
void SetGroupSmoothingAngle( SmoothingGroupHandle_t hGroup, float flAngle );
|
||||
float GetGroupSmoothingAngle( SmoothingGroupHandle_t hGroup );
|
||||
|
||||
int GetFaceCountInGroup( SmoothingGroupHandle_t hGroup );
|
||||
CMapFace *GetFaceFromGroup( SmoothingGroupHandle_t hGroup, int iFace );
|
||||
|
||||
ChunkFileResult_t SaveVMF( CChunkFile *pFile, CSaveInfo *pSaveInfo );
|
||||
ChunkFileResult_t LoadVMF( CChunkFile *pFile );
|
||||
|
||||
private:
|
||||
|
||||
#if 0
|
||||
static ChunkFileResult_t LoadSmoothingGroupMgrCallback( const char *szKey, const char *szValue, CSmoothingGroupMgr *pSmoothingGroupMgr );
|
||||
static ChunkFileResult_t LoadSmoothingGroupMgrKeyCallback( const char *szKey, const char *szValue, CSmoothingGroupMgr *pSmoothingGroupMgr );
|
||||
|
||||
static ChunkFileResult_t LoadSmoothingGroupCallback( CChunkFile *pFile, SmoothingGroup_t *pGroup );
|
||||
static ChunkFileResult_t LoadSmoothingGroupKeyCallback( const char *szKey, const char *szValue, SmoothingGroup_t *pGroup );
|
||||
#endif
|
||||
|
||||
private:
|
||||
|
||||
struct SmoothingGroup_t
|
||||
{
|
||||
int m_nID;
|
||||
CUtlVector<CMapFace*> m_aFaces;
|
||||
float m_flSmoothingAngle;
|
||||
};
|
||||
|
||||
CUtlVector<SmoothingGroup_t> m_aSmoothingGroups;
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
ISmoothingGroupMgr *SmoothingGroupMgr( void )
|
||||
{
|
||||
static CSmoothingGroupMgr s_SmoothingGroupMgr;
|
||||
return &s_SmoothingGroupMgr;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Constructor
|
||||
//-----------------------------------------------------------------------------
|
||||
CSmoothingGroupMgr::CSmoothingGroupMgr()
|
||||
{
|
||||
m_aSmoothingGroups.SetSize( MAX_SMOOTHING_GROUP_COUNT );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Deconstructor
|
||||
//-----------------------------------------------------------------------------
|
||||
CSmoothingGroupMgr::~CSmoothingGroupMgr()
|
||||
{
|
||||
m_aSmoothingGroups.Purge();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Add a face to the smoothing group.
|
||||
//-----------------------------------------------------------------------------
|
||||
void CSmoothingGroupMgr::AddFaceToGroup( SmoothingGroupHandle_t hGroup, CMapFace *pFace )
|
||||
{
|
||||
// Validate data.
|
||||
Assert( hGroup != INVALID_SMOOTHING_GROUP );
|
||||
Assert( hGroup >= 0 );
|
||||
Assert( hGroup < MAX_SMOOTHING_GROUP_COUNT );
|
||||
|
||||
int iGroup = static_cast<int>( hGroup );
|
||||
SmoothingGroup_t *pGroup = &m_aSmoothingGroups[iGroup];
|
||||
if ( pGroup )
|
||||
{
|
||||
// Check to see if we already have this face in this group.
|
||||
if ( pGroup->m_aFaces.Find( pFace ) == -1 )
|
||||
{
|
||||
pFace->AddSmoothingGroupHandle( hGroup );
|
||||
pGroup->m_aFaces.AddToTail( pFace );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
void CSmoothingGroupMgr::RemoveFaceFromGroup( SmoothingGroupHandle_t hGroup, CMapFace *pFace )
|
||||
{
|
||||
// Validate data.
|
||||
Assert( hGroup != INVALID_SMOOTHING_GROUP );
|
||||
Assert( hGroup >= 0 );
|
||||
Assert( hGroup < MAX_SMOOTHING_GROUP_COUNT );
|
||||
|
||||
int iGroup = static_cast<int>( hGroup );
|
||||
SmoothingGroup_t *pGroup = &m_aSmoothingGroups[iGroup];
|
||||
if ( pGroup )
|
||||
{
|
||||
int iFace = pGroup->m_aFaces.Find( pFace );
|
||||
if ( iFace != -1 )
|
||||
{
|
||||
pFace->RemoveSmoothingGroupHandle( hGroup );
|
||||
pGroup->m_aFaces.Remove( iFace );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
void CSmoothingGroupMgr::SetGroupSmoothingAngle( SmoothingGroupHandle_t hGroup, float flAngle )
|
||||
{
|
||||
// Validate data.
|
||||
Assert( hGroup != INVALID_SMOOTHING_GROUP );
|
||||
Assert( hGroup >= 0 );
|
||||
Assert( hGroup < MAX_SMOOTHING_GROUP_COUNT );
|
||||
|
||||
int iGroup = static_cast<int>( hGroup );
|
||||
SmoothingGroup_t *pGroup = &m_aSmoothingGroups[iGroup];
|
||||
if ( pGroup )
|
||||
{
|
||||
pGroup->m_flSmoothingAngle = flAngle;
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
float CSmoothingGroupMgr::GetGroupSmoothingAngle( SmoothingGroupHandle_t hGroup )
|
||||
{
|
||||
// Validate data.
|
||||
Assert( hGroup != INVALID_SMOOTHING_GROUP );
|
||||
Assert( hGroup >= 0 );
|
||||
Assert( hGroup < MAX_SMOOTHING_GROUP_COUNT );
|
||||
|
||||
int iGroup = static_cast<int>( hGroup );
|
||||
SmoothingGroup_t *pGroup = &m_aSmoothingGroups[iGroup];
|
||||
if ( pGroup )
|
||||
{
|
||||
return pGroup->m_flSmoothingAngle;
|
||||
}
|
||||
|
||||
return -1.0f;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
int CSmoothingGroupMgr::GetFaceCountInGroup( SmoothingGroupHandle_t hGroup )
|
||||
{
|
||||
// Validate data.
|
||||
Assert( hGroup != INVALID_SMOOTHING_GROUP );
|
||||
Assert( hGroup >= 0 );
|
||||
Assert( hGroup < MAX_SMOOTHING_GROUP_COUNT );
|
||||
|
||||
int iGroup = static_cast<int>( hGroup );
|
||||
SmoothingGroup_t *pGroup = &m_aSmoothingGroups[iGroup];
|
||||
if ( pGroup )
|
||||
{
|
||||
return pGroup->m_aFaces.Count();
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
CMapFace *CSmoothingGroupMgr::GetFaceFromGroup( SmoothingGroupHandle_t hGroup, int iFace )
|
||||
{
|
||||
// Validate data.
|
||||
Assert( hGroup != INVALID_SMOOTHING_GROUP );
|
||||
Assert( hGroup >= 0 );
|
||||
Assert( hGroup < MAX_SMOOTHING_GROUP_COUNT );
|
||||
|
||||
int iGroup = static_cast<int>( hGroup );
|
||||
SmoothingGroup_t *pGroup = &m_aSmoothingGroups[iGroup];
|
||||
if ( pGroup )
|
||||
{
|
||||
return pGroup->m_aFaces[iFace];
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Save the smoothing group data.
|
||||
//-----------------------------------------------------------------------------
|
||||
ChunkFileResult_t CSmoothingGroupMgr::SaveVMF( CChunkFile *pFile, CSaveInfo *pSaveInfo )
|
||||
{
|
||||
int nGroupCount = 0;
|
||||
for ( int iGroup = 0; iGroup < MAX_SMOOTHING_GROUP_COUNT; ++iGroup )
|
||||
{
|
||||
if ( m_aSmoothingGroups[iGroup].m_aFaces.Count() != 0 )
|
||||
{
|
||||
nGroupCount++;
|
||||
}
|
||||
}
|
||||
|
||||
if ( nGroupCount == 0 )
|
||||
return ChunkFile_Ok;
|
||||
|
||||
ChunkFileResult_t eResult = pFile->BeginChunk( "smoothing_groups" );
|
||||
|
||||
for ( iGroup = 0; iGroup < MAX_SMOOTHING_GROUP_COUNT; ++iGroup )
|
||||
{
|
||||
SmoothingGroup_t *pGroup = &m_aSmoothingGroups[iGroup];
|
||||
int nFaceCount = pGroup->m_aFaces.Count();
|
||||
if ( nFaceCount == 0 )
|
||||
continue;
|
||||
|
||||
char szBuf[MAX_KEYVALUE_LEN];
|
||||
char szTemp[80];
|
||||
|
||||
// Save the smoothing group.
|
||||
if ( eResult == ChunkFile_Ok )
|
||||
{
|
||||
eResult = pFile->BeginChunk( "group" );
|
||||
if ( eResult == ChunkFile_Ok )
|
||||
{
|
||||
eResult = pFile->WriteKeyValueInt( "id", iGroup );
|
||||
|
||||
if ( eResult == ChunkFile_Ok )
|
||||
{
|
||||
eResult = pFile->WriteKeyValueFloat( "angle", pGroup->m_flSmoothingAngle );
|
||||
}
|
||||
|
||||
if ( eResult == ChunkFile_Ok )
|
||||
{
|
||||
eResult = pFile->WriteKeyValueInt( "number_faces", nFaceCount );
|
||||
}
|
||||
|
||||
if ( eResult == ChunkFile_Ok )
|
||||
{
|
||||
int nColCount = 20;
|
||||
int nRowCount = ( nFaceCount / nColCount ) + 1;
|
||||
|
||||
for ( int iRow = 0; iRow < nRowCount; ++iRow )
|
||||
{
|
||||
bool bFirst = true;
|
||||
szBuf[0] = '\0';
|
||||
|
||||
for ( int iCol = 0; iCol < nColCount; ++iCol )
|
||||
{
|
||||
int iFace = ( iRow * 20 ) + iCol;
|
||||
if ( iFace >= nFaceCount )
|
||||
continue;
|
||||
|
||||
if (!bFirst)
|
||||
{
|
||||
strcat(szBuf, " ");
|
||||
}
|
||||
|
||||
CMapFace *pFace = pGroup->m_aFaces[iFace];
|
||||
if ( pFace )
|
||||
{
|
||||
bFirst = false;
|
||||
sprintf( szTemp, "%d", pFace->GetFaceID() );
|
||||
strcat( szBuf, szTemp );
|
||||
}
|
||||
}
|
||||
|
||||
char szKey[10];
|
||||
sprintf( szKey, "row%d", iRow );
|
||||
eResult = pFile->WriteKeyValue( szKey, szBuf );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( eResult == ChunkFile_Ok )
|
||||
{
|
||||
eResult = pFile->EndChunk();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( eResult == ChunkFile_Ok )
|
||||
{
|
||||
eResult = pFile->EndChunk();
|
||||
}
|
||||
|
||||
return eResult;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Load smoothing group data.
|
||||
//-----------------------------------------------------------------------------
|
||||
ChunkFileResult_t CSmoothingGroupMgr::LoadVMF( CChunkFile *pFile )
|
||||
{
|
||||
// ChunkFileResult_t eResult = pFile->ReadChunk( ( KeyHandler_t )LoadSmoothingGroupMgrCallback, this );
|
||||
// return eResult;
|
||||
|
||||
return ChunkFile_Ok;
|
||||
}
|
||||
|
||||
#if 0
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
ChunkFileResult_t CSmoothingGroupMgr::LoadSmoothingGroupMgrCallback( const char *szKey, const char *szValue,
|
||||
CSmoothingGroupMgr *pSmoothingGroupMgr )
|
||||
{
|
||||
// Get a pointer to the next available smoothing group slot.
|
||||
SmoothingGroup_t *pGroup = new SmoothingGroup_t;
|
||||
if ( !pGroup )
|
||||
return;
|
||||
|
||||
// Set up handlers for the subchunks that we are interested in.
|
||||
CChunkHandlerMap Handlers;
|
||||
Handlers.AddHandler( "group", ( ChunkHandler_t )LoadsSmoothingGroupCallback, SmoothingGroup_t *pGroup );
|
||||
|
||||
pFile->PushHandlers( &Handlers );
|
||||
ChunkFileResult_t eResult = pFile->ReadChunk( ( KeyHandler_t )LoadSmoothingGroupMgrCallback, this );
|
||||
pFile->PopHandlers();
|
||||
|
||||
if ( eResult == ChunkFile_Ok )
|
||||
{
|
||||
pGroup->m_nID
|
||||
|
||||
SmoothingGroup_t *pLoadGroup = &pSmoothingGroupMgr->m_aSmoothingGroups[pGroup->m_nID];
|
||||
if ( pLoadGroup )
|
||||
{
|
||||
pLoadGroup->m_nID = pGroup->m_nID;
|
||||
pLoadGroup->m_flSmoothingAngle = pGroup->m_flSmoothingAngle;
|
||||
pLoadGroup->m_aFaces.CopyArray( pGroup->m_aFaces.Base(), pGroup->m_aFaces.Count() );
|
||||
}
|
||||
}
|
||||
|
||||
return eResult;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
ChunkFileResult_t CSmoothingGroupMgr::LoadSmoothingGroupMgrKeyCallback( const char *szKey, const char *szValue,
|
||||
CSmoothingGroupMgr *pSmoothingGroupMgr )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
ChunkFileResult_t CSmoothingGroupMgr::LoadSmoothingGroupCallback( CChunkFile *pFile, SmoothingGroup_t *pGroup )
|
||||
{
|
||||
return( pFile->ReadChunk( ( KeyHandler_t )LoadDispNormalsKeyCallback, pGroup ) );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
ChunkFileResult_t CSmoothingGroupMgr::LoadSmoothingGroupKeyCallback( const char *szKey, const char *szValue, SmoothingGroup_t *pGroup )
|
||||
{
|
||||
int nId;
|
||||
if ( !strnicmp( szKey, "id", 2 ) )
|
||||
{
|
||||
CChunkFile::ReadKeyValueInt( szValue, pGroup->m_nID );
|
||||
}
|
||||
|
||||
if ( !strnicmp( szKey, "angle", 5 ) )
|
||||
{
|
||||
CChunkFile::ReadKeyValueFloat( szValue, pGroup->m_flSmoothingAngle );
|
||||
}
|
||||
|
||||
if ( !strnicmp( szKey, "number_faces", 12 ) )
|
||||
{
|
||||
int nFaceCount;
|
||||
CChunkFile::ReadKeyValueInt( szValue, nFaceCount );
|
||||
pGroup->m_aFaces.SetSize( nFaceCount );
|
||||
}
|
||||
|
||||
if ( !strnicmp(szKey, "row", 3 ) )
|
||||
{
|
||||
CMapDoc *pDoc = CMapDoc::GetActiveMapDoc();
|
||||
|
||||
char szBuf[MAX_KEYVALUE_LEN];
|
||||
strcpy( szBuf, szValue );
|
||||
|
||||
int iRow = atoi( &szKey[3] );
|
||||
|
||||
char *pszNext = strtok( szBuf, " " );
|
||||
int nIndex = nRow * 20;
|
||||
|
||||
int nFaceID;
|
||||
while ( pszNext != NULL )
|
||||
{
|
||||
nFaceID = ( float )atof( pszNext );
|
||||
CMapFace *pFace =
|
||||
|
||||
|
||||
|
||||
CMapFace *CMapWorld::FaceID_FaceForID(int nFaceID)
|
||||
|
||||
|
||||
pszNext = strtok( NULL, " " );
|
||||
nIndex++;
|
||||
}
|
||||
}
|
||||
|
||||
return ChunkFile_Ok ;
|
||||
}
|
||||
#endif
|
||||
|
||||
45
hammer/SmoothingGroupMgr.h
Normal file
45
hammer/SmoothingGroupMgr.h
Normal file
@@ -0,0 +1,45 @@
|
||||
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef SMOOTHINGGROUPMGR_H
|
||||
#define SMOOTHINGGROUPMGR_H
|
||||
#pragma once
|
||||
|
||||
class CMapFace;
|
||||
class CChunkFile;
|
||||
class CSaveInfo;
|
||||
|
||||
enum ChunkFileResult_t;
|
||||
|
||||
#define MAX_SMOOTHING_GROUP_COUNT 32
|
||||
#define INVALID_SMOOTHING_GROUP 0xff
|
||||
|
||||
typedef unsigned char SmoothingGroupHandle_t;
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
// Smoothing Group Manager
|
||||
//
|
||||
class ISmoothingGroupMgr
|
||||
{
|
||||
public:
|
||||
|
||||
virtual void AddFaceToGroup( SmoothingGroupHandle_t hGroup, CMapFace *pFace ) = 0;
|
||||
virtual void RemoveFaceFromGroup( SmoothingGroupHandle_t hGroup, CMapFace *pFace ) = 0;
|
||||
|
||||
virtual void SetGroupSmoothingAngle( SmoothingGroupHandle_t hGroup, float flAngle ) = 0;
|
||||
virtual float GetGroupSmoothingAngle( SmoothingGroupHandle_t hGroup ) = 0;
|
||||
|
||||
virtual int GetFaceCountInGroup( SmoothingGroupHandle_t hGroup ) = 0;
|
||||
virtual CMapFace *GetFaceFromGroup( SmoothingGroupHandle_t hGroup, int iFace ) = 0;
|
||||
|
||||
virtual ChunkFileResult_t SaveVMF( CChunkFile *pFile, CSaveInfo *pSaveInfo ) = 0;
|
||||
virtual ChunkFileResult_t LoadVMF( CChunkFile *pFile ) = 0;
|
||||
};
|
||||
|
||||
ISmoothingGroupMgr *SmoothingGroupMgr( void );
|
||||
|
||||
#endif // SMOOTHINGGROUPMGR_H
|
||||
378
hammer/SoundBrowser.cpp
Normal file
378
hammer/SoundBrowser.cpp
Normal file
@@ -0,0 +1,378 @@
|
||||
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================//
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "hammer.h"
|
||||
#include "SoundBrowser.h"
|
||||
#include "mmsystem.h"
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include <tier0/memdbgon.h>
|
||||
|
||||
static LPCTSTR s_pszSection = "SoundBrowser";
|
||||
CStringArray CSoundBrowser::m_FilterHistory;
|
||||
int CSoundBrowser::m_nFilterHistory;
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// CSoundBrowser dialog
|
||||
|
||||
|
||||
CSoundBrowser::CSoundBrowser( const char *pCurrentSoundName, CWnd* pParent /*=NULL*/ )
|
||||
: CDialog(CSoundBrowser::IDD, pParent)
|
||||
{
|
||||
//{{AFX_DATA_INIT(CSoundBrowser)
|
||||
m_Autoplay = FALSE;
|
||||
m_SoundFile = _T("");
|
||||
m_SoundSource = _T("");
|
||||
//}}AFX_DATA_INIT
|
||||
|
||||
m_SoundNameSelected = pCurrentSoundName;
|
||||
m_SoundType = AfxGetApp()->GetProfileInt(s_pszSection, "Sound Type", 0);
|
||||
m_Autoplay = AfxGetApp()->GetProfileInt(s_pszSection, "Sound Autoplay", 0);
|
||||
Q_strncpy(m_szFilter, (LPCSTR)(AfxGetApp()->GetProfileString(s_pszSection, "Sound Filter", "")), 256 );
|
||||
m_nSelectedSoundIndex = -1;
|
||||
|
||||
// m_bSoundPlayed = false;
|
||||
}
|
||||
|
||||
void CSoundBrowser::SaveValues()
|
||||
{
|
||||
AfxGetApp()->WriteProfileInt(s_pszSection, "Sound Type", m_SoundType);
|
||||
AfxGetApp()->WriteProfileInt(s_pszSection, "Sound Autoplay", m_Autoplay);
|
||||
AfxGetApp()->WriteProfileString(s_pszSection, "Sound Filter", m_szFilter);
|
||||
}
|
||||
|
||||
void CSoundBrowser::DoDataExchange(CDataExchange* pDX)
|
||||
{
|
||||
CDialog::DoDataExchange(pDX);
|
||||
//{{AFX_DATA_MAP(CSoundBrowser)
|
||||
DDX_Control(pDX, IDC_SOUND_LIST, m_SoundList);
|
||||
DDX_Text(pDX, IDC_SOUNDNAME_SELECTED, m_SoundNameSelected);
|
||||
DDX_CBIndex(pDX, IDC_SOUND_TYPE, m_SoundType);
|
||||
DDX_Check(pDX, IDC_AUTOPLAY, m_Autoplay);
|
||||
DDX_Text(pDX, IDC_SOUND_FILE, m_SoundFile);
|
||||
DDX_Text(pDX, IDC_SOUND_SOURCE_FILE, m_SoundSource);
|
||||
//}}AFX_DATA_MAP
|
||||
}
|
||||
|
||||
|
||||
BEGIN_MESSAGE_MAP(CSoundBrowser, CDialog)
|
||||
//{{AFX_MSG_MAP(CSoundBrowser)
|
||||
ON_WM_CLOSE()
|
||||
ON_CBN_EDITCHANGE(IDC_SOUND_FILTER, OnChangeFilter)
|
||||
ON_CBN_SELENDOK(IDC_SOUND_FILTER, OnUpdateFilterNOW)
|
||||
ON_CBN_SELCHANGE(IDC_SOUND_TYPE, OnSelchangeSoundType)
|
||||
ON_LBN_SELCHANGE(IDC_SOUND_LIST, OnSelchangeSoundList)
|
||||
ON_LBN_DBLCLK(IDC_SOUND_LIST, OnDblclkSoundList)
|
||||
ON_BN_CLICKED(IDC_PREVIEW, OnPreview)
|
||||
ON_BN_CLICKED(IDC_AUTOPLAY, OnAutoplay)
|
||||
ON_BN_CLICKED(IDC_STOPSOUND, OnBnClickedStopsound)
|
||||
ON_BN_CLICKED(IDC_REFRESH_SOUNDS, OnRefreshSounds)
|
||||
ON_WM_TIMER()
|
||||
ON_BN_CLICKED(IDC_OPEN_SOURCE, OnOpenSource)
|
||||
//}}AFX_MSG_MAP
|
||||
END_MESSAGE_MAP()
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// CSoundBrowser message handlers
|
||||
|
||||
BOOL CSoundBrowser::OnInitDialog()
|
||||
{
|
||||
CDialog::OnInitDialog();
|
||||
|
||||
m_cFilter.SubclassDlgItem(IDC_SOUND_FILTER, this);
|
||||
for ( int i = 0; i < m_nFilterHistory; ++i )
|
||||
{
|
||||
m_cFilter.AddString( m_FilterHistory[i] );
|
||||
}
|
||||
|
||||
m_cFilter.SetWindowText(m_szFilter);
|
||||
|
||||
CString temp = m_szFilter;
|
||||
OnFilterChanged( temp );
|
||||
|
||||
// Select an entry in the list that has the same name as the one passed in
|
||||
int nIndex = m_SoundList.FindString( -1, m_SoundNameSelected );
|
||||
if ( nIndex != LB_ERR)
|
||||
{
|
||||
m_SoundList.SetCurSel( nIndex );
|
||||
m_nSelectedSoundIndex = nIndex;
|
||||
int nSoundIndex = m_SoundList.GetItemData(nIndex);
|
||||
m_SoundFile = g_Sounds.SoundFile( GetSoundType(), nSoundIndex );
|
||||
m_SoundSource = g_Sounds.SoundSourceFile( GetSoundType(), nSoundIndex );
|
||||
UpdateData( FALSE );
|
||||
}
|
||||
|
||||
SetTimer(1, 500, NULL);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void CSoundBrowser::OnClose(void)
|
||||
{
|
||||
Shutdown();
|
||||
CDialog::OnClose();
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Shutdown
|
||||
//-----------------------------------------------------------------------------
|
||||
void CSoundBrowser::Shutdown()
|
||||
{
|
||||
SaveValues();
|
||||
PlaySound( NULL, NULL, SND_FILENAME | SND_NODEFAULT);
|
||||
|
||||
// save current filter string
|
||||
int i;
|
||||
for (i = 0; i < m_nFilterHistory; i++)
|
||||
{
|
||||
if (!m_FilterHistory[i].CompareNoCase(m_szFilter))
|
||||
break;
|
||||
}
|
||||
|
||||
if(i != m_nFilterHistory) // delete first
|
||||
{
|
||||
m_FilterHistory.RemoveAt(i);
|
||||
--m_nFilterHistory;
|
||||
}
|
||||
|
||||
if ( m_szFilter[0] )
|
||||
{
|
||||
m_FilterHistory.InsertAt(0, m_szFilter);
|
||||
++m_nFilterHistory;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Clears, fills sound list
|
||||
//-----------------------------------------------------------------------------
|
||||
void CSoundBrowser::ClearSoundList()
|
||||
{
|
||||
m_SoundList.ResetContent();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Sound filter
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CSoundBrowser::ShowSoundInList( const char *pSoundName )
|
||||
{
|
||||
for (int i = 0; i < m_nFilters; i++)
|
||||
{
|
||||
if ( Q_stristr(pSoundName, m_Filters[i]) == NULL )
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CSoundBrowser::PopulateSoundList()
|
||||
{
|
||||
m_SoundList.SetRedraw( FALSE );
|
||||
|
||||
ClearSoundList();
|
||||
|
||||
SoundType_t type = GetSoundType();
|
||||
for ( int i = g_Sounds.SoundCount( type ); --i >= 0; )
|
||||
{
|
||||
const char *pSoundName = g_Sounds.SoundName( type, i );
|
||||
if ( ShowSoundInList( pSoundName ) )
|
||||
{
|
||||
CString str;
|
||||
str.Format( _T(pSoundName) );
|
||||
int nIndex = m_SoundList.AddString( str );
|
||||
m_SoundList.SetItemDataPtr( nIndex, (PVOID)i );
|
||||
}
|
||||
}
|
||||
|
||||
m_SoundList.SetRedraw( TRUE );
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Sound type
|
||||
//-----------------------------------------------------------------------------
|
||||
SoundType_t CSoundBrowser::GetSoundType() const
|
||||
{
|
||||
if ( m_SoundType == 0 )
|
||||
return SOUND_TYPE_GAMESOUND;
|
||||
else if ( m_SoundType == 1 )
|
||||
return SOUND_TYPE_RAW;
|
||||
else
|
||||
return SOUND_TYPE_SCENE;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Sound name
|
||||
//-----------------------------------------------------------------------------
|
||||
void CSoundBrowser::CopySoundNameToSelected()
|
||||
{
|
||||
UpdateData( TRUE );
|
||||
|
||||
int nIndex = m_SoundList.GetCurSel();
|
||||
if ( nIndex != LB_ERR )
|
||||
{
|
||||
int nSoundIndex = m_SoundList.GetItemData(nIndex);
|
||||
m_SoundNameSelected = g_Sounds.SoundName( GetSoundType(), nSoundIndex );
|
||||
m_SoundFile = g_Sounds.SoundFile( GetSoundType(), nSoundIndex );
|
||||
m_SoundSource = g_Sounds.SoundSourceFile( GetSoundType(), nSoundIndex );
|
||||
m_nSelectedSoundIndex = nSoundIndex;
|
||||
UpdateData( FALSE );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Update the filter:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CSoundBrowser::OnFilterChanged( const char *pFilter )
|
||||
{
|
||||
Q_strncpy( m_szFilter, pFilter, 256 );
|
||||
m_nFilters = 0;
|
||||
char *p = strtok(m_szFilter, " ,;");
|
||||
while (p != NULL)
|
||||
{
|
||||
m_Filters[m_nFilters++] = p;
|
||||
p = strtok(NULL, " ,;");
|
||||
}
|
||||
PopulateSoundList();
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Timer used to control updates when the filter terms change.
|
||||
// Input : nIDEvent -
|
||||
//-----------------------------------------------------------------------------
|
||||
void CSoundBrowser::OnTimer(UINT nIDEvent)
|
||||
{
|
||||
if (!m_bFilterChanged)
|
||||
return;
|
||||
|
||||
if ((time(NULL) - m_uLastFilterChange) > 0)
|
||||
{
|
||||
KillTimer(nIDEvent);
|
||||
m_bFilterChanged = FALSE;
|
||||
|
||||
CString str;
|
||||
m_cFilter.GetWindowText(str);
|
||||
OnFilterChanged( str );
|
||||
|
||||
SetTimer(nIDEvent, 500, NULL);
|
||||
}
|
||||
|
||||
CDialog::OnTimer(nIDEvent);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Called when either the filter combo or the keywords combo text changes.
|
||||
//-----------------------------------------------------------------------------
|
||||
void CSoundBrowser::OnChangeFilter()
|
||||
{
|
||||
// Start a timer to repaint the texture window using the new filters.
|
||||
m_uLastFilterChange = time(NULL);
|
||||
m_bFilterChanged = true;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CSoundBrowser::OnUpdateFilterNOW()
|
||||
{
|
||||
m_uLastFilterChange = time(NULL);
|
||||
m_bFilterChanged = FALSE;
|
||||
|
||||
CString str;
|
||||
int iSel = m_cFilter.GetCurSel();
|
||||
m_cFilter.GetLBText(iSel, str);
|
||||
OnFilterChanged( str );
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Sound type changed
|
||||
//-----------------------------------------------------------------------------
|
||||
void CSoundBrowser::OnSelchangeSoundType()
|
||||
{
|
||||
UpdateData( TRUE );
|
||||
PopulateSoundList();
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Selected sound
|
||||
//-----------------------------------------------------------------------------
|
||||
const char *CSoundBrowser::GetSelectedSound()
|
||||
{
|
||||
return m_SoundNameSelected;
|
||||
}
|
||||
|
||||
|
||||
void CSoundBrowser::OnSelchangeSoundList()
|
||||
{
|
||||
CopySoundNameToSelected();
|
||||
if ( m_Autoplay )
|
||||
{
|
||||
OnPreview();
|
||||
}
|
||||
}
|
||||
|
||||
void CSoundBrowser::OnDblclkSoundList()
|
||||
{
|
||||
CopySoundNameToSelected();
|
||||
OnOK();
|
||||
}
|
||||
|
||||
void CSoundBrowser::OnPreview()
|
||||
{
|
||||
if ( m_nSelectedSoundIndex >= 0 )
|
||||
{
|
||||
g_Sounds.Play( GetSoundType(), m_nSelectedSoundIndex );
|
||||
}
|
||||
}
|
||||
|
||||
void CSoundBrowser::OnAutoplay()
|
||||
{
|
||||
UpdateData( TRUE );
|
||||
}
|
||||
|
||||
void CSoundBrowser::OnRefreshSounds()
|
||||
{
|
||||
// Set the title to "refreshing sounds..."
|
||||
CString oldTitle, newTitle;
|
||||
newTitle.LoadString( IDS_REFRESHING_SOUNDS );
|
||||
GetWindowText( oldTitle );
|
||||
SetWindowText( newTitle );
|
||||
|
||||
g_Sounds.Initialize();
|
||||
PopulateSoundList();
|
||||
|
||||
// Restore the title.
|
||||
SetWindowText( oldTitle );
|
||||
}
|
||||
|
||||
int CSoundBrowser::DoModal()
|
||||
{
|
||||
int nRet = CDialog::DoModal();
|
||||
Shutdown();
|
||||
return nRet;
|
||||
}
|
||||
|
||||
void CSoundBrowser::OnOpenSource()
|
||||
{
|
||||
if ( m_nSelectedSoundIndex >= 0 )
|
||||
{
|
||||
g_Sounds.OpenSource( GetSoundType(), m_nSelectedSoundIndex );
|
||||
}
|
||||
}
|
||||
|
||||
void CSoundBrowser::OnBnClickedStopsound()
|
||||
{
|
||||
g_Sounds.StopSound();
|
||||
}
|
||||
101
hammer/SoundBrowser.h
Normal file
101
hammer/SoundBrowser.h
Normal file
@@ -0,0 +1,101 @@
|
||||
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================//
|
||||
|
||||
#if !defined(AFX_SOUNDBROWSER_H__33046A12_7CF9_4031_AD10_A76200E73280__INCLUDED_)
|
||||
#define AFX_SOUNDBROWSER_H__33046A12_7CF9_4031_AD10_A76200E73280__INCLUDED_
|
||||
|
||||
#if _MSC_VER > 1000
|
||||
#pragma once
|
||||
#endif // _MSC_VER > 1000
|
||||
// SoundBrowser.h : header file
|
||||
//
|
||||
|
||||
#include "soundsystem.h"
|
||||
#include "AutoSelCombo.h"
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// CSoundBrowser dialog
|
||||
|
||||
class CSoundBrowser : public CDialog
|
||||
{
|
||||
// Construction
|
||||
public:
|
||||
CSoundBrowser( const char *pCurrentSoundName, CWnd* pParent = NULL); // standard constructor
|
||||
const char *GetSelectedSound();
|
||||
|
||||
// Dialog Data
|
||||
//{{AFX_DATA(CSoundBrowser)
|
||||
enum { IDD = IDD_SOUNDBROWSER };
|
||||
CListBox m_SoundList;
|
||||
CString m_SoundNameSelected;
|
||||
int m_SoundType;
|
||||
BOOL m_Autoplay;
|
||||
CString m_SoundFile;
|
||||
CString m_SoundSource;
|
||||
//}}AFX_DATA
|
||||
|
||||
|
||||
// Overrides
|
||||
// ClassWizard generated virtual function overrides
|
||||
//{{AFX_VIRTUAL(CSoundBrowser)
|
||||
public:
|
||||
virtual int DoModal();
|
||||
protected:
|
||||
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
|
||||
//}}AFX_VIRTUAL
|
||||
void SaveValues();
|
||||
|
||||
// Implementation
|
||||
protected:
|
||||
|
||||
// Generated message map functions
|
||||
//{{AFX_MSG(CSoundBrowser)
|
||||
virtual BOOL OnInitDialog();
|
||||
afx_msg void OnClose();
|
||||
afx_msg void OnChangeFilter();
|
||||
afx_msg void OnUpdateFilterNOW();
|
||||
afx_msg void OnSelchangeSoundType();
|
||||
afx_msg void OnSelchangeSoundList();
|
||||
afx_msg void OnDblclkSoundList();
|
||||
afx_msg void OnPreview();
|
||||
afx_msg void OnAutoplay();
|
||||
afx_msg void OnBnClickedStopsound();
|
||||
afx_msg void OnRefreshSounds();
|
||||
afx_msg void OnTimer(UINT nIDEvent);
|
||||
afx_msg void OnOpenSource();
|
||||
//}}AFX_MSG
|
||||
DECLARE_MESSAGE_MAP()
|
||||
|
||||
private:
|
||||
void Shutdown();
|
||||
void ClearSoundList();
|
||||
void PopulateSoundList();
|
||||
void CopySoundNameToSelected();
|
||||
SoundType_t GetSoundType() const;
|
||||
bool ShowSoundInList( const char *pSoundName );
|
||||
void OnFilterChanged( const char *pFilter );
|
||||
|
||||
DWORD m_uLastFilterChange;
|
||||
BOOL m_bFilterChanged;
|
||||
|
||||
BOOL m_bSoundPlayed; // used so we can do a timer query to keep disable the stop sound button
|
||||
DWORD m_uSoundPlayTime;
|
||||
|
||||
int m_nSelectedSoundIndex;
|
||||
|
||||
CAutoSelComboBox m_cFilter;
|
||||
char m_szFilter[256]; // Name filter, space, comma, or semicolon delimited.
|
||||
int m_nFilters; // The number of names that were parsed out of the name filter.
|
||||
char *m_Filters[64]; // The individual name filters.
|
||||
|
||||
static CStringArray m_FilterHistory;
|
||||
static int m_nFilterHistory;
|
||||
};
|
||||
|
||||
//{{AFX_INSERT_LOCATION}}
|
||||
// Microsoft Visual C++ will insert additional declarations immediately before the previous line.
|
||||
|
||||
#endif // !defined(AFX_SOUNDBROWSER_H__33046A12_7CF9_4031_AD10_A76200E73280__INCLUDED_)
|
||||
149
hammer/ToolAxisHandle.cpp
Normal file
149
hammer/ToolAxisHandle.cpp
Normal file
@@ -0,0 +1,149 @@
|
||||
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "History.h"
|
||||
#include "MainFrm.h" // For ObjectProperties
|
||||
#include "MapDoc.h"
|
||||
#include "MapAxisHandle.h"
|
||||
#include "MapPointHandle.h"
|
||||
#include "MapView2D.h"
|
||||
#include "Render2D.h"
|
||||
#include "StatusBarIDs.h" // For SetStatusText
|
||||
#include "ToolManager.h"
|
||||
#include "ToolAxisHandle.h"
|
||||
#include "ToolPointHandle.h"
|
||||
#include "Selection.h"
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include <tier0/memdbgon.h>
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Constructor.
|
||||
//-----------------------------------------------------------------------------
|
||||
CToolAxisHandle::CToolAxisHandle(void)
|
||||
{
|
||||
m_pAxis = NULL;
|
||||
m_nPointIndex = 0;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Attaches the point to the tool for manipulation.
|
||||
//-----------------------------------------------------------------------------
|
||||
void CToolAxisHandle::Attach(CMapAxisHandle *pAxis, int nPointIndex)
|
||||
{
|
||||
if ((pAxis != NULL) && (nPointIndex < 2))
|
||||
{
|
||||
m_pAxis = pAxis;
|
||||
m_nPointIndex = nPointIndex;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Handles left button down events in the 2D view.
|
||||
// Input : Per CWnd::OnLButtonDown.
|
||||
// Output : Returns true if the message was handled, false if not.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CToolAxisHandle::OnLMouseDown2D(CMapView2D *pView, UINT nFlags, const Vector2D &vPoint)
|
||||
{
|
||||
//
|
||||
// Activate this tool and start dragging the axis endpoint.
|
||||
//
|
||||
ToolManager()->PushTool(TOOL_AXIS_HANDLE);
|
||||
pView->SetCapture();
|
||||
|
||||
CMapDoc *pDoc = pView->GetMapDoc();
|
||||
GetHistory()->MarkUndoPosition(pDoc->GetSelection()->GetList(), "Modify Axis");
|
||||
GetHistory()->Keep(m_pAxis);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Handles left button up events in the 2D view.
|
||||
// Input : Per CWnd::OnLButtonUp.
|
||||
// Output : Returns true if the message was handled, false if not.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CToolAxisHandle::OnLMouseUp2D(CMapView2D *pView, UINT nFlags, const Vector2D &vPoint)
|
||||
{
|
||||
// dvsFIXME: do we need to update the point here?
|
||||
|
||||
ToolManager()->PopTool();
|
||||
ReleaseCapture();
|
||||
|
||||
CMapDoc *pDoc = pView->GetMapDoc();
|
||||
pDoc->UpdateAllViews( MAPVIEW_UPDATE_TOOL );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Handles mouse move events in the 2D view.
|
||||
// Input : Per CWnd::OnMouseMove.
|
||||
// Output : Returns true if the message was handled, false if not.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CToolAxisHandle::OnMouseMove2D(CMapView2D *pView, UINT nFlags, const Vector2D &vPoint)
|
||||
{
|
||||
//
|
||||
// Make sure the point is visible.
|
||||
//
|
||||
pView->ToolScrollToPoint( vPoint);
|
||||
|
||||
//
|
||||
// Snap the point to half the grid size. Do this so that we can always center
|
||||
// the axis even on odd-width objects.
|
||||
//
|
||||
Vector vecWorld;
|
||||
pView->ClientToWorld(vecWorld, vPoint);
|
||||
|
||||
CMapDoc *pDoc = pView->GetMapDoc();
|
||||
pDoc->Snap(vecWorld, constrainHalfSnap);
|
||||
|
||||
//
|
||||
// Move to the snapped position.
|
||||
//
|
||||
Vector vecPos[2];
|
||||
m_pAxis->GetEndPoint(vecPos[m_nPointIndex], m_nPointIndex);
|
||||
|
||||
vecPos[m_nPointIndex][pView->axHorz] = vecWorld[pView->axHorz];
|
||||
vecPos[m_nPointIndex][pView->axVert] = vecWorld[pView->axVert];
|
||||
|
||||
m_pAxis->UpdateEndPoint(vecPos[m_nPointIndex], m_nPointIndex);
|
||||
|
||||
int nOtherIndex = (m_nPointIndex == 0);
|
||||
m_pAxis->GetEndPoint(vecPos[nOtherIndex], nOtherIndex);
|
||||
|
||||
//
|
||||
// Update the status bar and the views.
|
||||
//
|
||||
char szBuf[128];
|
||||
sprintf(szBuf, " (%.0f %.0f %0.f) ", vecPos[m_nPointIndex][0], vecPos[m_nPointIndex][1], vecPos[m_nPointIndex][2]);
|
||||
SetStatusText(SBI_COORDS, szBuf);
|
||||
|
||||
pDoc->UpdateAllViews( MAPVIEW_UPDATE_TOOL );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Renders the tool in the 2D view.
|
||||
// Input : pRender - The interface to use for rendering.
|
||||
//-----------------------------------------------------------------------------
|
||||
void CToolAxisHandle::RenderTool2D(CRender2D *pRender)
|
||||
{
|
||||
SelectionState_t eState = m_pAxis->SetSelectionState(SELECT_MODIFY, m_nPointIndex);
|
||||
m_pAxis->Render2D(pRender);
|
||||
m_pAxis->SetSelectionState(eState);
|
||||
}
|
||||
|
||||
|
||||
47
hammer/ToolAxisHandle.h
Normal file
47
hammer/ToolAxisHandle.h
Normal file
@@ -0,0 +1,47 @@
|
||||
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef TOOLAXISHANDLE_H
|
||||
#define TOOLAXISHANDLE_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include "ToolInterface.h"
|
||||
|
||||
|
||||
class CMapAxisHandle;
|
||||
class CMapPointHandle;
|
||||
|
||||
|
||||
class CToolAxisHandle : public CBaseTool
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
CToolAxisHandle(void);
|
||||
void Attach(CMapAxisHandle *pPoint, int nPointIndex);
|
||||
|
||||
//
|
||||
// CBaseTool implementation.
|
||||
//
|
||||
virtual ToolID_t GetToolID(void) { return TOOL_AXIS_HANDLE; }
|
||||
|
||||
virtual bool OnLMouseDown2D(CMapView2D *pView, UINT nFlags, const Vector2D &vPoint);
|
||||
virtual bool OnLMouseUp2D(CMapView2D *pView, UINT nFlags, const Vector2D &vPoint);
|
||||
virtual bool OnMouseMove2D(CMapView2D *pView, UINT nFlags, const Vector2D &vPoint);
|
||||
|
||||
virtual void RenderTool2D(CRender2D *pRender);
|
||||
//virtual void RenderTool3D(CRender3D *pRender);
|
||||
|
||||
private:
|
||||
|
||||
CMapAxisHandle *m_pAxis; // The axis we are manipulating.
|
||||
int m_nPointIndex; // The index of the endpoint we are manipulating [0,1].
|
||||
};
|
||||
|
||||
#endif // TOOLAXISHANDLE_H
|
||||
45
hammer/ToolBase.cpp
Normal file
45
hammer/ToolBase.cpp
Normal file
@@ -0,0 +1,45 @@
|
||||
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================//
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "ToolInterface.h"
|
||||
#include "mapdoc.h"
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include <tier0/memdbgon.h>
|
||||
|
||||
void CBaseTool::Init( CMapDoc *pDocument )
|
||||
{
|
||||
m_bActiveTool = false;
|
||||
m_pDocument = pDocument;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Called whtn this tool is becoming the active tool.
|
||||
// Input : eOldTool - The tool that was previously active.
|
||||
//-----------------------------------------------------------------------------
|
||||
void CBaseTool::Activate()
|
||||
{
|
||||
OnActivate();
|
||||
|
||||
m_pDocument->UpdateAllViews( MAPVIEW_UPDATE_TOOL );
|
||||
|
||||
m_bActiveTool = true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Called when this tool is no longer the active tool.
|
||||
// Input : eNewTool - The tool that is being activated.
|
||||
//-----------------------------------------------------------------------------
|
||||
void CBaseTool::Deactivate()
|
||||
{
|
||||
OnDeactivate();
|
||||
|
||||
if ( m_pDocument )
|
||||
m_pDocument->UpdateAllViews( MAPVIEW_UPDATE_TOOL );
|
||||
|
||||
m_bActiveTool = false;
|
||||
}
|
||||
518
hammer/ToolBlock.cpp
Normal file
518
hammer/ToolBlock.cpp
Normal file
@@ -0,0 +1,518 @@
|
||||
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "History.h"
|
||||
#include "MainFrm.h"
|
||||
#include "MapDefs.h"
|
||||
#include "MapDoc.h"
|
||||
#include "MapView2D.h"
|
||||
#include "MapView3D.h"
|
||||
#include "Options.h"
|
||||
#include "StatusBarIDs.h"
|
||||
#include "ToolBlock.h"
|
||||
#include "ToolManager.h"
|
||||
#include "vgui/Cursor.h"
|
||||
#include "Selection.h"
|
||||
|
||||
|
||||
class CToolBlockMessageWnd : public CWnd
|
||||
{
|
||||
public:
|
||||
|
||||
bool Create(void);
|
||||
void PreMenu2D(CToolBlock *pTool, CMapView2D *pView);
|
||||
|
||||
protected:
|
||||
|
||||
//{{AFX_MSG_MAP(CToolBlockMessageWnd)
|
||||
afx_msg void OnCreateObject();
|
||||
//}}AFX_MSG
|
||||
|
||||
DECLARE_MESSAGE_MAP()
|
||||
|
||||
private:
|
||||
|
||||
CToolBlock *m_pToolBlock;
|
||||
CMapView2D *m_pView2D;
|
||||
};
|
||||
|
||||
|
||||
static CToolBlockMessageWnd s_wndToolMessage;
|
||||
static const char *g_pszClassName = "ValveEditor_BlockToolWnd";
|
||||
|
||||
|
||||
BEGIN_MESSAGE_MAP(CToolBlockMessageWnd, CWnd)
|
||||
//{{AFX_MSG_MAP(CToolMessageWnd)
|
||||
ON_COMMAND(ID_CREATEOBJECT, OnCreateObject)
|
||||
//}}AFX_MSG_MAP
|
||||
END_MESSAGE_MAP()
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Creates the hidden window that receives context menu commands for the
|
||||
// block tool.
|
||||
// Output : Returns true on success, false on failure.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CToolBlockMessageWnd::Create(void)
|
||||
{
|
||||
WNDCLASS wndcls;
|
||||
memset(&wndcls, 0, sizeof(WNDCLASS));
|
||||
wndcls.lpfnWndProc = AfxWndProc;
|
||||
wndcls.hInstance = AfxGetInstanceHandle();
|
||||
wndcls.lpszClassName = g_pszClassName;
|
||||
|
||||
if (!AfxRegisterClass(&wndcls))
|
||||
{
|
||||
return(false);
|
||||
}
|
||||
|
||||
return(CWnd::CreateEx(0, g_pszClassName, g_pszClassName, 0, CRect(0, 0, 10, 10), NULL, 0) == TRUE);
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Attaches the block tool to this window before activating the context
|
||||
// menu.
|
||||
//-----------------------------------------------------------------------------
|
||||
void CToolBlockMessageWnd::PreMenu2D(CToolBlock *pToolBlock, CMapView2D *pView)
|
||||
{
|
||||
Assert(pToolBlock != NULL);
|
||||
m_pToolBlock = pToolBlock;
|
||||
m_pView2D = pView;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CToolBlockMessageWnd::OnCreateObject()
|
||||
{
|
||||
m_pToolBlock->CreateMapObject(m_pView2D);
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Constructor.
|
||||
//-----------------------------------------------------------------------------
|
||||
CToolBlock::CToolBlock(void)
|
||||
{
|
||||
// We always show our dimensions when we render.
|
||||
SetDrawFlags(GetDrawFlags() | Box3D::boundstext);
|
||||
SetDrawColors(Options.colors.clrToolHandle, Options.colors.clrToolBlock);
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Destructor.
|
||||
//-----------------------------------------------------------------------------
|
||||
CToolBlock::~CToolBlock(void)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Handles key down events in the 2D view.
|
||||
// Input : Per CWnd::OnKeyDown.
|
||||
// Output : Returns true if the message was handled, false if not.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CToolBlock::OnKeyDown2D(CMapView2D *pView, UINT nChar, UINT nRepCnt, UINT nFlags)
|
||||
{
|
||||
switch (nChar)
|
||||
{
|
||||
case VK_RETURN:
|
||||
{
|
||||
if ( !IsEmpty() )
|
||||
{
|
||||
CreateMapObject(pView);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
case VK_ESCAPE:
|
||||
{
|
||||
OnEscape();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Handles context menu events in the 2D view.
|
||||
// Input : Per CWnd::OnContextMenu.
|
||||
// Output : Returns true if the message was handled, false if not.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CToolBlock::OnContextMenu2D(CMapView2D *pView, UINT nFlags, const Vector2D &vPoint)
|
||||
{
|
||||
static CMenu menu, menuCreate;
|
||||
static bool bInit = false;
|
||||
|
||||
if (!bInit)
|
||||
{
|
||||
bInit = true;
|
||||
|
||||
// Create the menu.
|
||||
menu.LoadMenu(IDR_POPUPS);
|
||||
menuCreate.Attach(::GetSubMenu(menu.m_hMenu, 1));
|
||||
|
||||
// Create the window that handles menu messages.
|
||||
s_wndToolMessage.Create();
|
||||
}
|
||||
|
||||
if ( !pView->PointInClientRect(vPoint) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( !IsEmpty() )
|
||||
{
|
||||
if ( HitTest(pView, vPoint, false) )
|
||||
{
|
||||
CPoint ptScreen( vPoint.x,vPoint.y);
|
||||
pView->ClientToScreen(&ptScreen);
|
||||
|
||||
s_wndToolMessage.PreMenu2D(this, pView);
|
||||
menuCreate.TrackPopupMenu(TPM_LEFTBUTTON | TPM_RIGHTBUTTON | TPM_LEFTALIGN, ptScreen.x, ptScreen.y, &s_wndToolMessage);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Handles left mouse button down events in the 2D view.
|
||||
// Input : Per CWnd::OnLButtonDown.
|
||||
// Output : Returns true if the message was handled, false if not.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CToolBlock::OnLMouseDown3D(CMapView3D *pView, UINT nFlags, const Vector2D &vPoint)
|
||||
{
|
||||
Tool3D::OnLMouseDown3D(pView, nFlags, vPoint);
|
||||
|
||||
//
|
||||
// If we have a box, see if they clicked on any part of it.
|
||||
//
|
||||
if ( !IsEmpty() )
|
||||
{
|
||||
if ( HitTest( pView, vPoint, true ) )
|
||||
{
|
||||
// just update current block
|
||||
StartTranslation( pView, vPoint, m_LastHitTestHandle );
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Handles left mouse button down events in the 2D view.
|
||||
// Input : Per CWnd::OnLButtonDown.
|
||||
// Output : Returns true if the message was handled, false if not.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CToolBlock::OnLMouseDown2D(CMapView2D *pView, UINT nFlags, const Vector2D &vPoint)
|
||||
{
|
||||
Tool3D::OnLMouseDown2D(pView, nFlags, vPoint);
|
||||
|
||||
// If we have a box, see if they clicked on any part of it.
|
||||
if ( !IsEmpty() )
|
||||
{
|
||||
if ( HitTest( pView, vPoint, true ) )
|
||||
{
|
||||
// just update current block
|
||||
StartTranslation( pView, vPoint, m_LastHitTestHandle );
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Handles left mouse button up events in the 2D view.
|
||||
// Input : Per CWnd::OnLButtonUp.
|
||||
// Output : Returns true if the message was handled, false if not.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CToolBlock::OnLMouseUp2D(CMapView2D *pView, UINT nFlags, const Vector2D &vPoint)
|
||||
{
|
||||
Tool3D::OnLMouseUp2D(pView, nFlags, vPoint);
|
||||
|
||||
if (IsTranslating())
|
||||
{
|
||||
FinishTranslation(true);
|
||||
}
|
||||
|
||||
m_pDocument->UpdateStatusbar();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Handles left mouse button up events in the 2D view.
|
||||
// Input : Per CWnd::OnLButtonUp.
|
||||
// Output : Returns true if the message was handled, false if not.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CToolBlock::OnLMouseUp3D(CMapView3D *pView, UINT nFlags, const Vector2D &vPoint)
|
||||
{
|
||||
Tool3D::OnLMouseUp3D(pView, nFlags, vPoint);
|
||||
|
||||
if (IsTranslating())
|
||||
{
|
||||
FinishTranslation(true);
|
||||
}
|
||||
|
||||
m_pDocument->UpdateStatusbar();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Handles mouse move events in the 2D view.
|
||||
// Input : Per CWnd::OnMouseMove.
|
||||
// Output : Returns true if the message was handled, false if not.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CToolBlock::OnMouseMove2D(CMapView2D *pView, UINT nFlags, const Vector2D &vPoint)
|
||||
{
|
||||
vgui::HCursor hCursor = vgui::dc_arrow;
|
||||
|
||||
// Snap it to the grid.
|
||||
unsigned int uConstraints = GetConstraints( nFlags );
|
||||
|
||||
Tool3D::OnMouseMove2D(pView, nFlags, vPoint);
|
||||
|
||||
//
|
||||
//
|
||||
// Convert to world coords.
|
||||
//
|
||||
Vector vecWorld;
|
||||
pView->ClientToWorld(vecWorld, vPoint);
|
||||
|
||||
//
|
||||
// Update status bar position display.
|
||||
//
|
||||
char szBuf[128];
|
||||
|
||||
if ( uConstraints & constrainSnap )
|
||||
m_pDocument->Snap(vecWorld,uConstraints);
|
||||
|
||||
sprintf(szBuf, " @%.0f, %.0f ", vecWorld[pView->axHorz], vecWorld[pView->axVert]);
|
||||
SetStatusText(SBI_COORDS, szBuf);
|
||||
|
||||
if ( IsTranslating() )
|
||||
{
|
||||
Tool3D::UpdateTranslation( pView, vPoint, uConstraints);
|
||||
|
||||
hCursor = vgui::dc_none;
|
||||
}
|
||||
else if ( m_bMouseDragged[MOUSE_LEFT] )
|
||||
{
|
||||
// Starting a new box. Build a starting point for the drag.
|
||||
pView->SetCursor( "Resource/block.cur" );
|
||||
|
||||
Vector vecStart;
|
||||
pView->ClientToWorld(vecStart, m_vMouseStart[MOUSE_LEFT] );
|
||||
|
||||
// Snap it to the grid.
|
||||
if ( uConstraints & constrainSnap )
|
||||
m_pDocument->Snap( vecStart, uConstraints);
|
||||
|
||||
// Start the new box with the extents of the last selected thing.
|
||||
|
||||
Vector bmins,bmaxs;
|
||||
m_pDocument->GetSelection()->GetLastValidBounds(bmins, bmaxs);
|
||||
|
||||
vecStart[pView->axThird] = bmins[pView->axThird];
|
||||
|
||||
StartNew(pView, vPoint, vecStart, pView->GetViewAxis() * (bmaxs-bmins) );
|
||||
}
|
||||
else if ( !IsEmpty() )
|
||||
{
|
||||
// If the cursor is on a handle, set it to a cross.
|
||||
if ( HitTest(pView, vPoint, true) )
|
||||
{
|
||||
hCursor = UpdateCursor( pView, m_LastHitTestHandle, m_TranslateMode );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if ( hCursor != vgui::dc_none )
|
||||
pView->SetCursor( hCursor );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CToolBlock::OnMouseMove3D(CMapView3D *pView, UINT nFlags, const Vector2D &vPoint)
|
||||
{
|
||||
Tool3D::OnMouseMove3D(pView, nFlags, vPoint);
|
||||
|
||||
if ( IsTranslating() )
|
||||
{
|
||||
unsigned int uConstraints = GetConstraints( nFlags );
|
||||
|
||||
// If they are dragging with a valid handle, update the views.
|
||||
Tool3D::UpdateTranslation( pView, vPoint, uConstraints );
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Handles key down events in the 3D view.
|
||||
// Input : Per CWnd::OnKeyDown.
|
||||
// Output : Returns true if the message was handled, false if not.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CToolBlock::OnKeyDown3D(CMapView3D *pView, UINT nChar, UINT nRepCnt, UINT nFlags)
|
||||
{
|
||||
switch (nChar)
|
||||
{
|
||||
case VK_RETURN:
|
||||
{
|
||||
if ( !IsEmpty() )
|
||||
{
|
||||
CreateMapObject(pView);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
case VK_ESCAPE:
|
||||
{
|
||||
OnEscape();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Handles the escape key in the 2D or 3D views.
|
||||
//-----------------------------------------------------------------------------
|
||||
void CToolBlock::OnEscape(void)
|
||||
{
|
||||
//
|
||||
// If we have nothing blocked, go back to the pointer tool.
|
||||
//
|
||||
if ( IsEmpty() )
|
||||
{
|
||||
ToolManager()->SetTool(TOOL_POINTER);
|
||||
}
|
||||
//
|
||||
// We're blocking out a region, so clear it.
|
||||
//
|
||||
else
|
||||
{
|
||||
SetEmpty();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Creates a solid in the given view.
|
||||
//-----------------------------------------------------------------------------
|
||||
void CToolBlock::CreateMapObject(CMapView *pView)
|
||||
{
|
||||
CMapWorld *pWorld = m_pDocument->GetMapWorld();
|
||||
|
||||
if (!(bmaxs[0] - bmins[0]) || !(bmaxs[1] - bmins[1]) || !(bmaxs[2] - bmins[2]))
|
||||
{
|
||||
AfxMessageBox("The box is empty.");
|
||||
SetEmpty();
|
||||
return;
|
||||
}
|
||||
|
||||
BoundBox NewBox = *this;
|
||||
if (Options.view2d.bOrientPrimitives)
|
||||
{
|
||||
switch (pView->GetDrawType())
|
||||
{
|
||||
case VIEW2D_XY:
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
case VIEW2D_YZ:
|
||||
{
|
||||
NewBox.Rotate90(AXIS_Y);
|
||||
break;
|
||||
}
|
||||
|
||||
case VIEW2D_XZ:
|
||||
{
|
||||
NewBox.Rotate90(AXIS_X);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Create the object within the given bounding box.
|
||||
CMapClass *pObject = GetMainWnd()->m_ObjectBar.CreateInBox(&NewBox, pView);
|
||||
if (pObject == NULL)
|
||||
{
|
||||
SetEmpty();
|
||||
return;
|
||||
}
|
||||
|
||||
m_pDocument->ExpandObjectKeywords(pObject, pWorld);
|
||||
|
||||
GetHistory()->MarkUndoPosition(m_pDocument->GetSelection()->GetList(), "New Object");
|
||||
|
||||
m_pDocument->AddObjectToWorld(pObject);
|
||||
|
||||
//
|
||||
// Do we need to rotate this object based on the view we created it in?
|
||||
//
|
||||
if (Options.view2d.bOrientPrimitives)
|
||||
{
|
||||
Vector center;
|
||||
pObject->GetBoundsCenter( center );
|
||||
|
||||
QAngle angles(0, 0, 0);
|
||||
switch (pView->GetDrawType())
|
||||
{
|
||||
case VIEW2D_XY:
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
case VIEW2D_YZ:
|
||||
{
|
||||
angles[1] = 90.f;
|
||||
pObject->TransRotate(center, angles);
|
||||
break;
|
||||
}
|
||||
|
||||
case VIEW2D_XZ:
|
||||
{
|
||||
angles[0] = 90.f;
|
||||
pObject->TransRotate(center, angles);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GetHistory()->KeepNew(pObject);
|
||||
|
||||
// Select the new object.
|
||||
m_pDocument->SelectObject(pObject, scClear|scSelect|scSaveChanges);
|
||||
|
||||
m_pDocument->SetModifiedFlag();
|
||||
|
||||
SetEmpty();
|
||||
ResetBounds();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
57
hammer/ToolBlock.h
Normal file
57
hammer/ToolBlock.h
Normal file
@@ -0,0 +1,57 @@
|
||||
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef TOOLBLOCK_H
|
||||
#define TOOLBLOCK_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
|
||||
#include "Box3D.h"
|
||||
#include "ToolInterface.h"
|
||||
|
||||
|
||||
class CToolBlockMessageWnd;
|
||||
|
||||
|
||||
class CToolBlock : public Box3D
|
||||
{
|
||||
|
||||
friend class CToolBlockMessageWnd;
|
||||
|
||||
public:
|
||||
|
||||
CToolBlock();
|
||||
~CToolBlock();
|
||||
|
||||
//
|
||||
// CBaseTool implementation.
|
||||
//
|
||||
virtual ToolID_t GetToolID(void) { return TOOL_BLOCK; }
|
||||
|
||||
virtual bool OnContextMenu2D(CMapView2D *pView, UINT nFlags, const Vector2D &vPoint);
|
||||
virtual bool OnKeyDown2D(CMapView2D *pView, UINT nChar, UINT nRepCnt, UINT nFlags);
|
||||
virtual bool OnLMouseDown2D(CMapView2D *pView, UINT nFlags, const Vector2D &vPoint);
|
||||
virtual bool OnLMouseDown3D(CMapView3D *pView, UINT nFlags, const Vector2D &vPoint) ;
|
||||
virtual bool OnLMouseUp2D(CMapView2D *pView, UINT nFlags, const Vector2D &vPoint);
|
||||
virtual bool OnMouseMove2D(CMapView2D *pView, UINT nFlags, const Vector2D &vPoint);
|
||||
virtual bool OnMouseMove3D(CMapView3D *pView, UINT nFlags, const Vector2D &vPoint);
|
||||
virtual bool OnLMouseUp3D(CMapView3D *pView, UINT nFlags, const Vector2D &vPoint);
|
||||
|
||||
virtual bool OnKeyDown3D(CMapView3D *pView, UINT nChar, UINT nRepCnt, UINT nFlags);
|
||||
|
||||
private:
|
||||
|
||||
void CreateMapObject(CMapView *pView);
|
||||
void OnEscape();
|
||||
|
||||
void SetBlockCursor();
|
||||
};
|
||||
|
||||
|
||||
#endif // TOOLBLOCK_H
|
||||
816
hammer/ToolCamera.cpp
Normal file
816
hammer/ToolCamera.cpp
Normal file
@@ -0,0 +1,816 @@
|
||||
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "ToolCamera.h"
|
||||
#include "SaveInfo.h"
|
||||
#include "MainFrm.h" // dvs: remove?
|
||||
#include "MapDefs.h"
|
||||
#include "MapDoc.h"
|
||||
#include "MapView2D.h"
|
||||
#include "MapView3D.h"
|
||||
#include "Options.h"
|
||||
#include "Render2D.h"
|
||||
#include "StatusBarIDs.h" // dvs: remove
|
||||
#include "ToolManager.h"
|
||||
#include "hammer_mathlib.h"
|
||||
#include "vgui/Cursor.h"
|
||||
#include "Selection.h"
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include <tier0/memdbgon.h>
|
||||
|
||||
#pragma warning(disable:4244)
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
Camera3D::Camera3D(void)
|
||||
{
|
||||
Cameras.EnsureCapacity(16);
|
||||
SetEmpty();
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Returns true if we are dragging a camera, false if not. // dvs: rename
|
||||
//-----------------------------------------------------------------------------
|
||||
bool Camera3D::IsEmpty(void)
|
||||
{
|
||||
return (Cameras.Count() == 0);
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void Camera3D::SetEmpty(void)
|
||||
{
|
||||
Cameras.RemoveAll();
|
||||
m_iActiveCamera = -1;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : pt -
|
||||
// BOOL -
|
||||
// Output : int
|
||||
//-----------------------------------------------------------------------------
|
||||
int Camera3D::HitTest(CMapView *pView, const Vector2D &ptClient, bool bTestHandles)
|
||||
{
|
||||
for(int i = 0; i < Cameras.Count(); i++)
|
||||
{
|
||||
for ( int j=0; j<2; j++ )
|
||||
{
|
||||
if( HitRect( pView, ptClient, Cameras[i].position[j], HANDLE_RADIUS ) )
|
||||
{
|
||||
return MAKELONG(i+1, j);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Get rid of extra cameras if we have too many.
|
||||
//-----------------------------------------------------------------------------
|
||||
void Camera3D::EnsureMaxCameras()
|
||||
{
|
||||
int nMax = max( Options.general.nMaxCameras, 1 );
|
||||
|
||||
int nToRemove = Cameras.Count() - nMax;
|
||||
if ( nToRemove > 0 )
|
||||
{
|
||||
m_iActiveCamera = max( m_iActiveCamera - nToRemove, 0 );
|
||||
|
||||
while ( nToRemove-- )
|
||||
Cameras.Remove( 0 );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : bSave -
|
||||
//-----------------------------------------------------------------------------
|
||||
void Camera3D::FinishTranslation(bool bSave)
|
||||
{
|
||||
if (bSave)
|
||||
{
|
||||
if ( m_iActiveCamera == Cameras.Count() )
|
||||
{
|
||||
Cameras.AddToTail();
|
||||
EnsureMaxCameras();
|
||||
}
|
||||
|
||||
Cameras[m_iActiveCamera] = m_MoveCamera;
|
||||
}
|
||||
|
||||
Tool3D::FinishTranslation(bSave);
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : pt -
|
||||
// uFlags -
|
||||
// CSize& -
|
||||
// Output : Returns TRUE on success, FALSE on failure.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool Camera3D::UpdateTranslation(const Vector &vUpdate, UINT uFlags)
|
||||
{
|
||||
Vector vCamDelta = m_MoveCamera.position[1] - m_MoveCamera.position[0];
|
||||
|
||||
Vector vNewPos = m_vOrgPos + vUpdate;
|
||||
|
||||
// snap point if need be
|
||||
if ( uFlags & constrainSnap )
|
||||
m_pDocument->Snap( vNewPos, uFlags );
|
||||
|
||||
m_MoveCamera.position[m_nMovePositionIndex] = vNewPos;
|
||||
|
||||
if(uFlags & constrainMoveAll)
|
||||
{
|
||||
m_MoveCamera.position[(m_nMovePositionIndex+1)%2] = vNewPos + vCamDelta;
|
||||
}
|
||||
|
||||
m_pDocument->UpdateAllViews( MAPVIEW_UPDATE_TOOL );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : pCamPos -
|
||||
// iCamera -
|
||||
//-----------------------------------------------------------------------------
|
||||
void Camera3D::GetCameraPos(Vector &vViewPos, Vector &vLookAt)
|
||||
{
|
||||
if(!inrange(m_iActiveCamera, 0, Cameras.Count()))
|
||||
{
|
||||
vViewPos.Init();
|
||||
vLookAt.Init();
|
||||
return;
|
||||
}
|
||||
|
||||
vViewPos = Cameras[m_iActiveCamera].position[0];
|
||||
vLookAt = Cameras[m_iActiveCamera].position[1];
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : pCamPos -
|
||||
// iCamera -
|
||||
//-----------------------------------------------------------------------------
|
||||
void Camera3D::AddCamera(CAMSTRUCT &camera)
|
||||
{
|
||||
Cameras.AddToTail( camera );
|
||||
EnsureMaxCameras();
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : pRender -
|
||||
//-----------------------------------------------------------------------------
|
||||
void Camera3D::RenderTool2D(CRender2D *pRender)
|
||||
{
|
||||
for (int i = 0; i < Cameras.Count(); i++)
|
||||
{
|
||||
CAMSTRUCT *pDrawCam = &Cameras[i];
|
||||
|
||||
if (IsTranslating() && (i == m_iActiveCamera))
|
||||
{
|
||||
pDrawCam = &m_MoveCamera;
|
||||
}
|
||||
|
||||
//
|
||||
// Draw the line between.
|
||||
//
|
||||
if (i == m_iActiveCamera)
|
||||
{
|
||||
pRender->SetDrawColor( 255, 0, 0 );
|
||||
}
|
||||
else
|
||||
{
|
||||
pRender->SetDrawColor( 0, 255, 255 );
|
||||
}
|
||||
|
||||
pRender->DrawLine( pDrawCam->position[MovePos], pDrawCam->position[MoveLook] );
|
||||
|
||||
//
|
||||
// Draw camera handle.
|
||||
//
|
||||
pRender->SetHandleStyle(HANDLE_RADIUS, CRender::HANDLE_CIRCLE );
|
||||
pRender->SetHandleColor( 0, 255, 255 );
|
||||
pRender->DrawHandle( pDrawCam->position[MovePos] );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Handles key values being read from the MAP file.
|
||||
// Input : szKey - Key being loaded.
|
||||
// szValue - Value of the key being loaded.
|
||||
// pCam - Camera structure to place the values into.
|
||||
// Output : Returns ChunkFile_Ok to indicate success.
|
||||
//-----------------------------------------------------------------------------
|
||||
ChunkFileResult_t Camera3D::LoadCameraKeyCallback(const char *szKey, const char *szValue, CAMSTRUCT *pCam)
|
||||
{
|
||||
if (!stricmp(szKey, "look"))
|
||||
{
|
||||
CChunkFile::ReadKeyValueVector3(szValue, pCam->position[MoveLook]);
|
||||
}
|
||||
else if (!stricmp(szKey, "position"))
|
||||
{
|
||||
CChunkFile::ReadKeyValueVector3(szValue, pCam->position[MovePos]);
|
||||
}
|
||||
|
||||
return(ChunkFile_Ok);
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Handles key values being read from the MAP file.
|
||||
// Input : szKey - Key being loaded.
|
||||
// szValue - Value of the key being loaded.
|
||||
// pCam - Camera structure to place the values into.
|
||||
// Output : Returns ChunkFile_Ok to indicate success.
|
||||
//-----------------------------------------------------------------------------
|
||||
ChunkFileResult_t Camera3D::LoadCamerasKeyCallback(const char *szKey, const char *szValue, Camera3D *pCameras)
|
||||
{
|
||||
if (!stricmp(szKey, "activecamera"))
|
||||
{
|
||||
pCameras->m_iActiveCamera = atoi(szValue);
|
||||
}
|
||||
|
||||
return(ChunkFile_Ok);
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : *pLoadInfo -
|
||||
// *pSolid -
|
||||
// Output : ChunkFileResult_t
|
||||
//-----------------------------------------------------------------------------
|
||||
ChunkFileResult_t Camera3D::LoadCameraCallback(CChunkFile *pFile, Camera3D *pCameras)
|
||||
{
|
||||
CAMSTRUCT Cam;
|
||||
memset(&Cam, 0, sizeof(Cam));
|
||||
|
||||
ChunkFileResult_t eResult = pFile->ReadChunk((KeyHandler_t)LoadCameraKeyCallback, &Cam);
|
||||
|
||||
if (eResult == ChunkFile_Ok)
|
||||
{
|
||||
pCameras->AddCamera( Cam );
|
||||
}
|
||||
|
||||
return(eResult);
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : *pFile -
|
||||
// Output : ChunkFileResult_t
|
||||
//-----------------------------------------------------------------------------
|
||||
ChunkFileResult_t Camera3D::LoadVMF(CChunkFile *pFile)
|
||||
{
|
||||
//
|
||||
// Set up handlers for the subchunks that we are interested in.
|
||||
//
|
||||
CChunkHandlerMap Handlers;
|
||||
Handlers.AddHandler("camera", (ChunkHandler_t)LoadCameraCallback, this);
|
||||
|
||||
pFile->PushHandlers(&Handlers);
|
||||
ChunkFileResult_t eResult = pFile->ReadChunk((KeyHandler_t)LoadCamerasKeyCallback, this);
|
||||
pFile->PopHandlers();
|
||||
|
||||
if (eResult == ChunkFile_Ok)
|
||||
{
|
||||
//
|
||||
// Make sure the active camera is legal.
|
||||
//
|
||||
if (Cameras.Count() == 0)
|
||||
{
|
||||
m_iActiveCamera = -1;
|
||||
}
|
||||
else if (!inrange(m_iActiveCamera, 0, Cameras.Count()))
|
||||
{
|
||||
m_iActiveCamera = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return(eResult);
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : &dir -
|
||||
// &pos -
|
||||
//-----------------------------------------------------------------------------
|
||||
void Camera3D::UpdateActiveCamera(Vector &vViewPos, Vector &vDir)
|
||||
{
|
||||
if(!inrange(m_iActiveCamera, 0, Cameras.Count()))
|
||||
return;
|
||||
|
||||
Vector& camPos = Cameras[m_iActiveCamera].position[MovePos];
|
||||
Vector& lookPos = Cameras[m_iActiveCamera].position[MoveLook];
|
||||
|
||||
// get current length
|
||||
Vector delta;
|
||||
for(int i = 0; i < 3; i++)
|
||||
delta[i] = camPos[i] - lookPos[i];
|
||||
|
||||
float length = VectorLength(delta);
|
||||
|
||||
if ( length < 1 )
|
||||
length = 1;
|
||||
|
||||
camPos = vViewPos;
|
||||
|
||||
for(int i = 0; i < 3; i++)
|
||||
lookPos[i] = camPos[i] + vDir[i] * length;
|
||||
|
||||
if ( IsActiveTool() )
|
||||
{
|
||||
if (Options.view2d.bCenteroncamera)
|
||||
{
|
||||
VIEW2DINFO vi;
|
||||
vi.wFlags = VI_CENTER;
|
||||
vi.ptCenter = vViewPos;
|
||||
m_pDocument->SetView2dInfo(vi);
|
||||
}
|
||||
|
||||
m_pDocument->UpdateAllViews( MAPVIEW_UPDATE_TOOL );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : type -
|
||||
//-----------------------------------------------------------------------------
|
||||
void Camera3D::SetNextCamera(SNCTYPE type)
|
||||
{
|
||||
if(Cameras.Count()==0)
|
||||
{
|
||||
m_iActiveCamera = -1;
|
||||
return;
|
||||
}
|
||||
|
||||
switch(type)
|
||||
{
|
||||
case sncNext:
|
||||
++m_iActiveCamera;
|
||||
if(m_iActiveCamera >= Cameras.Count() )
|
||||
m_iActiveCamera = 0;
|
||||
break;
|
||||
case sncPrev:
|
||||
--m_iActiveCamera;
|
||||
if(m_iActiveCamera < 0)
|
||||
m_iActiveCamera = Cameras.Count()-1;
|
||||
break;
|
||||
case sncFirst:
|
||||
m_iActiveCamera = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void Camera3D::DeleteActiveCamera()
|
||||
{
|
||||
if(!inrange(m_iActiveCamera, 0, Cameras.Count()))
|
||||
return;
|
||||
|
||||
Cameras.Remove(m_iActiveCamera);
|
||||
|
||||
if(m_iActiveCamera >= Cameras.Count() )
|
||||
m_iActiveCamera = Cameras.Count()-1;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : file -
|
||||
// fIsStoring -
|
||||
//-----------------------------------------------------------------------------
|
||||
void Camera3D::SerializeRMF(std::fstream& file, BOOL fIsStoring)
|
||||
{
|
||||
float fVersion = 0.2f, fThisVersion;
|
||||
|
||||
int nCameras = Cameras.Count();
|
||||
|
||||
if(fIsStoring)
|
||||
{
|
||||
file.write((char*)&fVersion, sizeof(fVersion) );
|
||||
|
||||
file.write((char*)&m_iActiveCamera, sizeof(m_iActiveCamera) );
|
||||
file.write((char*)&nCameras, sizeof(nCameras));
|
||||
for(int i = 0; i < nCameras; i++)
|
||||
{
|
||||
file.write((char*)&Cameras[i], sizeof(CAMSTRUCT));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
file.read((char*)&fThisVersion, sizeof(fThisVersion) );
|
||||
|
||||
if(fThisVersion >= 0.2f)
|
||||
{
|
||||
file.read((char*)&m_iActiveCamera, sizeof(m_iActiveCamera));
|
||||
}
|
||||
|
||||
file.read((char*)&nCameras, sizeof (nCameras) );
|
||||
|
||||
Cameras.RemoveAll();
|
||||
Cameras.EnsureCapacity(nCameras);
|
||||
|
||||
for(int i = 0; i < nCameras; i++)
|
||||
{
|
||||
CAMSTRUCT cam;
|
||||
file.read((char*)&cam, sizeof(CAMSTRUCT));
|
||||
Cameras.AddToTail( cam );
|
||||
}
|
||||
EnsureMaxCameras();
|
||||
|
||||
Assert( Cameras.Count() == nCameras );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : *pFile -
|
||||
// Output : ChunkFileResult_t
|
||||
//-----------------------------------------------------------------------------
|
||||
ChunkFileResult_t Camera3D::SaveVMF(CChunkFile *pFile, CSaveInfo *pSaveInfo)
|
||||
{
|
||||
ChunkFileResult_t eResult = pFile->BeginChunk( GetVMFChunkName() );
|
||||
if (eResult == ChunkFile_Ok)
|
||||
{
|
||||
eResult = pFile->WriteKeyValueInt("activecamera", m_iActiveCamera);
|
||||
}
|
||||
|
||||
if (eResult == ChunkFile_Ok)
|
||||
{
|
||||
for (int i = 0; i < Cameras.Count(); i++)
|
||||
{
|
||||
eResult = pFile->BeginChunk("camera");
|
||||
|
||||
if (eResult == ChunkFile_Ok)
|
||||
{
|
||||
eResult = pFile->WriteKeyValueVector3("position", Cameras[i].position[MovePos]);
|
||||
}
|
||||
|
||||
if (eResult == ChunkFile_Ok)
|
||||
{
|
||||
eResult = pFile->WriteKeyValueVector3("look", Cameras[i].position[MoveLook]);
|
||||
}
|
||||
|
||||
if (eResult == ChunkFile_Ok)
|
||||
{
|
||||
eResult = pFile->EndChunk();
|
||||
}
|
||||
|
||||
if (eResult != ChunkFile_Ok)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (eResult == ChunkFile_Ok)
|
||||
{
|
||||
eResult = pFile->EndChunk();
|
||||
}
|
||||
|
||||
return(eResult);
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Handles the key down event in the 2D view.
|
||||
// Input : Per CWnd::OnKeyDown.
|
||||
// Output : Returns true if the message was handled, false if not.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool Camera3D::OnKeyDown2D(CMapView2D *pView, UINT nChar, UINT nRepCnt, UINT nFlags)
|
||||
{
|
||||
if (nChar == VK_DELETE || nChar == VK_NEXT || nChar == VK_PRIOR)
|
||||
{
|
||||
CMapDoc *pDoc = pView->GetMapDoc();
|
||||
|
||||
if (nChar == VK_DELETE)
|
||||
{
|
||||
DeleteActiveCamera();
|
||||
}
|
||||
else if (nChar == VK_NEXT)
|
||||
{
|
||||
SetNextCamera(Camera3D::sncNext);
|
||||
}
|
||||
else
|
||||
{
|
||||
SetNextCamera(Camera3D::sncPrev);
|
||||
}
|
||||
|
||||
Vector viewPos,lookAt;
|
||||
|
||||
GetCameraPos( viewPos, lookAt );
|
||||
pDoc->UpdateAllCameras( &viewPos, &lookAt, NULL );
|
||||
|
||||
return true;
|
||||
}
|
||||
else if (nChar == VK_ESCAPE)
|
||||
{
|
||||
OnEscape();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Handles the left mouse button down event in the 2D view.
|
||||
// Input : Per CWnd::OnLButtonDown.
|
||||
// Output : Returns true if the message was handled, false if not.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool Camera3D::OnLMouseDown2D(CMapView2D *pView, UINT nFlags, const Vector2D &vPoint)
|
||||
{
|
||||
CMapDoc *pDoc = pView->GetMapDoc();
|
||||
|
||||
pView->SetCapture();
|
||||
|
||||
//
|
||||
// If there are no cameras created yet or they are holding down
|
||||
// the SHIFT key, create a new camera now.
|
||||
//
|
||||
|
||||
Vector vecWorld;
|
||||
pView->ClientToWorld( vecWorld, vPoint );
|
||||
|
||||
if ( IsEmpty() || (nFlags & MK_SHIFT))
|
||||
{
|
||||
//
|
||||
// Build a point in world space to place the new camera.
|
||||
//
|
||||
|
||||
if ( !pDoc->GetSelection()->IsEmpty() )
|
||||
{
|
||||
Vector vecCenter;
|
||||
pDoc->GetSelection()->GetBoundsCenter(vecCenter);
|
||||
vecWorld[pView->axThird] = vecCenter[pView->axThird];
|
||||
}
|
||||
else
|
||||
{
|
||||
vecWorld[pView->axThird] = COORD_NOTINIT;
|
||||
pDoc->GetBestVisiblePoint(vecWorld);
|
||||
}
|
||||
|
||||
//
|
||||
// Create a new camera.
|
||||
//
|
||||
m_vOrgPos = vecWorld;
|
||||
m_MoveCamera.position[MovePos] = vecWorld;
|
||||
m_MoveCamera.position[MoveLook] = vecWorld;
|
||||
m_nMovePositionIndex = MoveLook;
|
||||
|
||||
// set as active camera
|
||||
m_iActiveCamera = Cameras.AddToTail(m_MoveCamera);;
|
||||
EnsureMaxCameras();
|
||||
|
||||
StartTranslation(pView, vPoint );
|
||||
}
|
||||
//
|
||||
// Otherwise, try to drag an existing camera handle.
|
||||
//
|
||||
else
|
||||
{
|
||||
int dwHit = HitTest( pView, vPoint );
|
||||
|
||||
if ( dwHit )
|
||||
{
|
||||
m_iActiveCamera = LOWORD(dwHit)-1;
|
||||
m_MoveCamera = Cameras[m_iActiveCamera];
|
||||
m_nMovePositionIndex = HIWORD(dwHit);
|
||||
m_vOrgPos = m_MoveCamera.position[m_nMovePositionIndex];
|
||||
StartTranslation( pView, vPoint );
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Handles the left mouse button up event in the 2D view.
|
||||
// Input : Per CWnd::OnLButtonUp.
|
||||
// Output : Returns true if the message was handled, false if not.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool Camera3D::OnLMouseUp2D(CMapView2D *pView, UINT nFlags, const Vector2D &vPoint)
|
||||
{
|
||||
ReleaseCapture();
|
||||
|
||||
if (IsTranslating())
|
||||
{
|
||||
FinishTranslation(true);
|
||||
|
||||
Vector viewPos, lookAt;
|
||||
GetCameraPos( viewPos, lookAt );
|
||||
|
||||
m_pDocument->UpdateAllCameras( &viewPos, &lookAt, NULL );
|
||||
}
|
||||
|
||||
m_pDocument->UpdateStatusbar();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
unsigned int Camera3D::GetConstraints(unsigned int nKeyFlags)
|
||||
{
|
||||
unsigned int uConstraints = Tool3D::GetConstraints( nKeyFlags );
|
||||
|
||||
if(nKeyFlags & MK_CONTROL)
|
||||
{
|
||||
uConstraints |= constrainMoveAll;
|
||||
}
|
||||
|
||||
return uConstraints;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Handles the mouse move event in the 2D view.
|
||||
// Input : Per CWnd::OnMouseMove.
|
||||
// Output : Returns true if the message was handled, false if not.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool Camera3D::OnMouseMove2D(CMapView2D *pView, UINT nFlags, const Vector2D &vPoint)
|
||||
{
|
||||
CMapDoc *pDoc = pView->GetMapDoc();
|
||||
if (!pDoc)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
vgui::HCursor hCursor = vgui::dc_arrow;
|
||||
|
||||
unsigned int uConstraints = GetConstraints( nFlags );
|
||||
|
||||
// Make sure the point is visible.
|
||||
|
||||
pView->ToolScrollToPoint( vPoint );
|
||||
|
||||
//
|
||||
// Convert to world coords.
|
||||
//
|
||||
Vector vecWorld;
|
||||
pView->ClientToWorld(vecWorld, vPoint);
|
||||
|
||||
//
|
||||
// Update status bar position display.
|
||||
//
|
||||
char szBuf[128];
|
||||
|
||||
m_pDocument->Snap(vecWorld,uConstraints);
|
||||
|
||||
sprintf(szBuf, " @%.0f, %.0f ", vecWorld[pView->axHorz], vecWorld[pView->axVert] );
|
||||
SetStatusText(SBI_COORDS, szBuf);
|
||||
|
||||
if (IsTranslating())
|
||||
{
|
||||
Tool3D::UpdateTranslation(pView, vPoint, uConstraints );
|
||||
|
||||
hCursor = vgui::dc_none;
|
||||
}
|
||||
else if ( !IsEmpty() )
|
||||
{
|
||||
//
|
||||
// If the cursor is on a handle, set it to a cross.
|
||||
//
|
||||
if ( HitTest( pView, vPoint, true) )
|
||||
{
|
||||
hCursor = vgui::dc_crosshair;
|
||||
}
|
||||
}
|
||||
|
||||
if ( hCursor != vgui::dc_none )
|
||||
pView->SetCursor( hCursor );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Handles the left mouse button down event in the 3D view.
|
||||
// Input : Per CWnd::OnLButtonDown.
|
||||
// Output : Returns true if the message was handled, false if not.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool Camera3D::OnLMouseDown3D(CMapView3D *pView, UINT nFlags, const Vector2D &vPoint)
|
||||
{
|
||||
pView->EnableRotating(true);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Handles the left mouse up down event in the 3D view.
|
||||
// Input : Per CWnd::OnLButtonUp.
|
||||
// Output : Returns true if the message was handled, false if not.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool Camera3D::OnLMouseUp3D(CMapView3D *pView, UINT nFlags, const Vector2D &vPoint)
|
||||
{
|
||||
pView->EnableRotating(false);
|
||||
pView->UpdateCameraVariables();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Handles the right mouse button down event in the 3D view.
|
||||
// Input : Per CWnd::OnRButtonDown.
|
||||
// Output : Returns true if the message was handled, false if not.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool Camera3D::OnRMouseDown3D(CMapView3D *pView, UINT nFlags, const Vector2D &vPoint)
|
||||
{
|
||||
pView->EnableStrafing(true);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Handles the right mouse button up event in the 3D view.
|
||||
// Input : Per CWnd::OnRButtonUp.
|
||||
// Output : Returns true if the message was handled, false if not.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool Camera3D::OnRMouseUp3D(CMapView3D *pView, UINT nFlags, const Vector2D &vPoint)
|
||||
{
|
||||
pView->EnableStrafing(false);
|
||||
pView->UpdateCameraVariables();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Handles the key down event in the 3D view.
|
||||
// Input : Per CWnd::OnKeyDown.
|
||||
// Output : Returns true if the message was handled, false if not.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool Camera3D::OnKeyDown3D(CMapView3D *pView, UINT nChar, UINT nRepCnt, UINT nFlags)
|
||||
{
|
||||
if (nChar == VK_DELETE || nChar == VK_NEXT || nChar == VK_PRIOR)
|
||||
{
|
||||
CMapDoc *pDoc = pView->GetMapDoc();
|
||||
|
||||
if (nChar == VK_DELETE)
|
||||
{
|
||||
DeleteActiveCamera();
|
||||
}
|
||||
else if (nChar == VK_NEXT)
|
||||
{
|
||||
SetNextCamera(Camera3D::sncNext);
|
||||
}
|
||||
else
|
||||
{
|
||||
SetNextCamera(Camera3D::sncPrev);
|
||||
}
|
||||
|
||||
Vector viewPos, lookAt;
|
||||
GetCameraPos( viewPos, lookAt );
|
||||
|
||||
pDoc->UpdateAllCameras( &viewPos, &lookAt, NULL );
|
||||
|
||||
return true;
|
||||
}
|
||||
else if (nChar == VK_ESCAPE)
|
||||
{
|
||||
OnEscape();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Handles the escape key in the 2D or 3D views.
|
||||
//-----------------------------------------------------------------------------
|
||||
void Camera3D::OnEscape(void)
|
||||
{
|
||||
//
|
||||
// Stop using the camera tool.
|
||||
//
|
||||
m_pDocument->GetTools()->SetTool(TOOL_POINTER);
|
||||
}
|
||||
|
||||
132
hammer/ToolCamera.h
Normal file
132
hammer/ToolCamera.h
Normal file
@@ -0,0 +1,132 @@
|
||||
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef CAMERA3D_H
|
||||
#define CAMERA3D_H
|
||||
#pragma once
|
||||
|
||||
|
||||
#include "Tool3D.h"
|
||||
#include "ToolInterface.h"
|
||||
#include "utlvector.h"
|
||||
#pragma warning(push, 1)
|
||||
#pragma warning(disable:4701 4702 4530)
|
||||
#include <fstream>
|
||||
#pragma warning(pop)
|
||||
|
||||
|
||||
|
||||
class CChunkFile;
|
||||
class CSaveInfo;
|
||||
|
||||
|
||||
enum ChunkFileResult_t;
|
||||
|
||||
|
||||
//
|
||||
// Defines a camera position/look pair.
|
||||
//
|
||||
struct CAMSTRUCT
|
||||
{
|
||||
// index 0 = camera origin, 1 = pos look to
|
||||
Vector position[2];
|
||||
};
|
||||
|
||||
|
||||
class Camera3D : public Tool3D
|
||||
{
|
||||
public:
|
||||
|
||||
Camera3D(void);
|
||||
|
||||
enum SNCTYPE
|
||||
{
|
||||
sncNext = -1,
|
||||
sncFirst = 0,
|
||||
sncPrev = 1
|
||||
};
|
||||
|
||||
int GetActiveCamera(void) { return m_iActiveCamera; }
|
||||
void GetCameraPos(Vector &vViewPos, Vector &vLookAt);
|
||||
void UpdateActiveCamera(Vector &vViewPos, Vector &vLookAt);
|
||||
|
||||
//
|
||||
// Serialization.
|
||||
//
|
||||
const char *GetVMFChunkName() { return "cameras"; }
|
||||
ChunkFileResult_t LoadVMF(CChunkFile *pFile);
|
||||
ChunkFileResult_t SaveVMF(CChunkFile *pFile, CSaveInfo *pSaveInfo);
|
||||
void SerializeRMF(std::fstream &file, BOOL fIsStoring);
|
||||
|
||||
//
|
||||
// Tool3D implementation.
|
||||
//
|
||||
virtual bool IsEmpty(void);
|
||||
virtual void SetEmpty(void);
|
||||
virtual unsigned int GetConstraints(unsigned int nKeyFlags);
|
||||
|
||||
//
|
||||
// CBaseTool implementation.
|
||||
//
|
||||
virtual ToolID_t GetToolID(void) { return TOOL_CAMERA; }
|
||||
|
||||
virtual bool OnKeyDown2D(CMapView2D *pView, UINT nChar, UINT nRepCnt, UINT nFlags);
|
||||
virtual bool OnLMouseDown2D(CMapView2D *pView, UINT nFlags, const Vector2D &vPoint);
|
||||
virtual bool OnLMouseUp2D(CMapView2D *pView, UINT nFlags, const Vector2D &vPoint);
|
||||
virtual bool OnMouseMove2D(CMapView2D *pView, UINT nFlags, const Vector2D &vPoint);
|
||||
|
||||
virtual bool OnLMouseDown3D(CMapView3D *pView, UINT nFlags, const Vector2D &vPoint);
|
||||
virtual bool OnLMouseUp3D(CMapView3D *pView, UINT nFlags, const Vector2D &vPoint);
|
||||
virtual bool OnRMouseDown3D(CMapView3D *pView, UINT nFlags, const Vector2D &vPoint);
|
||||
virtual bool OnRMouseUp3D(CMapView3D *pView, UINT nFlags, const Vector2D &vPoint);
|
||||
virtual bool OnKeyDown3D(CMapView3D *pView, UINT nChar, UINT nRepCnt, UINT nFlags);
|
||||
|
||||
virtual void RenderTool2D(CRender2D *pRender);
|
||||
|
||||
protected:
|
||||
|
||||
//
|
||||
// Tool3D implementation.
|
||||
//
|
||||
virtual int HitTest(CMapView *pView, const Vector2D &vPoint, bool bTestHandles = false);
|
||||
virtual bool UpdateTranslation(const Vector &vUpdate, UINT flags = 0);
|
||||
virtual void FinishTranslation(bool bSave);
|
||||
|
||||
private:
|
||||
|
||||
int GetCameraCount() { return Cameras.Count(); }
|
||||
void AddCamera(CAMSTRUCT &pCamPos);
|
||||
|
||||
void SetNextCamera(SNCTYPE next);
|
||||
void DeleteActiveCamera(void);
|
||||
|
||||
void OnEscape(void);
|
||||
void EnsureMaxCameras();
|
||||
|
||||
static ChunkFileResult_t LoadCameraKeyCallback(const char *szKey, const char *szValue, CAMSTRUCT *pCam);
|
||||
static ChunkFileResult_t LoadCamerasKeyCallback(const char *szKey, const char *szValue, Camera3D *pCameras);
|
||||
static ChunkFileResult_t LoadCameraCallback(CChunkFile *pFile, Camera3D *pCameras);
|
||||
|
||||
|
||||
|
||||
CUtlVector<CAMSTRUCT> Cameras; // The cameras that have been created.
|
||||
CAMSTRUCT m_MoveCamera;
|
||||
|
||||
enum
|
||||
{
|
||||
MovePos = 0,
|
||||
MoveLook = 1,
|
||||
};
|
||||
|
||||
int m_iActiveCamera;
|
||||
int m_nMovePositionIndex;
|
||||
Vector m_vOrgPos;
|
||||
};
|
||||
|
||||
|
||||
#endif // CAMERA3D_H
|
||||
|
||||
987
hammer/ToolClipper.cpp
Normal file
987
hammer/ToolClipper.cpp
Normal file
@@ -0,0 +1,987 @@
|
||||
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "GlobalFunctions.h"
|
||||
#include "History.h"
|
||||
#include "MapDefs.h"
|
||||
#include "MapDoc.h"
|
||||
#include "MapFace.h"
|
||||
#include "MapSolid.h"
|
||||
#include "MapView2D.h"
|
||||
#include "MapWorld.h"
|
||||
#include "Options.h"
|
||||
#include "Render2D.h"
|
||||
#include "Render3D.h"
|
||||
#include "RenderUtils.h"
|
||||
#include "StatusBarIDs.h" // dvs: remove
|
||||
#include "ToolClipper.h"
|
||||
#include "ToolManager.h"
|
||||
#include "vgui/Cursor.h"
|
||||
#include "Selection.h"
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include <tier0/memdbgon.h>
|
||||
|
||||
|
||||
#pragma warning( disable:4244 )
|
||||
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
// Friend Function (for MapClass->EnumChildren Callback)
|
||||
//
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: This function creates a new clip group with the given solid as
|
||||
// the original solid.
|
||||
// Input: pSolid - the original solid to put in the clip list
|
||||
// pClipper - the clipper tool
|
||||
// Output: successful?? (true/false)
|
||||
//-----------------------------------------------------------------------------
|
||||
BOOL AddToClipList( CMapSolid *pSolid, Clipper3D *pClipper )
|
||||
{
|
||||
CClipGroup *pClipGroup = new CClipGroup;
|
||||
if( !pClipGroup )
|
||||
return false;
|
||||
|
||||
pClipGroup->SetOrigSolid( pSolid );
|
||||
pClipper->m_ClipResults.AddToTail( pClipGroup );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
// CClipGroup
|
||||
//
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Destructor. Gets rid of the unnecessary clip solids.
|
||||
//-----------------------------------------------------------------------------
|
||||
CClipGroup::~CClipGroup()
|
||||
{
|
||||
delete m_pClipSolids[0];
|
||||
delete m_pClipSolids[1];
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: constructor - initialize the clipper variables
|
||||
//-----------------------------------------------------------------------------
|
||||
Clipper3D::Clipper3D(void)
|
||||
{
|
||||
m_Mode = FRONT;
|
||||
|
||||
m_ClipPlane.normal.Init();
|
||||
m_ClipPlane.dist = 0.0f;
|
||||
m_ClipPoints[0].Init();
|
||||
m_ClipPoints[1].Init();
|
||||
m_ClipPointHit = -1;
|
||||
|
||||
m_pOrigObjects = NULL;
|
||||
|
||||
m_bDrawMeasurements = false;
|
||||
SetEmpty();
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: deconstructor
|
||||
//-----------------------------------------------------------------------------
|
||||
Clipper3D::~Clipper3D(void)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Called when the tool is activated.
|
||||
// Input : eOldTool - The ID of the previously active tool.
|
||||
//-----------------------------------------------------------------------------
|
||||
void Clipper3D::OnActivate()
|
||||
{
|
||||
if (IsActiveTool())
|
||||
{
|
||||
//
|
||||
// Already the active tool - toggle the mode.
|
||||
//
|
||||
IterateClipMode();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Called when the tool is deactivated.
|
||||
// Input : eNewTool - The ID of the tool that is being activated.
|
||||
//-----------------------------------------------------------------------------
|
||||
void Clipper3D::OnDeactivate()
|
||||
{
|
||||
SetEmpty();
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: (virtual imp) This function handles the "dragging" of the mouse
|
||||
// while the left mouse button is depressed. It updates the position
|
||||
// of the clippoing plane point selected in the StartTranslation
|
||||
// function. This function rebuilds the clipping plane and updates
|
||||
// the clipping solids when necessary.
|
||||
// Input: pt - current location of the mouse in the 2DView
|
||||
// uFlags - constrained clipping plane point movement
|
||||
// *dragSize - not used in the virtual implementation
|
||||
// Output: success of translation (TRUE/FALSE)
|
||||
//-----------------------------------------------------------------------------
|
||||
bool Clipper3D::UpdateTranslation( const Vector &vUpdate, UINT uFlags )
|
||||
{
|
||||
// sanity check
|
||||
if( IsEmpty() )
|
||||
return false;
|
||||
|
||||
Vector vNewPos = m_vOrgPos + vUpdate;
|
||||
|
||||
// snap point if need be
|
||||
if ( uFlags & constrainSnap )
|
||||
m_pDocument->Snap( vNewPos, uFlags );
|
||||
|
||||
//
|
||||
// update clipping point positions
|
||||
//
|
||||
if ( m_ClipPoints[m_ClipPointHit] == vNewPos )
|
||||
return false;
|
||||
|
||||
|
||||
if( uFlags & constrainMoveAll )
|
||||
{
|
||||
//
|
||||
// calculate the point and delta - to move both clip points simultaneously
|
||||
//
|
||||
|
||||
Vector delta = vNewPos - m_ClipPoints[m_ClipPointHit];
|
||||
m_ClipPoints[(m_ClipPointHit+1)%2] += delta;
|
||||
}
|
||||
|
||||
m_ClipPoints[m_ClipPointHit] = vNewPos;
|
||||
|
||||
// build the new clip plane and update clip results
|
||||
BuildClipPlane();
|
||||
|
||||
GetClipResults();
|
||||
|
||||
m_pDocument->UpdateAllViews( MAPVIEW_UPDATE_TOOL );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: (virtual imp) This function defines all finishing functionality
|
||||
// necessary at the end of a clipping action. Nothing really!!!
|
||||
// Input : bSave - passed along the the Tool finish translation call
|
||||
//-----------------------------------------------------------------------------
|
||||
void Clipper3D::FinishTranslation( bool bSave )
|
||||
{
|
||||
// get the clip results -- in case the update is a click and not a drag
|
||||
GetClipResults();
|
||||
|
||||
Tool3D::FinishTranslation( bSave );
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: iterate through the types of clipping modes, update after an
|
||||
// iteration takes place to visualize the new clip results
|
||||
//-----------------------------------------------------------------------------
|
||||
void Clipper3D::IterateClipMode( void )
|
||||
{
|
||||
//
|
||||
// increment the clipping mode (wrap when necessary)
|
||||
//
|
||||
m_Mode++;
|
||||
|
||||
if( m_Mode > BOTH )
|
||||
{
|
||||
m_Mode = FRONT;
|
||||
}
|
||||
|
||||
// update the clipped objects based on the mode
|
||||
GetClipResults();
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: This resets the solids to clip (the original list) and calls the
|
||||
// CalcClipResults function to generate new "clip" solids
|
||||
//-----------------------------------------------------------------------------
|
||||
void Clipper3D::GetClipResults( void )
|
||||
{
|
||||
// reset the clip list to the original solid lsit
|
||||
SetClipObjects( m_pOrigObjects );
|
||||
|
||||
// calculate the clipped objects based on the current "clip plane"
|
||||
CalcClipResults();
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: This function allows one to specifically set the clipping plane
|
||||
// information, as opposed to building a clip plane during "translation"
|
||||
// Input: pPlane - the plane information used to create the clip plane
|
||||
//-----------------------------------------------------------------------------
|
||||
void Clipper3D::SetClipPlane( PLANE *pPlane )
|
||||
{
|
||||
//
|
||||
// copy the clipping plane info
|
||||
//
|
||||
m_ClipPlane.normal = pPlane->normal;
|
||||
m_ClipPlane.dist = pPlane->dist;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: This function builds a clipping plane based on the clip point
|
||||
// locations manipulated in the "translation" functions and the 2DView
|
||||
//-----------------------------------------------------------------------------
|
||||
void Clipper3D::BuildClipPlane( void )
|
||||
{
|
||||
// calculate the up vector
|
||||
Vector upVect = m_vPlaneNormal;
|
||||
|
||||
// calculate the right vector
|
||||
Vector rightVect;
|
||||
VectorSubtract( m_ClipPoints[1], m_ClipPoints[0], rightVect );
|
||||
|
||||
// calculate the forward (normal) vector
|
||||
Vector forwardVect;
|
||||
CrossProduct( upVect, rightVect, forwardVect );
|
||||
VectorNormalize( forwardVect );
|
||||
|
||||
//
|
||||
// save the clip plane info
|
||||
//
|
||||
m_ClipPlane.normal = forwardVect;
|
||||
m_ClipPlane.dist = DotProduct( m_ClipPoints[0], forwardVect );
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: This functions sets up the list of objects to be clipped.
|
||||
// Initially the list is passed in (typically a Selection set). On
|
||||
// subsequent "translation" updates the list is refreshed from the
|
||||
// m_pOrigObjects list.
|
||||
// Input: pList - the list of objects (solids) to be clipped
|
||||
//-----------------------------------------------------------------------------
|
||||
void Clipper3D::SetClipObjects( const CMapObjectList *pList )
|
||||
{
|
||||
// check for an empty list
|
||||
if( !pList )
|
||||
return;
|
||||
|
||||
// save the original list
|
||||
m_pOrigObjects = pList;
|
||||
|
||||
// clear the clip results list
|
||||
ResetClipResults();
|
||||
|
||||
//
|
||||
// copy solids into the clip list
|
||||
//
|
||||
FOR_EACH_OBJ( *m_pOrigObjects, pos )
|
||||
{
|
||||
CMapClass *pObject = (CUtlReference< CMapClass >)m_pOrigObjects->Element( pos );
|
||||
if( !pObject )
|
||||
continue;
|
||||
|
||||
if( pObject->IsMapClass( MAPCLASS_TYPE( CMapSolid ) ) )
|
||||
{
|
||||
AddToClipList( ( CMapSolid* )pObject, this );
|
||||
}
|
||||
|
||||
pObject->EnumChildren( ENUMMAPCHILDRENPROC( AddToClipList ), DWORD( this ), MAPCLASS_TYPE( CMapSolid ) );
|
||||
}
|
||||
|
||||
// the clipping list is not empty anymore
|
||||
m_bEmpty = false;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: This function calculates based on the defined or given clipping
|
||||
// plane and clipping mode the new clip solids.
|
||||
//-----------------------------------------------------------------------------
|
||||
void Clipper3D::CalcClipResults( void )
|
||||
{
|
||||
// sanity check
|
||||
if( IsEmpty() )
|
||||
return;
|
||||
|
||||
//
|
||||
// iterate through and clip all of the solids in the clip list
|
||||
//
|
||||
FOR_EACH_OBJ( m_ClipResults, pos )
|
||||
{
|
||||
CClipGroup *pClipGroup = m_ClipResults.Element( pos );
|
||||
CMapSolid *pOrigSolid = pClipGroup->GetOrigSolid();
|
||||
if( !pOrigSolid )
|
||||
continue;
|
||||
|
||||
//
|
||||
// check the modes for which solids to generate
|
||||
//
|
||||
CMapSolid *pFront = NULL;
|
||||
CMapSolid *pBack = NULL;
|
||||
if( m_Mode == FRONT )
|
||||
{
|
||||
pOrigSolid->Split( &m_ClipPlane, &pFront, NULL );
|
||||
}
|
||||
else if( m_Mode == BACK )
|
||||
{
|
||||
pOrigSolid->Split( &m_ClipPlane, NULL, &pBack );
|
||||
}
|
||||
else if( m_Mode == BOTH )
|
||||
{
|
||||
pOrigSolid->Split( &m_ClipPlane, &pFront, &pBack );
|
||||
}
|
||||
|
||||
if( pFront )
|
||||
{
|
||||
pFront->SetTemporary(true);
|
||||
pClipGroup->SetClipSolid( pFront, FRONT );
|
||||
}
|
||||
|
||||
if( pBack )
|
||||
{
|
||||
pBack->SetTemporary(true);
|
||||
pClipGroup->SetClipSolid( pBack, BACK );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: This function handles the removal of the "original" solid when it
|
||||
// has been clipped into new solid(s) or removed from the world (group
|
||||
// or entity) entirely. It handles this in an undo safe fashion.
|
||||
// Input: pOrigSolid - the solid to remove
|
||||
//-----------------------------------------------------------------------------
|
||||
void Clipper3D::RemoveOrigSolid( CMapSolid *pOrigSolid )
|
||||
{
|
||||
m_pDocument->DeleteObject(pOrigSolid);
|
||||
|
||||
//
|
||||
// remove the solid from the selection set if in the seleciton set and
|
||||
// its parent is the world, or set the selection state to none parent is group
|
||||
// or entity in the selection set
|
||||
//
|
||||
|
||||
CSelection *pSelection = m_pDocument->GetSelection();
|
||||
|
||||
if ( pSelection->IsSelected( pOrigSolid ) )
|
||||
{
|
||||
pSelection->SelectObject( pOrigSolid, scUnselect );
|
||||
}
|
||||
else
|
||||
{
|
||||
pOrigSolid->SetSelectionState( SELECT_NONE );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: This function handles the saving of newly clipped solids (derived
|
||||
// from an "original" solid). It handles them in an undo safe fashion.
|
||||
// Input: pSolid - the newly clipped solid
|
||||
// pOrigSolid - the "original" solid or solid the clipped solid was
|
||||
// derived from
|
||||
//-----------------------------------------------------------------------------
|
||||
void Clipper3D::SaveClipSolid( CMapSolid *pSolid, CMapSolid *pOrigSolid )
|
||||
{
|
||||
//
|
||||
// no longer a temporary solid
|
||||
//
|
||||
pSolid->SetTemporary( FALSE );
|
||||
|
||||
//
|
||||
// Add the new solid to the original solid's parent (group, entity, world, etc.).
|
||||
//
|
||||
m_pDocument->AddObjectToWorld(pSolid, pOrigSolid->GetParent());
|
||||
|
||||
//
|
||||
// handle linking solid into selection -- via selection set when parent is the world
|
||||
// and selected, or set the selection state if parent is group or entity in selection set
|
||||
//
|
||||
if( m_pDocument->GetSelection()->IsSelected( pOrigSolid ) )
|
||||
{
|
||||
m_pDocument->SelectObject( pSolid, scSelect );
|
||||
}
|
||||
else
|
||||
{
|
||||
pSolid->SetSelectionState( SELECT_NORMAL );
|
||||
}
|
||||
|
||||
GetHistory()->KeepNew( pSolid );
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: This function saves all the clipped solid information. If new solids
|
||||
// were generated from the original, they are saved and the original is
|
||||
// set for desctruciton. Otherwise, the original solid is kept.
|
||||
//-----------------------------------------------------------------------------
|
||||
void Clipper3D::SaveClipResults( void )
|
||||
{
|
||||
// sanity check!
|
||||
if( IsEmpty() )
|
||||
return;
|
||||
|
||||
// mark this place in the history
|
||||
GetHistory()->MarkUndoPosition( NULL, "Clip Objects" );
|
||||
|
||||
//
|
||||
// save all new objects into the selection list
|
||||
//
|
||||
FOR_EACH_OBJ( m_ClipResults, pos )
|
||||
{
|
||||
CClipGroup *pClipGroup = m_ClipResults.Element( pos );
|
||||
if( !pClipGroup )
|
||||
continue;
|
||||
|
||||
CMapSolid *pOrigSolid = pClipGroup->GetOrigSolid();
|
||||
CMapSolid *pBackSolid = pClipGroup->GetClipSolid( CClipGroup::BACK );
|
||||
CMapSolid *pFrontSolid = pClipGroup->GetClipSolid( CClipGroup::FRONT );
|
||||
|
||||
//
|
||||
// save the front clip solid and clear the clip results list of itself
|
||||
//
|
||||
if( pFrontSolid )
|
||||
{
|
||||
SaveClipSolid( pFrontSolid, pOrigSolid );
|
||||
pClipGroup->SetClipSolid( NULL, CClipGroup::FRONT );
|
||||
}
|
||||
|
||||
//
|
||||
// save the front clip solid and clear the clip results list of itself
|
||||
//
|
||||
if( pBackSolid )
|
||||
{
|
||||
SaveClipSolid( pBackSolid, pOrigSolid );
|
||||
pClipGroup->SetClipSolid( NULL, CClipGroup::BACK );
|
||||
}
|
||||
|
||||
// Send the notification that this solid as been clipped.
|
||||
pOrigSolid->PostUpdate( Notify_Clipped );
|
||||
|
||||
// remove the original solid
|
||||
RemoveOrigSolid( pOrigSolid );
|
||||
}
|
||||
|
||||
// set the the clipping results list as empty
|
||||
ResetClipResults();
|
||||
|
||||
// update world and views
|
||||
|
||||
m_pDocument->SetModifiedFlag();
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Draws the measurements of a brush in the 2D view.
|
||||
// Input : pRender -
|
||||
// pSolid -
|
||||
// nFlags -
|
||||
//-----------------------------------------------------------------------------
|
||||
void Clipper3D::DrawBrushExtents( CRender2D *pRender, CMapSolid *pSolid, int nFlags )
|
||||
{
|
||||
//
|
||||
// get the bounds of the solid
|
||||
//
|
||||
Vector Mins, Maxs;
|
||||
pSolid->GetRender2DBox( Mins, Maxs );
|
||||
|
||||
//
|
||||
// Determine which side of the clipping plane this solid is on in screen
|
||||
// space. This tells us where to draw the extents.
|
||||
//
|
||||
if( ( m_ClipPlane.normal[0] == 0 ) && ( m_ClipPlane.normal[1] == 0 ) && ( m_ClipPlane.normal[2] == 0 ) )
|
||||
return;
|
||||
|
||||
Vector normal = m_ClipPlane.normal;
|
||||
|
||||
if( nFlags & DBT_BACK )
|
||||
{
|
||||
VectorNegate( normal );
|
||||
}
|
||||
|
||||
Vector2D planeNormal;
|
||||
|
||||
pRender->TransformNormal( planeNormal, normal );
|
||||
|
||||
if( planeNormal.x <= 0 )
|
||||
{
|
||||
nFlags &= ~DBT_RIGHT;
|
||||
nFlags |= DBT_LEFT;
|
||||
}
|
||||
else if( planeNormal.x > 0 )
|
||||
{
|
||||
nFlags &= ~DBT_LEFT;
|
||||
nFlags |= DBT_RIGHT;
|
||||
}
|
||||
|
||||
if( planeNormal.y <= 0 )
|
||||
{
|
||||
nFlags &= ~DBT_BOTTOM;
|
||||
nFlags |= DBT_TOP;
|
||||
}
|
||||
else if( planeNormal.y > 0 )
|
||||
{
|
||||
nFlags &= ~DBT_TOP;
|
||||
nFlags |= DBT_BOTTOM;
|
||||
}
|
||||
|
||||
DrawBoundsText(pRender, Mins, Maxs, nFlags);
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : *pRender -
|
||||
//-----------------------------------------------------------------------------
|
||||
void Clipper3D::RenderTool2D(CRender2D *pRender)
|
||||
{
|
||||
if ( IsEmpty() )
|
||||
return;
|
||||
|
||||
// check flag for rendering vertices
|
||||
bool bDrawVerts = ( bool )( Options.view2d.bDrawVertices == TRUE );
|
||||
|
||||
// setup the line to use
|
||||
|
||||
pRender->SetDrawColor( 255, 255, 255 );
|
||||
|
||||
//
|
||||
// render the clipped solids
|
||||
//
|
||||
FOR_EACH_OBJ( m_ClipResults, pos )
|
||||
{
|
||||
CClipGroup *pClipGroup = m_ClipResults.Element( pos );
|
||||
CMapSolid *pClipBack = pClipGroup->GetClipSolid( CClipGroup::BACK );
|
||||
CMapSolid *pClipFront = pClipGroup->GetClipSolid( CClipGroup::FRONT );
|
||||
if( !pClipBack && !pClipFront )
|
||||
continue;
|
||||
|
||||
//
|
||||
// draw clip solids with the extents
|
||||
//
|
||||
if( pClipBack )
|
||||
{
|
||||
int faceCount = pClipBack->GetFaceCount();
|
||||
for( int i = 0; i < faceCount; i++ )
|
||||
{
|
||||
CMapFace *pFace = pClipBack->GetFace( i );
|
||||
|
||||
// size 4
|
||||
pRender->DrawPolyLine( pFace->nPoints, pFace->Points );
|
||||
|
||||
if ( bDrawVerts )
|
||||
{
|
||||
pRender->DrawHandles( pFace->nPoints, pFace->Points );
|
||||
}
|
||||
|
||||
if( m_bDrawMeasurements )
|
||||
{
|
||||
DrawBrushExtents( pRender, pClipBack, DBT_TOP | DBT_LEFT | DBT_BACK );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( pClipFront )
|
||||
{
|
||||
int faceCount = pClipFront->GetFaceCount();
|
||||
for( int i = 0; i < faceCount; i++ )
|
||||
{
|
||||
CMapFace *pFace = pClipFront->GetFace( i );
|
||||
|
||||
pRender->DrawPolyLine( pFace->nPoints, pFace->Points );
|
||||
|
||||
if ( bDrawVerts )
|
||||
{
|
||||
pRender->DrawHandles( pFace->nPoints, pFace->Points );
|
||||
}
|
||||
|
||||
if( m_bDrawMeasurements )
|
||||
{
|
||||
DrawBrushExtents( pRender, pClipFront, DBT_BOTTOM | DBT_RIGHT );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// draw the clip-plane
|
||||
//
|
||||
pRender->SetDrawColor( 0, 255, 255 );
|
||||
pRender->DrawLine( m_ClipPoints[0], m_ClipPoints[1] );
|
||||
|
||||
//
|
||||
// draw the clip-plane endpoints
|
||||
//
|
||||
|
||||
pRender->SetHandleStyle( HANDLE_RADIUS, CRender::HANDLE_SQUARE );
|
||||
pRender->SetHandleColor( 255, 255, 255 );
|
||||
|
||||
pRender->DrawHandle( m_ClipPoints[0] );
|
||||
pRender->DrawHandle( m_ClipPoints[1] );
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Renders the brushes that will be left by the clipper in white
|
||||
// wireframe.
|
||||
// Input : pRender - Rendering interface.
|
||||
//-----------------------------------------------------------------------------
|
||||
void Clipper3D::RenderTool3D( CRender3D *pRender )
|
||||
{
|
||||
// is there anything to render?
|
||||
if( m_bEmpty )
|
||||
return;
|
||||
|
||||
//
|
||||
// setup the renderer
|
||||
//
|
||||
pRender->PushRenderMode( RENDER_MODE_WIREFRAME );
|
||||
|
||||
FOR_EACH_OBJ( m_ClipResults, pos )
|
||||
{
|
||||
CClipGroup *pClipGroup = m_ClipResults.Element( pos );
|
||||
|
||||
CMapSolid *pFrontSolid = pClipGroup->GetClipSolid( CClipGroup::FRONT );
|
||||
if( pFrontSolid )
|
||||
{
|
||||
color32 rgbColor = pFrontSolid->GetRenderColor();
|
||||
pFrontSolid->SetRenderColor(255, 255, 255);
|
||||
pFrontSolid->Render3D(pRender);
|
||||
pFrontSolid->SetRenderColor(rgbColor);
|
||||
}
|
||||
|
||||
CMapSolid *pBackSolid = pClipGroup->GetClipSolid( CClipGroup::BACK );
|
||||
if( pBackSolid )
|
||||
{
|
||||
color32 rgbColor = pBackSolid->GetRenderColor();
|
||||
pBackSolid->SetRenderColor(255, 255, 255);
|
||||
pBackSolid->Render3D(pRender);
|
||||
pBackSolid->SetRenderColor(rgbColor);
|
||||
}
|
||||
}
|
||||
|
||||
pRender->PopRenderMode();
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: (virtual imp)
|
||||
// Input : pt -
|
||||
// BOOL -
|
||||
// Output : int
|
||||
//-----------------------------------------------------------------------------
|
||||
int Clipper3D::HitTest(CMapView *pView, const Vector2D &ptClient, bool bTestHandles)
|
||||
{
|
||||
// check points
|
||||
|
||||
for ( int i=0; i<2;i++ )
|
||||
{
|
||||
if ( HitRect(pView, ptClient, m_ClipPoints[i], HANDLE_RADIUS) )
|
||||
{
|
||||
return i+1; // return clip point index + 1
|
||||
}
|
||||
}
|
||||
|
||||
// neither point hit
|
||||
return 0;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Reset (clear) the clip results.
|
||||
//-----------------------------------------------------------------------------
|
||||
void Clipper3D::ResetClipResults( void )
|
||||
{
|
||||
//
|
||||
// delete the clip solids held in the list -- originals are just pointers
|
||||
// to pre-existing objects
|
||||
//
|
||||
FOR_EACH_OBJ( m_ClipResults, pos )
|
||||
{
|
||||
CClipGroup *pClipGroup = m_ClipResults.Element(pos);
|
||||
|
||||
if( pClipGroup )
|
||||
{
|
||||
delete pClipGroup;
|
||||
}
|
||||
}
|
||||
|
||||
m_ClipResults.RemoveAll();
|
||||
|
||||
// the clipping list is empty
|
||||
SetEmpty();
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : nChar -
|
||||
// nRepCnt -
|
||||
// nFlags -
|
||||
//-----------------------------------------------------------------------------
|
||||
bool Clipper3D::OnKeyDown2D(CMapView2D *pView, UINT nChar, UINT nRepCnt, UINT nFlags)
|
||||
{
|
||||
switch (nChar)
|
||||
{
|
||||
case 'O':
|
||||
{
|
||||
//
|
||||
// Toggle the rendering of measurements.
|
||||
//
|
||||
ToggleMeasurements();
|
||||
return true;
|
||||
}
|
||||
|
||||
case VK_RETURN:
|
||||
{
|
||||
//
|
||||
// Do the clip.
|
||||
//
|
||||
if (!IsEmpty() )
|
||||
{
|
||||
SaveClipResults();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
case VK_ESCAPE:
|
||||
{
|
||||
OnEscape();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Handles left mouse button down events in the 2D view.
|
||||
// Input : Per CWnd::OnLButtonDown.
|
||||
// Output : Returns true if the message was handled, false if not.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool Clipper3D::OnLMouseDown2D(CMapView2D *pView, UINT nFlags, const Vector2D &vPoint)
|
||||
{
|
||||
Tool3D::OnLMouseDown2D(pView, nFlags, vPoint);
|
||||
|
||||
unsigned int uConstraints = GetConstraints( nFlags );
|
||||
|
||||
//
|
||||
// Convert point to world coords.
|
||||
//
|
||||
Vector vecWorld;
|
||||
pView->ClientToWorld(vecWorld, vPoint);
|
||||
vecWorld[pView->axThird] = COORD_NOTINIT;
|
||||
|
||||
// getvisiblepoint fills in any coord that's still set to COORD_NOTINIT:
|
||||
m_pDocument->GetBestVisiblePoint(vecWorld);
|
||||
|
||||
// snap starting position to grid
|
||||
if ( uConstraints & constrainSnap )
|
||||
m_pDocument->Snap(vecWorld, uConstraints);
|
||||
|
||||
|
||||
bool bStarting = false;
|
||||
|
||||
// if the tool is not empty, and shift is not held down (to
|
||||
// start a new camera), don't do anything.
|
||||
if(!IsEmpty())
|
||||
{
|
||||
// test for clip point hit (result = {0, 1, 2}
|
||||
int hitPoint = HitTest( pView, vPoint );
|
||||
|
||||
if ( hitPoint > 0 )
|
||||
{
|
||||
// test for clip point hit (result = {0, 1, -1})
|
||||
m_ClipPointHit = hitPoint-1; // convert back to index
|
||||
m_vOrgPos = m_ClipPoints[m_ClipPointHit];
|
||||
StartTranslation( pView, vPoint );
|
||||
}
|
||||
else if ( m_vPlaneNormal != pView->GetViewAxis() )
|
||||
{
|
||||
SetEmpty();
|
||||
bStarting = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (nFlags & MK_SHIFT)
|
||||
{
|
||||
SetEmpty();
|
||||
bStarting = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return true; // do nothing;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
bStarting = true;
|
||||
}
|
||||
|
||||
SetClipObjects(m_pDocument->GetSelection()->GetList());
|
||||
|
||||
if (bStarting)
|
||||
{
|
||||
// start the tools translation functionality
|
||||
StartTranslation( pView, vPoint );
|
||||
|
||||
// set the initial clip points
|
||||
m_ClipPointHit = 0;
|
||||
m_ClipPoints[0] = vecWorld;
|
||||
m_ClipPoints[1] = vecWorld;
|
||||
m_vOrgPos = vecWorld;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Handles left mouse button up events in the 2D view.
|
||||
// Input : Per CWnd::OnLButtonUp.
|
||||
// Output : Returns true if the message was handled, false if not.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool Clipper3D::OnLMouseUp2D(CMapView2D *pView, UINT nFlags, const Vector2D &vPoint)
|
||||
{
|
||||
Tool3D::OnLMouseUp2D(pView, nFlags, vPoint);
|
||||
|
||||
if ( IsTranslating() )
|
||||
{
|
||||
FinishTranslation(true);
|
||||
}
|
||||
|
||||
m_pDocument->UpdateStatusbar();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
unsigned int Clipper3D::GetConstraints(unsigned int nKeyFlags)
|
||||
{
|
||||
unsigned int uConstraints = Tool3D::GetConstraints( nKeyFlags );
|
||||
|
||||
if(nKeyFlags & MK_CONTROL)
|
||||
{
|
||||
uConstraints |= constrainMoveAll;
|
||||
}
|
||||
|
||||
return uConstraints;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Handles mouse move events in the 2D view.
|
||||
// Input : Per CWnd::OnMouseMove.
|
||||
// Output : Returns true if the message was handled, false if not.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool Clipper3D::OnMouseMove2D(CMapView2D *pView, UINT nFlags, const Vector2D &vPoint)
|
||||
{
|
||||
vgui::HCursor hCursor = vgui::dc_arrow;
|
||||
unsigned int uConstraints = GetConstraints( nFlags );
|
||||
|
||||
Tool3D::OnMouseMove2D(pView, nFlags, vPoint);
|
||||
|
||||
//
|
||||
// Convert to world coords.
|
||||
//
|
||||
Vector vecWorld;
|
||||
pView->ClientToWorld(vecWorld, vPoint);
|
||||
|
||||
//
|
||||
// Update status bar position display.
|
||||
//
|
||||
char szBuf[128];
|
||||
|
||||
if ( uConstraints & constrainSnap )
|
||||
m_pDocument->Snap(vecWorld,uConstraints);
|
||||
|
||||
sprintf(szBuf, " @%.0f, %.0f ", vecWorld[pView->axHorz], vecWorld[pView->axVert]);
|
||||
SetStatusText(SBI_COORDS, szBuf);
|
||||
|
||||
if (IsTranslating())
|
||||
{
|
||||
// cursor is cross here
|
||||
Tool3D::UpdateTranslation( pView, vPoint, uConstraints);
|
||||
|
||||
hCursor = vgui::dc_none;
|
||||
}
|
||||
else if (!IsEmpty())
|
||||
{
|
||||
//
|
||||
// If the cursor is on a handle, set it to a cross.
|
||||
//
|
||||
if (HitTest( pView, vPoint, true))
|
||||
{
|
||||
hCursor = vgui::dc_crosshair;
|
||||
}
|
||||
}
|
||||
|
||||
if ( hCursor != vgui::dc_none )
|
||||
pView->SetCursor( hCursor );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Handles character events.
|
||||
// Input : Per CWnd::OnKeyDown.
|
||||
// Output : Returns true if the message was handled, false if not.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool Clipper3D::OnKeyDown3D(CMapView3D *pView, UINT nChar, UINT nRepCnt, UINT nFlags)
|
||||
{
|
||||
switch (nChar)
|
||||
{
|
||||
case VK_RETURN:
|
||||
{
|
||||
if (!IsEmpty()) // dvs: what does isempty mean for the clipper?
|
||||
{
|
||||
SaveClipResults();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
case VK_ESCAPE:
|
||||
{
|
||||
OnEscape();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Handles the escape key in the 2D or 3D views.
|
||||
//-----------------------------------------------------------------------------
|
||||
void Clipper3D::OnEscape(void)
|
||||
{
|
||||
// If we're clipping, clear it
|
||||
if (!IsEmpty())
|
||||
{
|
||||
SetEmpty();
|
||||
}
|
||||
else
|
||||
{
|
||||
m_pDocument->GetTools()->SetTool(TOOL_POINTER);
|
||||
}
|
||||
}
|
||||
|
||||
186
hammer/ToolClipper.h
Normal file
186
hammer/ToolClipper.h
Normal file
@@ -0,0 +1,186 @@
|
||||
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef CLIPPER3D_H
|
||||
#define CLIPPER3D_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
|
||||
#include "MapClass.h" // For CMapObjectList
|
||||
#include "Tool3D.h"
|
||||
#include "ToolInterface.h"
|
||||
#include "Render2D.h"
|
||||
#include "MapFace.h"
|
||||
|
||||
|
||||
class CMapSolid;
|
||||
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
// CClipGroup
|
||||
//
|
||||
|
||||
class CClipGroup
|
||||
{
|
||||
public:
|
||||
|
||||
enum { FRONT = 0, BACK };
|
||||
|
||||
inline CClipGroup();
|
||||
~CClipGroup();
|
||||
|
||||
inline void SetOrigSolid( CMapSolid *pSolid );
|
||||
inline CMapSolid *GetOrigSolid( void );
|
||||
|
||||
inline void SetClipSolid( CMapSolid *pSolid, int side );
|
||||
inline CMapSolid *GetClipSolid( int side );
|
||||
|
||||
private:
|
||||
|
||||
CMapSolid *m_pOrigSolid;
|
||||
CMapSolid *m_pClipSolids[2]; // front, back
|
||||
};
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
inline CClipGroup::CClipGroup()
|
||||
{
|
||||
m_pOrigSolid = NULL;
|
||||
m_pClipSolids[0] = NULL;
|
||||
m_pClipSolids[1] = NULL;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
inline void CClipGroup::SetOrigSolid( CMapSolid *pSolid )
|
||||
{
|
||||
m_pOrigSolid = pSolid;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
inline CMapSolid *CClipGroup::GetOrigSolid( void )
|
||||
{
|
||||
return m_pOrigSolid;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
inline void CClipGroup::SetClipSolid( CMapSolid *pSolid, int side )
|
||||
{
|
||||
m_pClipSolids[side] = pSolid;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
inline CMapSolid *CClipGroup::GetClipSolid( int side )
|
||||
{
|
||||
return m_pClipSolids[side];
|
||||
}
|
||||
|
||||
|
||||
class Clipper3D : public Tool3D
|
||||
{
|
||||
friend BOOL AddToClipList( CMapSolid *pSolid, Clipper3D *pClipper );
|
||||
|
||||
public:
|
||||
|
||||
enum { FRONT = 0, BACK, BOTH };
|
||||
|
||||
Clipper3D();
|
||||
~Clipper3D();
|
||||
|
||||
void IterateClipMode( void );
|
||||
|
||||
inline void ToggleMeasurements( void );
|
||||
|
||||
//
|
||||
// Tool3D implementation.
|
||||
//
|
||||
virtual int HitTest( CMapView *pView, const Vector2D &vPoint, bool bTestHandles = false );
|
||||
virtual unsigned int GetConstraints(unsigned int nKeyFlags);
|
||||
|
||||
//
|
||||
// CBaseTool implementation.
|
||||
//
|
||||
virtual void OnActivate();
|
||||
virtual void OnDeactivate();
|
||||
virtual ToolID_t GetToolID(void) { return TOOL_CLIPPER; }
|
||||
|
||||
virtual void RenderTool2D(CRender2D *pRender);
|
||||
virtual void RenderTool3D(CRender3D *pRender);
|
||||
|
||||
virtual bool OnKeyDown2D(CMapView2D *pView, UINT nChar, UINT nRepCnt, UINT nFlags);
|
||||
virtual bool OnKeyDown3D(CMapView3D *pView, UINT nChar, UINT nRepCnt, UINT nFlags);
|
||||
|
||||
virtual bool OnLMouseDown2D(CMapView2D *pView, UINT nFlags, const Vector2D &vPoint);
|
||||
virtual bool OnLMouseUp2D(CMapView2D *pView, UINT nFlags, const Vector2D &vPoint);
|
||||
virtual bool OnMouseMove2D(CMapView2D *pView, UINT nFlags, const Vector2D &vPoint);
|
||||
|
||||
|
||||
|
||||
protected:
|
||||
|
||||
//
|
||||
// Tool3D implementation.
|
||||
//
|
||||
virtual bool UpdateTranslation( const Vector &vUpdate, UINT uFlags = 0 );
|
||||
virtual void FinishTranslation( bool bSave );
|
||||
|
||||
private:
|
||||
|
||||
void OnEscape(void);
|
||||
|
||||
void SetClipObjects( const CMapObjectList *pList );
|
||||
void SetClipPlane( PLANE *pPlane );
|
||||
void BuildClipPlane( void );
|
||||
|
||||
void SaveClipResults( void );
|
||||
void GetClipResults( void );
|
||||
void CalcClipResults( void );
|
||||
void ResetClipResults( void );
|
||||
|
||||
void RemoveOrigSolid( CMapSolid *pOrigSolid );
|
||||
void SaveClipSolid( CMapSolid *pSolid, CMapSolid *pOrigSolid );
|
||||
|
||||
void DrawBrushExtents(CRender2D *pRender, CMapSolid *pSolid, int nFlags);
|
||||
|
||||
int m_Mode; // current clipping mode { back, front, both }
|
||||
|
||||
PLANE m_ClipPlane; // the clipping plane -- front/back is uneccesary
|
||||
Vector m_ClipPoints[2]; // 2D clipping points -- used to create the clip plane
|
||||
int m_ClipPointHit; // the clipping that was "hit" {0, 1, -1}
|
||||
Vector m_vOrgPos;
|
||||
|
||||
const CMapObjectList *m_pOrigObjects; // list of the initial objects to clip
|
||||
CUtlVector<CClipGroup*> m_ClipResults; // list of clipped objects
|
||||
|
||||
bool m_bDrawMeasurements; // Whether to draw brush dimensions in the 2D view.
|
||||
|
||||
CRender2D m_Render2D; // 2d renderer
|
||||
};
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Toggles the clipper's rendering of brush measurements in the 2D view.
|
||||
//-----------------------------------------------------------------------------
|
||||
inline void Clipper3D::ToggleMeasurements( void )
|
||||
{
|
||||
m_bDrawMeasurements = !m_bDrawMeasurements;
|
||||
m_pDocument->UpdateAllViews( MAPVIEW_UPDATE_TOOL );
|
||||
}
|
||||
|
||||
|
||||
#endif // CLIPPER3D_H
|
||||
400
hammer/ToolCordon.cpp
Normal file
400
hammer/ToolCordon.cpp
Normal file
@@ -0,0 +1,400 @@
|
||||
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: Implements the cordon tool. The cordon tool defines a rectangular
|
||||
// volume that acts as a visibility filter. Only objects that intersect
|
||||
// the cordon are rendered in the views. When saving the MAP file while
|
||||
// the cordon tool is active, only brushes that intersect the cordon
|
||||
// bounds are saved. The cordon box is replaced by brushes in order to
|
||||
// seal the map.
|
||||
//
|
||||
//=============================================================================//
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "ChunkFile.h"
|
||||
#include "ToolCordon.h"
|
||||
#include "History.h"
|
||||
#include "GlobalFunctions.h"
|
||||
#include "MainFrm.h"
|
||||
#include "MapDoc.h"
|
||||
#include "MapDefs.h"
|
||||
#include "MapSolid.h"
|
||||
#include "MapView2D.h"
|
||||
#include "MapView3D.h"
|
||||
#include "MapWorld.h"
|
||||
#include "render2d.h"
|
||||
#include "StatusBarIDs.h"
|
||||
#include "ToolManager.h"
|
||||
#include "Options.h"
|
||||
#include "WorldSize.h"
|
||||
#include "vgui/Cursor.h"
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include <tier0/memdbgon.h>
|
||||
|
||||
|
||||
Vector Cordon3D::m_vecLastMins; // Last mins & maxs the user dragged out with this tool;
|
||||
Vector Cordon3D::m_vecLastMaxs; // used to fill in the third axis when starting a new box.
|
||||
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Constructor.
|
||||
//-----------------------------------------------------------------------------
|
||||
Cordon3D::Cordon3D(void)
|
||||
{
|
||||
SetDrawColors(RGB(0, 255, 255), RGB(255, 0, 0));
|
||||
m_vecLastMins.Init( COORD_NOTINIT, COORD_NOTINIT, COORD_NOTINIT );
|
||||
m_vecLastMaxs.Init( COORD_NOTINIT, COORD_NOTINIT, COORD_NOTINIT );
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Called when the tool is activated.
|
||||
// Input : eOldTool - The ID of the previously active tool.
|
||||
//-----------------------------------------------------------------------------
|
||||
void Cordon3D::OnActivate()
|
||||
{
|
||||
RefreshToolState();
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Fetch data from the document and update our internal state.
|
||||
//-----------------------------------------------------------------------------
|
||||
void Cordon3D::RefreshToolState()
|
||||
{
|
||||
Vector mins( COORD_NOTINIT, COORD_NOTINIT, COORD_NOTINIT );
|
||||
Vector maxs( COORD_NOTINIT, COORD_NOTINIT, COORD_NOTINIT );
|
||||
|
||||
if ( m_pDocument->Cordon_GetCount() > 0 )
|
||||
{
|
||||
m_pDocument->Cordon_GetEditCordon( mins, maxs );
|
||||
m_vecLastMins = mins;
|
||||
m_vecLastMaxs = maxs;
|
||||
}
|
||||
|
||||
SetBounds( mins, maxs );
|
||||
m_bEmpty = !IsValidBox();
|
||||
EnableHandles( true );
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Return true of the boxes intersect (but not if they just touch).
|
||||
//-----------------------------------------------------------------------------
|
||||
inline bool BoxesIntersect2D( const Vector2D &vBox1Min, const Vector2D &vBox1Max, const Vector2D &vBox2Min, const Vector2D &vBox2Max )
|
||||
{
|
||||
return ( vBox1Min.x < vBox2Max.x ) && ( vBox1Max.x > vBox2Min.x ) &&
|
||||
( vBox1Min.y < vBox2Max.y ) && ( vBox1Max.y > vBox2Min.y );
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Handles left mouse button down events in the 2D view.
|
||||
// Input : Per CWnd::OnLButtonDown.
|
||||
// Output : Returns true if the message was handled, false if not.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool Cordon3D::OnLMouseDown2D(CMapView2D *pView, UINT nFlags, const Vector2D &vPoint)
|
||||
{
|
||||
Tool3D::OnLMouseDown2D(pView, nFlags, vPoint);
|
||||
|
||||
Vector vecWorld;
|
||||
pView->ClientToWorld(vecWorld, vPoint);
|
||||
|
||||
unsigned int uConstraints = GetConstraints( nFlags );
|
||||
|
||||
if ( HitTest(pView, vPoint, true) )
|
||||
{
|
||||
StartTranslation( pView, vPoint, m_LastHitTestHandle );
|
||||
}
|
||||
else
|
||||
{
|
||||
//
|
||||
// Test against all active cordons
|
||||
//
|
||||
CMapDoc *pDoc = pView->GetMapDoc();
|
||||
if ( !pDoc )
|
||||
return true;
|
||||
|
||||
// Make a little box around the cursor to test against.
|
||||
const int iSelUnits = 2;
|
||||
Vector2D selMins( vPoint.x - iSelUnits, vPoint.y - iSelUnits );
|
||||
Vector2D selMaxs( vPoint.x + iSelUnits, vPoint.y + iSelUnits );
|
||||
|
||||
for ( int i = 0; i < pDoc->Cordon_GetCount(); i++ )
|
||||
{
|
||||
Cordon_t *cordon = pDoc->Cordon_GetCordon( i );
|
||||
if ( !cordon->m_bActive )
|
||||
continue;
|
||||
|
||||
for ( int j = 0; j < cordon->m_Boxes.Count(); j++ )
|
||||
{
|
||||
BoundBox *box = &cordon->m_Boxes[j];
|
||||
|
||||
Vector2D vecClientMins;
|
||||
Vector2D vecClientMaxs;
|
||||
pView->WorldToClient( vecClientMins, box->bmins );
|
||||
pView->WorldToClient( vecClientMaxs, box->bmaxs );
|
||||
|
||||
// 2D projection can flip Y
|
||||
NormalizeBox( vecClientMins, vecClientMaxs );
|
||||
|
||||
if ( BoxesIntersect2D( vecClientMins, vecClientMaxs, selMins, selMaxs ) )
|
||||
{
|
||||
pDoc->Cordon_SelectCordonForEditing( cordon, box, SELECT_CORDON_FROM_TOOL );
|
||||
RefreshToolState();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// getvisiblepoint fills in any coord that's still set to COORD_NOTINIT:
|
||||
vecWorld[pView->axThird] = m_vecLastMins[pView->axThird];
|
||||
m_pDocument->GetBestVisiblePoint(vecWorld);
|
||||
|
||||
// snap starting position to grid
|
||||
if ( uConstraints & constrainSnap )
|
||||
m_pDocument->Snap(vecWorld,uConstraints);
|
||||
|
||||
// Create a new box
|
||||
// Add it to the current edit cordon
|
||||
// Set the edit cordon to current edit cordon and the new box
|
||||
Cordon_t *cordon = m_pDocument->Cordon_GetSelectedCordonForEditing();
|
||||
BoundBox *box = NULL;
|
||||
if ( !cordon )
|
||||
{
|
||||
// No cordon, we need a new one.
|
||||
cordon = m_pDocument->Cordon_CreateNewCordon( DEFAULT_CORDON_NAME, &box );
|
||||
}
|
||||
else
|
||||
{
|
||||
// Just add a box to the current cordon.
|
||||
box = m_pDocument->Cordon_AddBox( cordon );
|
||||
}
|
||||
|
||||
box->bmins = box->bmaxs = vecWorld;
|
||||
|
||||
Vector vecSize( 0, 0, 0 );
|
||||
if ( ( m_vecLastMins[pView->axThird] == COORD_NOTINIT ) || ( m_vecLastMaxs[pView->axThird] == COORD_NOTINIT ) )
|
||||
{
|
||||
vecSize[pView->axThird] = pDoc->GetGridSpacing();
|
||||
}
|
||||
else
|
||||
{
|
||||
vecSize[pView->axThird] = m_vecLastMaxs[pView->axThird] - m_vecLastMins[pView->axThird];
|
||||
}
|
||||
StartNew( pView, vPoint, vecWorld, vecSize );
|
||||
|
||||
m_pDocument->Cordon_SelectCordonForEditing( cordon, box, SELECT_CORDON_FROM_TOOL );
|
||||
|
||||
if ( pDoc->Cordon_IsCordoning() )
|
||||
{
|
||||
pDoc->UpdateVisibilityAll();
|
||||
}
|
||||
|
||||
pDoc->SetModifiedFlag( true );
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Handles left mouse button up events in the 2D view.
|
||||
// Input : Per CWnd::OnLButtonUp.
|
||||
// Output : Returns true if the message was handled, false if not.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool Cordon3D::OnLMouseUp2D(CMapView2D *pView, UINT nFlags, const Vector2D &vPoint)
|
||||
{
|
||||
bool bShift = ( nFlags & MK_SHIFT ) != 0;
|
||||
|
||||
Tool3D::OnLMouseUp2D(pView, nFlags, vPoint) ;
|
||||
|
||||
if ( IsTranslating() )
|
||||
{
|
||||
if ( bShift )
|
||||
{
|
||||
}
|
||||
|
||||
FinishTranslation( true );
|
||||
|
||||
if ( bShift )
|
||||
{
|
||||
// Clone the selected cordon
|
||||
Cordon_t *cordon = m_pDocument->Cordon_GetSelectedCordonForEditing();
|
||||
|
||||
BoundBox *box = m_pDocument->Cordon_AddBox( cordon );
|
||||
box->bmins = bmins;
|
||||
box->bmaxs = bmaxs;
|
||||
|
||||
m_pDocument->Cordon_SelectCordonForEditing( cordon, box, SELECT_CORDON_FROM_TOOL );
|
||||
RefreshToolState();
|
||||
}
|
||||
else
|
||||
{
|
||||
m_pDocument->Cordon_SetEditCordon( bmins, bmaxs );
|
||||
|
||||
// Remember these bounds for the next time we start dragging out a new cordon.
|
||||
m_vecLastMins = bmins;
|
||||
m_vecLastMaxs = bmaxs;
|
||||
}
|
||||
}
|
||||
|
||||
m_pDocument->UpdateStatusbar();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Handles mouse move events in the 2D view.
|
||||
// Input : Per CWnd::OnMouseMove.
|
||||
// Output : Returns true if the message was handled, false if not.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool Cordon3D::OnMouseMove2D(CMapView2D *pView, UINT nFlags, const Vector2D &vPoint)
|
||||
{
|
||||
vgui::HCursor hCursor = vgui::dc_arrow;
|
||||
|
||||
Tool3D::OnMouseMove2D(pView, nFlags, vPoint) ;
|
||||
|
||||
unsigned int uConstraints = GetConstraints( nFlags );
|
||||
|
||||
// Convert to world coords.
|
||||
Vector vecWorld;
|
||||
pView->ClientToWorld(vecWorld, vPoint);
|
||||
|
||||
// Update status bar position display.
|
||||
//
|
||||
char szBuf[128];
|
||||
|
||||
m_pDocument->Snap(vecWorld,uConstraints);
|
||||
|
||||
sprintf(szBuf, " @%.0f, %.0f ", vecWorld[pView->axHorz], vecWorld[pView->axVert]);
|
||||
SetStatusText(SBI_COORDS, szBuf);
|
||||
|
||||
if ( IsTranslating() )
|
||||
{
|
||||
// cursor is cross here
|
||||
Tool3D::UpdateTranslation( pView, vPoint, uConstraints );
|
||||
|
||||
hCursor = vgui::dc_none;
|
||||
}
|
||||
else if ( HitTest(pView, vPoint, true) )
|
||||
{
|
||||
hCursor = UpdateCursor( pView, m_LastHitTestHandle, m_TranslateMode );
|
||||
}
|
||||
|
||||
if ( hCursor != vgui::dc_none )
|
||||
pView->SetCursor( hCursor );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Handles the escape key in the 2D or 3D views.
|
||||
//-----------------------------------------------------------------------------
|
||||
void Cordon3D::OnEscape(void)
|
||||
{
|
||||
if ( IsTranslating() )
|
||||
{
|
||||
FinishTranslation( false );
|
||||
}
|
||||
else
|
||||
{
|
||||
m_pDocument->GetTools()->SetTool(TOOL_POINTER);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Deletes the currently selected cordon in response to the user hitting DELETE
|
||||
//-----------------------------------------------------------------------------
|
||||
void Cordon3D::OnDelete()
|
||||
{
|
||||
BoundBox *pBox = NULL;
|
||||
Cordon_t *pCordon = m_pDocument->Cordon_GetSelectedCordonForEditing( &pBox );
|
||||
if ( !pCordon || !pBox )
|
||||
return;
|
||||
|
||||
if ( !pBox || ( pCordon->m_Boxes.Count() <= 1 ) )
|
||||
{
|
||||
m_pDocument->Cordon_RemoveCordon( pCordon );
|
||||
}
|
||||
else
|
||||
{
|
||||
m_pDocument->Cordon_RemoveBox( pCordon, pBox );
|
||||
}
|
||||
|
||||
m_pDocument->UpdateVisibilityAll();
|
||||
m_pDocument->SetModifiedFlag( true );
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
bool Cordon3D::OnKeyDown2D(CMapView2D *pView, UINT nChar, UINT nRepCnt, UINT nFlags)
|
||||
{
|
||||
if (nChar == VK_ESCAPE)
|
||||
{
|
||||
OnEscape();
|
||||
return true;
|
||||
}
|
||||
|
||||
if ( nChar == VK_DELETE )
|
||||
{
|
||||
OnDelete();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
bool Cordon3D::OnKeyDown3D(CMapView3D *pView, UINT nChar, UINT nRepCnt, UINT nFlags)
|
||||
{
|
||||
if (nChar == VK_ESCAPE)
|
||||
{
|
||||
OnEscape();
|
||||
return true;
|
||||
}
|
||||
|
||||
if ( nChar == VK_DELETE )
|
||||
{
|
||||
OnDelete();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
void Cordon3D::RenderTool2D( CRender2D *pRender )
|
||||
{
|
||||
pRender->PushRenderMode( RENDER_MODE_DOTTED );
|
||||
pRender->SetDrawColor( 255, 255, 0 );
|
||||
|
||||
// If cordoning is active, the document's rendering code handles drawing the cordons.
|
||||
if ( !m_pDocument->Cordon_IsCordoning() )
|
||||
{
|
||||
int nCount = m_pDocument->Cordon_GetCount();
|
||||
for ( int i = 0; i < nCount; i++ )
|
||||
{
|
||||
Cordon_t *pCordon = m_pDocument->Cordon_GetCordon( i );
|
||||
if ( pCordon->m_bActive )
|
||||
{
|
||||
for ( int j = 0; j < pCordon->m_Boxes.Count(); j++ )
|
||||
{
|
||||
// draw simple rectangle
|
||||
pRender->DrawRectangle( pCordon->m_Boxes[j].bmins, pCordon->m_Boxes[j].bmaxs, false, 0 );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pRender->PopRenderMode();
|
||||
|
||||
BaseClass::RenderTool2D( pRender );
|
||||
}
|
||||
61
hammer/ToolCordon.h
Normal file
61
hammer/ToolCordon.h
Normal file
@@ -0,0 +1,61 @@
|
||||
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ====
|
||||
//
|
||||
// Defines the cordon tool. The cordon tool defines a rectangular
|
||||
// volume that acts as a visibility filter. Only objects that intersect
|
||||
// the cordon are rendered in the views. When saving the MAP file while
|
||||
// the cordon tool is active, only brushes that intersect the cordon
|
||||
// bounds are saved. The cordon box is replaced by brushes in order to
|
||||
// seal the map.
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
#ifndef CORDON3D_H
|
||||
#define CORDON3D_H
|
||||
#pragma once
|
||||
|
||||
|
||||
#include "Box3D.h"
|
||||
#include "ToolInterface.h"
|
||||
|
||||
|
||||
class CChunkFile;
|
||||
class CSaveInfo;
|
||||
class CMapWorld;
|
||||
class CMapView2D;
|
||||
class CMapView3D;
|
||||
|
||||
|
||||
enum ChunkFileResult_t;
|
||||
|
||||
|
||||
class Cordon3D : public Box3D
|
||||
{
|
||||
typedef Box3D BaseClass;
|
||||
|
||||
public:
|
||||
|
||||
Cordon3D(void);
|
||||
|
||||
// CBaseTool implementation.
|
||||
virtual void OnActivate();
|
||||
virtual ToolID_t GetToolID(void) { return TOOL_EDITCORDON; }
|
||||
virtual void RefreshToolState();
|
||||
|
||||
virtual bool OnLMouseDown2D(CMapView2D *pView, UINT nFlags, const Vector2D &vPoint);
|
||||
virtual bool OnLMouseUp2D(CMapView2D *pView, UINT nFlags, const Vector2D &vPoint);
|
||||
virtual bool OnMouseMove2D(CMapView2D *pView, UINT nFlags, const Vector2D &vPoint);
|
||||
virtual bool OnKeyDown2D(CMapView2D *pView, UINT nChar, UINT nRepCnt, UINT nFlags);
|
||||
virtual bool OnKeyDown3D(CMapView3D *pView, UINT nChar, UINT nRepCnt, UINT nFlags);
|
||||
|
||||
virtual void RenderTool2D( CRender2D *pRender );
|
||||
|
||||
private:
|
||||
|
||||
void OnDelete();
|
||||
void OnEscape();
|
||||
|
||||
static Vector m_vecLastMins; // Last mins & maxs the user dragged out with this tool;
|
||||
static Vector m_vecLastMaxs; // used to fill in the third axis when starting a new box.
|
||||
};
|
||||
|
||||
#endif // CORDON3D_H
|
||||
163
hammer/ToolDecal.cpp
Normal file
163
hammer/ToolDecal.cpp
Normal file
@@ -0,0 +1,163 @@
|
||||
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "GlobalFunctions.h"
|
||||
#include "History.h"
|
||||
#include "MapDoc.h"
|
||||
#include "MapDecal.h"
|
||||
#include "MapSolid.h"
|
||||
#include "MapView3D.h"
|
||||
#include "resource.h"
|
||||
#include "ToolManager.h"
|
||||
#include "ToolDecal.h"
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include <tier0/memdbgon.h>
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Handles key down events in the 2D view.
|
||||
// Input : Per CWnd::OnKeyDown.
|
||||
// Output : Returns true on success, false on failure.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CToolDecal::OnKeyDown2D(CMapView2D *pView, UINT nChar, UINT nRepCnt, UINT nFlags)
|
||||
{
|
||||
switch (nChar)
|
||||
{
|
||||
case VK_ESCAPE:
|
||||
{
|
||||
ToolManager()->SetTool(TOOL_POINTER);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Handles mouse move events in the 2D view.
|
||||
// Input : Per CWnd::OnMouseMove.
|
||||
// Output : Returns true if the message was handled, false if not.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CToolDecal::OnMouseMove2D(CMapView2D *pView, UINT nFlags, const Vector2D &vPoint)
|
||||
{
|
||||
SetDecalCursor();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Handles key down events in the 3D view.
|
||||
// Input : Per CWnd::OnKeyDown.
|
||||
// Output : Returns true if the message was handled, false if not.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CToolDecal::OnKeyDown3D(CMapView3D *pView, UINT nChar, UINT nRepCnt, UINT nFlags)
|
||||
{
|
||||
switch (nChar)
|
||||
{
|
||||
case VK_ESCAPE:
|
||||
{
|
||||
ToolManager()->SetTool(TOOL_POINTER);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Handles left button down events in the 3D view.
|
||||
// Input : Per CWnd::OnLButtonDown.
|
||||
// Output : Returns true if the message was handled, false if not.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CToolDecal::OnLMouseDown3D(CMapView3D *pView, UINT nFlags, const Vector2D &vPoint)
|
||||
{
|
||||
//
|
||||
// See if they clicked on a brush face. If so, apply a decal where they clicked.
|
||||
//
|
||||
CMapDoc *pDoc = pView->GetMapDoc();
|
||||
|
||||
ULONG ulFace;
|
||||
CMapClass *pObject;
|
||||
|
||||
if ((pObject = pView->NearestObjectAt( vPoint, ulFace)) != NULL)
|
||||
{
|
||||
CMapSolid *pSolid = dynamic_cast <CMapSolid *> (pObject);
|
||||
if (pSolid == NULL)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
//
|
||||
// Build a ray to trace against the face that they clicked on to
|
||||
// find the point of intersection.
|
||||
//
|
||||
Vector Start,End;
|
||||
pView->GetCamera()->BuildRay( vPoint, Start, End);
|
||||
|
||||
Vector HitPos, HitNormal;
|
||||
CMapFace *pFace = pSolid->GetFace(ulFace);
|
||||
if (pFace->TraceLine(HitPos, HitNormal, Start, End))
|
||||
{
|
||||
GetHistory()->MarkUndoPosition(NULL, "Create decal");
|
||||
|
||||
CMapEntity *pEntity = new CMapEntity;
|
||||
pEntity->SetKeyValue("texture", GetDefaultTextureName());
|
||||
pEntity->SetPlaceholder(TRUE);
|
||||
pEntity->SetOrigin(HitPos);
|
||||
pEntity->SetClass("infodecal");
|
||||
|
||||
CMapWorld *pWorld = pDoc->GetMapWorld();
|
||||
|
||||
CMapDecal *pDecal = pEntity->GetChildOfType((CMapDecal *)NULL);
|
||||
if (pDecal != NULL)
|
||||
{
|
||||
pDecal->DecalAllSolids(pWorld);
|
||||
}
|
||||
|
||||
pEntity->CalcBounds(TRUE);
|
||||
pDoc->AddObjectToWorld(pEntity);
|
||||
|
||||
GetHistory()->KeepNew(pEntity);
|
||||
|
||||
pDoc->SetModifiedFlag();
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Handles mouse move events in the 3D view.
|
||||
// Input : Per CWnd::OnMouseMove.
|
||||
// Output : Returns true if the message was handled, false if not.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CToolDecal::OnMouseMove3D(CMapView3D *pView, UINT nFlags, const Vector2D &vPoint)
|
||||
{
|
||||
SetDecalCursor();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Sets the cursor to the decal application cursor.
|
||||
//-----------------------------------------------------------------------------
|
||||
void CToolDecal::SetDecalCursor(void)
|
||||
{
|
||||
static HCURSOR hcurDecal;
|
||||
|
||||
if (!hcurDecal)
|
||||
{
|
||||
hcurDecal = LoadCursor(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDC_DECAL));
|
||||
}
|
||||
|
||||
SetCursor(hcurDecal);
|
||||
}
|
||||
|
||||
39
hammer/ToolDecal.h
Normal file
39
hammer/ToolDecal.h
Normal file
@@ -0,0 +1,39 @@
|
||||
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef TOOLDECAL_H
|
||||
#define TOOLDECAL_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include "ToolInterface.h"
|
||||
|
||||
|
||||
class CToolDecal : public CBaseTool
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
//
|
||||
// CBaseTool implementation.
|
||||
//
|
||||
virtual ToolID_t GetToolID(void) { return TOOL_DECAL; }
|
||||
|
||||
virtual bool OnKeyDown2D(CMapView2D *pView, UINT nChar, UINT nRepCnt, UINT nFlags);
|
||||
virtual bool OnMouseMove2D(CMapView2D *pView, UINT nFlags, const Vector2D &vPoint);
|
||||
virtual bool OnKeyDown3D(CMapView3D *pView, UINT nChar, UINT nRepCnt, UINT nFlags);
|
||||
virtual bool OnLMouseDown3D(CMapView3D *pView, UINT nFlags, const Vector2D &vPoint);
|
||||
virtual bool OnMouseMove3D(CMapView3D *pView, UINT nFlags, const Vector2D &vPoint);
|
||||
|
||||
private:
|
||||
|
||||
void SetDecalCursor(void);
|
||||
};
|
||||
|
||||
|
||||
#endif // TOOLDECAL_H
|
||||
730
hammer/ToolEntity.cpp
Normal file
730
hammer/ToolEntity.cpp
Normal file
@@ -0,0 +1,730 @@
|
||||
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: Implements the entity/prefab placement tool.
|
||||
//
|
||||
//=============================================================================//
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "History.h"
|
||||
#include "MainFrm.h"
|
||||
#include "MapDefs.h"
|
||||
#include "MapSolid.h"
|
||||
#include "MapDoc.h"
|
||||
#include "MapView2D.h"
|
||||
#include "MapView3D.h"
|
||||
#include "Material.h"
|
||||
#include "materialsystem/IMesh.h"
|
||||
#include "Render2D.h"
|
||||
#include "Render3D.h"
|
||||
#include "StatusBarIDs.h"
|
||||
#include "TextureSystem.h"
|
||||
#include "ToolEntity.h"
|
||||
#include "ToolManager.h"
|
||||
#include "hammer.h"
|
||||
#include "vgui/Cursor.h"
|
||||
#include "Selection.h"
|
||||
#include "vstdlib/random.h"
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include <tier0/memdbgon.h>
|
||||
|
||||
|
||||
//#pragma warning(disable:4244)
|
||||
|
||||
|
||||
static HCURSOR s_hcurEntity = NULL;
|
||||
|
||||
|
||||
class CToolEntityMessageWnd : public CWnd
|
||||
{
|
||||
public:
|
||||
|
||||
bool Create(void);
|
||||
void PreMenu2D(CToolEntity *pTool, CMapView2D *pView);
|
||||
|
||||
protected:
|
||||
|
||||
//{{AFX_MSG_MAP(CToolEntityMessageWnd)
|
||||
afx_msg void OnCreateObject();
|
||||
//}}AFX_MSG
|
||||
|
||||
DECLARE_MESSAGE_MAP()
|
||||
|
||||
private:
|
||||
|
||||
CToolEntity *m_pToolEntity;
|
||||
CMapView2D *m_pView2D;
|
||||
};
|
||||
|
||||
|
||||
static CToolEntityMessageWnd s_wndToolMessage;
|
||||
static const char *g_pszClassName = "ValveEditor_EntityToolWnd";
|
||||
|
||||
|
||||
BEGIN_MESSAGE_MAP(CToolEntityMessageWnd, CWnd)
|
||||
//{{AFX_MSG_MAP(CToolMessageWnd)
|
||||
ON_COMMAND(ID_CREATEOBJECT, OnCreateObject)
|
||||
//}}AFX_MSG_MAP
|
||||
END_MESSAGE_MAP()
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Creates the hidden window that receives context menu commands for the
|
||||
// entity tool.
|
||||
// Output : Returns true on success, false on failure.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CToolEntityMessageWnd::Create(void)
|
||||
{
|
||||
WNDCLASS wndcls;
|
||||
memset(&wndcls, 0, sizeof(WNDCLASS));
|
||||
wndcls.lpfnWndProc = AfxWndProc;
|
||||
wndcls.hInstance = AfxGetInstanceHandle();
|
||||
wndcls.lpszClassName = g_pszClassName;
|
||||
|
||||
if (!AfxRegisterClass(&wndcls))
|
||||
{
|
||||
return(false);
|
||||
}
|
||||
|
||||
return(CWnd::CreateEx(0, g_pszClassName, g_pszClassName, 0, CRect(0, 0, 10, 10), NULL, 0) == TRUE);
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Attaches the entity tool to this window before activating the context
|
||||
// menu.
|
||||
//-----------------------------------------------------------------------------
|
||||
void CToolEntityMessageWnd::PreMenu2D(CToolEntity *pToolEntity, CMapView2D *pView)
|
||||
{
|
||||
Assert(pToolEntity != NULL);
|
||||
m_pToolEntity = pToolEntity;
|
||||
m_pView2D = pView;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CToolEntityMessageWnd::OnCreateObject()
|
||||
{
|
||||
m_pToolEntity->CreateMapObject(m_pView2D);
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
CToolEntity::CToolEntity(void)
|
||||
{
|
||||
SetEmpty();
|
||||
|
||||
m_vecPos.Init();
|
||||
|
||||
if (s_hcurEntity == NULL)
|
||||
{
|
||||
s_hcurEntity = LoadCursor(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDC_ENTITY));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
CToolEntity::~CToolEntity(void)
|
||||
{
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : pt -
|
||||
// BOOL -
|
||||
// Output :
|
||||
//-----------------------------------------------------------------------------
|
||||
int CToolEntity::HitTest(CMapView *pView, const Vector2D &ptClient, bool bTestHandles)
|
||||
{
|
||||
return HitRect( pView, ptClient, m_vecPos, 8 )?TRUE:FALSE;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : bSave -
|
||||
//-----------------------------------------------------------------------------
|
||||
void CToolEntity::FinishTranslation(bool bSave)
|
||||
{
|
||||
if (bSave)
|
||||
{
|
||||
TranslatePoint( m_vecPos );
|
||||
m_bEmpty = false;
|
||||
}
|
||||
|
||||
Tool3D::FinishTranslation(bSave);
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : pt -
|
||||
// uFlags -
|
||||
// size -
|
||||
// Output : Returns true if the translation delta was nonzero.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CToolEntity::UpdateTranslation( const Vector &vUpdate, UINT uFlags)
|
||||
{
|
||||
Vector vOldDelta = m_vTranslation;
|
||||
|
||||
if ( !Tool3D::UpdateTranslation( vUpdate, uFlags ) )
|
||||
return false;
|
||||
|
||||
// apply snap to grid constrain
|
||||
if ( uFlags )
|
||||
{
|
||||
ProjectOnTranslationPlane( m_vecPos + m_vTranslation, m_vTranslation, uFlags );
|
||||
m_vTranslation -= m_vecPos;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : pRender -
|
||||
//-----------------------------------------------------------------------------
|
||||
void CToolEntity::RenderTool2D(CRender2D *pRender)
|
||||
{
|
||||
Vector v = m_vecPos;
|
||||
|
||||
if ( IsTranslating() )
|
||||
{
|
||||
TranslatePoint( v );
|
||||
}
|
||||
else if ( IsEmpty() )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
pRender->SetDrawColor( 35, 255, 75 );
|
||||
|
||||
//
|
||||
// Draw center rect.
|
||||
//
|
||||
pRender->DrawRectangle( v, v, false, 6.0f );
|
||||
|
||||
//
|
||||
// Draw crosshair
|
||||
//
|
||||
pRender->DrawLine( Vector( g_MIN_MAP_COORD, v.y, v.z), Vector( g_MAX_MAP_COORD, v.y , v.z) );
|
||||
pRender->DrawLine( Vector( v.x, g_MIN_MAP_COORD, v.z), Vector( v.x, g_MAX_MAP_COORD, v.z) );
|
||||
pRender->DrawLine( Vector( v.x, v.y, g_MIN_MAP_COORD), Vector( v.x, v.y, g_MAX_MAP_COORD) );
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : pView -
|
||||
// point -
|
||||
// Output :
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CToolEntity::OnContextMenu2D(CMapView2D *pView, UINT nFlags, const Vector2D &vPoint)
|
||||
{
|
||||
if (!IsEmpty())
|
||||
{
|
||||
CMapDoc *pDoc = pView->GetMapDoc();
|
||||
if (pDoc == NULL)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!pView->PointInClientRect(vPoint))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if ( HitTest( pView, vPoint, false) )
|
||||
{
|
||||
static CMenu menu, menuCreate;
|
||||
static bool bInit = false;
|
||||
|
||||
if (!bInit)
|
||||
{
|
||||
bInit = true;
|
||||
menu.LoadMenu(IDR_POPUPS);
|
||||
menuCreate.Attach(::GetSubMenu(menu.m_hMenu, 1));
|
||||
|
||||
// Create the window that handles menu messages.
|
||||
s_wndToolMessage.Create();
|
||||
}
|
||||
|
||||
CPoint ptScreen( vPoint.x,vPoint.y);
|
||||
pView->ClientToScreen(&ptScreen);
|
||||
|
||||
s_wndToolMessage.PreMenu2D(this, pView);
|
||||
menuCreate.TrackPopupMenu(TPM_LEFTBUTTON | TPM_RIGHTBUTTON | TPM_LEFTALIGN, ptScreen.x, ptScreen.y, &s_wndToolMessage);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : *pView -
|
||||
// nChar -
|
||||
// nRepCnt -
|
||||
// nFlags -
|
||||
// Output : Returns true on success, false on failure.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CToolEntity::OnKeyDown2D(CMapView2D *pView, UINT nChar, UINT nRepCnt, UINT nFlags)
|
||||
{
|
||||
switch (nChar)
|
||||
{
|
||||
case VK_RETURN:
|
||||
{
|
||||
if (!IsEmpty())
|
||||
{
|
||||
CreateMapObject(pView);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
case VK_ESCAPE:
|
||||
{
|
||||
OnEscape();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : pView -
|
||||
// nFlags -
|
||||
// point -
|
||||
// Output : Returns true on success, false on failure.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CToolEntity::OnLMouseDown2D(CMapView2D *pView, UINT nFlags, const Vector2D &vPoint)
|
||||
{
|
||||
unsigned int uConstraints = GetConstraints( nFlags );
|
||||
|
||||
Tool3D::OnLMouseDown2D(pView, nFlags, vPoint);
|
||||
|
||||
if ( HitTest( pView, vPoint, false) )
|
||||
{
|
||||
// translate existing object
|
||||
StartTranslation( pView, vPoint );
|
||||
}
|
||||
else
|
||||
{
|
||||
Vector vecWorld;
|
||||
pView->ClientToWorld(vecWorld, vPoint );
|
||||
|
||||
//
|
||||
// Snap starting position to grid.
|
||||
//
|
||||
if ( uConstraints & constrainSnap )
|
||||
m_pDocument->Snap(vecWorld, uConstraints);
|
||||
|
||||
// create new one, keep old third axis
|
||||
m_vecPos[pView->axHorz] = vecWorld[pView->axHorz];
|
||||
m_vecPos[pView->axVert] = vecWorld[pView->axVert];
|
||||
m_bEmpty = false;
|
||||
StartTranslation( pView, vPoint );
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// set temp transformation plane
|
||||
|
||||
void CToolEntity::StartTranslation( CMapView *pView, const Vector2D &vPoint )
|
||||
{
|
||||
Vector vOrigin, v1,v2,v3;
|
||||
|
||||
pView->GetBestTransformPlane( v1,v2,v3 );
|
||||
|
||||
SetTransformationPlane(m_vecPos, v1, v2, v3 );
|
||||
// align translation plane to world origin
|
||||
ProjectOnTranslationPlane( vec3_origin, vOrigin, 0 );
|
||||
// set transformation plane
|
||||
SetTransformationPlane(vOrigin, v1, v2, v3 );
|
||||
|
||||
Tool3D::StartTranslation( pView, vPoint, false );
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : Pre CWnd::OnLButtonUp.
|
||||
// Output : Returns true on success, false on failure.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CToolEntity::OnLMouseUp2D(CMapView2D *pView, UINT nFlags, const Vector2D &vPoint)
|
||||
{
|
||||
Tool3D::OnLMouseUp2D(pView, nFlags, vPoint);
|
||||
|
||||
if (IsTranslating())
|
||||
{
|
||||
FinishTranslation( true );
|
||||
}
|
||||
|
||||
m_pDocument->UpdateStatusbar();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Returns true if the message was handled, false otherwise.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CToolEntity::OnMouseMove2D(CMapView2D *pView, UINT nFlags, const Vector2D &vPoint)
|
||||
{
|
||||
Tool3D::OnMouseMove2D(pView, nFlags, vPoint);
|
||||
|
||||
vgui::HCursor hCursor = vgui::dc_arrow;
|
||||
|
||||
unsigned int uConstraints = GetConstraints( nFlags );
|
||||
|
||||
// Convert to world coords.
|
||||
|
||||
Vector vecWorld;
|
||||
pView->ClientToWorld(vecWorld, vPoint);
|
||||
|
||||
// Update status bar position display.
|
||||
|
||||
char szBuf[128];
|
||||
|
||||
if ( uConstraints & constrainSnap )
|
||||
m_pDocument->Snap(vecWorld,uConstraints);
|
||||
|
||||
sprintf(szBuf, " @%.0f, %.0f ", vecWorld[pView->axHorz], vecWorld[pView->axVert] );
|
||||
SetStatusText(SBI_COORDS, szBuf);
|
||||
|
||||
//
|
||||
// If we are currently dragging the marker, update that operation based on
|
||||
// the current cursor position and keyboard state.
|
||||
//
|
||||
if (IsTranslating())
|
||||
{
|
||||
Tool3D::UpdateTranslation( pView, vPoint, uConstraints );
|
||||
|
||||
// Don't change the cursor while dragging - it should remain a cross.
|
||||
hCursor = vgui::dc_none;
|
||||
}
|
||||
else if (!IsEmpty())
|
||||
{
|
||||
// Don't change the cursor while dragging - it should remain a cross.
|
||||
hCursor = vgui::dc_crosshair;
|
||||
}
|
||||
|
||||
if ( hCursor != vgui::dc_none )
|
||||
pView->SetCursor( hCursor );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Returns true if the message was handled, false otherwise.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CToolEntity::OnMouseMove3D(CMapView3D *pView, UINT nFlags, const Vector2D &vPoint)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Returns true if the message was handled, false otherwise.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CToolEntity::OnKeyDown3D(CMapView3D *pView, UINT nChar, UINT nRepCnt, UINT nFlags)
|
||||
{
|
||||
CMapDoc *pDoc = pView->GetMapDoc();
|
||||
if (pDoc == NULL)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (nChar)
|
||||
{
|
||||
case VK_RETURN:
|
||||
{
|
||||
//
|
||||
// Create the entity or prefab.
|
||||
//
|
||||
if (!IsEmpty())
|
||||
{
|
||||
//CreateMapObject(pView); // TODO: support in 3D
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
case VK_ESCAPE:
|
||||
{
|
||||
OnEscape();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Handles the escape key in the 2D or 3D views.
|
||||
//-----------------------------------------------------------------------------
|
||||
void CToolEntity::OnEscape(void)
|
||||
{
|
||||
//
|
||||
// Cancel the object creation tool.
|
||||
//
|
||||
if (!IsEmpty())
|
||||
{
|
||||
SetEmpty();
|
||||
}
|
||||
else
|
||||
{
|
||||
ToolManager()->SetTool(TOOL_POINTER);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : *pView -
|
||||
// nFlags -
|
||||
// point -
|
||||
// Output : Returns true on success, false on failure.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CToolEntity::OnLMouseDown3D(CMapView3D *pView, UINT nFlags, const Vector2D &vPoint)
|
||||
{
|
||||
ULONG ulFace;
|
||||
VMatrix LocalMatrix, LocalMatrixNeg;
|
||||
CMapClass *pObject = pView->NearestObjectAt( vPoint, ulFace, FLAG_OBJECTS_AT_RESOLVE_INSTANCES, &LocalMatrix );
|
||||
Tool3D::OnLMouseDown3D(pView, nFlags, vPoint);
|
||||
|
||||
if (pObject != NULL)
|
||||
{
|
||||
CMapSolid *pSolid = dynamic_cast <CMapSolid *> (pObject);
|
||||
if (pSolid == NULL)
|
||||
{
|
||||
// Clicked on a point entity - do nothing.
|
||||
return true;
|
||||
}
|
||||
|
||||
LocalMatrix.InverseTR( LocalMatrixNeg );
|
||||
|
||||
// Build a ray to trace against the face that they clicked on to
|
||||
// find the point of intersection.
|
||||
|
||||
Vector Start,End;
|
||||
pView->GetCamera()->BuildRay( vPoint, Start, End);
|
||||
|
||||
Vector HitPos, HitNormal;
|
||||
CMapFace *pFace = pSolid->GetFace(ulFace);
|
||||
Vector vFinalStart, vFinalEnd;
|
||||
LocalMatrixNeg.V3Mul( Start, vFinalStart );
|
||||
LocalMatrixNeg.V3Mul( End, vFinalEnd );
|
||||
if (pFace->TraceLine( HitPos, HitNormal, vFinalStart, vFinalEnd))
|
||||
{
|
||||
Vector vFinalHitPos, vFinalHitNormal;
|
||||
LocalMatrix.V3Mul( HitPos, vFinalHitPos );
|
||||
vFinalHitNormal = LocalMatrix.ApplyRotation( HitNormal );
|
||||
CMapClass *pNewObject = NULL;
|
||||
|
||||
if (GetMainWnd()->m_ObjectBar.IsEntityToolCreatingPrefab())
|
||||
{
|
||||
//
|
||||
// Prefab creation.
|
||||
//
|
||||
unsigned int uConstraints = GetConstraints( nFlags );
|
||||
m_pDocument->Snap(vFinalHitPos,uConstraints);
|
||||
|
||||
GetHistory()->MarkUndoPosition(m_pDocument->GetSelection()->GetList(), "New Prefab");
|
||||
|
||||
// Get prefab object
|
||||
CMapClass *pPrefabObject = GetMainWnd()->m_ObjectBar.BuildPrefabObjectAtPoint(vFinalHitPos);
|
||||
|
||||
//
|
||||
// Add prefab to the world.
|
||||
//
|
||||
CMapWorld *pWorld = m_pDocument->GetMapWorld();
|
||||
m_pDocument->ExpandObjectKeywords(pPrefabObject, pWorld);
|
||||
|
||||
pNewObject = pPrefabObject;
|
||||
}
|
||||
else if (GetMainWnd()->m_ObjectBar.IsEntityToolCreatingEntity())
|
||||
{
|
||||
//
|
||||
// Entity creation.
|
||||
//
|
||||
GetHistory()->MarkUndoPosition(m_pDocument->GetSelection()->GetList(), "New Entity");
|
||||
|
||||
CMapEntity *pEntity = new CMapEntity;
|
||||
pEntity->SetPlaceholder(TRUE);
|
||||
pEntity->SetOrigin(vFinalHitPos);
|
||||
pEntity->SetClass(CObjectBar::GetDefaultEntityClass());
|
||||
|
||||
VPlane BeforeTransform( pFace->plane.normal, pFace->plane.dist ), AfterTransform;
|
||||
LocalMatrix.TransformPlane( BeforeTransform, AfterTransform );
|
||||
|
||||
PLANE NewPlane;
|
||||
|
||||
NewPlane.dist = AfterTransform.m_Dist;
|
||||
NewPlane.normal = AfterTransform.m_Normal;
|
||||
// Align the entity on the plane properly
|
||||
pEntity->AlignOnPlane(vFinalHitPos, &NewPlane, (vFinalHitNormal.z > 0.0f) ? CMapEntity::ALIGN_BOTTOM : CMapEntity::ALIGN_TOP);
|
||||
|
||||
pNewObject = pEntity;
|
||||
}
|
||||
|
||||
if ( pNewObject )
|
||||
{
|
||||
if ( GetMainWnd()->m_ObjectBar.UseRandomYawOnEntityPlacement() )
|
||||
{
|
||||
// They checked "random yaw" on the object bar, so come up with a random yaw.
|
||||
VMatrix vmRotate, vmT1, vmT2;
|
||||
Vector vOrigin;
|
||||
QAngle angRandom( 0, RandomInt( -180, 180 ), 0 );
|
||||
|
||||
pNewObject->GetOrigin( vOrigin );
|
||||
|
||||
// Setup a matrix that translates them to the origin, rotates it, then translates back.
|
||||
MatrixFromAngles( angRandom, vmRotate );
|
||||
MatrixBuildTranslation( vmT1, -vOrigin );
|
||||
MatrixBuildTranslation( vmT2, vOrigin );
|
||||
|
||||
// Transform the object.
|
||||
pNewObject->Transform( vmT2 * vmRotate * vmT1 );
|
||||
}
|
||||
|
||||
m_pDocument->AddObjectToWorld( pNewObject );
|
||||
GetHistory()->KeepNew( pNewObject );
|
||||
|
||||
// Select the new object.
|
||||
m_pDocument->SelectObject( pNewObject, scClear|scSelect|scSaveChanges );
|
||||
|
||||
m_pDocument->SetModifiedFlag();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Renders a selection gizmo at our bounds center.
|
||||
// Input : pRender - Rendering interface.
|
||||
//-----------------------------------------------------------------------------
|
||||
void CToolEntity::RenderTool3D(CRender3D *pRender)
|
||||
{
|
||||
Vector pos = m_vecPos;
|
||||
|
||||
if ( IsTranslating() )
|
||||
{
|
||||
TranslatePoint( pos );
|
||||
}
|
||||
else if ( IsEmpty() )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
// Setup the renderer.
|
||||
//
|
||||
pRender->PushRenderMode( RENDER_MODE_WIREFRAME);
|
||||
|
||||
CMeshBuilder meshBuilder;
|
||||
CMatRenderContextPtr pRenderContext( MaterialSystemInterface() );
|
||||
IMesh* pMesh = pRenderContext->GetDynamicMesh();
|
||||
|
||||
meshBuilder.Begin(pMesh, MATERIAL_LINES, 3);
|
||||
|
||||
meshBuilder.Position3f(g_MIN_MAP_COORD, pos.y, pos.z);
|
||||
meshBuilder.Color3ub(255, 0, 0);
|
||||
meshBuilder.AdvanceVertex();
|
||||
meshBuilder.Position3f(g_MAX_MAP_COORD, pos.y, pos.z);
|
||||
meshBuilder.Color3ub(255, 0, 0);
|
||||
meshBuilder.AdvanceVertex();
|
||||
|
||||
meshBuilder.Position3f(pos.x, g_MIN_MAP_COORD, pos.z);
|
||||
meshBuilder.Color3ub(0, 255, 0);
|
||||
meshBuilder.AdvanceVertex();
|
||||
meshBuilder.Position3f(pos.x, g_MAX_MAP_COORD, pos.z);
|
||||
meshBuilder.Color3ub(0, 255, 0);
|
||||
meshBuilder.AdvanceVertex();
|
||||
|
||||
meshBuilder.Position3f(pos.x, pos.y, g_MIN_MAP_COORD);
|
||||
meshBuilder.Color3ub(0, 0, 255);
|
||||
meshBuilder.AdvanceVertex();
|
||||
meshBuilder.Position3f(pos.x, pos.y, g_MAX_MAP_COORD);
|
||||
meshBuilder.Color3ub(0, 0, 255);
|
||||
meshBuilder.AdvanceVertex();
|
||||
|
||||
meshBuilder.End();
|
||||
pMesh->Draw();
|
||||
|
||||
pRender->PopRenderMode();
|
||||
}
|
||||
|
||||
|
||||
void CToolEntity::CreateMapObject(CMapView2D *pView)
|
||||
{
|
||||
CMapWorld *pWorld = m_pDocument->GetMapWorld();
|
||||
CMapClass *pobj = NULL;
|
||||
|
||||
//
|
||||
// Handle prefab creation.
|
||||
//
|
||||
if (GetMainWnd()->m_ObjectBar.IsEntityToolCreatingPrefab())
|
||||
{
|
||||
GetHistory()->MarkUndoPosition(m_pDocument->GetSelection()->GetList(), "New Prefab");
|
||||
|
||||
CMapClass *pPrefabObject = GetMainWnd()->m_ObjectBar.BuildPrefabObjectAtPoint(m_vecPos);
|
||||
|
||||
if (pPrefabObject == NULL)
|
||||
{
|
||||
pView->MessageBox("Unable to load prefab", "Error", MB_OK);
|
||||
SetEmpty();
|
||||
return;
|
||||
}
|
||||
|
||||
m_pDocument->ExpandObjectKeywords(pPrefabObject, pWorld);
|
||||
m_pDocument->AddObjectToWorld(pPrefabObject);
|
||||
|
||||
GetHistory()->KeepNew(pPrefabObject);
|
||||
|
||||
pobj = pPrefabObject;
|
||||
}
|
||||
//
|
||||
// Handle entity creation.
|
||||
//
|
||||
else if (GetMainWnd()->m_ObjectBar.IsEntityToolCreatingEntity())
|
||||
{
|
||||
GetHistory()->MarkUndoPosition(m_pDocument->GetSelection()->GetList(), "New Entity");
|
||||
|
||||
CMapEntity *pEntity = new CMapEntity;
|
||||
|
||||
pEntity->SetPlaceholder(TRUE);
|
||||
pEntity->SetOrigin(m_vecPos);
|
||||
pEntity->SetClass(CObjectBar::GetDefaultEntityClass());
|
||||
|
||||
m_pDocument->AddObjectToWorld(pEntity);
|
||||
|
||||
pobj = pEntity;
|
||||
|
||||
GetHistory()->KeepNew(pEntity);
|
||||
}
|
||||
|
||||
//
|
||||
// Select the new object.
|
||||
//
|
||||
m_pDocument->SelectObject(pobj, scClear |scSelect|scSaveChanges);
|
||||
|
||||
SetEmpty();
|
||||
|
||||
m_pDocument->SetModifiedFlag();
|
||||
}
|
||||
|
||||
|
||||
79
hammer/ToolEntity.h
Normal file
79
hammer/ToolEntity.h
Normal file
@@ -0,0 +1,79 @@
|
||||
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ====
|
||||
//
|
||||
// Purpose: Defines the interface to the entity placement tool.
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
#ifndef TOOLENTITY_H
|
||||
#define TOOLENTITY_H
|
||||
#pragma once
|
||||
|
||||
|
||||
#include "ToolInterface.h"
|
||||
#include "Tool3D.h"
|
||||
|
||||
|
||||
class CRender2D;
|
||||
class CRender3D;
|
||||
|
||||
|
||||
class CToolEntity : public Tool3D
|
||||
{
|
||||
|
||||
friend class CToolEntityMessageWnd;
|
||||
|
||||
public:
|
||||
|
||||
CToolEntity(void);
|
||||
~CToolEntity(void);
|
||||
|
||||
inline void GetPos(Vector &vecPos);
|
||||
|
||||
//
|
||||
// CBaseTool implementation.
|
||||
//
|
||||
virtual ToolID_t GetToolID(void) { return TOOL_ENTITY; }
|
||||
|
||||
virtual bool OnContextMenu2D(CMapView2D *pView, UINT nFlags, const Vector2D &vPoint);
|
||||
virtual bool OnKeyDown2D(CMapView2D *pView, UINT nChar, UINT nRepCnt, UINT nFlags);
|
||||
|
||||
virtual bool OnLMouseDown2D(CMapView2D *pView, UINT nFlags, const Vector2D &vPoint);
|
||||
virtual bool OnLMouseUp2D(CMapView2D *pView, UINT nFlags, const Vector2D &vPoint);
|
||||
virtual bool OnMouseMove2D(CMapView2D *pView, UINT nFlags, const Vector2D &vPoint);
|
||||
|
||||
virtual bool OnMouseMove3D(CMapView3D *pView, UINT nFlags, const Vector2D &vPoint);
|
||||
virtual bool OnKeyDown3D(CMapView3D *pView, UINT nChar, UINT nRepCnt, UINT nFlags);
|
||||
virtual bool OnLMouseDown3D(CMapView3D *pView, UINT nFlags, const Vector2D &vPoint);
|
||||
|
||||
virtual void RenderTool2D(CRender2D *pRender);
|
||||
virtual void RenderTool3D(CRender3D *pRender);
|
||||
|
||||
protected:
|
||||
|
||||
//
|
||||
// Tool3D implementation.
|
||||
//
|
||||
void StartTranslation( CMapView *pView, const Vector2D &vPoint);
|
||||
virtual bool UpdateTranslation(const Vector &vUpdate, UINT flags);
|
||||
virtual void FinishTranslation(bool bSave);
|
||||
virtual int HitTest(CMapView *pView, const Vector2D &vPoint, bool bTestHandles = false);
|
||||
|
||||
private:
|
||||
|
||||
void OnEscape(void);
|
||||
void CreateMapObject(CMapView2D *pView);
|
||||
|
||||
Vector m_vecPos; // Current position of the marker.
|
||||
};
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Returns the current position of the marker.
|
||||
//-----------------------------------------------------------------------------
|
||||
inline void CToolEntity::GetPos(Vector &vecPos)
|
||||
{
|
||||
vecPos = m_vecPos;
|
||||
}
|
||||
|
||||
|
||||
#endif // TOOLENTITY_H
|
||||
85
hammer/ToolMagnify.cpp
Normal file
85
hammer/ToolMagnify.cpp
Normal file
@@ -0,0 +1,85 @@
|
||||
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "MapDoc.h"
|
||||
#include "MapView2D.h"
|
||||
#include "resource.h"
|
||||
#include "ToolMagnify.h"
|
||||
#include "HammerVGui.h"
|
||||
#include <VGuiMatSurface/IMatSystemSurface.h>
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include <tier0/memdbgon.h>
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Loads the cursor (only once).
|
||||
//-----------------------------------------------------------------------------
|
||||
CToolMagnify::CToolMagnify(void)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : *pView -
|
||||
// nFlags -
|
||||
// point -
|
||||
// Output : Returns true on success, false on failure.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CToolMagnify::OnContextMenu2D(CMapView2D *pView, UINT nFlags, const Vector2D &vPoint)
|
||||
{
|
||||
// Return true to suppress the default view context menu behavior.
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : pView -
|
||||
// nFlags -
|
||||
// point -
|
||||
// Output : Returns true to indicate that the message was handled.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CToolMagnify::OnLMouseDown2D(CMapView2D *pView, UINT nFlags, const Vector2D &vPoint)
|
||||
{
|
||||
pView->SetZoom(pView->GetZoom() * 2);
|
||||
pView->Invalidate();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : pView -
|
||||
// nFlags -
|
||||
// point -
|
||||
// Output : Returns true to indicate that the message was handled.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CToolMagnify::OnMouseMove2D(CMapView2D *pView, UINT nFlags, const Vector2D &vPoint)
|
||||
{
|
||||
// cursors are cached by surface
|
||||
pView->SetCursor( "Resource/magnify.cur" );
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : pView -
|
||||
// nFlags -
|
||||
// point -
|
||||
// Output : Returns true to indicate that the message was handled.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CToolMagnify::OnRMouseDown2D(CMapView2D *pView, UINT nFlags, const Vector2D &vPoint)
|
||||
{
|
||||
pView->SetZoom(pView->GetZoom() * 0.5f);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
35
hammer/ToolMagnify.h
Normal file
35
hammer/ToolMagnify.h
Normal file
@@ -0,0 +1,35 @@
|
||||
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef TOOLMAGNIFY_H
|
||||
#define TOOLMAGNIFY_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include "ToolInterface.h"
|
||||
|
||||
|
||||
class CToolMagnify : public CBaseTool
|
||||
{
|
||||
public:
|
||||
|
||||
CToolMagnify(void);
|
||||
~CToolMagnify(void) {}
|
||||
|
||||
//
|
||||
// CBaseTool implementation.
|
||||
//
|
||||
virtual ToolID_t GetToolID(void) { return TOOL_MAGNIFY; }
|
||||
|
||||
virtual bool OnContextMenu2D(CMapView2D *pView, UINT nFlags, const Vector2D &vPoint);
|
||||
virtual bool OnLMouseDown2D(CMapView2D *pView, UINT nFlags, const Vector2D &vPoint);
|
||||
virtual bool OnRMouseDown2D(CMapView2D *pView, UINT nFlags, const Vector2D &vPoint);
|
||||
virtual bool OnMouseMove2D(CMapView2D *pView, UINT nFlags, const Vector2D &vPoint);
|
||||
};
|
||||
|
||||
#endif // TOOLMAGNIFY_H
|
||||
306
hammer/ToolManager.cpp
Normal file
306
hammer/ToolManager.cpp
Normal file
@@ -0,0 +1,306 @@
|
||||
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// TODO: add an autoregistration system for tools a la LINK_ENTITY_TO_CLASS
|
||||
//=============================================================================//
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "MapDoc.h"
|
||||
#include "MainFrm.h"
|
||||
#include "MapView2D.h" // FIXME: for MapView2D::updTool
|
||||
#include "ToolAxisHandle.h"
|
||||
#include "ToolDecal.h"
|
||||
#include "ToolDisplace.h"
|
||||
#include "ToolManager.h"
|
||||
#include "ToolMagnify.h"
|
||||
#include "ToolMaterial.h"
|
||||
#include "ToolPickFace.h"
|
||||
#include "ToolPickAngles.h"
|
||||
#include "ToolPickEntity.h"
|
||||
#include "ToolPointHandle.h"
|
||||
#include "ToolSphere.h"
|
||||
#include "ToolSweptHull.h"
|
||||
#include "ToolBlock.h"
|
||||
#include "ToolCamera.h"
|
||||
#include "ToolClipper.h"
|
||||
#include "ToolCordon.h"
|
||||
#include "ToolEntity.h"
|
||||
#include "ToolMorph.h"
|
||||
#include "ToolOverlay.h"
|
||||
#include "ToolSelection.h"
|
||||
#include "ToolMagnify.h"
|
||||
#include "ToolMaterial.h"
|
||||
#include "toolsprinkle.h"
|
||||
#include "ChunkFile.h"
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include <tier0/memdbgon.h>
|
||||
|
||||
static CToolManager s_DummyToolmanager;
|
||||
|
||||
CToolManager* ToolManager()
|
||||
{
|
||||
CMapDoc *pDoc = CMapDoc::GetActiveMapDoc();
|
||||
|
||||
if ( pDoc )
|
||||
return pDoc->GetTools();
|
||||
|
||||
return &s_DummyToolmanager;
|
||||
}
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Prepares the tool manager for use.
|
||||
// Output : Returns true on success, false on failure.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CToolManager::Init( CMapDoc *pDocument )
|
||||
{
|
||||
|
||||
// add default tools
|
||||
|
||||
//
|
||||
// Create the tools that are held by the tool manager and add them
|
||||
// to the internal tools list.
|
||||
//
|
||||
|
||||
RemoveAllTools();
|
||||
|
||||
m_pDocument = pDocument;
|
||||
|
||||
AddTool( new CToolDisplace );
|
||||
AddTool( new CToolMagnify );
|
||||
AddTool( new CToolDecal );
|
||||
AddTool( new CToolMaterial );
|
||||
AddTool( new CToolAxisHandle );
|
||||
AddTool( new CToolPointHandle );
|
||||
AddTool( new CToolSphere );
|
||||
AddTool( new CToolPickAngles );
|
||||
AddTool( new CToolPickEntity );
|
||||
AddTool( new CToolPickFace );
|
||||
AddTool( new CToolSweptPlayerHull );
|
||||
AddTool( new Selection3D );
|
||||
AddTool( new CToolBlock );
|
||||
AddTool( new CToolEntity );
|
||||
AddTool( new Camera3D );
|
||||
AddTool( new Morph3D );
|
||||
AddTool( new Clipper3D );
|
||||
AddTool( new Cordon3D );
|
||||
AddTool( new CToolOverlay );
|
||||
AddTool( new CToolEntitySprinkle );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Shuts down the tool manager - called on app exit.
|
||||
//-----------------------------------------------------------------------------
|
||||
void CToolManager::Shutdown()
|
||||
{
|
||||
m_pActiveTool = NULL;
|
||||
m_pDocument = NULL;
|
||||
RemoveAllTools();
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Constructor. Allocates the tools.
|
||||
//-----------------------------------------------------------------------------
|
||||
CToolManager::CToolManager()
|
||||
{
|
||||
m_pActiveTool = NULL;
|
||||
m_pDocument = NULL;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Destructor. Deletes the tools.
|
||||
//-----------------------------------------------------------------------------
|
||||
CToolManager::~CToolManager()
|
||||
{
|
||||
Shutdown();
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CToolManager::AddTool(CBaseTool *pTool)
|
||||
{
|
||||
if ( GetToolForID( pTool->GetToolID() ) )
|
||||
{
|
||||
Assert( !pTool );
|
||||
Msg("CToolManager::AddTool: Tool %i already registered.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
pTool->Init( m_pDocument );
|
||||
|
||||
m_Tools.AddToTail(pTool);
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
CBaseTool *CToolManager::GetActiveTool()
|
||||
{
|
||||
return m_pActiveTool;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Returns a tool pointer for a given tool ID, NULL if there is no
|
||||
// corresponding tool.
|
||||
//-----------------------------------------------------------------------------
|
||||
CBaseTool *CToolManager::GetToolForID(ToolID_t eToolID)
|
||||
{
|
||||
int nToolCount = GetToolCount();
|
||||
for (int i = 0; i < nToolCount; i++)
|
||||
{
|
||||
CBaseTool *pTool = GetTool(i);
|
||||
if (pTool->GetToolID() == eToolID)
|
||||
{
|
||||
return pTool;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Returns the ID of the active tool.
|
||||
//-----------------------------------------------------------------------------
|
||||
ToolID_t CToolManager::GetActiveToolID()
|
||||
{
|
||||
if ( m_pActiveTool )
|
||||
return m_pActiveTool->GetToolID();
|
||||
else
|
||||
return TOOL_NONE;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Pushes a new tool onto the tool stack and activates it. The active
|
||||
// tool will be deactivated and reactivated when PopTool is called.
|
||||
//-----------------------------------------------------------------------------
|
||||
void CToolManager::PushTool(ToolID_t eToolID)
|
||||
{
|
||||
//
|
||||
// Add the new tool to the top of the tool stack.
|
||||
//
|
||||
if (eToolID != GetActiveToolID())
|
||||
{
|
||||
m_ToolIDStack.AddToHead(GetActiveToolID());
|
||||
}
|
||||
|
||||
SetTool(eToolID);
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Restores the active tool to what it was when PushTool was called.
|
||||
// If the stack is underflowed somehow, the pointer is restored.
|
||||
//-----------------------------------------------------------------------------
|
||||
void CToolManager::PopTool()
|
||||
{
|
||||
int nCount = m_ToolIDStack.Count();
|
||||
if (nCount > 0)
|
||||
{
|
||||
ToolID_t eNewTool = m_ToolIDStack.Element(0);
|
||||
m_ToolIDStack.Remove(0);
|
||||
|
||||
SetTool(eNewTool);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Sets the current active tool by ID.
|
||||
// Input : iTool - ID of the tool to activate.
|
||||
//-----------------------------------------------------------------------------
|
||||
void CToolManager::SetTool(ToolID_t eNewTool)
|
||||
{
|
||||
CBaseTool *pNewTool = GetToolForID(eNewTool);
|
||||
CBaseTool *pOldTool = m_pActiveTool;
|
||||
|
||||
// Check to see that we can deactive the current tool
|
||||
if ( pOldTool && (pOldTool != pNewTool) )
|
||||
{
|
||||
// Deactivate the current tool unless we are just 'reactivating' it.
|
||||
if( !pOldTool->CanDeactivate() )
|
||||
return;
|
||||
}
|
||||
|
||||
// set active tool to new tool already so old tool can peek whats coming next
|
||||
m_pActiveTool = pNewTool;
|
||||
|
||||
// deactivate the old tool if different.
|
||||
if ( pOldTool && (pOldTool != pNewTool) )
|
||||
{
|
||||
pOldTool->Deactivate();
|
||||
}
|
||||
|
||||
// always activate the new tool
|
||||
if ( pNewTool )
|
||||
{
|
||||
pNewTool->Activate();
|
||||
}
|
||||
|
||||
// FIXME: When we start up, we end up here before the main window is created because
|
||||
// CFaceEditDispPage::OnSetActive() calls SetTool(TOOL_FACEEDIT_DISP). This
|
||||
// behavior is rather nonsensical during startup.
|
||||
CMainFrame *pwndMain = GetMainWnd();
|
||||
if (pwndMain != NULL)
|
||||
{
|
||||
pwndMain->m_ObjectBar.UpdateListForTool(eNewTool);
|
||||
}
|
||||
|
||||
if ( m_pDocument )
|
||||
m_pDocument->UpdateAllViews( MAPVIEW_UPDATE_TOOL );
|
||||
}
|
||||
|
||||
ChunkFileResult_t CToolManager::SaveVMF(CChunkFile *pFile, CSaveInfo *pSaveInfo)
|
||||
{
|
||||
for (int i=0;i<m_Tools.Count(); i++)
|
||||
{
|
||||
if ( m_Tools[i]->GetVMFChunkName() != NULL )
|
||||
{
|
||||
m_Tools[i]->SaveVMF( pFile, pSaveInfo );
|
||||
}
|
||||
}
|
||||
|
||||
return ChunkFile_Ok;
|
||||
}
|
||||
|
||||
|
||||
ChunkFileResult_t CToolManager::LoadCallback(CChunkFile *pFile, CBaseTool *pTool)
|
||||
{
|
||||
return pTool->LoadVMF( pFile );
|
||||
}
|
||||
|
||||
|
||||
void CToolManager::AddToolHandlers( CChunkHandlerMap *pHandlersMap )
|
||||
{
|
||||
for (int i=0;i<m_Tools.Count(); i++)
|
||||
{
|
||||
if ( m_Tools[i]->GetVMFChunkName() != NULL )
|
||||
{
|
||||
pHandlersMap->AddHandler( m_Tools[i]->GetVMFChunkName(), (ChunkHandler_t)LoadCallback, m_Tools[i] );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Removes all the document-created tools from the tools list.
|
||||
//-----------------------------------------------------------------------------
|
||||
void CToolManager::RemoveAllTools()
|
||||
{
|
||||
m_pActiveTool = NULL;
|
||||
m_Tools.PurgeAndDeleteElements();
|
||||
m_ToolIDStack.RemoveAll();
|
||||
}
|
||||
|
||||
|
||||
96
hammer/ToolManager.h
Normal file
96
hammer/ToolManager.h
Normal file
@@ -0,0 +1,96 @@
|
||||
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef TOOLMANAGER_H
|
||||
#define TOOLMANAGER_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include "ToolInterface.h"
|
||||
#include "UtlVector.h"
|
||||
|
||||
|
||||
class CToolAxisHandle;
|
||||
class CToolDecal;
|
||||
class CToolDisplace;
|
||||
class CToolMagnify;
|
||||
class CToolMaterial;
|
||||
class CToolPickAngles;
|
||||
class CToolPickEntity;
|
||||
class CToolPickFace;
|
||||
class CToolPointHandle;
|
||||
class CToolSphere;
|
||||
class CBaseTool;
|
||||
class CToolSweptPlayerHull;
|
||||
class CChunkHandlerMap;
|
||||
|
||||
class CToolManager
|
||||
{
|
||||
public:
|
||||
|
||||
CToolManager();
|
||||
~CToolManager();
|
||||
|
||||
bool Init(CMapDoc *pDocument);
|
||||
void Shutdown();
|
||||
|
||||
CBaseTool *GetActiveTool();
|
||||
ToolID_t GetActiveToolID();
|
||||
|
||||
CBaseTool *GetToolForID(ToolID_t eToolID);
|
||||
|
||||
void SetTool(ToolID_t nToolID); // changes current tool without touching the tool stack
|
||||
void PushTool(ToolID_t nToolID); // activates a new tool and put current tool on stack
|
||||
void PopTool(); // restores last tool on stack
|
||||
|
||||
inline int GetToolCount();
|
||||
inline CBaseTool *GetTool(int nIndex);
|
||||
|
||||
void RemoveAllTools();
|
||||
void AddTool(CBaseTool *pTool);
|
||||
|
||||
static ChunkFileResult_t LoadCallback(CChunkFile *pFile, CBaseTool *pTool);
|
||||
void AddToolHandlers( CChunkHandlerMap *pHandlersMap );
|
||||
ChunkFileResult_t SaveVMF(CChunkFile *pFile, CSaveInfo *pSaveInfo);
|
||||
ChunkFileResult_t LoadVMF(CChunkFile *pFile);
|
||||
|
||||
private:
|
||||
|
||||
void ActivateTool( CBaseTool *pTool );
|
||||
void DeactivateTool( CBaseTool *pTool );
|
||||
|
||||
CUtlVector<CBaseTool *> m_Tools; // List of ALL the tools.
|
||||
|
||||
CMapDoc *m_pDocument; // document the manager is responisble for
|
||||
CBaseTool *m_pActiveTool; // Pointer to the active new tool, NULL if none.
|
||||
|
||||
CUtlVector<ToolID_t> m_ToolIDStack; // Stack of active tool IDs, for PushTool/PopTool.
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Accessor for iterating tools.
|
||||
//-----------------------------------------------------------------------------
|
||||
int CToolManager::GetToolCount()
|
||||
{
|
||||
return m_Tools.Count();
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Accessor for iterating tools.
|
||||
//-----------------------------------------------------------------------------
|
||||
CBaseTool *CToolManager::GetTool(int nIndex)
|
||||
{
|
||||
return m_Tools.Element(nIndex);
|
||||
}
|
||||
|
||||
// get the tool manager for the current active document:
|
||||
CToolManager *ToolManager();
|
||||
|
||||
|
||||
|
||||
#endif // TOOLMANAGER_H
|
||||
280
hammer/ToolMaterial.cpp
Normal file
280
hammer/ToolMaterial.cpp
Normal file
@@ -0,0 +1,280 @@
|
||||
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: Handles the selection of faces and material application.
|
||||
//
|
||||
// TODO: consider making face selection a mode of the selection tool
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "FaceEditSheet.h"
|
||||
#include "History.h"
|
||||
#include "MainFrm.h"
|
||||
#include "MapDoc.h"
|
||||
#include "MapSolid.h"
|
||||
#include "MapView2D.h"
|
||||
#include "MapView3D.h"
|
||||
#include "StatusBarIDs.h"
|
||||
#include "ToolManager.h"
|
||||
#include "ToolMaterial.h"
|
||||
#include "Options.h"
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include <tier0/memdbgon.h>
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Called when this tool is deactivated in favor of another tool.
|
||||
// Input : eNewTool - The tool that is being activated.
|
||||
//-----------------------------------------------------------------------------
|
||||
void CToolMaterial::OnDeactivate()
|
||||
{
|
||||
if ( m_pDocument->GetTools()->GetActiveToolID() != TOOL_FACEEDIT_DISP )
|
||||
{
|
||||
// Clear the selected faces when we are deactivated.
|
||||
m_pDocument->SelectFace(NULL, 0, scClear );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : pView -
|
||||
// nFlags -
|
||||
// point -
|
||||
// Output : Returns true if the message was handled, false if not.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CToolMaterial::OnLMouseDown2D(CMapView2D *pView, UINT nFlags, const Vector2D &vPoint)
|
||||
{
|
||||
if (nFlags & MK_CONTROL)
|
||||
{
|
||||
//
|
||||
// CONTROL is down, perform selection only.
|
||||
//
|
||||
pView->SelectAt( vPoint, false, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
pView->SelectAt( vPoint, true, true);
|
||||
}
|
||||
|
||||
return (true);
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Handles left mouse button down events in the 3D view.
|
||||
// Input : Per CWnd::OnLButtonDown.
|
||||
// Output : Returns true if the message was handled, false if not.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CToolMaterial::OnLMouseDown3D(CMapView3D *pView, UINT nFlags, const Vector2D &vPoint)
|
||||
{
|
||||
CMapDoc *pDoc = pView->GetMapDoc();
|
||||
if (pDoc == NULL)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool bShift = ((GetAsyncKeyState(VK_SHIFT) & 0x8000) != 0);
|
||||
|
||||
ULONG ulFace;
|
||||
CMapClass *pObject = pView->NearestObjectAt( vPoint, ulFace);
|
||||
|
||||
if ((pObject != NULL) && (pObject->IsMapClass(MAPCLASS_TYPE(CMapSolid))))
|
||||
{
|
||||
CMapSolid *pSolid = (CMapSolid *)pObject;
|
||||
|
||||
int cmd = scToggle | scClear;
|
||||
|
||||
// No clear if CTRL pressed.
|
||||
if (GetAsyncKeyState(VK_CONTROL) & 0x8000)
|
||||
{
|
||||
cmd &= ~scClear;
|
||||
}
|
||||
|
||||
// If they are holding down SHIFT, select the entire solid.
|
||||
if (bShift)
|
||||
{
|
||||
pDoc->SelectFace(pSolid, -1, cmd);
|
||||
}
|
||||
// Otherwise, select a single face.
|
||||
else
|
||||
{
|
||||
pDoc->SelectFace(pSolid, ulFace, cmd);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Handles right mouse button down events in the 3D view.
|
||||
// Input : Per CWnd::OnRButtonDown.
|
||||
// Output : Returns true if the message was handled, false if not.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CToolMaterial::OnRMouseDown3D(CMapView3D *pView, UINT nFlags, const Vector2D &vPoint)
|
||||
{
|
||||
BOOL bShift = ((GetAsyncKeyState(VK_SHIFT) & 0x8000) != 0);
|
||||
BOOL bEdgeAlign = ((GetAsyncKeyState(VK_MENU) & 0x8000) != 0);
|
||||
|
||||
ULONG ulFace;
|
||||
CMapClass *pObject = pView->NearestObjectAt( vPoint, ulFace);
|
||||
|
||||
if (pObject != NULL)
|
||||
{
|
||||
if (pObject->IsMapClass(MAPCLASS_TYPE(CMapSolid)))
|
||||
{
|
||||
CMapSolid *pSolid = (CMapSolid *)pObject;
|
||||
GetHistory()->MarkUndoPosition(NULL, "Apply texture");
|
||||
GetHistory()->Keep(pSolid);
|
||||
|
||||
// Setup the flags.
|
||||
int cmdFlags = 0;
|
||||
if (bEdgeAlign)
|
||||
{
|
||||
cmdFlags |= CFaceEditSheet::cfEdgeAlign;
|
||||
}
|
||||
|
||||
// If we're in a lightmap grid preview window, only apply the lightmap scale.
|
||||
int eMode;
|
||||
if (pView->GetDrawType() == VIEW3D_LIGHTMAP_GRID)
|
||||
{
|
||||
eMode = CFaceEditSheet::ModeApplyLightmapScale;
|
||||
}
|
||||
else
|
||||
{
|
||||
eMode = CFaceEditSheet::ModeApplyAll;
|
||||
}
|
||||
|
||||
// If they are holding down the shift key, apply to the entire solid.
|
||||
if (bShift)
|
||||
{
|
||||
int nFaces = pSolid->GetFaceCount();
|
||||
for(int i = 0; i < nFaces; i++)
|
||||
{
|
||||
GetMainWnd()->m_pFaceEditSheet->ClickFace(pSolid, i, cmdFlags, eMode);
|
||||
}
|
||||
}
|
||||
// If not, apply to a single face.
|
||||
else
|
||||
{
|
||||
GetMainWnd()->m_pFaceEditSheet->ClickFace(pSolid, ulFace, cmdFlags, eMode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Handles the mouse move message in the 3D view.
|
||||
// Input : Per CWnd::OnMouseMove.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CToolMaterial::OnMouseMove3D(CMapView3D *pView, UINT nFlags, const Vector2D &vPoint)
|
||||
{
|
||||
//
|
||||
// Manage the cursor.
|
||||
//
|
||||
static HCURSOR hcurFacePaint = 0;
|
||||
if (!hcurFacePaint)
|
||||
{
|
||||
hcurFacePaint = LoadCursor(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDC_FACEPAINT));
|
||||
}
|
||||
|
||||
SetCursor(hcurFacePaint);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CToolMaterial::UpdateStatusBar()
|
||||
{
|
||||
CString str;
|
||||
str.Format("%d faces selected", GetMainWnd()->m_pFaceEditSheet->GetFaceListCount() );
|
||||
SetStatusText(SBI_SELECTION, str);
|
||||
SetStatusText(SBI_SIZE, "");
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Handles the key down event in the 3D view.
|
||||
// Input : Per CWnd::OnKeyDown.
|
||||
// Output : Returns true if the message was handled, false if not.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CToolMaterial::OnKeyDown3D( CMapView3D *pView, UINT nChar, UINT nRepCnt, UINT nFlags )
|
||||
{
|
||||
// TO DO: undo?
|
||||
// justify (SHIFT?)
|
||||
|
||||
CMapDoc *pDoc = pView->GetMapDoc();
|
||||
if ( pDoc == NULL )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( nChar == VK_UP || nChar == VK_DOWN || nChar == VK_LEFT || nChar == VK_RIGHT )
|
||||
{
|
||||
// Bail out if the user doesn't have Nudging enabled.
|
||||
if ( !Options.view2d.bNudge )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
CFaceEditSheet *pSheet = GetMainWnd()->m_pFaceEditSheet;
|
||||
if( pSheet )
|
||||
{
|
||||
// Check for a face list.
|
||||
int nFaceCount = pSheet->GetFaceListCount();
|
||||
if( nFaceCount == 0 )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
int nGridSize = m_pDocument->GetGridSpacing();
|
||||
bool bCtrlDown = ( ( GetAsyncKeyState( VK_CONTROL ) & 0x8000 ) != 0 );
|
||||
|
||||
if ( bCtrlDown )
|
||||
{
|
||||
nGridSize = 1;
|
||||
}
|
||||
|
||||
for( int ndxface = 0; ndxface < nFaceCount; ndxface++ )
|
||||
{
|
||||
CMapFace *pFace;
|
||||
pFace = pSheet->GetFaceListDataFace( ndxface );
|
||||
|
||||
TEXTURE &t = pFace->texture;
|
||||
|
||||
if ( nChar == VK_UP )
|
||||
{
|
||||
t.VAxis[ 3 ] = ( (int)( t.VAxis[ 3 ] + nGridSize ) % 1024 );
|
||||
}
|
||||
else if ( nChar == VK_DOWN )
|
||||
{
|
||||
t.VAxis[ 3 ] = ( (int)( t.VAxis[ 3 ] - nGridSize ) % 1024 );
|
||||
|
||||
}
|
||||
else if ( nChar == VK_LEFT )
|
||||
{
|
||||
t.UAxis[ 3 ] = ( (int)( t.UAxis[ 3 ] + nGridSize ) % 1024 );
|
||||
}
|
||||
else
|
||||
{
|
||||
t.UAxis[ 3 ] = ( (int)( t.UAxis[ 3 ] - nGridSize ) % 1024 );
|
||||
}
|
||||
|
||||
pFace->CalcTextureCoords();
|
||||
pSheet->m_MaterialPage.UpdateDialogData( pFace );
|
||||
}
|
||||
pDoc->SetModifiedFlag();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
37
hammer/ToolMaterial.h
Normal file
37
hammer/ToolMaterial.h
Normal file
@@ -0,0 +1,37 @@
|
||||
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef TOOLMATERIAL_H
|
||||
#define TOOLMATERIAL_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
|
||||
#include "ToolInterface.h"
|
||||
|
||||
|
||||
class CToolMaterial : public CBaseTool
|
||||
{
|
||||
//
|
||||
// CBaseTool implementation.
|
||||
//
|
||||
virtual ToolID_t GetToolID(void) { return TOOL_FACEEDIT_MATERIAL; }
|
||||
|
||||
virtual bool OnLMouseDown2D(CMapView2D *pView, UINT nFlags, const Vector2D &vPoint);
|
||||
virtual bool OnKeyDown3D(CMapView3D *pView, UINT nChar, UINT nRepCnt, UINT nFlags);
|
||||
virtual bool OnLMouseDown3D(CMapView3D *pView, UINT nFlags, const Vector2D &vPoint);
|
||||
virtual bool OnRMouseDown3D(CMapView3D *pView, UINT nFlags, const Vector2D &vPoint);
|
||||
virtual bool OnMouseMove3D(CMapView3D *pView, UINT nFlags, const Vector2D &vPoint);
|
||||
|
||||
virtual void UpdateStatusBar();
|
||||
|
||||
virtual void OnDeactivate();
|
||||
};
|
||||
|
||||
|
||||
#endif // TOOLMATERIAL_H
|
||||
2107
hammer/ToolMorph.cpp
Normal file
2107
hammer/ToolMorph.cpp
Normal file
File diff suppressed because it is too large
Load Diff
200
hammer/ToolMorph.h
Normal file
200
hammer/ToolMorph.h
Normal file
@@ -0,0 +1,200 @@
|
||||
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef MORPH3D_H
|
||||
#define MORPH3D_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include "MapClass.h" // dvs: For CMapObjectList
|
||||
#include "Box3D.h"
|
||||
#include "SSolid.h"
|
||||
#include "Resource.h"
|
||||
#include "ScaleVerticesDlg.h"
|
||||
#include "ToolInterface.h"
|
||||
#include "mathlib/vector.h"
|
||||
|
||||
|
||||
class IMesh;
|
||||
class Morph3D;
|
||||
class CRender2D;
|
||||
class CRender3D;
|
||||
|
||||
|
||||
const SSHANDLE SSH_SCALEORIGIN = 0xffff0L;
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
CMapSolid *pMapSolid;
|
||||
CSSolid *pStrucSolid;
|
||||
SSHANDLE ssh;
|
||||
} MORPHHANDLE;
|
||||
|
||||
|
||||
class Morph3D : public Box3D
|
||||
{
|
||||
public:
|
||||
|
||||
Morph3D();
|
||||
virtual ~Morph3D();
|
||||
|
||||
BOOL IsMorphing(CMapSolid *pSolid, CSSolid **pStrucSolidRvl = NULL);
|
||||
|
||||
bool SplitFace();
|
||||
bool CanSplitFace();
|
||||
|
||||
void SelectHandle(MORPHHANDLE *pInfo, UINT cmd = scSelect);
|
||||
void SelectHandle2D( CMapView2D *pView, MORPHHANDLE *pInfo, UINT cmd = scSelect);
|
||||
void DeselectHandle(MORPHHANDLE *pInfo);
|
||||
|
||||
void MoveSelectedHandles(const Vector &Delta);
|
||||
int GetSelectedHandleCount(void) { return m_SelectedHandles.Count(); }
|
||||
void GetSelectedCenter(Vector& pt);
|
||||
SSHANDLETYPE GetSelectedType() { return m_SelectedType; }
|
||||
bool IsSelected(MORPHHANDLE &mh);
|
||||
|
||||
void SelectObject(CMapSolid *pSolid, UINT cmd = scSelect);
|
||||
bool SelectAt( CMapView *pView, UINT nFlags, const Vector2D &vPoint );
|
||||
|
||||
void GetMorphBounds(Vector &mins, Vector &maxs, bool bReset);
|
||||
|
||||
// Toggle mode - vertex & edge, vertex, edge.
|
||||
void ToggleMode();
|
||||
|
||||
void OnScaleCmd(BOOL bReInit = FALSE);
|
||||
void UpdateScale();
|
||||
BOOL IsScaling() { return m_bScaling; }
|
||||
|
||||
void GetMorphingObjects(CUtlVector<CMapClass *> &List);
|
||||
|
||||
inline int GetObjectCount(void);
|
||||
inline CSSolid *GetObject(int pos);
|
||||
|
||||
//
|
||||
// Tool3D implementation.
|
||||
//
|
||||
virtual bool IsEmpty() { return !m_StrucSolids.Count() && !m_bBoxSelecting; }
|
||||
virtual void SetEmpty();
|
||||
virtual void FinishTranslation(bool bSave);
|
||||
virtual unsigned int GetConstraints(unsigned int nKeyFlags);
|
||||
|
||||
//
|
||||
// CBaseTool implementation.
|
||||
//
|
||||
virtual void OnActivate();
|
||||
virtual void OnDeactivate();
|
||||
virtual ToolID_t GetToolID(void) { return TOOL_MORPH; }
|
||||
|
||||
virtual bool CanDeactivate( void );
|
||||
|
||||
virtual bool OnKeyDown2D(CMapView2D *pView, UINT nChar, UINT nRepCnt, UINT nFlags);
|
||||
virtual bool OnChar2D(CMapView2D *pView, UINT nChar, UINT nRepCnt, UINT nFlags);
|
||||
virtual bool OnLMouseDown2D(CMapView2D *pView, UINT nFlags, const Vector2D &vPoint);
|
||||
virtual bool OnLMouseUp2D(CMapView2D *pView, UINT nFlags, const Vector2D &vPoint);
|
||||
virtual bool OnMouseMove2D(CMapView2D *pView, UINT nFlags, const Vector2D &vPoint);
|
||||
|
||||
virtual bool OnLMouseDown3D(CMapView3D *pView, UINT nFlags, const Vector2D &vPoint);
|
||||
virtual bool OnLMouseUp3D(CMapView3D *pView, UINT nFlags, const Vector2D &vPoint);
|
||||
virtual bool OnKeyDown3D(CMapView3D *pView, UINT nChar, UINT nRepCnt, UINT nFlags);
|
||||
virtual bool OnMouseMove3D(CMapView3D *pView, UINT nFlags, const Vector2D &vPoint);
|
||||
|
||||
virtual void RenderTool2D(CRender2D *pRender);
|
||||
virtual void RenderTool3D(CRender3D *pRender);
|
||||
|
||||
private:
|
||||
|
||||
void OnEscape(void);
|
||||
bool NudgeHandles(CMapView *pView, UINT nChar, bool bSnap);
|
||||
|
||||
bool MorphHitTest(CMapView *pView, const Vector2D &vPoint, MORPHHANDLE *pInfo);
|
||||
|
||||
void GetHandlePos(MORPHHANDLE *pInfo, Vector& pt);
|
||||
|
||||
SSHANDLE Get2DMatches(CMapView2D *pView, CSSolid *pStrucSolid, SSHANDLEINFO &hi, CUtlVector<SSHANDLE>*pSimilarList = NULL);
|
||||
|
||||
void StartTranslation(CMapView *pView, const Vector2D &vPoint, MORPHHANDLE *pInfo );
|
||||
|
||||
void RenderSolid3D(CRender3D *pRender, CSSolid *pSolid);
|
||||
|
||||
//
|
||||
// Tool3D implementations.
|
||||
//
|
||||
int HitTest(CMapView *pView, const Vector2D &ptClient, bool bTestHandles = false);
|
||||
|
||||
virtual bool UpdateTranslation( const Vector &pos, UINT uFlags );
|
||||
|
||||
bool StartBoxSelection( CMapView *pView, const Vector2D &vPoint, const Vector &vStart);
|
||||
void SelectInBox();
|
||||
void EndBoxSelection();
|
||||
bool IsBoxSelecting() { return m_bBoxSelecting; }
|
||||
|
||||
bool CanDeselectList( void );
|
||||
|
||||
// list of active Structured Solids:
|
||||
CUtlVector<CSSolid*> m_StrucSolids;
|
||||
|
||||
// list of selected nodes:
|
||||
CUtlVector<MORPHHANDLE> m_SelectedHandles;
|
||||
|
||||
// type of selected handles:
|
||||
SSHANDLETYPE m_SelectedType;
|
||||
|
||||
// main morph handle:
|
||||
MORPHHANDLE m_MorphHandle;
|
||||
Vector m_OrigHandlePos;
|
||||
|
||||
// morph bounds:
|
||||
BoundBox m_MorphBounds;
|
||||
|
||||
// handle mode:
|
||||
enum
|
||||
{
|
||||
hmBoth = 0x01 | 0x02,
|
||||
hmVertex = 0x01,
|
||||
hmEdge = 0x02
|
||||
};
|
||||
|
||||
bool m_bLButtonDownControlState;
|
||||
Vector2D m_vLastMouseMovement;
|
||||
|
||||
bool m_bHit;
|
||||
|
||||
MORPHHANDLE m_DragHandle; // The morph handle that we are dragging.
|
||||
|
||||
bool m_bMorphing;
|
||||
bool m_bMovingSelected; // not moving them yet - might just select this
|
||||
|
||||
int m_HandleMode;
|
||||
bool m_bBoxSelecting;
|
||||
bool m_bScaling;
|
||||
bool m_bUpdateOrg;
|
||||
CScaleVerticesDlg m_ScaleDlg;
|
||||
Vector *m_pOrigPosList;
|
||||
Vector m_ScaleOrg;
|
||||
};
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Returns the number of solids selected for morphing.
|
||||
//-----------------------------------------------------------------------------
|
||||
inline int Morph3D::GetObjectCount(void)
|
||||
{
|
||||
return(m_StrucSolids.Count());
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Iterates the selected solids.
|
||||
//-----------------------------------------------------------------------------
|
||||
inline CSSolid *Morph3D::GetObject(int pos)
|
||||
{
|
||||
return(m_StrucSolids.Element(pos));
|
||||
}
|
||||
|
||||
#endif // MORPH3D_H
|
||||
592
hammer/ToolOverlay.cpp
Normal file
592
hammer/ToolOverlay.cpp
Normal file
@@ -0,0 +1,592 @@
|
||||
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#include <stdafx.h>
|
||||
#include "MapWorld.h"
|
||||
#include "GlobalFunctions.h"
|
||||
#include "MainFrm.h"
|
||||
#include "ToolOverlay.h"
|
||||
#include "MapDoc.h"
|
||||
#include "History.h"
|
||||
#include "CollisionUtils.h"
|
||||
#include "cmodel.h"
|
||||
#include "MapView3D.h"
|
||||
#include "MapView2D.h"
|
||||
#include "MapSolid.h"
|
||||
#include "Camera.h"
|
||||
#include "ObjectProperties.h" // FIXME: For ObjectProperties::RefreshData
|
||||
#include "Selection.h"
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include <tier0/memdbgon.h>
|
||||
|
||||
#define OVERLAY_TOOL_SNAP_DISTANCE 35.0f
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Constructor
|
||||
//-----------------------------------------------------------------------------
|
||||
CToolOverlay::CToolOverlay()
|
||||
{
|
||||
m_bDragging = false;
|
||||
m_pActiveOverlay = NULL;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Destructor
|
||||
//-----------------------------------------------------------------------------
|
||||
CToolOverlay::~CToolOverlay()
|
||||
{
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
void CToolOverlay::OnActivate()
|
||||
{
|
||||
m_bDragging = false;
|
||||
m_pActiveOverlay = NULL;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
void CToolOverlay::OnDeactivate()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Handles key down events in the 2D view.
|
||||
// Input : Per CWnd::OnKeyDown.
|
||||
// Output : Returns true if the message was handled, false if not.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CToolOverlay::OnKeyDown2D(CMapView2D *pView, UINT nChar, UINT nRepCnt, UINT nFlags)
|
||||
{
|
||||
switch (nChar)
|
||||
{
|
||||
|
||||
case VK_ESCAPE:
|
||||
{
|
||||
ToolManager()->SetTool(TOOL_POINTER);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Handles key down events in the 3D view.
|
||||
// Input : Per CWnd::OnKeyDown.
|
||||
// Output : Returns true if the message was handled, false if not.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CToolOverlay::OnKeyDown3D(CMapView3D *pView, UINT nChar, UINT nRepCnt, UINT nFlags)
|
||||
{
|
||||
switch (nChar)
|
||||
{
|
||||
|
||||
case VK_ESCAPE:
|
||||
{
|
||||
ToolManager()->SetTool(TOOL_POINTER);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CToolOverlay::OnLMouseUp3D( CMapView3D *pView, UINT nFlags, const Vector2D &vPoint )
|
||||
{
|
||||
// Post drag events.
|
||||
PostDrag();
|
||||
|
||||
// Update the entity properties dialog.
|
||||
GetMainWnd()->pObjectProperties->MarkDataDirty();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CToolOverlay::OnLMouseDown3D( CMapView3D *pView, UINT nFlags, const Vector2D &vPoint )
|
||||
{
|
||||
// Handle the overlay "handle" selection.
|
||||
if ( HandleSelection( pView, vPoint ) )
|
||||
{
|
||||
PreDrag();
|
||||
return true;
|
||||
}
|
||||
|
||||
// Handle adding and removing overlay entities from the selection list.
|
||||
OverlaySelection( pView, nFlags, vPoint );
|
||||
|
||||
// Handle the overlay creation and placement (if we hit a solid).
|
||||
ULONG ulFace;
|
||||
CMapClass *pObject = NULL;
|
||||
if ( ( pObject = pView->NearestObjectAt( vPoint, ulFace ) ) != NULL )
|
||||
{
|
||||
CMapSolid *pSolid = dynamic_cast<CMapSolid*>( pObject );
|
||||
if ( pSolid )
|
||||
{
|
||||
return CreateOverlay( pSolid, ulFace, pView, vPoint );
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CToolOverlay::OnMouseMove3D( CMapView3D *pView, UINT nFlags, const Vector2D &vPoint )
|
||||
{
|
||||
if ( m_bDragging )
|
||||
{
|
||||
bool bShift = ( ( GetKeyState( VK_SHIFT ) & 0x8000 ) != 0 );
|
||||
|
||||
// Build the ray and drag the overlay handle to the impact point.
|
||||
const CCamera *pCamera = pView->GetCamera();
|
||||
if ( pCamera )
|
||||
{
|
||||
Vector vecStart, vecEnd;
|
||||
pView->BuildRay( vPoint, vecStart, vecEnd );
|
||||
OnDrag( vecStart, vecEnd, bShift );
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CToolOverlay::CreateOverlay( CMapSolid *pSolid, ULONG iFace, CMapView3D *pView, Vector2D point )
|
||||
{
|
||||
// Build a ray to trace against the face that they clicked on to
|
||||
// find the point of intersection.
|
||||
Vector vecStart, vecEnd;
|
||||
pView->BuildRay( point, vecStart, vecEnd );
|
||||
|
||||
Vector vecHitPos, vecHitNormal;
|
||||
CMapFace *pFace = pSolid->GetFace( iFace );
|
||||
if( pFace->TraceLine( vecHitPos, vecHitNormal, vecStart, vecEnd ) )
|
||||
{
|
||||
// Create and initialize the "entity" --> "overlay."
|
||||
CMapEntity *pEntity = new CMapEntity;
|
||||
pEntity->SetKeyValue( "material", GetDefaultTextureName() );
|
||||
pEntity->SetPlaceholder( TRUE );
|
||||
pEntity->SetOrigin( vecHitPos );
|
||||
pEntity->SetClass( "info_overlay" );
|
||||
|
||||
// Add the entity to the world.
|
||||
m_pDocument->AddObjectToWorld( pEntity );
|
||||
|
||||
// Setup "history."
|
||||
GetHistory()->MarkUndoPosition( NULL, "Create Overlay" );
|
||||
GetHistory()->KeepNew( pEntity );
|
||||
|
||||
// Initialize the overlay.
|
||||
InitOverlay( pEntity, pFace );
|
||||
|
||||
pEntity->CalcBounds( TRUE );
|
||||
|
||||
// Add to selection list.
|
||||
m_pDocument->SelectObject( pEntity, scSelect );
|
||||
m_bEmpty = false;
|
||||
|
||||
// Set modified and update views.
|
||||
m_pDocument->SetModifiedFlag();
|
||||
|
||||
m_pShoreline = NULL;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CToolOverlay::InitOverlay( CMapEntity *pEntity, CMapFace *pFace )
|
||||
{
|
||||
// Valid face?
|
||||
if ( !pFace )
|
||||
return;
|
||||
|
||||
const CMapObjectList *pChildren = pEntity->GetChildren();
|
||||
|
||||
FOR_EACH_OBJ( *pChildren, pos )
|
||||
{
|
||||
CMapClass *pMapClassObj = (CUtlReference< CMapClass >)pChildren->Element(pos);
|
||||
CMapOverlay *pOverlay = dynamic_cast<CMapOverlay*>( pMapClassObj );
|
||||
if ( pOverlay )
|
||||
{
|
||||
pOverlay->Basis_Init( pFace );
|
||||
pOverlay->Handles_Init( pFace );
|
||||
pOverlay->SideList_Init( pFace );
|
||||
pOverlay->SetOverlayType( OVERLAY_TYPE_GENERIC );
|
||||
pOverlay->SetLoaded( true );
|
||||
pOverlay->CalcBounds( true );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
void CToolOverlay::OverlaySelection( CMapView3D *pView, UINT nFlags, const Vector2D &vPoint )
|
||||
{
|
||||
CMapObjectList aSelectionList;
|
||||
m_pDocument->GetSelection()->ClearHitList();
|
||||
|
||||
// Find out how many (and what) map objects are under the point clicked on.
|
||||
HitInfo_t Objects[MAX_PICK_HITS];
|
||||
int nHits = pView->ObjectsAt( vPoint, Objects, sizeof( Objects ) / sizeof( Objects[0] ) );
|
||||
if ( nHits != 0 )
|
||||
{
|
||||
// We now have an array of pointers to CMapAtoms. Any that can be upcast to CMapClass objects?
|
||||
for ( int iHit = 0; iHit < nHits; ++iHit )
|
||||
{
|
||||
CMapClass *pMapClass = dynamic_cast<CMapClass*>( Objects[iHit].pObject );
|
||||
if ( pMapClass )
|
||||
{
|
||||
aSelectionList.AddToTail( pMapClass );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Did we hit anything?
|
||||
if ( !aSelectionList.Count() )
|
||||
{
|
||||
m_pDocument->SelectFace( NULL, 0, scClear );
|
||||
m_pDocument->SelectObject( NULL, scClear|scSaveChanges );
|
||||
SetEmpty();
|
||||
return;
|
||||
}
|
||||
|
||||
// Find overlays.
|
||||
bool bUpdateViews = false;
|
||||
|
||||
SelectMode_t eSelectMode = m_pDocument->GetSelection()->GetMode();
|
||||
|
||||
FOR_EACH_OBJ( aSelectionList, pos )
|
||||
{
|
||||
CMapClass *pObject = aSelectionList.Element( pos );
|
||||
CMapClass *pHitObject = pObject->PrepareSelection( eSelectMode );
|
||||
if ( pHitObject )
|
||||
{
|
||||
if ( pHitObject->IsMapClass( MAPCLASS_TYPE( CMapEntity ) ) )
|
||||
{
|
||||
const CMapObjectList *pChildren = pHitObject->GetChildren();
|
||||
FOR_EACH_OBJ( *pChildren, pos2 )
|
||||
{
|
||||
CMapClass *pMapClassObj = (CUtlReference< CMapClass >)pChildren->Element(pos2);
|
||||
CMapOverlay *pOverlay = dynamic_cast<CMapOverlay*>( pMapClassObj );
|
||||
if ( pOverlay )
|
||||
{
|
||||
m_pDocument->GetSelection()->AddHit( pHitObject );
|
||||
m_bEmpty = false;
|
||||
|
||||
UINT cmd = scClear | scSelect | scSaveChanges;
|
||||
if (nFlags & MK_CONTROL)
|
||||
{
|
||||
cmd = scToggle;
|
||||
}
|
||||
m_pDocument->SelectObject( pHitObject, cmd );
|
||||
bUpdateViews = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Update the views.
|
||||
if ( bUpdateViews )
|
||||
{
|
||||
m_pDocument->UpdateAllViews( MAPVIEW_UPDATE_OBJECTS );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CToolOverlay::OnContextMenu2D( CMapView2D *pView, UINT nFlags, const Vector2D &vPoint )
|
||||
{
|
||||
static CMenu menu, menuOverlay;
|
||||
static bool bInit = false;
|
||||
|
||||
if ( !bInit )
|
||||
{
|
||||
// Create the menu.
|
||||
menu.LoadMenu( IDR_POPUPS );
|
||||
menuOverlay.Attach( ::GetSubMenu( menu.m_hMenu, 6 ) );
|
||||
bInit = true;
|
||||
}
|
||||
|
||||
if ( !pView->PointInClientRect(vPoint) )
|
||||
return false;
|
||||
|
||||
if (!IsEmpty())
|
||||
{
|
||||
if ( HitTest( pView, vPoint, false ) )
|
||||
{
|
||||
CPoint ptScreen( vPoint.x,vPoint.y);
|
||||
pView->ClientToScreen(&ptScreen);
|
||||
menuOverlay.TrackPopupMenu( TPM_LEFTBUTTON | TPM_RIGHTBUTTON | TPM_LEFTALIGN, ptScreen.x, ptScreen.y, pView );
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CToolOverlay::UpdateTranslation( const Vector &vUpdate, UINT nFlags)
|
||||
{
|
||||
// if( m_bBoxSelecting )
|
||||
// return Box3D::UpdateTranslation( pt, nFlags );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
void CToolOverlay::HandlesReset( void )
|
||||
{
|
||||
// Go through selection list and reset overlay handles.
|
||||
const CMapObjectList *pSelection = m_pDocument->GetSelection()->GetList();
|
||||
for( int iSelection = 0; iSelection < pSelection->Count(); ++iSelection )
|
||||
{
|
||||
CMapClass *pMapClass = (CUtlReference< CMapClass >)pSelection->Element( iSelection );
|
||||
if ( pMapClass && pMapClass->IsMapClass( MAPCLASS_TYPE( CMapEntity ) ) )
|
||||
{
|
||||
const CMapObjectList *pChildren = pMapClass->GetChildren();
|
||||
FOR_EACH_OBJ( *pChildren, pos )
|
||||
{
|
||||
CMapClass *pMapClassCast = (CUtlReference< CMapClass >)pChildren->Element( pos );
|
||||
CMapOverlay *pOverlay = dynamic_cast<CMapOverlay*>( pMapClassCast );
|
||||
if ( pOverlay )
|
||||
{
|
||||
pOverlay->HandlesReset();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CToolOverlay::HandleSelection( CMapView *pView, const Vector2D &vPoint )
|
||||
{
|
||||
// Reset the hit overlay.
|
||||
m_pActiveOverlay = NULL;
|
||||
|
||||
// Go through selection list and test all overlay's handles and set the
|
||||
// "hit" overlay current.
|
||||
const CMapObjectList *pSelection = m_pDocument->GetSelection()->GetList();
|
||||
for ( int iSelection = 0; iSelection < pSelection->Count(); ++iSelection )
|
||||
{
|
||||
CMapClass *pMapClass = (CUtlReference< CMapClass >)pSelection->Element( iSelection );
|
||||
if ( pMapClass && pMapClass->IsMapClass( MAPCLASS_TYPE( CMapEntity ) ) )
|
||||
{
|
||||
const CMapObjectList *pChildren = pMapClass->GetChildren();
|
||||
FOR_EACH_OBJ( *pChildren, pos )
|
||||
{
|
||||
CMapClass *pMapClassCast = (CUtlReference< CMapClass >)pChildren->Element(pos);
|
||||
CMapOverlay *pOverlay = dynamic_cast<CMapOverlay*>( pMapClassCast );
|
||||
if ( pOverlay && pOverlay->IsSelected() )
|
||||
{
|
||||
if ( pOverlay->HandlesHitTest( pView, vPoint ) )
|
||||
{
|
||||
m_pActiveOverlay = pOverlay;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( !m_pActiveOverlay )
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CToolOverlay::HandleSnap( CMapOverlay *pOverlay, Vector &vecHandlePt )
|
||||
{
|
||||
Vector vecTmp;
|
||||
for ( int i = 0; i < OVERLAY_HANDLES_COUNT; i++ )
|
||||
{
|
||||
pOverlay->GetHandlePos( i, vecTmp );
|
||||
vecTmp -= vecHandlePt;
|
||||
float flDist = vecTmp.Length();
|
||||
|
||||
if ( flDist < OVERLAY_TOOL_SNAP_DISTANCE )
|
||||
{
|
||||
// Snap!
|
||||
pOverlay->GetHandlePos( i, vecHandlePt );
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CToolOverlay::HandleInBBox( CMapOverlay *pOverlay, Vector const &vecHandlePt )
|
||||
{
|
||||
Vector vecMin, vecMax;
|
||||
pOverlay->GetCullBox( vecMin, vecMax );
|
||||
|
||||
for ( int iAxis = 0; iAxis < 3; iAxis++ )
|
||||
{
|
||||
vecMin[iAxis] -= OVERLAY_TOOL_SNAP_DISTANCE;
|
||||
vecMax[iAxis] += OVERLAY_TOOL_SNAP_DISTANCE;
|
||||
|
||||
if( ( vecHandlePt[iAxis] < vecMin[iAxis] ) || ( vecHandlePt[iAxis] > vecMax[iAxis] ) )
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
void CToolOverlay::SnapHandle( Vector &vecHandlePt )
|
||||
{
|
||||
CMapWorld *pWorld = GetActiveWorld();
|
||||
if ( !pWorld )
|
||||
return;
|
||||
|
||||
EnumChildrenPos_t pos;
|
||||
CMapClass *pChild = pWorld->GetFirstDescendent( pos );
|
||||
while ( pChild )
|
||||
{
|
||||
CMapEntity *pEntity = dynamic_cast<CMapEntity*>( pChild );
|
||||
if ( pEntity )
|
||||
{
|
||||
const CMapObjectList *pChildren = pEntity->GetChildren();
|
||||
FOR_EACH_OBJ( *pChildren, pos )
|
||||
{
|
||||
CMapClass *pMapClassCast = (CUtlReference< CMapClass >)pChildren->Element(pos);
|
||||
CMapOverlay *pOverlay = dynamic_cast<CMapOverlay*>( pMapClassCast );
|
||||
if ( pOverlay && pOverlay != m_pActiveOverlay && pOverlay->IsSelected() )
|
||||
{
|
||||
// Intersection test and attempt to snap
|
||||
if ( HandleInBBox( pOverlay, vecHandlePt ) )
|
||||
{
|
||||
if ( HandleSnap( pOverlay, vecHandlePt ) )
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pChild = pWorld->GetNextDescendent( pos );
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
void CToolOverlay::OnDrag( Vector const &vecRayStart, Vector const &vecRayEnd, bool bShift )
|
||||
{
|
||||
// Get the current overlay.
|
||||
CMapOverlay *pOverlay = m_pActiveOverlay;
|
||||
if ( !pOverlay )
|
||||
return;
|
||||
|
||||
// Get a list of faces and test for "impact."
|
||||
Vector vecImpact( 0.0f, 0.0f, 0.0f );
|
||||
Vector vecImpactNormal( 0.0f, 0.0f, 0.0f );
|
||||
CMapFace *pFace = NULL;
|
||||
|
||||
int nFaceCount = pOverlay->GetFaceCount();
|
||||
int iFace;
|
||||
for ( iFace = 0; iFace < nFaceCount; iFace++ )
|
||||
{
|
||||
pFace = pOverlay->GetFace( iFace );
|
||||
if ( pFace )
|
||||
{
|
||||
if ( pFace->TraceLineInside( vecImpact, vecImpactNormal, vecRayStart, vecRayEnd ) )
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Test for impact (face index = count mean no impact).
|
||||
if ( iFace == nFaceCount )
|
||||
return;
|
||||
|
||||
if ( bShift )
|
||||
{
|
||||
SnapHandle( vecImpact );
|
||||
}
|
||||
|
||||
// Pass the new handle position to the overlay.
|
||||
pOverlay->HandlesDragTo( vecImpact, pFace );
|
||||
|
||||
m_pDocument->UpdateAllViews( MAPVIEW_UPDATE_ONLY_3D );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
void CToolOverlay::PreDrag( void )
|
||||
{
|
||||
m_bDragging = true;
|
||||
SetupHandleDragUndo();
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Renders the cordon tool in the 3D view.
|
||||
//-----------------------------------------------------------------------------
|
||||
void CToolOverlay::RenderTool3D(CRender3D *pRender)
|
||||
{
|
||||
// TODO render tool handles here and not in overlay rendering code
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
void CToolOverlay::PostDrag( void )
|
||||
{
|
||||
if ( !m_bDragging )
|
||||
return;
|
||||
|
||||
m_bDragging = false;
|
||||
|
||||
// Get the current overlay.
|
||||
CMapOverlay *pOverlay = m_pActiveOverlay;
|
||||
if ( pOverlay )
|
||||
{
|
||||
pOverlay->DoClip();
|
||||
pOverlay->CenterEntity();
|
||||
pOverlay->PostUpdate( Notify_Changed );
|
||||
m_pDocument->UpdateAllViews( MAPVIEW_UPDATE_OBJECTS );
|
||||
}
|
||||
|
||||
// Reset the overlay handles.
|
||||
HandlesReset();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
void CToolOverlay::SetupHandleDragUndo( void )
|
||||
{
|
||||
// Get the current overlay.
|
||||
CMapOverlay *pOverlay = m_pActiveOverlay;
|
||||
if ( pOverlay )
|
||||
{
|
||||
CMapEntity *pEntity = ( CMapEntity* )pOverlay->GetParent();
|
||||
if ( pEntity )
|
||||
{
|
||||
// Setup for drag undo.
|
||||
GetHistory()->MarkUndoPosition( m_pDocument->GetSelection()->GetList(), "Drag Overlay Handle" );
|
||||
GetHistory()->Keep( ( CMapClass* )pEntity );
|
||||
}
|
||||
}
|
||||
}
|
||||
79
hammer/ToolOverlay.h
Normal file
79
hammer/ToolOverlay.h
Normal file
@@ -0,0 +1,79 @@
|
||||
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef OVERLAY3D_H
|
||||
#define OVERLAY3D_H
|
||||
#pragma once
|
||||
|
||||
#include <afxwin.h>
|
||||
#include "Box3D.h"
|
||||
#include "ToolInterface.h"
|
||||
#include "MapOverlay.h"
|
||||
#include "ToolManager.h"
|
||||
|
||||
class CMapDoc;
|
||||
struct Shoreline_t;
|
||||
|
||||
class CToolOverlay : public Box3D
|
||||
{
|
||||
public:
|
||||
|
||||
//=========================================================================
|
||||
//
|
||||
// Constructur/Destructor
|
||||
//
|
||||
CToolOverlay();
|
||||
~CToolOverlay();
|
||||
|
||||
//=========================================================================
|
||||
//
|
||||
// CBaseTool virtual implementations
|
||||
//
|
||||
ToolID_t GetToolID( void ) { return TOOL_OVERLAY; }
|
||||
|
||||
void OnActivate();
|
||||
void OnDeactivate();
|
||||
|
||||
virtual bool OnKeyDown2D(CMapView2D *pView, UINT nChar, UINT nRepCnt, UINT nFlags);
|
||||
virtual bool OnKeyDown3D(CMapView3D *pView, UINT nChar, UINT nRepCnt, UINT nFlags);
|
||||
bool OnLMouseUp3D( CMapView3D *pView, UINT nFlags, const Vector2D &vPoint );
|
||||
bool OnLMouseDown3D( CMapView3D *pView, UINT nFlags, const Vector2D &vPoint );
|
||||
bool OnMouseMove3D( CMapView3D *pView, UINT nFlags, const Vector2D &vPoint );
|
||||
bool OnContextMenu2D( CMapView2D *pView, UINT nFlags, const Vector2D &vPoint );
|
||||
|
||||
void RenderTool3D(CRender3D *pRender);
|
||||
|
||||
protected:
|
||||
|
||||
bool UpdateTranslation( const Vector &vUpdate, UINT = 0 );
|
||||
|
||||
private:
|
||||
|
||||
bool HandleSelection( CMapView *pView, const Vector2D &vPoint );
|
||||
void OverlaySelection( CMapView3D *pView, UINT nFlags, const Vector2D &vPoint );
|
||||
|
||||
bool CreateOverlay( CMapSolid *pSolid, ULONG iFace, CMapView3D *pView, Vector2D point );
|
||||
void InitOverlay( CMapEntity *pEntity, CMapFace *pFace );
|
||||
|
||||
void OnDrag( Vector const &vecRayStart, Vector const &vecRayEnd, bool bShift );
|
||||
void PreDrag( void );
|
||||
void PostDrag( void );
|
||||
void SetupHandleDragUndo( void );
|
||||
|
||||
void HandlesReset( void );
|
||||
void SnapHandle( Vector &vecHandlePt );
|
||||
bool HandleInBBox( CMapOverlay *pOverlay, Vector const &vecHandlePt );
|
||||
bool HandleSnap( CMapOverlay *pOverlay, Vector &vecHandlePt );
|
||||
|
||||
private:
|
||||
|
||||
bool m_bDragging; // Are we dragging overlay handles?
|
||||
Shoreline_t *m_pShoreline; //
|
||||
CMapOverlay *m_pActiveOverlay; // The overlay currently being acted upon
|
||||
};
|
||||
|
||||
#endif // OVERLAY3D_H
|
||||
174
hammer/ToolPickAngles.cpp
Normal file
174
hammer/ToolPickAngles.cpp
Normal file
@@ -0,0 +1,174 @@
|
||||
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: Tool used for point-and-click setting of angles.
|
||||
//
|
||||
//=============================================================================//
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "resource.h"
|
||||
#include "ToolPickAngles.h"
|
||||
#include "MapView3D.h"
|
||||
#include "MapSolid.h"
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include <tier0/memdbgon.h>
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Constructor. Inits data members.
|
||||
//-----------------------------------------------------------------------------
|
||||
CToolPickAngles::CToolPickAngles(void)
|
||||
{
|
||||
m_pNotifyTarget = NULL;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Destructor.
|
||||
//-----------------------------------------------------------------------------
|
||||
CToolPickAngles::~CToolPickAngles(void)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Handles the left mouse button up message in the 3D view.
|
||||
// Input : pView - The view that the event occurred in.
|
||||
// nFlags - Flags per the Windows mouse message.
|
||||
// point - Point in client coordinates where the event occurred.
|
||||
// Output : Returns true if the message was handled by the tool, false if not.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CToolPickAngles::OnLMouseUp3D(CMapView3D *pView, UINT nFlags, const Vector2D &vPoint)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Handles the left mouse button up message in the 3D view.
|
||||
// Input : pView - The view that the event occurred in.
|
||||
// nFlags - Flags per the Windows mouse message.
|
||||
// point - Point in client coordinates where the event occurred.
|
||||
// Output : Returns true if the message was handled by the tool, false if not.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CToolPickAngles::OnLMouseDown3D(CMapView3D *pView, UINT nFlags, const Vector2D &vPoint)
|
||||
{
|
||||
unsigned long ulFace;
|
||||
CMapClass *pObject = pView->NearestObjectAt( vPoint, ulFace);
|
||||
if (pObject != NULL)
|
||||
{
|
||||
CMapClass *pSelObject = pObject->PrepareSelection(selectObjects);
|
||||
CMapEntity *pEntity = dynamic_cast <CMapEntity *>(pSelObject);
|
||||
if (pEntity != NULL)
|
||||
{
|
||||
//
|
||||
// We clicked on an entity.
|
||||
//
|
||||
if (m_pNotifyTarget)
|
||||
{
|
||||
Vector vecCenter;
|
||||
pEntity->GetBoundsCenter(vecCenter);
|
||||
m_pNotifyTarget->OnNotifyPickAngles(vecCenter);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
CMapSolid *pSolid = dynamic_cast <CMapSolid *> (pObject);
|
||||
if (pSolid == NULL)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
//
|
||||
// Build a ray to trace against the face that they clicked on to
|
||||
// find the point of intersection.
|
||||
//
|
||||
Vector Start,End;
|
||||
pView->GetCamera()->BuildRay( vPoint, Start, End);
|
||||
|
||||
Vector HitPos;
|
||||
Vector HitNormal;
|
||||
CMapFace *pFace = pSolid->GetFace(ulFace);
|
||||
if (pFace->TraceLine(HitPos, HitNormal, Start, End))
|
||||
{
|
||||
if (m_pNotifyTarget)
|
||||
{
|
||||
m_pNotifyTarget->OnNotifyPickAngles(HitPos);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Handles the left mouse button double click message in the 3D view.
|
||||
// Input : pView - The view that the event occurred in.
|
||||
// nFlags - Flags per the Windows mouse message.
|
||||
// point - Point in client coordinates where the event occurred.
|
||||
// Output : Returns true if the message was handled by the tool, false if not.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CToolPickAngles::OnLMouseDblClk3D(CMapView3D *pView, UINT nFlags, const Vector2D &vPoint)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Handles the right mouse button up message in the 3D view.
|
||||
// Input : pView - The view that the event occurred in.
|
||||
// nFlags - Flags per the Windows mouse message.
|
||||
// point - Point in client coordinates where the event occurred.
|
||||
// Output : Returns true if the message was handled by the tool, false if not.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CToolPickAngles::OnRMouseUp3D(CMapView3D *pView, UINT nFlags, const Vector2D &vPoint)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Handles the mouse button up message in the 3D view.
|
||||
// Input : pView - The view that the event occurred in.
|
||||
// nFlags - Flags per the Windows mouse message.
|
||||
// point - Point in client coordinates where the event occurred.
|
||||
// Output : Returns true if the message was handled by the tool, false if not.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CToolPickAngles::OnRMouseDown3D(CMapView3D *pView, UINT nFlags, const Vector2D &vPoint)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Handles the mouse move message in the 3D view.
|
||||
// Input : pView - The view that the event occurred in.
|
||||
// nFlags - Flags per the Windows mouse message.
|
||||
// point - Point in client coordinates where the event occurred.
|
||||
// Output : Returns true if the message was handled by the tool, false if not.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CToolPickAngles::OnMouseMove3D(CMapView3D *pView, UINT nFlags, const Vector2D &vPoint)
|
||||
{
|
||||
SetToolCursor();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Sets the cursor to the correct cursor for this tool.
|
||||
//-----------------------------------------------------------------------------
|
||||
void CToolPickAngles::SetToolCursor(void)
|
||||
{
|
||||
static HCURSOR hcur = NULL;
|
||||
|
||||
if (!hcur)
|
||||
{
|
||||
hcur = LoadCursor(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDC_CROSSHAIR));
|
||||
}
|
||||
|
||||
SetCursor(hcur);
|
||||
}
|
||||
|
||||
|
||||
77
hammer/ToolPickAngles.h
Normal file
77
hammer/ToolPickAngles.h
Normal file
@@ -0,0 +1,77 @@
|
||||
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: Tool used for point-and-click picking of angles for filling out
|
||||
// entity properties.
|
||||
//
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef TOOLPICKANGLES_H
|
||||
#define TOOLPICKANGLES_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include "MapEntity.h"
|
||||
#include "ToolInterface.h"
|
||||
|
||||
|
||||
class CMapView3D;
|
||||
class CToolPickAngles;
|
||||
|
||||
|
||||
//
|
||||
// Interface for notification by the angles picking tool. Inherit from this if you
|
||||
// are a client of the angles picker.
|
||||
//
|
||||
class IPickAnglesTarget
|
||||
{
|
||||
public:
|
||||
virtual void OnNotifyPickAngles(const Vector &vecPos) = 0;
|
||||
};
|
||||
|
||||
|
||||
class CToolPickAngles : public CBaseTool
|
||||
{
|
||||
public:
|
||||
|
||||
//
|
||||
// Constructor/Destructor
|
||||
//
|
||||
CToolPickAngles();
|
||||
~CToolPickAngles();
|
||||
|
||||
//
|
||||
// CBaseTool virtual implementations
|
||||
//
|
||||
virtual ToolID_t GetToolID(void) { return TOOL_PICK_ANGLES; }
|
||||
|
||||
virtual bool OnLMouseUp3D(CMapView3D *pView, UINT nFlags, const Vector2D &vPoint);
|
||||
virtual bool OnLMouseDown3D(CMapView3D *pView, UINT nFlags, const Vector2D &vPoint);
|
||||
virtual bool OnLMouseDblClk3D(CMapView3D *pView, UINT nFlags, const Vector2D &vPoint);
|
||||
virtual bool OnRMouseUp3D(CMapView3D *pView, UINT nFlags, const Vector2D &vPoint);
|
||||
virtual bool OnRMouseDown3D(CMapView3D *pView, UINT nFlags, const Vector2D &vPoint);
|
||||
virtual bool OnMouseMove3D(CMapView3D *pView, UINT nFlags, const Vector2D &vPoint);
|
||||
|
||||
//
|
||||
// Functions specific to this tool.
|
||||
//
|
||||
inline void Attach(IPickAnglesTarget *pTarget);
|
||||
|
||||
protected:
|
||||
|
||||
void SetToolCursor(void);
|
||||
|
||||
IPickAnglesTarget *m_pNotifyTarget; // Object to notify when selection events occur.
|
||||
};
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Attaches the given notification target to this tool. That object
|
||||
// will be used for all future notifications and updates by the tool.
|
||||
//-----------------------------------------------------------------------------
|
||||
void CToolPickAngles::Attach(IPickAnglesTarget *pNotifyTarget)
|
||||
{
|
||||
m_pNotifyTarget = pNotifyTarget;
|
||||
}
|
||||
|
||||
#endif // TOOLPICKANGLES_H
|
||||
470
hammer/ToolPickEntity.cpp
Normal file
470
hammer/ToolPickEntity.cpp
Normal file
@@ -0,0 +1,470 @@
|
||||
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: Tool used for picking entities. This is used anywhere a field that
|
||||
// contains an entity name is found.
|
||||
//
|
||||
// Left click - single select entity
|
||||
// +Ctrl - multiselect a single entity
|
||||
//
|
||||
//=============================================================================//
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "resource.h"
|
||||
#include "ToolPickEntity.h"
|
||||
#include "MapViewLogical.h"
|
||||
#include "MapView3D.h"
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include <tier0/memdbgon.h>
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Constructor. Inits data members.
|
||||
//-----------------------------------------------------------------------------
|
||||
CToolPickEntity::CToolPickEntity(void)
|
||||
{
|
||||
m_pNotifyTarget = NULL;
|
||||
m_bAllowMultiSelect = false;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Destructor.
|
||||
//-----------------------------------------------------------------------------
|
||||
CToolPickEntity::~CToolPickEntity(void)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Enables or disables multiselect for this tool.
|
||||
//-----------------------------------------------------------------------------
|
||||
void CToolPickEntity::AllowMultiSelect(bool bAllow)
|
||||
{
|
||||
m_bAllowMultiSelect = bAllow;
|
||||
|
||||
//
|
||||
// Shouldn't ever happen, but you never know.
|
||||
//
|
||||
if ((!bAllow) && (m_Entities.Count() > 1))
|
||||
{
|
||||
CMapEntity *pEntity = m_Entities[0].pEntity;
|
||||
DeselectAll();
|
||||
SelectEntity(pEntity);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Called when the tool is deactivated.
|
||||
// Input : eNewTool - The ID of the tool that is being activated.
|
||||
//-----------------------------------------------------------------------------
|
||||
void CToolPickEntity::OnDeactivate()
|
||||
{
|
||||
DeselectAll();
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Handles the left mouse button up message in the 3D view.
|
||||
// Input : pView - The view that the event occurred in.
|
||||
// nFlags - Flags per the Windows mouse message.
|
||||
// point - Point in client coordinates where the event occurred.
|
||||
// Output : Returns true if the message was handled by the tool, false if not.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CToolPickEntity::OnLMouseUp3D(CMapView3D *pView, UINT nFlags, const Vector2D &vPoint)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Handles the left mouse button up message in the 3D view.
|
||||
// Input : pView - The view that the event occurred in.
|
||||
// nFlags - Flags per the Windows mouse message.
|
||||
// point - Point in client coordinates where the event occurred.
|
||||
// Output : Returns true if the message was handled by the tool, false if not.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CToolPickEntity::OnLMouseDown3D(CMapView3D *pView, UINT nFlags, const Vector2D &vPoint)
|
||||
{
|
||||
bool bControl = ((nFlags & MK_CONTROL) != 0);
|
||||
|
||||
unsigned long uEntity;
|
||||
CMapClass *pObject = pView->NearestObjectAt( vPoint, uEntity);
|
||||
if (pObject != NULL)
|
||||
{
|
||||
CMapClass *pSelObject = pObject->PrepareSelection(selectObjects);
|
||||
CMapEntity *pEntity = dynamic_cast <CMapEntity *>(pSelObject);
|
||||
if (pEntity != NULL)
|
||||
{
|
||||
//
|
||||
// We clicked on an entity.
|
||||
//
|
||||
if ((!m_bAllowMultiSelect) || (!bControl))
|
||||
{
|
||||
// Single select.
|
||||
DeselectAll();
|
||||
SelectEntity(pEntity);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Multiselect.
|
||||
CycleSelectEntity(pEntity);
|
||||
}
|
||||
|
||||
if (m_pNotifyTarget)
|
||||
{
|
||||
m_pNotifyTarget->OnNotifyPickEntity(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Handles the left mouse button up message in the 3D view.
|
||||
// Input : pView - The view that the event occurred in.
|
||||
// nFlags - Flags per the Windows mouse message.
|
||||
// point - Point in client coordinates where the event occurred.
|
||||
// Output : Returns true if the message was handled by the tool, false if not.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CToolPickEntity::OnLMouseDownLogical(CMapViewLogical *pView, UINT nFlags, const Vector2D &vPoint)
|
||||
{
|
||||
bool bControl = ((nFlags & MK_CONTROL) != 0);
|
||||
|
||||
HitInfo_t hitData;
|
||||
int nHits = pView->ObjectsAt( vPoint, &hitData, 1 );
|
||||
if ( ( nHits > 0 ) && hitData.pObject )
|
||||
{
|
||||
CMapClass *pSelObject = hitData.pObject->PrepareSelection( selectObjects );
|
||||
CMapEntity *pEntity = dynamic_cast <CMapEntity *>( pSelObject );
|
||||
if (pEntity != NULL)
|
||||
{
|
||||
//
|
||||
// We clicked on an entity.
|
||||
//
|
||||
if ((!m_bAllowMultiSelect) || (!bControl))
|
||||
{
|
||||
// Single select.
|
||||
DeselectAll();
|
||||
SelectEntity(pEntity);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Multiselect.
|
||||
CycleSelectEntity(pEntity);
|
||||
}
|
||||
|
||||
if (m_pNotifyTarget)
|
||||
{
|
||||
m_pNotifyTarget->OnNotifyPickEntity(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Handles the left mouse button double click message in the 3D view.
|
||||
// Input : pView - The view that the event occurred in.
|
||||
// nFlags - Flags per the Windows mouse message.
|
||||
// point - Point in client coordinates where the event occurred.
|
||||
// Output : Returns true if the message was handled by the tool, false if not.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CToolPickEntity::OnLMouseDblClk3D(CMapView3D *pView, UINT nFlags, const Vector2D &vPoint)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Handles the right mouse button up message in the 3D view.
|
||||
// Input : pView - The view that the event occurred in.
|
||||
// nFlags - Flags per the Windows mouse message.
|
||||
// point - Point in client coordinates where the event occurred.
|
||||
// Output : Returns true if the message was handled by the tool, false if not.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CToolPickEntity::OnRMouseUp3D(CMapView3D *pView, UINT nFlags, const Vector2D &vPoint)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Handles the mouse button up message in the 3D view.
|
||||
// Input : pView - The view that the event occurred in.
|
||||
// nFlags - Flags per the Windows mouse message.
|
||||
// point - Point in client coordinates where the event occurred.
|
||||
// Output : Returns true if the message was handled by the tool, false if not.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CToolPickEntity::OnRMouseDown3D(CMapView3D *pView, UINT nFlags, const Vector2D &vPoint)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Handles the mouse move message in the 3D view.
|
||||
// Input : pView - The view that the event occurred in.
|
||||
// nFlags - Flags per the Windows mouse message.
|
||||
// point - Point in client coordinates where the event occurred.
|
||||
// Output : Returns true if the message was handled by the tool, false if not.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CToolPickEntity::OnMouseMove3D(CMapView3D *pView, UINT nFlags, const Vector2D &vPoint)
|
||||
{
|
||||
SetEyedropperCursor();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool CToolPickEntity::OnMouseMoveLogical(CMapViewLogical *pView, UINT nFlags, const Vector2D &vPoint)
|
||||
{
|
||||
SetEyedropperCursor();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Sets the cursor to the eyedropper cursor.
|
||||
//-----------------------------------------------------------------------------
|
||||
void CToolPickEntity::SetEyedropperCursor(void)
|
||||
{
|
||||
static HCURSOR hcurEyedropper = NULL;
|
||||
|
||||
if (!hcurEyedropper)
|
||||
{
|
||||
hcurEyedropper = LoadCursor(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDC_EYEDROPPER));
|
||||
}
|
||||
|
||||
SetCursor(hcurEyedropper);
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : pEntity -
|
||||
//-----------------------------------------------------------------------------
|
||||
void CToolPickEntity::CycleSelectEntity(CMapEntity *pEntity)
|
||||
{
|
||||
int nIndex = FindEntity(pEntity);
|
||||
if (nIndex != -1)
|
||||
{
|
||||
//
|
||||
// The entity is in our list, update its selection state.
|
||||
//
|
||||
if (m_Entities[nIndex].eState == EntityState_Partial)
|
||||
{
|
||||
DeselectEntity(nIndex);
|
||||
}
|
||||
else if (m_Entities[nIndex].eState == EntityState_Select)
|
||||
{
|
||||
if (m_Entities[nIndex].eOriginalState == EntityState_Partial)
|
||||
{
|
||||
m_Entities[nIndex].eState = EntityState_Partial;
|
||||
//pEntity->SetSelectionState(SELECT_MULTI_PARTIAL);
|
||||
}
|
||||
else
|
||||
{
|
||||
DeselectEntity(nIndex);
|
||||
}
|
||||
}
|
||||
else if (m_Entities[nIndex].eState == EntityState_None)
|
||||
{
|
||||
m_Entities[nIndex].eState = EntityState_Select;
|
||||
//pEntity->SetSelectionState(SELECT_NORMAL);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//
|
||||
// The entity is not in our list, add it.
|
||||
//
|
||||
AddToList(pEntity, EntityState_Select);
|
||||
//pEntity->SetSelectionState(SELECT_NORMAL);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Sets the fully selected and partially selected entities for the picker.
|
||||
// Input : EntityListFull -
|
||||
// EntityListPartial -
|
||||
//-----------------------------------------------------------------------------
|
||||
void CToolPickEntity::SetSelectedEntities(CMapEntityList &EntityListFull, CMapEntityList &EntityListPartial)
|
||||
{
|
||||
m_Entities.RemoveAll();
|
||||
|
||||
for (int i = 0; i < EntityListFull.Count(); i++)
|
||||
{
|
||||
CMapEntity *pEntity = EntityListFull.Element(i);
|
||||
|
||||
AddToList(pEntity, EntityState_Select);
|
||||
pEntity->SetSelectionState(SELECT_NORMAL);
|
||||
}
|
||||
|
||||
for (int i = 0; i < EntityListPartial.Count(); i++)
|
||||
{
|
||||
CMapEntity *pEntity = EntityListPartial.Element(i);
|
||||
|
||||
AddToList(pEntity, EntityState_Partial);
|
||||
pEntity->SetSelectionState(SELECT_MULTI_PARTIAL);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : pEntity -
|
||||
//-----------------------------------------------------------------------------
|
||||
int CToolPickEntity::FindEntity(CMapEntity *pEntity)
|
||||
{
|
||||
for (int i = 0; i < m_Entities.Count(); i++)
|
||||
{
|
||||
if (m_Entities[i].pEntity == pEntity)
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Clears the selection set.
|
||||
//-----------------------------------------------------------------------------
|
||||
void CToolPickEntity::DeselectAll(void)
|
||||
{
|
||||
for (int i = 0; i < m_Entities.Count(); i++)
|
||||
{
|
||||
m_Entities[i].pEntity->SetSelectionState(SELECT_NONE);
|
||||
}
|
||||
|
||||
m_Entities.RemoveAll();
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Selects the entity unconditionally.
|
||||
// Input : pEntity - entity to select.
|
||||
//-----------------------------------------------------------------------------
|
||||
void CToolPickEntity::SelectEntity(CMapEntity *pEntity)
|
||||
{
|
||||
int nIndex = FindEntity(pEntity);
|
||||
if (nIndex != -1)
|
||||
{
|
||||
//
|
||||
// The entity is in our list, update its selection state.
|
||||
//
|
||||
m_Entities[nIndex].eState = EntityState_Select;
|
||||
pEntity->SetSelectionState(SELECT_NORMAL);
|
||||
}
|
||||
else
|
||||
{
|
||||
//
|
||||
// The entity is not in our list, add it.
|
||||
//
|
||||
AddToList(pEntity, EntityState_Select);
|
||||
pEntity->SetSelectionState(SELECT_NORMAL);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Deselects the given entity.
|
||||
//-----------------------------------------------------------------------------
|
||||
void CToolPickEntity::DeselectEntity(CMapEntity *pEntity)
|
||||
{
|
||||
int nIndex = FindEntity(pEntity);
|
||||
if (nIndex != -1)
|
||||
{
|
||||
DeselectEntity(nIndex);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Removes the entity at the given index from the selection set.
|
||||
// Input : nIndex - Index of the entity in the selection list.
|
||||
//-----------------------------------------------------------------------------
|
||||
void CToolPickEntity::DeselectEntity(int nIndex)
|
||||
{
|
||||
Assert(m_Entities.IsValidIndex(nIndex));
|
||||
|
||||
if (m_Entities.IsValidIndex(nIndex))
|
||||
{
|
||||
if (m_Entities[nIndex].eOriginalState != EntityState_Partial)
|
||||
{
|
||||
m_Entities[nIndex].pEntity->SetSelectionState(SELECT_NONE);
|
||||
|
||||
//
|
||||
// Remove the entity from our list.
|
||||
//
|
||||
RemoveFromList(nIndex);
|
||||
}
|
||||
else
|
||||
{
|
||||
//
|
||||
// Just set the state to deselected so we can cycle back to partial selection.
|
||||
//
|
||||
m_Entities[nIndex].pEntity->SetSelectionState(SELECT_NONE);
|
||||
m_Entities[nIndex].eState = EntityState_None;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : pEntity -
|
||||
// eState -
|
||||
//-----------------------------------------------------------------------------
|
||||
void CToolPickEntity::AddToList(CMapEntity *pEntity, EntityState_t eState)
|
||||
{
|
||||
int nIndex = m_Entities.AddToTail();
|
||||
m_Entities[nIndex].pEntity = pEntity;
|
||||
m_Entities[nIndex].eState = eState;
|
||||
m_Entities[nIndex].eOriginalState = eState;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : nIndex -
|
||||
//-----------------------------------------------------------------------------
|
||||
void CToolPickEntity::RemoveFromList(int nIndex)
|
||||
{
|
||||
Assert(m_Entities.IsValidIndex(nIndex));
|
||||
|
||||
if (m_Entities.IsValidIndex(nIndex))
|
||||
{
|
||||
m_Entities.FastRemove(nIndex);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Returns lists of fully selected and partially selected entities.
|
||||
//-----------------------------------------------------------------------------
|
||||
void CToolPickEntity::GetSelectedEntities(CMapEntityList &EntityListFull, CMapEntityList &EntityListPartial)
|
||||
{
|
||||
EntityListFull.RemoveAll();
|
||||
EntityListPartial.RemoveAll();
|
||||
|
||||
for (int i = 0; i < m_Entities.Count(); i++)
|
||||
{
|
||||
if (m_Entities[i].eState == EntityState_Select)
|
||||
{
|
||||
EntityListFull.AddToTail(m_Entities[i].pEntity);
|
||||
}
|
||||
else if (m_Entities[i].eState == EntityState_Partial)
|
||||
{
|
||||
EntityListPartial.AddToTail(m_Entities[i].pEntity);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
127
hammer/ToolPickEntity.h
Normal file
127
hammer/ToolPickEntity.h
Normal file
@@ -0,0 +1,127 @@
|
||||
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: Tool used for picking entities for filling out entity properties and
|
||||
// I/O connections. Anywhere you see an entity name field there should
|
||||
// be an eyedropper button next to it for picking the entity.
|
||||
//
|
||||
// TODO: make the entity field / picker button a single control?
|
||||
// TODO: combine the face picker with the entity picker?
|
||||
//
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef TOOLPICKENTITY_H
|
||||
#define TOOLPICKENTITY_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include "MapEntity.h"
|
||||
#include "ToolInterface.h"
|
||||
|
||||
|
||||
class CMapView3D;
|
||||
class CMapViewLogical;
|
||||
class CToolPickEntity;
|
||||
|
||||
|
||||
//
|
||||
// Selection states for entries in our list of selected faces.
|
||||
//
|
||||
enum EntityState_t
|
||||
{
|
||||
EntityState_Select = 0, //
|
||||
EntityState_Partial, // Used for multiselect; the face is in at least one of the face lists being edited.
|
||||
EntityState_None, // Used for multiselect; to deselect partially selected faces. Otherwise they are removed from the list.
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// An entry in our list of selected entities.
|
||||
//
|
||||
struct SelectedEntity_t
|
||||
{
|
||||
CMapEntity *pEntity; // Pointer to the entity.
|
||||
EntityState_t eState; // The current selection state of this entity.
|
||||
EntityState_t eOriginalState; // The original selection state of this entity.
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// Interface for notification by the entity picking tool. Inherit from this if you
|
||||
// are a client of the entity picker.
|
||||
//
|
||||
class IPickEntityTarget
|
||||
{
|
||||
public:
|
||||
virtual void OnNotifyPickEntity(CToolPickEntity *pTool) = 0;
|
||||
};
|
||||
|
||||
|
||||
class CToolPickEntity : public CBaseTool
|
||||
{
|
||||
public:
|
||||
|
||||
//
|
||||
// Constructor/Destructor
|
||||
//
|
||||
CToolPickEntity();
|
||||
~CToolPickEntity();
|
||||
|
||||
//
|
||||
// CBaseTool virtual implementations
|
||||
//
|
||||
virtual void OnDeactivate();
|
||||
virtual ToolID_t GetToolID(void) { return TOOL_PICK_ENTITY; }
|
||||
|
||||
virtual bool OnLMouseUp3D(CMapView3D *pView, UINT nFlags, const Vector2D &vPoint);
|
||||
virtual bool OnLMouseDown3D(CMapView3D *pView, UINT nFlags, const Vector2D &vPoint);
|
||||
virtual bool OnLMouseDblClk3D(CMapView3D *pView, UINT nFlags, const Vector2D &vPoint);
|
||||
virtual bool OnRMouseUp3D(CMapView3D *pView, UINT nFlags, const Vector2D &vPoint);
|
||||
virtual bool OnRMouseDown3D(CMapView3D *pView, UINT nFlags, const Vector2D &vPoint);
|
||||
virtual bool OnMouseMove3D(CMapView3D *pView, UINT nFlags, const Vector2D &vPoint);
|
||||
|
||||
virtual bool OnLMouseUpLogical(CMapViewLogical *pView, UINT nFlags, const Vector2D &vPoint) { return true; }
|
||||
virtual bool OnLMouseDownLogical(CMapViewLogical *pView, UINT nFlags, const Vector2D &vPoint);
|
||||
virtual bool OnLMouseDblClkLogical(CMapViewLogical *pView, UINT nFlags, const Vector2D &vPoint) { return true; }
|
||||
virtual bool OnRMouseUpLogical(CMapViewLogical *pView, UINT nFlags, const Vector2D &vPoint) { return true; }
|
||||
virtual bool OnRMouseDownLogical(CMapViewLogical *pView, UINT nFlags, const Vector2D &vPoint) { return true; }
|
||||
virtual bool OnMouseMoveLogical(CMapViewLogical *pView, UINT nFlags, const Vector2D &vPoint);
|
||||
|
||||
//
|
||||
// Functions specific to this tool.
|
||||
//
|
||||
inline void Attach(IPickEntityTarget *pTarget);
|
||||
void AllowMultiSelect(bool bAllow);
|
||||
void GetSelectedEntities(CMapEntityList &EntityListFull, CMapEntityList &EntityListPartial);
|
||||
void SetSelectedEntities(CMapEntityList &EntityListFull, CMapEntityList &EntityListPartial);
|
||||
|
||||
protected:
|
||||
|
||||
void CycleSelectEntity(CMapEntity *pEntity);
|
||||
void DeselectAll(void);
|
||||
void DeselectEntity(int nIndex);
|
||||
void DeselectEntity(CMapEntity *pEntity);
|
||||
int FindEntity(CMapEntity *pEntity);
|
||||
void SelectEntity(CMapEntity *pEntity);
|
||||
|
||||
void AddToList(CMapEntity *pEntity, EntityState_t eState);
|
||||
void RemoveFromList(int nIndex);
|
||||
|
||||
void SetEyedropperCursor(void);
|
||||
|
||||
IPickEntityTarget *m_pNotifyTarget; // Object to notify when selection events occur.
|
||||
bool m_bAllowMultiSelect; // If false, only one entity can be selected at a time.
|
||||
CUtlVector <SelectedEntity_t> m_Entities; // Picked entities and their selection state (partial or full).
|
||||
};
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Attaches the given notification target to this tool. That object
|
||||
// will be used for all future notifications and updates by the tool.
|
||||
//-----------------------------------------------------------------------------
|
||||
void CToolPickEntity::Attach(IPickEntityTarget *pNotifyTarget)
|
||||
{
|
||||
m_pNotifyTarget = pNotifyTarget;
|
||||
}
|
||||
|
||||
#endif // TOOLPICKENTITY_H
|
||||
269
hammer/ToolPointHandle.cpp
Normal file
269
hammer/ToolPointHandle.cpp
Normal file
@@ -0,0 +1,269 @@
|
||||
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================//
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "History.h"
|
||||
#include "MainFrm.h" // FIXME: For ObjectProperties
|
||||
#include "MapDoc.h"
|
||||
#include "MapView2D.h"
|
||||
#include "MapPointHandle.h"
|
||||
#include "PopupMenus.h"
|
||||
#include "Render2D.h"
|
||||
#include "StatusBarIDs.h" // For SetStatusText
|
||||
#include "ToolManager.h"
|
||||
#include "ToolPointHandle.h"
|
||||
#include "Selection.h"
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include <tier0/memdbgon.h>
|
||||
|
||||
|
||||
class CToolPointHandleMsgWnd : public CWnd
|
||||
{
|
||||
public:
|
||||
|
||||
bool Create(void);
|
||||
void PreMenu2D(CToolPointHandle *pTool, CMapView2D *pView);
|
||||
|
||||
protected:
|
||||
|
||||
//{{AFX_MSG_MAP(CToolPointHandleMsgWnd)
|
||||
afx_msg void OnCenter();
|
||||
//}}AFX_MSG
|
||||
|
||||
DECLARE_MESSAGE_MAP()
|
||||
|
||||
private:
|
||||
|
||||
CToolPointHandle *m_pToolPointHandle;
|
||||
CMapView2D *m_pView2D;
|
||||
};
|
||||
|
||||
|
||||
static CToolPointHandleMsgWnd s_wndToolMessage;
|
||||
static const char *g_pszClassName = "ValveEditor_PointHandleToolWnd";
|
||||
|
||||
|
||||
BEGIN_MESSAGE_MAP(CToolPointHandleMsgWnd, CWnd)
|
||||
//{{AFX_MSG_MAP(CToolPointHandleMsgWnd)
|
||||
ON_COMMAND(ID_CENTER_ON_ENTITY, OnCenter)
|
||||
//}}AFX_MSG_MAP
|
||||
END_MESSAGE_MAP()
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Creates the hidden window that receives context menu commands for the
|
||||
// block tool.
|
||||
// Output : Returns true on success, false on failure.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CToolPointHandleMsgWnd::Create(void)
|
||||
{
|
||||
WNDCLASS wndcls;
|
||||
memset(&wndcls, 0, sizeof(WNDCLASS));
|
||||
wndcls.lpfnWndProc = AfxWndProc;
|
||||
wndcls.hInstance = AfxGetInstanceHandle();
|
||||
wndcls.lpszClassName = g_pszClassName;
|
||||
|
||||
if (!AfxRegisterClass(&wndcls))
|
||||
{
|
||||
return(false);
|
||||
}
|
||||
|
||||
return(CWnd::CreateEx(0, g_pszClassName, g_pszClassName, 0, CRect(0, 0, 10, 10), NULL, 0) == TRUE);
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Attaches the tool to this window before activating the context menu.
|
||||
//-----------------------------------------------------------------------------
|
||||
void CToolPointHandleMsgWnd::PreMenu2D(CToolPointHandle *pToolPointHandle, CMapView2D *pView)
|
||||
{
|
||||
Assert(pToolPointHandle != NULL);
|
||||
m_pToolPointHandle = pToolPointHandle;
|
||||
m_pView2D = pView;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CToolPointHandleMsgWnd::OnCenter()
|
||||
{
|
||||
if (m_pToolPointHandle)
|
||||
{
|
||||
m_pToolPointHandle->CenterOnParent(m_pView2D);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Constructor.
|
||||
//-----------------------------------------------------------------------------
|
||||
CToolPointHandle::CToolPointHandle(void)
|
||||
{
|
||||
m_pPoint = NULL;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Attaches the point to the tool for manipulation.
|
||||
//-----------------------------------------------------------------------------
|
||||
void CToolPointHandle::Attach(CMapPointHandle *pPoint)
|
||||
{
|
||||
m_pPoint = pPoint;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Handles left button down events in the 2D view.
|
||||
// Input : Per CWnd::OnLButtonDown.
|
||||
// Output : Returns true if the message was handled, false if not.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CToolPointHandle::OnLMouseDown2D(CMapView2D *pView, UINT nFlags, const Vector2D &VPoint)
|
||||
{
|
||||
//
|
||||
// Activate this tool and start dragging the axis endpoint.
|
||||
//
|
||||
ToolManager()->PushTool(TOOL_POINT_HANDLE);
|
||||
pView->SetCapture();
|
||||
|
||||
GetHistory()->MarkUndoPosition( m_pDocument->GetSelection()->GetList(), "Modify Origin");
|
||||
GetHistory()->Keep(m_pPoint);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Handles left button up events in the 2D view.
|
||||
// Input : Per CWnd::OnLButtonUp.
|
||||
// Output : Returns true if the message was handled, false if not.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CToolPointHandle::OnLMouseUp2D(CMapView2D *pView, UINT nFlags, const Vector2D &VPoint)
|
||||
{
|
||||
m_pPoint->UpdateOrigin(m_pPoint->m_Origin);
|
||||
|
||||
ToolManager()->PopTool();
|
||||
ReleaseCapture();
|
||||
|
||||
m_pDocument->SetModifiedFlag();
|
||||
|
||||
m_pDocument->UpdateAllViews( MAPVIEW_UPDATE_TOOL );
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Handles mouse move events in the 2D view.
|
||||
// Input : Per CWnd::OnMouseMove.
|
||||
// Output : Returns true if the message was handled, false if not.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CToolPointHandle::OnMouseMove2D(CMapView2D *pView, UINT nFlags, const Vector2D &vPoint)
|
||||
{
|
||||
//
|
||||
// Make sure the point is visible.
|
||||
//
|
||||
pView->ToolScrollToPoint( vPoint );
|
||||
|
||||
//
|
||||
// Snap the point to half the grid size. Do this so that we can always center
|
||||
// the origin even on odd-width objects.
|
||||
//
|
||||
Vector vecWorld;
|
||||
pView->ClientToWorld(vecWorld, vPoint);
|
||||
|
||||
m_pDocument->Snap(vecWorld, constrainHalfSnap);
|
||||
|
||||
//
|
||||
// Move to the snapped position.
|
||||
//
|
||||
m_pPoint->m_Origin[pView->axHorz] = vecWorld[pView->axHorz];
|
||||
m_pPoint->m_Origin[pView->axVert] = vecWorld[pView->axVert];
|
||||
|
||||
//
|
||||
// Update the status bar and the views.
|
||||
//
|
||||
char szBuf[128];
|
||||
sprintf(szBuf, " @%.0f, %.0f ", m_pPoint->m_Origin[pView->axHorz], m_pPoint->m_Origin[pView->axVert]);
|
||||
SetStatusText(SBI_COORDS, szBuf);
|
||||
|
||||
m_pDocument->UpdateAllViews( MAPVIEW_UPDATE_TOOL );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Renders the tool in the 2D view.
|
||||
// Input : pRender - The interface to use for rendering.
|
||||
//-----------------------------------------------------------------------------
|
||||
void CToolPointHandle::RenderTool2D(CRender2D *pRender)
|
||||
{
|
||||
SelectionState_t eState = m_pPoint->SetSelectionState(SELECT_MODIFY);
|
||||
m_pPoint->Render2D(pRender);
|
||||
m_pPoint->SetSelectionState(eState);
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : *pView -
|
||||
// point -
|
||||
// Output : Returns true on success, false on failure.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CToolPointHandle::OnContextMenu2D(CMapView2D *pView, UINT nFlags, const Vector2D &vPoint)
|
||||
{
|
||||
static CMenu menu, menuCreate;
|
||||
static bool bInit = false;
|
||||
|
||||
if (!bInit)
|
||||
{
|
||||
bInit = true;
|
||||
|
||||
// Create the menu.
|
||||
menu.LoadMenu(IDR_POPUPS);
|
||||
menuCreate.Attach(::GetSubMenu(menu.m_hMenu, IDM_POPUP_POINT_HANDLE));
|
||||
|
||||
// Create the window that handles menu messages.
|
||||
s_wndToolMessage.Create();
|
||||
}
|
||||
|
||||
if (!pView->PointInClientRect(vPoint) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
CPoint ptScreen( vPoint.x,vPoint.y);
|
||||
pView->ClientToScreen(&ptScreen);
|
||||
|
||||
s_wndToolMessage.PreMenu2D(this, pView);
|
||||
menuCreate.TrackPopupMenu(TPM_LEFTBUTTON | TPM_RIGHTBUTTON | TPM_LEFTALIGN, ptScreen.x, ptScreen.y, &s_wndToolMessage);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CToolPointHandle::CenterOnParent(CMapView *pView)
|
||||
{
|
||||
if (m_pPoint)
|
||||
{
|
||||
GetHistory()->MarkUndoPosition(m_pDocument->GetSelection()->GetList(), "Center Origin");
|
||||
GetHistory()->Keep(m_pPoint);
|
||||
|
||||
CMapClass *pParent = m_pPoint->GetParent();
|
||||
|
||||
Vector vecCenter;
|
||||
pParent->GetBoundsCenter(vecCenter);
|
||||
m_pPoint->UpdateOrigin(vecCenter);
|
||||
|
||||
m_pDocument->SetModifiedFlag();
|
||||
|
||||
m_pDocument->UpdateAllViews( MAPVIEW_UPDATE_TOOL );
|
||||
}
|
||||
}
|
||||
|
||||
49
hammer/ToolPointHandle.h
Normal file
49
hammer/ToolPointHandle.h
Normal file
@@ -0,0 +1,49 @@
|
||||
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef TOOLPOINTHANDLE_H
|
||||
#define TOOLPOINTHANDLE_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include "ToolInterface.h"
|
||||
|
||||
|
||||
class CMapPointHandle;
|
||||
|
||||
|
||||
class CToolPointHandle : public CBaseTool
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
CToolPointHandle(void);
|
||||
void Attach(CMapPointHandle *pPoint);
|
||||
|
||||
void CenterOnParent(CMapView *pView);
|
||||
|
||||
//
|
||||
// CBaseTool implementation.
|
||||
//
|
||||
virtual ToolID_t GetToolID(void) { return TOOL_POINT_HANDLE; }
|
||||
|
||||
virtual bool OnLMouseDown2D(CMapView2D *pView, UINT nFlags, const Vector2D &vPoint);
|
||||
virtual bool OnLMouseUp2D(CMapView2D *pView, UINT nFlags, const Vector2D &vPoint);
|
||||
virtual bool OnMouseMove2D(CMapView2D *pView, UINT nFlags, const Vector2D &vPoint);
|
||||
virtual bool OnContextMenu2D(CMapView2D *pView, UINT nFlags, const Vector2D &vPoint);
|
||||
|
||||
virtual void RenderTool2D(CRender2D *pRender);
|
||||
//virtual void RenderTool3D(CRender3D *pRender);
|
||||
|
||||
private:
|
||||
|
||||
CMapPointHandle *m_pPoint;
|
||||
};
|
||||
|
||||
|
||||
#endif // TOOLPOINTHANDLE_H
|
||||
1987
hammer/ToolSelection.cpp
Normal file
1987
hammer/ToolSelection.cpp
Normal file
File diff suppressed because it is too large
Load Diff
162
hammer/ToolSelection.h
Normal file
162
hammer/ToolSelection.h
Normal file
@@ -0,0 +1,162 @@
|
||||
//===== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//===========================================================================//
|
||||
|
||||
#ifndef SELECTION3D_H
|
||||
#define SELECTION3D_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
|
||||
#include "Box3D.h"
|
||||
#include "MapClass.h" // For CMapObjectList
|
||||
#include "ToolInterface.h"
|
||||
#include "UtlVector.h"
|
||||
|
||||
|
||||
class CMapWorld;
|
||||
class CMapView;
|
||||
class CMapView2D;
|
||||
class CMapView3D;
|
||||
class GDinputvariable;
|
||||
class CRender2D;
|
||||
|
||||
class Selection3D : public Box3D
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
Selection3D();
|
||||
~Selection3D();
|
||||
|
||||
void Init( CMapDoc *pDocument );
|
||||
|
||||
inline bool IsBoxSelecting();
|
||||
inline bool IsLogicalBoxSelecting();
|
||||
void EndBoxSelection();
|
||||
|
||||
// Start, end logical selection
|
||||
void StartLogicalBoxSelection( CMapViewLogical *pView, const Vector &vStart );
|
||||
void EndLogicalBoxSelection( );
|
||||
|
||||
// Tool3D implementation.
|
||||
virtual void SetEmpty();
|
||||
virtual bool IsEmpty();
|
||||
|
||||
//
|
||||
// CBaseTool implementation.
|
||||
//
|
||||
virtual void OnActivate();
|
||||
virtual void OnDeactivate();
|
||||
virtual ToolID_t GetToolID() { return TOOL_POINTER; }
|
||||
|
||||
virtual bool OnContextMenu2D(CMapView2D *pView, UINT nFlags, const Vector2D &vPoint);
|
||||
virtual bool OnKeyDown2D(CMapView2D *pView, UINT nChar, UINT nRepCnt, UINT nFlags);
|
||||
virtual bool OnLMouseDown2D(CMapView2D *pView, UINT nFlags, const Vector2D &vPoint);
|
||||
virtual bool OnLMouseUp2D(CMapView2D *pView, UINT nFlags, const Vector2D &vPoint);
|
||||
virtual bool OnMouseMove2D(CMapView2D *pView, UINT nFlags, const Vector2D &vPoint);
|
||||
|
||||
virtual bool OnKeyDown3D(CMapView3D *pView, UINT nChar, UINT nRepCnt, UINT nFlags);
|
||||
virtual bool OnLMouseDblClk3D(CMapView3D *pView, UINT nFlags, const Vector2D &vPoint);
|
||||
virtual bool OnLMouseDown3D(CMapView3D *pView, UINT nFlags, const Vector2D &vPoint);
|
||||
virtual bool OnLMouseUp3D(CMapView3D *pView, UINT nFlags, const Vector2D &vPoint);
|
||||
virtual bool OnMouseMove3D(CMapView3D *pView, UINT nFlags, const Vector2D &vPoint);
|
||||
|
||||
virtual void RenderTool2D(CRender2D *pRender);
|
||||
virtual void RenderToolLogical(CRender2D *pRender);
|
||||
virtual void RenderTool3D(CRender3D *pRender);
|
||||
|
||||
virtual bool OnContextMenuLogical(CMapViewLogical *pView, UINT nFlags, const Vector2D &vPoint);
|
||||
virtual bool OnKeyDownLogical(CMapViewLogical *pView, UINT nChar, UINT nRepCnt, UINT nFlags);
|
||||
virtual bool OnLMouseDownLogical(CMapViewLogical *pView, UINT nFlags, const Vector2D &vPoint);
|
||||
virtual bool OnLMouseUpLogical(CMapViewLogical *pView, UINT nFlags, const Vector2D &vPoint);
|
||||
virtual bool OnMouseMoveLogical(CMapViewLogical *pView, UINT nFlags, const Vector2D &vPoint);
|
||||
virtual bool OnLMouseDblClkLogical(CMapViewLogical *pView, UINT nFlags, const Vector2D &vPoint);
|
||||
|
||||
void UpdateSelectionBounds();
|
||||
|
||||
bool m_bBoxSelection;
|
||||
|
||||
protected:
|
||||
|
||||
void TransformSelection();
|
||||
void TransformLogicalSelection( const Vector2D &vecTranslation );
|
||||
|
||||
void FinishTranslation(bool bSave, bool bClone );
|
||||
void StartTranslation(CMapView *pView, const Vector2D &vPoint, const Vector &vHandleOrigin );
|
||||
bool StartBoxSelection( CMapView *pView, const Vector2D &vPoint, const Vector &vStart);
|
||||
|
||||
void UpdateHandleState();
|
||||
|
||||
virtual unsigned int GetConstraints(unsigned int nKeyFlags);
|
||||
|
||||
void NudgeObjects(CMapView *pView, int nChar, bool bSnap, bool bClone);
|
||||
|
||||
GDinputvariable *ChooseEyedropperVar(CMapView *pView, CUtlVector<GDinputvariable *> &VarList);
|
||||
|
||||
CMapEntity *FindEntityInTree(CMapClass *pObject);
|
||||
|
||||
void SelectInBox(CMapDoc *pDoc, bool bInsideOnly);
|
||||
CBaseTool *GetToolObject( CMapView2D *pView, const Vector2D &ptScreen, bool bAttach );
|
||||
CBaseTool *GetToolObjectLogical( CMapViewLogical *pView, const Vector2D &vPoint, bool bAttach );
|
||||
|
||||
void SetEyedropperCursor();
|
||||
|
||||
void EyedropperPick2D(CMapView2D *pView, const Vector2D &vPoint);
|
||||
void EyedropperPick3D(CMapView3D *pView, const Vector2D &vPoint);
|
||||
void EyedropperPick(CMapView *pView, CMapClass *pObject);
|
||||
|
||||
void OnEscape(CMapDoc *pDoc);
|
||||
|
||||
//
|
||||
// Tool3D implementation.
|
||||
//
|
||||
virtual int HitTest(CMapView *pView, const Vector2D &pt, bool bTestHandles = false);
|
||||
|
||||
// Methods related to logical operations
|
||||
void EyedropperPickLogical( CMapViewLogical *pView, const Vector2D &vPoint );
|
||||
bool HitTestLogical( CMapView *pView, const Vector2D &ptClient );
|
||||
void SelectInLogicalBox(CMapDoc *pDoc, bool bInsideOnly);
|
||||
|
||||
CSelection *m_pSelection; // the documents selection opject
|
||||
|
||||
bool m_bEyedropper; // True if we are holding down the eyedropper hotkey.
|
||||
|
||||
bool m_bSelected; // Did we select an object on left button down?
|
||||
bool m_b3DEditMode; // editing mode in 3D on/off
|
||||
|
||||
bool m_bDrawAsSolidBox; // sometimes we want to render the tool bbox solid
|
||||
|
||||
// These are fields related to manipulation in logical views
|
||||
Vector2D m_vLDownLogicalClient; // Logical client pos at which lbutton was pressed.
|
||||
Vector2D m_vecLogicalSelBoxMins;
|
||||
Vector2D m_vecLogicalSelBoxMaxs;
|
||||
bool m_bInLogicalBoxSelection; // Are we doing box selection in the logical mode?
|
||||
COLORREF m_clrLogicalBox; // The color of the logical box
|
||||
Vector2D m_vLastLogicalDragPoint; // Last point at which we dragged (world coords)
|
||||
Vector2D m_vLogicalTranslation;
|
||||
bool m_bIsLogicalTranslating; // true while translation in logical view
|
||||
bool m_bLButtonDown;
|
||||
bool m_bLeftDragged;
|
||||
};
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Are we in box selection?
|
||||
//-----------------------------------------------------------------------------
|
||||
inline bool Selection3D::IsBoxSelecting()
|
||||
{
|
||||
return m_bBoxSelection;
|
||||
}
|
||||
|
||||
inline bool Selection3D::IsLogicalBoxSelecting()
|
||||
{
|
||||
return m_bInLogicalBoxSelection;
|
||||
}
|
||||
|
||||
|
||||
#endif // SELECTION3D_H
|
||||
119
hammer/ToolSphere.cpp
Normal file
119
hammer/ToolSphere.cpp
Normal file
@@ -0,0 +1,119 @@
|
||||
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "History.h"
|
||||
#include "MainFrm.h" // FIXME: For ObjectProperties
|
||||
#include "MapDoc.h"
|
||||
#include "MapView2D.h"
|
||||
#include "MapSphere.h"
|
||||
#include "StatusBarIDs.h" // For updating status bar text
|
||||
#include "ToolManager.h"
|
||||
#include "ToolSphere.h"
|
||||
#include "Selection.h"
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include <tier0/memdbgon.h>
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
CToolSphere::CToolSphere()
|
||||
{
|
||||
m_pSphere = NULL;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : pSphere -
|
||||
//-----------------------------------------------------------------------------
|
||||
void CToolSphere::Attach(CMapSphere *pSphere)
|
||||
{
|
||||
m_pSphere = pSphere;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : pView -
|
||||
// nFlags -
|
||||
// point -
|
||||
// Output : Returns true if the message was handled, false otherwise.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CToolSphere::OnLMouseDown2D(CMapView2D *pView, UINT nFlags, const Vector2D &vPoint)
|
||||
{
|
||||
//
|
||||
// Activate this tool and start resizing the sphere.
|
||||
//
|
||||
ToolManager()->PushTool(TOOL_SPHERE);
|
||||
pView->SetCapture();
|
||||
|
||||
GetHistory()->MarkUndoPosition(m_pDocument->GetSelection()->GetList(), "Modify Radius");
|
||||
GetHistory()->Keep(m_pSphere);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : pView -
|
||||
// nFlags -
|
||||
// point -
|
||||
// Output : Returns true if the message was handled, false otherwise.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CToolSphere::OnLMouseUp2D(CMapView2D *pView, UINT nFlags, const Vector2D &vPoint)
|
||||
{
|
||||
ToolManager()->PopTool();
|
||||
|
||||
ReleaseCapture();
|
||||
|
||||
m_pDocument->SetModifiedFlag();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : pView -
|
||||
// nFlags -
|
||||
// point -
|
||||
// Output : Returns true if the message was handled, false otherwise.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CToolSphere::OnMouseMove2D(CMapView2D *pView, UINT nFlags, const Vector2D &vPoint)
|
||||
{
|
||||
// Make sure the point is visible.
|
||||
pView->ToolScrollToPoint( vPoint );
|
||||
|
||||
Vector vecWorld;
|
||||
pView->ClientToWorld( vecWorld, vPoint );
|
||||
m_pDocument->Snap( vecWorld, constrainSnap );
|
||||
|
||||
//
|
||||
// Use whichever axis they dragged the most along as the drag axis.
|
||||
// Calculate the drag distance in client coordinates.
|
||||
//
|
||||
float flHorzRadius = fabs((float)vecWorld[pView->axHorz] - m_pSphere->m_Origin[pView->axHorz]);
|
||||
float flVertRadius = fabs((float)vecWorld[pView->axVert] - m_pSphere->m_Origin[pView->axVert]);
|
||||
float flRadius = max(flHorzRadius, flVertRadius);
|
||||
|
||||
m_pSphere->SetRadius(flRadius);
|
||||
|
||||
//
|
||||
// Update the status bar text with the new value of the radius.
|
||||
//
|
||||
char szBuf[128];
|
||||
sprintf(szBuf, " %s = %g ", m_pSphere->m_szKeyName, (double)m_pSphere->m_flRadius);
|
||||
SetStatusText(SBI_COORDS, szBuf);
|
||||
|
||||
m_pDocument->UpdateAllViews( MAPVIEW_UPDATE_TOOL );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
49
hammer/ToolSphere.h
Normal file
49
hammer/ToolSphere.h
Normal file
@@ -0,0 +1,49 @@
|
||||
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef TOOLSPHERE_H
|
||||
#define TOOLSPHERE_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
|
||||
#include "ToolInterface.h"
|
||||
|
||||
|
||||
class CMapSphere;
|
||||
|
||||
|
||||
class CToolSphere : public CBaseTool
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
CToolSphere();
|
||||
|
||||
void Attach(CMapSphere *pShere);
|
||||
|
||||
//
|
||||
// CBaseTool implementation.
|
||||
//
|
||||
virtual ToolID_t GetToolID(void) { return TOOL_SPHERE; }
|
||||
|
||||
virtual bool OnLMouseDown2D(CMapView2D *pView, UINT nFlags, const Vector2D &vPoint);
|
||||
virtual bool OnLMouseUp2D(CMapView2D *pView, UINT nFlags, const Vector2D &vPoint);
|
||||
virtual bool OnMouseMove2D(CMapView2D *pView, UINT nFlags, const Vector2D &vPoint);
|
||||
|
||||
//virtual void RenderTool2D(CRender2D *pRender);
|
||||
|
||||
private:
|
||||
|
||||
CMapSphere *m_pSphere;
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif // TOOLSPHERE_H
|
||||
535
hammer/TorusDlg.cpp
Normal file
535
hammer/TorusDlg.cpp
Normal file
@@ -0,0 +1,535 @@
|
||||
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $Workfile: $
|
||||
// $Date: $
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "hammer.h"
|
||||
#include "hammer_mathlib.h"
|
||||
#include "TorusDlg.h"
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include <tier0/memdbgon.h>
|
||||
|
||||
|
||||
static LPCTSTR pszSection = "Torus";
|
||||
|
||||
void MakeArcCenterRadius(float xCenter, float yCenter, float xrad, float yrad, int npoints, float start_ang, float fArc, float points[][2]);
|
||||
void MakeArc(float x1, float y1, float x2, float y2, int npoints, float start_ang, float fArc, float points[][2]);
|
||||
|
||||
CTorusDlg::CTorusDlg(Vector& boxmins, Vector& boxmaxs, CWnd* pParent /*=NULL*/)
|
||||
: CDialog(CTorusDlg::IDD, pParent)
|
||||
{
|
||||
bmins = boxmins;
|
||||
bmaxs = boxmaxs;
|
||||
|
||||
//{{AFX_DATA_INIT(CTorusDlg)
|
||||
m_iSides = 0;
|
||||
m_iWallWidth = 0;
|
||||
m_iAddHeight = 0;
|
||||
m_fArc = 0.0f;
|
||||
m_fAngle = 0.0f;
|
||||
m_fRotationArc = 0.0f;
|
||||
m_fRotationAngle = 0.0f;
|
||||
m_iRotationSides = 0;
|
||||
m_fCrossSectionRadius = 0;
|
||||
//}}AFX_DATA_INIT
|
||||
|
||||
// load up old defaults
|
||||
CString str;
|
||||
m_iWallWidth = AfxGetApp()->GetProfileInt(pszSection, "Wall Width", 32);
|
||||
str = AfxGetApp()->GetProfileString(pszSection, "Arc_", "360");
|
||||
m_fArc = atof(str);
|
||||
m_iSides = AfxGetApp()->GetProfileInt(pszSection, "Sides", 16);
|
||||
str = AfxGetApp()->GetProfileString(pszSection, "Start Angle_", "0");
|
||||
m_fAngle = atof(str);
|
||||
|
||||
str = AfxGetApp()->GetProfileString(pszSection, "Rotation Arc_", "360");
|
||||
m_fRotationArc = atof(str);
|
||||
m_iRotationSides = AfxGetApp()->GetProfileInt(pszSection, "Rotation Sides", 16);
|
||||
str = AfxGetApp()->GetProfileString(pszSection, "Rotation Start Angle_", "0");
|
||||
m_fRotationAngle = atof(str);
|
||||
|
||||
m_iAddHeight = AfxGetApp()->GetProfileInt(pszSection, "Add Height", 0);
|
||||
|
||||
Vector vecSize;
|
||||
VectorSubtract( bmaxs, bmins, vecSize );
|
||||
if ( m_iAddHeight > vecSize.z )
|
||||
{
|
||||
m_iAddHeight = vecSize.z;
|
||||
}
|
||||
|
||||
// This is the maximum cross-section radius
|
||||
m_fCrossSectionRadius = MaxTorusCrossSectionRadius();
|
||||
}
|
||||
|
||||
void CTorusDlg::SaveValues()
|
||||
{
|
||||
CString str;
|
||||
AfxGetApp()->WriteProfileInt(pszSection, "Wall Width", m_iWallWidth);
|
||||
str.Format("%f", m_fArc);
|
||||
AfxGetApp()->WriteProfileString(pszSection, "Arc_", str);
|
||||
AfxGetApp()->WriteProfileInt(pszSection, "Sides", m_iSides);
|
||||
str.Format("%f", m_fAngle);
|
||||
AfxGetApp()->WriteProfileString(pszSection, "Start Angle_", str);
|
||||
|
||||
str.Format("%f", m_fRotationArc);
|
||||
AfxGetApp()->WriteProfileString(pszSection, "Rotation Arc_", str);
|
||||
str.Format("%f", m_fRotationAngle);
|
||||
AfxGetApp()->WriteProfileString(pszSection, "Rotation Start Angle_", str);
|
||||
AfxGetApp()->WriteProfileInt(pszSection, "Rotation Sides", m_iRotationSides);
|
||||
AfxGetApp()->WriteProfileInt(pszSection, "Add Height", m_iAddHeight);
|
||||
}
|
||||
|
||||
void CTorusDlg::DoDataExchange(CDataExchange* pDX)
|
||||
{
|
||||
CDialog::DoDataExchange(pDX);
|
||||
//{{AFX_DATA_MAP(CTorusDlg)
|
||||
DDX_Control(pDX, IDC_ANGLESPIN, m_cStartAngleSpin);
|
||||
DDX_Control(pDX, IDC_WALLWIDTHSPIN, m_cWallWidthSpin);
|
||||
DDX_Control(pDX, IDC_WALLWIDTH, m_cWallWidth);
|
||||
DDX_Control(pDX, IDC_SIDESSPIN, m_cSidesSpin);
|
||||
DDX_Control(pDX, IDC_SIDES, m_cSides);
|
||||
DDX_Control(pDX, IDC_ARCSPIN, m_cArcSpin);
|
||||
DDX_Control(pDX, IDC_ARC, m_cArc);
|
||||
DDX_Control(pDX, IDC_PREVIEW, m_cPreview);
|
||||
DDX_Control(pDX, IDC_PREVIEW_TOP_VIEW, m_cTopViewPreview);
|
||||
DDX_Text(pDX, IDC_SIDES, m_iSides);
|
||||
DDV_MinMaxInt(pDX, m_iSides, 3, 2048);
|
||||
DDX_Text(pDX, IDC_WALLWIDTH, m_iWallWidth);
|
||||
DDX_Text(pDX, IDC_ADDHEIGHT, m_iAddHeight);
|
||||
DDX_Text(pDX, IDC_ARC, m_fArc);
|
||||
DDV_MinMaxFloat(pDX, m_fArc, 8.f, 360.f);
|
||||
DDX_Text(pDX, IDC_ANGLE, m_fAngle);
|
||||
DDV_MinMaxFloat(pDX, m_fAngle, -360.0f, 360.f);
|
||||
DDX_Text(pDX, IDC_ROTATION_ARC, m_fRotationArc);
|
||||
DDV_MinMaxFloat(pDX, m_fRotationArc, 0.f, 3600.f);
|
||||
DDX_Text(pDX, IDC_ROTATION_ANGLE, m_fRotationAngle);
|
||||
DDV_MinMaxFloat(pDX, m_fRotationAngle, -360.0f, 360.f);
|
||||
DDX_Text(pDX, IDC_ROTATION_SIDES, m_iRotationSides);
|
||||
DDV_MinMaxInt(pDX, m_iRotationSides, 3, 2048);
|
||||
DDX_Text(pDX, IDC_CROSS_SECTION_RADIUS, m_fCrossSectionRadius);
|
||||
DDV_MinMaxFloat(pDX, m_fCrossSectionRadius, 0.f, 5000.f);
|
||||
//}}AFX_DATA_MAP
|
||||
|
||||
if ( pDX->m_bSaveAndValidate )
|
||||
{
|
||||
Vector vecSize;
|
||||
VectorSubtract( bmaxs, bmins, vecSize );
|
||||
if ( m_iAddHeight > vecSize.z )
|
||||
{
|
||||
m_iAddHeight = vecSize.z;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
BEGIN_MESSAGE_MAP(CTorusDlg, CDialog)
|
||||
//{{AFX_MSG_MAP(CTorusDlg)
|
||||
ON_EN_CHANGE(IDC_ARC, OnChangeArc)
|
||||
ON_EN_CHANGE(IDC_ROTATION_ARC, OnChangeTorusArc)
|
||||
ON_BN_CLICKED(IDC_CIRCLE, OnCircle)
|
||||
ON_BN_CLICKED(IDC_TORUS_COMPUTE_RADIUS, OnComputeRadius)
|
||||
ON_EN_UPDATE(IDC_SIDES, OnUpdateSides)
|
||||
ON_EN_UPDATE(IDC_WALLWIDTH, OnUpdateWallwidth)
|
||||
ON_WM_PAINT()
|
||||
ON_BN_CLICKED(IDC_TORUS_PREVIEW, OnTorusPreview)
|
||||
//}}AFX_MSG_MAP
|
||||
END_MESSAGE_MAP()
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// CTorusDlg message handlers
|
||||
|
||||
void CTorusDlg::OnChangeArc()
|
||||
{
|
||||
}
|
||||
|
||||
void CTorusDlg::OnChangeTorusArc()
|
||||
{
|
||||
}
|
||||
|
||||
void CTorusDlg::OnCircle()
|
||||
{
|
||||
m_cArcSpin.SetPos(360);
|
||||
OnTorusPreview();
|
||||
}
|
||||
|
||||
void CTorusDlg::OnComputeRadius()
|
||||
{
|
||||
UpdateData( TRUE );
|
||||
|
||||
// This is the maximum cross-section radius
|
||||
m_fCrossSectionRadius = MaxTorusCrossSectionRadius();
|
||||
UpdateData( FALSE );
|
||||
OnTorusPreview();
|
||||
}
|
||||
|
||||
void CTorusDlg::OnUpdateSides()
|
||||
{
|
||||
}
|
||||
|
||||
void CTorusDlg::OnUpdateWallwidth()
|
||||
{
|
||||
}
|
||||
|
||||
BOOL CTorusDlg::OnInitDialog()
|
||||
{
|
||||
CDialog::OnInitDialog();
|
||||
|
||||
m_cArcSpin.SetRange(8, 360);
|
||||
m_cSidesSpin.SetRange(3, 100);
|
||||
m_cWallWidthSpin.SetRange(2, m_iMaxWallWidth);
|
||||
m_cStartAngleSpin.SetRange(0, 360);
|
||||
|
||||
m_cPreview.ShowWindow(SW_HIDE);
|
||||
m_cTopViewPreview.ShowWindow(SW_HIDE);
|
||||
|
||||
bInitialized = TRUE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void CTorusDlg::OnPaint()
|
||||
{
|
||||
CPaintDC dc(this); // device context for painting
|
||||
|
||||
CBrush black(RGB(0,0,0));
|
||||
CBrush grey(RGB(128,128,128));
|
||||
|
||||
// Do not call CDialog::OnPaint() for painting messages
|
||||
CRect rcPreview;
|
||||
m_cPreview.GetWindowRect(&rcPreview);
|
||||
ScreenToClient(&rcPreview);
|
||||
dc.FillRect(rcPreview, &black);
|
||||
|
||||
DrawTorusCrossSection( &dc );
|
||||
|
||||
rcPreview.InflateRect(1,1);
|
||||
dc.FrameRect(rcPreview, &grey);
|
||||
ValidateRect(rcPreview);
|
||||
|
||||
m_cTopViewPreview.GetWindowRect(&rcPreview);
|
||||
ScreenToClient(&rcPreview);
|
||||
dc.FillRect(rcPreview, &black);
|
||||
|
||||
DrawTorusTopView( &dc );
|
||||
|
||||
rcPreview.InflateRect(1,1);
|
||||
dc.FrameRect(rcPreview, &grey);
|
||||
ValidateRect(rcPreview);
|
||||
|
||||
bInitialized = TRUE;
|
||||
}
|
||||
|
||||
void CTorusDlg::OnTorusPreview()
|
||||
{
|
||||
//
|
||||
// Build preview.
|
||||
//
|
||||
bInitialized = TRUE;
|
||||
InvalidateRect(NULL);
|
||||
UpdateWindow();
|
||||
}
|
||||
|
||||
CTorusDlg::~CTorusDlg()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Gets the inner radius of the torus cross-section
|
||||
//-----------------------------------------------------------------------------
|
||||
float CTorusDlg::MaxTorusCrossSectionRadius() const
|
||||
{
|
||||
Vector vecSize;
|
||||
VectorSubtract( bmaxs, bmins, vecSize );
|
||||
|
||||
float flTorusRadius = (vecSize.z - m_iAddHeight);
|
||||
|
||||
// Check for multiple revolutions...
|
||||
if ( ( m_fRotationArc > 360 ) || (( m_fRotationArc == 360 ) && ( m_iAddHeight != 0 )) )
|
||||
{
|
||||
// Height per revolution
|
||||
float flHeightPerRev = 360.0f * m_iAddHeight / m_fRotationArc;
|
||||
if ( flHeightPerRev < flTorusRadius )
|
||||
{
|
||||
flTorusRadius = flHeightPerRev;
|
||||
}
|
||||
}
|
||||
|
||||
// Also constrain it based on x & y too...
|
||||
if ( (vecSize.x * 0.5f) < flTorusRadius )
|
||||
{
|
||||
flTorusRadius = vecSize.x * 0.5f;
|
||||
}
|
||||
|
||||
if ( (vecSize.y * 0.5f) < flTorusRadius )
|
||||
{
|
||||
flTorusRadius = vecSize.y * 0.5f;
|
||||
}
|
||||
|
||||
flTorusRadius *= 0.5f;
|
||||
if ( flTorusRadius < m_iWallWidth )
|
||||
{
|
||||
flTorusRadius = m_iWallWidth;
|
||||
}
|
||||
|
||||
return flTorusRadius;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Gets the inner radius of the torus cross-section
|
||||
//-----------------------------------------------------------------------------
|
||||
float CTorusDlg::GetTorusCrossSectionRadius() const
|
||||
{
|
||||
Vector vecSize;
|
||||
VectorSubtract( bmaxs, bmins, vecSize );
|
||||
|
||||
float flTorusRadius = m_fCrossSectionRadius;
|
||||
|
||||
// Also constrain it based on x & y too...
|
||||
if ( (vecSize.x * 0.25f) < flTorusRadius )
|
||||
{
|
||||
flTorusRadius = vecSize.x * 0.25f;
|
||||
}
|
||||
|
||||
if ( (vecSize.y * 0.25f) < flTorusRadius )
|
||||
{
|
||||
flTorusRadius = vecSize.y * 0.25f;
|
||||
}
|
||||
|
||||
return flTorusRadius;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Draws the torus cross-section
|
||||
//-----------------------------------------------------------------------------
|
||||
void CTorusDlg::DrawTorusCrossSection(CDC* pDC )
|
||||
{
|
||||
int iSides, iWallWidth;
|
||||
float fArc, fStartAngle;
|
||||
|
||||
int i;
|
||||
float fOuterPoints[ARC_MAX_POINTS][2];
|
||||
float fInnerPoints[ARC_MAX_POINTS][2];
|
||||
|
||||
float fScaleX;
|
||||
float fScaleY;
|
||||
|
||||
UpdateData(TRUE);
|
||||
|
||||
CPen m_hPen, *pOldPen;
|
||||
|
||||
m_hPen.CreatePen(PS_SOLID, 1, RGB(255,255,255));
|
||||
|
||||
pOldPen = pDC->SelectObject(&m_hPen);
|
||||
|
||||
CRect rcItem;
|
||||
m_cPreview.GetWindowRect(&rcItem);
|
||||
ScreenToClient(&rcItem);
|
||||
|
||||
CPoint pt;
|
||||
pt.x = rcItem.left + rcItem.Width() / 2;
|
||||
pt.y = rcItem.top + rcItem.Height() / 2;
|
||||
|
||||
float flMaxRadius = GetTorusCrossSectionRadius();
|
||||
iWallWidth = m_iWallWidth;
|
||||
if ( iWallWidth > flMaxRadius )
|
||||
iWallWidth = flMaxRadius;
|
||||
float flTorusRadius = flMaxRadius - iWallWidth;
|
||||
|
||||
float flDeltaZ = bmaxs[2] - bmins[2];
|
||||
if (flDeltaZ)
|
||||
{
|
||||
if ( flDeltaZ < flMaxRadius * 2.0f )
|
||||
{
|
||||
flDeltaZ = flMaxRadius * 2.0f;
|
||||
}
|
||||
fScaleX = rcItem.Width()/flDeltaZ;
|
||||
fScaleY = rcItem.Height()/flDeltaZ;
|
||||
}
|
||||
else
|
||||
{
|
||||
fScaleX = fScaleY = 1.0f;
|
||||
// fScaleX = rcItem.Width() / (2.0f * flMaxRadius);
|
||||
// fScaleY = rcItem.Height() / (2.0f * flMaxRadius);
|
||||
}
|
||||
|
||||
fArc = m_fArc;
|
||||
fStartAngle = m_fAngle;
|
||||
iSides = m_iSides;
|
||||
|
||||
MakeArcCenterRadius(0, 0,
|
||||
flTorusRadius + iWallWidth, flTorusRadius + iWallWidth,
|
||||
iSides, fStartAngle, fArc, fOuterPoints);
|
||||
|
||||
MakeArcCenterRadius(0, 0,
|
||||
flTorusRadius, flTorusRadius,
|
||||
iSides, fStartAngle, fArc, fInnerPoints);
|
||||
|
||||
// check wall width - if it's half or more of the total,
|
||||
// set the inner poinst to the center point of the box
|
||||
// and turn off the CreateSouthFace flag
|
||||
|
||||
Vector points[4];
|
||||
for (i = 0; i < iSides; i++)
|
||||
{
|
||||
int iNextPoint = i+1;
|
||||
if (iNextPoint >= iSides + 1)
|
||||
{
|
||||
iNextPoint = 0;
|
||||
}
|
||||
|
||||
points[0][0] = fOuterPoints[i][0];
|
||||
points[0][1] = fOuterPoints[i][1];
|
||||
|
||||
points[1][0] = fOuterPoints[iNextPoint][0];
|
||||
points[1][1] = fOuterPoints[iNextPoint][1];
|
||||
|
||||
points[2][0] = fInnerPoints[iNextPoint][0];
|
||||
points[2][1] = fInnerPoints[iNextPoint][1];
|
||||
|
||||
points[3][0] = fInnerPoints[i][0];
|
||||
points[3][1] = fInnerPoints[i][1];
|
||||
|
||||
for (int j = 0; j < 4; j++)
|
||||
{
|
||||
points[j][0] = fScaleX * points[j][0];
|
||||
points[j][1] = fScaleY * points[j][1];
|
||||
}
|
||||
|
||||
pDC->MoveTo(pt.x + (int)points[1][0], pt.y - (int)points[1][1]);
|
||||
pDC->LineTo(pt.x + (int)points[0][0], pt.y - (int)points[0][1]);
|
||||
pDC->LineTo(pt.x + (int)points[3][0], pt.y - (int)points[3][1]);
|
||||
pDC->LineTo(pt.x + (int)points[2][0], pt.y - (int)points[2][1]);
|
||||
}
|
||||
|
||||
// Close the cross-section off...
|
||||
if ( fArc != 360.0f )
|
||||
{
|
||||
pDC->LineTo(pt.x + (int)points[1][0], pt.y - (int)points[1][1]);
|
||||
}
|
||||
|
||||
pDC->SelectObject(pOldPen);
|
||||
}
|
||||
|
||||
|
||||
void CTorusDlg::DrawTorusTopView( CDC* pDC )
|
||||
{
|
||||
int i;
|
||||
float fOuterPoints[ARC_MAX_POINTS][2];
|
||||
float fInnerPoints[ARC_MAX_POINTS][2];
|
||||
|
||||
float fScaleX;
|
||||
float fScaleY;
|
||||
|
||||
UpdateData(TRUE);
|
||||
|
||||
CPen m_hPen, *pOldPen;
|
||||
|
||||
m_hPen.CreatePen(PS_SOLID, 1, RGB(255,255,255));
|
||||
|
||||
pOldPen = pDC->SelectObject(&m_hPen);
|
||||
|
||||
CRect rcItem;
|
||||
m_cTopViewPreview.GetWindowRect(&rcItem);
|
||||
ScreenToClient(&rcItem);
|
||||
|
||||
CPoint pt;
|
||||
pt.x = rcItem.left + rcItem.Width() / 2;
|
||||
pt.y = rcItem.top + rcItem.Height() / 2;
|
||||
|
||||
if (bmaxs[0] - bmins[0])
|
||||
{
|
||||
fScaleX = rcItem.Width() /(bmaxs[0] - bmins[0]);
|
||||
}
|
||||
else
|
||||
{
|
||||
fScaleX = 1.0f;
|
||||
}
|
||||
|
||||
if (bmaxs[1] - bmins[1])
|
||||
{
|
||||
fScaleY = rcItem.Height() /(bmaxs[1] - bmins[1]);
|
||||
}
|
||||
else
|
||||
{
|
||||
fScaleY = 1.0f;
|
||||
}
|
||||
|
||||
int iSides, iWallWidth;
|
||||
float fArc, fStartAngle;
|
||||
|
||||
fArc = m_fRotationArc;
|
||||
fStartAngle = m_fRotationAngle;
|
||||
iSides = m_iRotationSides;
|
||||
iWallWidth = GetTorusCrossSectionRadius() * 2.0f;
|
||||
|
||||
float xCenter = (bmaxs[0] + bmins[0]) * 0.5f;
|
||||
float yCenter = (bmaxs[1] + bmins[1]) * 0.5f;
|
||||
float xRad = (bmaxs[0] - xCenter - iWallWidth);
|
||||
float yRad = (bmaxs[1] - yCenter - iWallWidth);
|
||||
if (xRad < 0.0f )
|
||||
{
|
||||
xRad = 0.0f;
|
||||
}
|
||||
if (yRad < 0.0f )
|
||||
{
|
||||
yRad = 0.0f;
|
||||
}
|
||||
|
||||
MakeArcCenterRadius(xCenter, yCenter, xRad + iWallWidth, yRad + iWallWidth,
|
||||
iSides, fStartAngle, fArc, fOuterPoints);
|
||||
|
||||
MakeArcCenterRadius(xCenter, yCenter, xRad, yRad,
|
||||
iSides, fStartAngle, fArc, fInnerPoints);
|
||||
|
||||
Vector vecCenter;
|
||||
VectorLerp( bmins, bmaxs, 0.5f, vecCenter );
|
||||
|
||||
Vector points[4];
|
||||
for (i = 0; i < iSides; i++)
|
||||
{
|
||||
int iNextPoint = i+1;
|
||||
if (iNextPoint >= iSides + 1)
|
||||
{
|
||||
iNextPoint = 0;
|
||||
}
|
||||
|
||||
points[0][0] = fOuterPoints[i][0];
|
||||
points[0][1] = fOuterPoints[i][1];
|
||||
|
||||
points[1][0] = fOuterPoints[iNextPoint][0];
|
||||
points[1][1] = fOuterPoints[iNextPoint][1];
|
||||
|
||||
points[2][0] = fInnerPoints[iNextPoint][0];
|
||||
points[2][1] = fInnerPoints[iNextPoint][1];
|
||||
|
||||
points[3][0] = fInnerPoints[i][0];
|
||||
points[3][1] = fInnerPoints[i][1];
|
||||
|
||||
for (int j = 0; j < 4; j++)
|
||||
{
|
||||
points[j][0] = fScaleX * (points[j][0] - vecCenter[0]);
|
||||
points[j][1] = fScaleY * (points[j][1] - vecCenter[1]);
|
||||
}
|
||||
|
||||
pDC->MoveTo(pt.x + (int)points[1][0], pt.y - (int)points[1][1]);
|
||||
pDC->LineTo(pt.x + (int)points[0][0], pt.y - (int)points[0][1]);
|
||||
pDC->LineTo(pt.x + (int)points[3][0], pt.y - (int)points[3][1]);
|
||||
pDC->LineTo(pt.x + (int)points[2][0], pt.y - (int)points[2][1]);
|
||||
}
|
||||
|
||||
// Close the cross-section off...
|
||||
if ( fArc != 360.0f )
|
||||
{
|
||||
pDC->LineTo(pt.x + (int)points[1][0], pt.y - (int)points[1][1]);
|
||||
}
|
||||
|
||||
pDC->SelectObject(pOldPen);
|
||||
}
|
||||
303
hammer/VGuiWnd.cpp
Normal file
303
hammer/VGuiWnd.cpp
Normal file
@@ -0,0 +1,303 @@
|
||||
//===== Copyright © 1996-2007, Valve Corporation, All rights reserved. ======//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $Workfile: $
|
||||
// $Date: $
|
||||
// $NoKeywords: $
|
||||
//===========================================================================//
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "vguiwnd.h"
|
||||
#include <vgui_controls/EditablePanel.h>
|
||||
#include "vgui/ISurface.h"
|
||||
#include "vgui/IVGui.h"
|
||||
#include "VGuiMatSurface/IMatSystemSurface.h"
|
||||
#include "HammerVGui.h"
|
||||
#include "material.h"
|
||||
#include "istudiorender.h"
|
||||
#include "hammer.h"
|
||||
#include "toolutils/enginetools_int.h"
|
||||
#include "toolframework/ienginetool.h"
|
||||
#include "ienginevgui.h"
|
||||
|
||||
|
||||
IMPLEMENT_DYNCREATE(CVGuiPanelWnd, CWnd)
|
||||
|
||||
#define REPAINT_TIMER_ID 1042 //random value, hopfully no collisions
|
||||
|
||||
class CBaseMainPanel : public vgui::EditablePanel
|
||||
{
|
||||
public:
|
||||
|
||||
CBaseMainPanel(Panel *parent, const char *panelName) : vgui::EditablePanel( parent, panelName ) {};
|
||||
|
||||
virtual void OnSizeChanged(int newWide, int newTall)
|
||||
{
|
||||
// call Panel and not EditablePanel OnSizeChanged.
|
||||
Panel::OnSizeChanged(newWide, newTall);
|
||||
}
|
||||
};
|
||||
|
||||
LRESULT CVGuiPanelWnd::WindowProc( UINT message, WPARAM wParam, LPARAM lParam )
|
||||
{
|
||||
if ( !WindowProcVGui( message, wParam, lParam ) )
|
||||
{
|
||||
return CWnd::WindowProc( message, wParam, lParam ) ;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
BOOL CVGuiPanelWnd::OnEraseBkgnd(CDC* pDC)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BEGIN_MESSAGE_MAP(CVGuiPanelWnd, CWnd)
|
||||
ON_WM_ERASEBKGND()
|
||||
END_MESSAGE_MAP()
|
||||
|
||||
CVGuiWnd::CVGuiWnd(void)
|
||||
{
|
||||
m_pMainPanel = NULL;
|
||||
m_pParentWnd = NULL;
|
||||
m_hVGuiContext = vgui::DEFAULT_VGUI_CONTEXT;
|
||||
m_bIsDrawing = false;
|
||||
m_ClearColor.SetColor( 0,0,0,255 );
|
||||
m_bClearZBuffer = true;
|
||||
}
|
||||
|
||||
CVGuiWnd::~CVGuiWnd(void)
|
||||
{
|
||||
if ( HammerVGui()->HasFocus( this ) )
|
||||
{
|
||||
HammerVGui()->SetFocus( NULL );
|
||||
}
|
||||
|
||||
if ( m_hVGuiContext != vgui::DEFAULT_VGUI_CONTEXT )
|
||||
{
|
||||
vgui::ivgui()->DestroyContext( m_hVGuiContext );
|
||||
m_hVGuiContext = vgui::DEFAULT_VGUI_CONTEXT;
|
||||
}
|
||||
|
||||
// kill the timer if any
|
||||
::KillTimer( m_pParentWnd->GetSafeHwnd(), REPAINT_TIMER_ID );
|
||||
|
||||
|
||||
if ( m_pMainPanel )
|
||||
m_pMainPanel->MarkForDeletion();
|
||||
}
|
||||
|
||||
void CVGuiWnd::SetParentWindow(CWnd *pParent)
|
||||
{
|
||||
m_pParentWnd = pParent;
|
||||
|
||||
m_pParentWnd->EnableWindow( true );
|
||||
m_pParentWnd->SetFocus();
|
||||
}
|
||||
|
||||
int CVGuiWnd::GetVGuiContext()
|
||||
{
|
||||
return m_hVGuiContext;
|
||||
}
|
||||
|
||||
void CVGuiWnd::SetCursor(vgui::HCursor cursor)
|
||||
{
|
||||
if ( m_pMainPanel )
|
||||
{
|
||||
m_pMainPanel->SetCursor( cursor );
|
||||
}
|
||||
}
|
||||
|
||||
void CVGuiWnd::SetCursor(const char *filename)
|
||||
{
|
||||
vgui::HCursor hCursor = vgui::surface()->CreateCursorFromFile( filename );
|
||||
m_pMainPanel->SetCursor( hCursor );
|
||||
}
|
||||
|
||||
void CVGuiWnd::SetMainPanel( vgui::EditablePanel * pPanel )
|
||||
{
|
||||
Assert( m_pMainPanel == NULL );
|
||||
Assert( m_hVGuiContext == vgui::DEFAULT_VGUI_CONTEXT );
|
||||
|
||||
m_pMainPanel = pPanel;
|
||||
|
||||
m_pMainPanel->SetParent( vgui::surface()->GetEmbeddedPanel() );
|
||||
m_pMainPanel->SetVisible( true );
|
||||
m_pMainPanel->SetPaintBackgroundEnabled( false );
|
||||
m_pMainPanel->SetCursor( vgui::dc_arrow );
|
||||
|
||||
// Initially, don't trap mouse input in case the engine is around (if we have this set to true and they go to the engine,
|
||||
// it'll hog mouse input that the engine should get).
|
||||
m_pMainPanel->SetMouseInputEnabled( false );
|
||||
|
||||
m_hVGuiContext = vgui::ivgui()->CreateContext();
|
||||
vgui::ivgui()->AssociatePanelWithContext( m_hVGuiContext, m_pMainPanel->GetVPanel() );
|
||||
}
|
||||
|
||||
vgui::EditablePanel *CVGuiWnd::CreateDefaultPanel()
|
||||
{
|
||||
return new CBaseMainPanel( NULL, "mainpanel" );
|
||||
}
|
||||
|
||||
vgui::EditablePanel *CVGuiWnd::GetMainPanel()
|
||||
{
|
||||
return m_pMainPanel;
|
||||
}
|
||||
|
||||
CWnd *CVGuiWnd::GetParentWnd()
|
||||
{
|
||||
return m_pParentWnd;
|
||||
}
|
||||
|
||||
void CVGuiWnd::SetRepaintInterval( int msecs )
|
||||
{
|
||||
::SetTimer( m_pParentWnd->GetSafeHwnd(), REPAINT_TIMER_ID, msecs, NULL );
|
||||
}
|
||||
|
||||
void CVGuiWnd::DrawVGuiPanel()
|
||||
{
|
||||
if ( !m_pMainPanel || !m_pParentWnd || m_bIsDrawing )
|
||||
return;
|
||||
|
||||
m_bIsDrawing = true; // avoid recursion
|
||||
|
||||
HWND hWnd = m_pParentWnd->GetSafeHwnd();
|
||||
|
||||
int w,h;
|
||||
RECT rect; ::GetClientRect(hWnd, &rect);
|
||||
CMatRenderContextPtr pRenderContext( MaterialSystemInterface() );
|
||||
|
||||
MaterialSystemInterface()->SetView( hWnd );
|
||||
|
||||
pRenderContext->Viewport( 0, 0, rect.right, rect.bottom );
|
||||
|
||||
pRenderContext->ClearColor4ub( m_ClearColor.r(), m_ClearColor.g(), m_ClearColor.b(), m_ClearColor.a() );
|
||||
|
||||
pRenderContext->ClearBuffers( true, m_bClearZBuffer );
|
||||
|
||||
MaterialSystemInterface()->BeginFrame( 0 );
|
||||
g_pStudioRender->BeginFrame();
|
||||
|
||||
// draw from the main panel down
|
||||
|
||||
m_pMainPanel->GetSize( w , h );
|
||||
|
||||
if ( w != rect.right || h != rect.bottom )
|
||||
{
|
||||
m_pMainPanel->SetBounds(0, 0, rect.right, rect.bottom );
|
||||
m_pMainPanel->Repaint();
|
||||
}
|
||||
|
||||
HammerVGui()->Simulate();
|
||||
|
||||
// Don't draw the engine's vgui stuff when in .
|
||||
int iWasVisible = -1;
|
||||
vgui::VPANEL hRoot = NULL;
|
||||
if ( APP()->IsFoundryMode() && enginevgui )
|
||||
{
|
||||
hRoot = enginevgui->GetPanel( PANEL_ROOT );
|
||||
iWasVisible = g_pVGuiPanel->IsVisible( hRoot );
|
||||
g_pVGuiPanel->SetVisible( hRoot, false );
|
||||
}
|
||||
|
||||
vgui::surface()->RestrictPaintToSinglePanel( m_pMainPanel->GetVPanel(), true );
|
||||
vgui::surface()->PaintTraverseEx( m_pMainPanel->GetVPanel(), true );
|
||||
vgui::surface()->RestrictPaintToSinglePanel( NULL );
|
||||
|
||||
if ( iWasVisible != -1 )
|
||||
{
|
||||
g_pVGuiPanel->SetVisible( hRoot, (iWasVisible != 0) );
|
||||
}
|
||||
|
||||
g_pStudioRender->EndFrame();
|
||||
MaterialSystemInterface()->EndFrame();
|
||||
|
||||
MaterialSystemInterface()->SwapBuffers();
|
||||
|
||||
if ( enginetools )
|
||||
{
|
||||
MaterialSystemInterface()->SetView( enginetools->GetEngineHwnd() );
|
||||
}
|
||||
|
||||
m_bIsDrawing = false;
|
||||
}
|
||||
|
||||
LRESULT CVGuiWnd::WindowProcVGui( UINT uMsg, WPARAM wParam, LPARAM lParam )
|
||||
{
|
||||
switch(uMsg)
|
||||
{
|
||||
|
||||
case WM_GETDLGCODE :
|
||||
{
|
||||
// forward all keyboard into to vgui panel
|
||||
return DLGC_WANTALLKEYS|DLGC_WANTCHARS;
|
||||
}
|
||||
|
||||
case WM_PAINT :
|
||||
{
|
||||
// draw the VGUI panel now
|
||||
DrawVGuiPanel();
|
||||
break;
|
||||
}
|
||||
|
||||
case WM_TIMER :
|
||||
{
|
||||
if ( wParam == REPAINT_TIMER_ID )
|
||||
{
|
||||
m_pParentWnd->Invalidate();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case WM_SETCURSOR:
|
||||
return 1; // don't pass WM_SETCURSOR
|
||||
|
||||
case WM_LBUTTONDOWN:
|
||||
case WM_RBUTTONDOWN:
|
||||
case WM_MBUTTONDOWN:
|
||||
case WM_MOUSEMOVE:
|
||||
{
|
||||
// switch vgui focus to this panel
|
||||
HammerVGui()->SetFocus( this );
|
||||
|
||||
// request keyboard focus too on mouse down
|
||||
if ( uMsg != WM_MOUSEMOVE)
|
||||
{
|
||||
m_pParentWnd->Invalidate();
|
||||
m_pParentWnd->SetFocus();
|
||||
}
|
||||
break;
|
||||
}
|
||||
case WM_KILLFOCUS:
|
||||
{
|
||||
// restore normal arrow cursor when mouse leaves VGUI panel
|
||||
SetCursor( vgui::dc_arrow );
|
||||
break;
|
||||
}
|
||||
|
||||
case WM_LBUTTONUP:
|
||||
case WM_RBUTTONUP:
|
||||
case WM_MBUTTONUP:
|
||||
case WM_LBUTTONDBLCLK:
|
||||
case WM_RBUTTONDBLCLK:
|
||||
case WM_MBUTTONDBLCLK:
|
||||
case WM_MOUSEWHEEL:
|
||||
case WM_KEYDOWN:
|
||||
case WM_SYSKEYDOWN:
|
||||
case WM_SYSCHAR:
|
||||
case WM_CHAR:
|
||||
case WM_KEYUP:
|
||||
case WM_SYSKEYUP:
|
||||
{
|
||||
// redraw window
|
||||
if ( m_pParentWnd )
|
||||
{
|
||||
m_pParentWnd->Invalidate();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
77
hammer/VGuiWnd.h
Normal file
77
hammer/VGuiWnd.h
Normal file
@@ -0,0 +1,77 @@
|
||||
#pragma once
|
||||
#include "afxwin.h"
|
||||
#include "color.h"
|
||||
|
||||
namespace vgui
|
||||
{
|
||||
class EditablePanel;
|
||||
typedef unsigned long HCursor;
|
||||
}
|
||||
|
||||
class CVGuiWnd
|
||||
{
|
||||
|
||||
public:
|
||||
CVGuiWnd(void);
|
||||
~CVGuiWnd(void);
|
||||
|
||||
public:
|
||||
|
||||
void SetMainPanel( vgui::EditablePanel * pPanel );
|
||||
vgui::EditablePanel *GetMainPanel(); // returns VGUI main panel
|
||||
vgui::EditablePanel *CreateDefaultPanel();
|
||||
|
||||
void SetParentWindow(CWnd *pParent);
|
||||
CWnd *GetParentWnd(); // return CWnd handle
|
||||
|
||||
void SetCursor(vgui::HCursor cursor);
|
||||
void SetCursor(const char *filename);
|
||||
|
||||
void SetRepaintInterval( int msecs );
|
||||
int GetVGuiContext();
|
||||
|
||||
// The Hammer 2D views basically ignore vgui input. They're only there to render on top of.
|
||||
// When we pass true here, CMatSystemSurface::RunFrame ignores all the input events.
|
||||
// If we pass false (as the model browser does), then it does process input events and send them to the vgui panels.
|
||||
// Eventually, we could change the 2D views' input events to come from the input system instead of from MFC.
|
||||
virtual bool IsModal()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
void DrawVGuiPanel(); // overridden to draw this view
|
||||
long WindowProcVGui( UINT message, WPARAM wParam, LPARAM lParam ); //
|
||||
|
||||
vgui::EditablePanel *m_pMainPanel;
|
||||
CWnd *m_pParentWnd;
|
||||
int m_hVGuiContext;
|
||||
bool m_bIsDrawing;
|
||||
Color m_ClearColor;
|
||||
bool m_bClearZBuffer;
|
||||
};
|
||||
|
||||
class CVGuiPanelWnd: public CWnd, public CVGuiWnd
|
||||
{
|
||||
protected:
|
||||
DECLARE_DYNCREATE(CVGuiPanelWnd)
|
||||
|
||||
public:
|
||||
|
||||
// Generated message map functions
|
||||
//{{AFX_MSG(CVGuiViewModel)
|
||||
BOOL OnEraseBkgnd(CDC* pDC);
|
||||
//}}AFX_MSG
|
||||
|
||||
virtual LRESULT WindowProc( UINT message, WPARAM wParam, LPARAM lParam );
|
||||
|
||||
// See CVGuiWnd's function for a description but this basically tells Hammer to actually pass vgui messages to our panel.
|
||||
virtual bool IsModal()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
DECLARE_MESSAGE_MAP()
|
||||
};
|
||||
|
||||
1492
hammer/_vpc_/manifest_hammer_dll/win32/manifest.txt
Normal file
1492
hammer/_vpc_/manifest_hammer_dll/win32/manifest.txt
Normal file
File diff suppressed because it is too large
Load Diff
281
hammer/activeitemlist.h
Normal file
281
hammer/activeitemlist.h
Normal file
@@ -0,0 +1,281 @@
|
||||
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $Workfile: $
|
||||
// $Date: $
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
// $Log: $
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef ACTIVEITEMLIST_H
|
||||
#define ACTIVEITEMLIST_H
|
||||
#pragma once
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include <tier0/memdbgon.h>
|
||||
|
||||
//=============================================================================
|
||||
|
||||
typedef int ITEM_HANDLE;
|
||||
|
||||
//=============================================================================
|
||||
|
||||
template <class T> class ActiveItemList
|
||||
{
|
||||
public:
|
||||
|
||||
ActiveItemList();
|
||||
ActiveItemList( int size );
|
||||
|
||||
void SetSize( int size );
|
||||
int GetSize( void );
|
||||
|
||||
int GetNumberOfItems( void );
|
||||
T* GetFirstItem( void );
|
||||
T* GetNextItem( void );
|
||||
|
||||
ITEM_HANDLE GetEmptyItemHandle( void );
|
||||
|
||||
T* GetItem( ITEM_HANDLE handle );
|
||||
void RemoveItem( ITEM_HANDLE handle );
|
||||
|
||||
void SetActiveItem( ITEM_HANDLE handle );
|
||||
T* GetActiveItem( void );
|
||||
|
||||
void Free( void );
|
||||
|
||||
protected:
|
||||
|
||||
int m_NumItems; // the number of items in the list
|
||||
int m_ActiveItem; // the active item index
|
||||
int m_CurrentItem;
|
||||
int m_ListSize; // size of the list
|
||||
T *m_pList; // the active item list
|
||||
bool *m_pEmptyList; // keep an empty list
|
||||
};
|
||||
|
||||
//=============================================================================
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
template <class T> ActiveItemList<T>::ActiveItemList()
|
||||
{
|
||||
m_NumItems = 0;
|
||||
m_ActiveItem = -1;
|
||||
m_CurrentItem = -1;
|
||||
m_ListSize = 0;
|
||||
m_pList = NULL;
|
||||
m_pEmptyList = NULL;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
template <class T> ActiveItemList<T>::ActiveItemList( int size )
|
||||
{
|
||||
int i; // loop counter
|
||||
|
||||
// set the size of the list
|
||||
m_ListSize = size;
|
||||
|
||||
//
|
||||
// allocate memory for the list
|
||||
//
|
||||
if( !( m_pList = new T[size] ) )
|
||||
return;
|
||||
|
||||
if( !( m_pEmptyList = new bool[size] ) )
|
||||
return;
|
||||
|
||||
//
|
||||
// initialize the active item list
|
||||
//
|
||||
m_NumItems = 0;
|
||||
m_ActiveItem = -1;
|
||||
m_CurrentItem = -1;
|
||||
|
||||
for( i = 0; i < size; i++ )
|
||||
m_pEmptyList[i] = true;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
template <class T> void ActiveItemList<T>::SetSize( int size )
|
||||
{
|
||||
int i; // loop counter
|
||||
|
||||
// set the size of the list
|
||||
m_ListSize = size;
|
||||
|
||||
//
|
||||
// allocate memory for the list
|
||||
//
|
||||
if( !( m_pList = new T[size] ) )
|
||||
return;
|
||||
|
||||
if( !( m_pEmptyList = new bool[size] ) )
|
||||
return;
|
||||
|
||||
//
|
||||
// initialize the active item list
|
||||
//
|
||||
m_NumItems = 0;
|
||||
m_ActiveItem = -1;
|
||||
m_CurrentItem = -1;
|
||||
|
||||
for( i = 0; i < size; i++ )
|
||||
m_pEmptyList[i] = true;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
template <class T> int ActiveItemList<T>::GetSize( void )
|
||||
{
|
||||
return m_ListSize;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
template <class T> int ActiveItemList<T>::GetNumberOfItems( void )
|
||||
{
|
||||
return m_NumItems;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
template <class T> T* ActiveItemList<T>::GetFirstItem( void )
|
||||
{
|
||||
int i; // loop counter
|
||||
|
||||
// reset current item index
|
||||
m_CurrentItem = -1;
|
||||
|
||||
//
|
||||
// find the first item in the list
|
||||
//
|
||||
for( i = 0; i < m_ListSize; i++ )
|
||||
{
|
||||
if( !m_pEmptyList[i] )
|
||||
{
|
||||
m_CurrentItem = i;
|
||||
return &m_pList[i];
|
||||
}
|
||||
}
|
||||
|
||||
// no items found
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
template <class T> T* ActiveItemList<T>::GetNextItem( void )
|
||||
{
|
||||
int i; // loop counter
|
||||
|
||||
//
|
||||
// find the next item in the list
|
||||
//
|
||||
for( i = m_CurrentItem + 1; i < m_ListSize; i++ )
|
||||
{
|
||||
if( !m_pEmptyList[i] )
|
||||
{
|
||||
m_CurrentItem = i;
|
||||
return &m_pList[i];
|
||||
}
|
||||
}
|
||||
|
||||
// no more items found
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
template <class T> ITEM_HANDLE ActiveItemList<T>::GetEmptyItemHandle( void )
|
||||
{
|
||||
int i; // loop counter
|
||||
|
||||
//
|
||||
// find an empty item slot and return the handle
|
||||
//
|
||||
for( i = 0; i < m_ListSize; i++ )
|
||||
{
|
||||
if( m_pEmptyList[i] )
|
||||
{
|
||||
m_pEmptyList[i] = false;
|
||||
m_NumItems++;
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
// no empty item slot
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
template <class T> T* ActiveItemList<T>::GetItem( ITEM_HANDLE handle )
|
||||
{
|
||||
return &m_pList[handle];
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
template <class T> void ActiveItemList<T>::RemoveItem( ITEM_HANDLE handle )
|
||||
{
|
||||
//
|
||||
// set the item to empty and decrement the number of items in list
|
||||
//
|
||||
m_pEmptyList[handle] = true;
|
||||
m_NumItems--;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
template <class T> void ActiveItemList<T>::SetActiveItem( ITEM_HANDLE handle )
|
||||
{
|
||||
// set the active item
|
||||
m_ActiveItem = handle;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
template <class T> T* ActiveItemList<T>::GetActiveItem( void )
|
||||
{
|
||||
if( m_ActiveItem == -1 )
|
||||
return NULL;
|
||||
|
||||
return &m_pList[m_ActiveItem];
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
template <class T> void ActiveItemList<T>::Free( void )
|
||||
{
|
||||
//
|
||||
// clean up lists
|
||||
//
|
||||
if( m_pList )
|
||||
delete [] m_pList;
|
||||
|
||||
if( m_pEmptyList )
|
||||
delete [] m_pEmptyList;
|
||||
}
|
||||
|
||||
|
||||
#endif // ACTIVEITEMLIST_H
|
||||
562
hammer/anglebox.cpp
Normal file
562
hammer/anglebox.cpp
Normal file
@@ -0,0 +1,562 @@
|
||||
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: Implements the angle custom control, a circle with a line indicating
|
||||
// a rotation angle.
|
||||
//
|
||||
//=============================================================================//
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "hammer.h"
|
||||
#include "AngleBox.h"
|
||||
#include "hammer_mathlib.h"
|
||||
#include "CustomMessages.h"
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
#pragma warning(disable: 4244)
|
||||
|
||||
|
||||
BEGIN_MESSAGE_MAP(CAngleBox, CWnd)
|
||||
//{{AFX_MSG_MAP(CAngleBox)
|
||||
ON_WM_MOUSEMOVE()
|
||||
ON_WM_LBUTTONUP()
|
||||
ON_WM_LBUTTONDOWN()
|
||||
ON_WM_PAINT()
|
||||
//}}AFX_MSG_MAP
|
||||
END_MESSAGE_MAP()
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Constructor.
|
||||
//-----------------------------------------------------------------------------
|
||||
CAngleBox::CAngleBox(void)
|
||||
{
|
||||
m_vecAngles.Init();
|
||||
m_bDragging = false;
|
||||
m_pEdit = NULL;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Destructor.
|
||||
//-----------------------------------------------------------------------------
|
||||
CAngleBox::~CAngleBox()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : nFlags -
|
||||
// point -
|
||||
//-----------------------------------------------------------------------------
|
||||
void CAngleBox::OnMouseMove(UINT nFlags, CPoint point)
|
||||
{
|
||||
if (m_bDragging)
|
||||
{
|
||||
//
|
||||
// Remove old angle line by redrawing it (XOR).
|
||||
//
|
||||
DrawAngleLine(&m_DragDC);
|
||||
|
||||
//
|
||||
// Calculate new yaw.
|
||||
//
|
||||
int nNewYaw = fixang(180 - (int)lineangle(point.x, point.y, m_ptClientCenter.x, m_ptClientCenter.y));
|
||||
m_vecAngles.Init();
|
||||
m_vecAngles[YAW] = nNewYaw;
|
||||
|
||||
//
|
||||
// Draw the new angle line.
|
||||
//
|
||||
DrawAngleLine(&m_DragDC);
|
||||
}
|
||||
|
||||
CWnd::OnMouseMove(nFlags, point);
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : nFlags -
|
||||
// point -
|
||||
//-----------------------------------------------------------------------------
|
||||
void CAngleBox::OnLButtonUp(UINT nFlags, CPoint point)
|
||||
{
|
||||
// release dc
|
||||
if (m_bDragging)
|
||||
{
|
||||
::ReleaseDC(m_hWnd, m_DragDC.Detach());
|
||||
m_bDragging = false;
|
||||
ReleaseCapture();
|
||||
|
||||
//
|
||||
// They've explicity set the angles, so clear the different flag for
|
||||
// the multiselect case.
|
||||
//
|
||||
SetDifferent(false);
|
||||
|
||||
GetParent()->PostMessage(ABN_CHANGED, GetDlgCtrlID(), 0);
|
||||
}
|
||||
|
||||
CWnd::OnLButtonUp(nFlags, point);
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : nFlags -
|
||||
// point -
|
||||
//-----------------------------------------------------------------------------
|
||||
void CAngleBox::OnLButtonDown(UINT nFlags, CPoint point)
|
||||
{
|
||||
//
|
||||
// Start dragging.
|
||||
//
|
||||
m_DragDC.Attach(::GetDC(m_hWnd));
|
||||
m_bDragging = true;
|
||||
SetCapture();
|
||||
|
||||
CWnd::OnLButtonDown(nFlags, point);
|
||||
|
||||
OnMouseMove(0, point);
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : pDC -
|
||||
//-----------------------------------------------------------------------------
|
||||
void CAngleBox::DrawAngleLine(CDC *pDC)
|
||||
{
|
||||
if ((m_vecAngles[PITCH] != 0) || (m_vecAngles[ROLL] != 0) ||
|
||||
(m_vecAngles[YAW] < 0 || m_vecAngles[YAW] > 359) || m_bDifferent)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
pDC->SetROP2(R2_XORPEN);
|
||||
pDC->SelectStockObject(WHITE_PEN);
|
||||
|
||||
CRect r;
|
||||
GetClientRect(r);
|
||||
m_ptClientCenter = r.CenterPoint();
|
||||
|
||||
double rad = r.Width() / 2 - 3;
|
||||
|
||||
CPoint pt;
|
||||
pt.x = m_ptClientCenter.x + sin(DEG2RAD((double)(m_vecAngles[YAW] + 90))) * rad + 0.5;
|
||||
pt.y = m_ptClientCenter.y + cos(DEG2RAD((double)(m_vecAngles[YAW] + 90))) * rad + 0.5;
|
||||
|
||||
pDC->MoveTo(m_ptClientCenter);
|
||||
pDC->LineTo(pt);
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Returns the current state of the control as a keyvalue string.
|
||||
// Input : szAngles - Buffer to receive angles string.
|
||||
// Output : Returns 'szAngles'.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CAngleBox::GetAngles(QAngle &vecAngles)
|
||||
{
|
||||
if (m_bDifferent)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
vecAngles = m_vecAngles;
|
||||
|
||||
return(true);
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Returns the current state of the control as a keyvalue string.
|
||||
// Input : szAngles - Buffer to receive angles string.
|
||||
// Output : Returns 'szAngles'.
|
||||
//-----------------------------------------------------------------------------
|
||||
char *CAngleBox::GetAngles(char *szAngles)
|
||||
{
|
||||
QAngle vecAngles;
|
||||
GetAngles(vecAngles);
|
||||
sprintf(szAngles, "%g %g %g", (double)vecAngles[0], (double)vecAngles[1], (double)vecAngles[2]);
|
||||
return(szAngles);
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Returns a string indicating the current state of the angle control.
|
||||
// This is used for setting the text in the companion edit control.
|
||||
// Input : szBuf - Buffer to receive string.
|
||||
//-----------------------------------------------------------------------------
|
||||
char *CAngleBox::GetAngleEditText(char *szBuf)
|
||||
{
|
||||
szBuf[0] = '\0';
|
||||
|
||||
if (m_bDifferent)
|
||||
{
|
||||
strcpy(szBuf, "(diff)");
|
||||
}
|
||||
else if ((m_vecAngles[PITCH] == 90) && (m_vecAngles[YAW] == 0) && (m_vecAngles[ROLL] == 0))
|
||||
{
|
||||
strcpy(szBuf, "Down");
|
||||
}
|
||||
else if ((m_vecAngles[PITCH] == -90) && (m_vecAngles[YAW] == 0) && (m_vecAngles[ROLL] == 0))
|
||||
{
|
||||
strcpy(szBuf, "Up");
|
||||
}
|
||||
else if (m_vecAngles[YAW] >= 0)
|
||||
{
|
||||
itoa((int)m_vecAngles[YAW], szBuf, 10);
|
||||
}
|
||||
|
||||
return(szBuf);
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Called internally and by the linked combo box, this updates the angles
|
||||
// without updating the linked combo box.
|
||||
// Input : szAngles -
|
||||
// bRedraw -
|
||||
//-----------------------------------------------------------------------------
|
||||
void CAngleBox::SetAnglesInternal(const QAngle &vecAngles, bool bRedraw)
|
||||
{
|
||||
QAngle vecAngleSet = vecAngles;
|
||||
while (vecAngleSet[YAW] < 0)
|
||||
{
|
||||
vecAngleSet[YAW] += 360.0;
|
||||
}
|
||||
|
||||
CDC *pDC = NULL;
|
||||
|
||||
if (bRedraw)
|
||||
{
|
||||
//
|
||||
// Erase the old line.
|
||||
//
|
||||
Assert(::IsWindow(m_hWnd));
|
||||
pDC = GetDC();
|
||||
if (pDC != NULL)
|
||||
{
|
||||
DrawAngleLine(pDC);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Update the data member.
|
||||
//
|
||||
m_vecAngles = vecAngleSet;
|
||||
|
||||
if ((bRedraw) && (pDC != NULL))
|
||||
{
|
||||
//
|
||||
// Draw the new line.
|
||||
//
|
||||
DrawAngleLine(pDC);
|
||||
ReleaseDC(pDC);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Called from the client code, this sets our angles and updates the
|
||||
// linked combo box.
|
||||
// Input : szAngles -
|
||||
// bRedraw -
|
||||
//-----------------------------------------------------------------------------
|
||||
void CAngleBox::SetAngles(const QAngle &vecAngles, bool bRedraw)
|
||||
{
|
||||
SetAnglesInternal(vecAngles, bRedraw);
|
||||
UpdateAngleEditText();
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Called from the client code, this sets our angles via a string and
|
||||
// updates the linked combo box.
|
||||
// Input : szAngles -
|
||||
// bRedraw -
|
||||
//-----------------------------------------------------------------------------
|
||||
void CAngleBox::SetAngles(const char *szAngles, bool bRedraw)
|
||||
{
|
||||
QAngle vecAngles(0, 0, 0);
|
||||
sscanf(szAngles, "%f %f %f", &vecAngles[PITCH], &vecAngles[YAW], &vecAngles[ROLL]);
|
||||
SetAngles(vecAngles, bRedraw);
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Called internally and by the linked combo box, this sets our
|
||||
// 'different' state without updating the linked combo box.
|
||||
// Input : bDifferent -
|
||||
// bRedraw -
|
||||
//-----------------------------------------------------------------------------
|
||||
void CAngleBox::SetDifferentInternal(bool bDifferent, bool bRedraw)
|
||||
{
|
||||
CDC *pDC = NULL;
|
||||
|
||||
if (bRedraw)
|
||||
{
|
||||
//
|
||||
// Erase the old line.
|
||||
//
|
||||
Assert(::IsWindow(m_hWnd));
|
||||
pDC = GetDC();
|
||||
if (pDC != NULL)
|
||||
{
|
||||
DrawAngleLine(pDC);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Update the data member.
|
||||
//
|
||||
m_bDifferent = bDifferent;
|
||||
|
||||
if ((bRedraw) && (pDC != NULL))
|
||||
{
|
||||
//
|
||||
// Draw the new line.
|
||||
//
|
||||
DrawAngleLine(pDC);
|
||||
ReleaseDC(pDC);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Sets our state to indicate multiselect of objects with different
|
||||
// angles to avoid mucking with the angles unless they explicitly set
|
||||
// them to something new.
|
||||
//-----------------------------------------------------------------------------
|
||||
void CAngleBox::SetDifferent(bool bDifferent, bool bRedraw)
|
||||
{
|
||||
SetDifferentInternal(bDifferent, bRedraw);
|
||||
UpdateAngleEditText();
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CAngleBox::OnPaint(void)
|
||||
{
|
||||
PAINTSTRUCT ps;
|
||||
CDC *pDC = BeginPaint(&ps);
|
||||
|
||||
if (pDC == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
CBrush brushWindow(GetSysColor(COLOR_3DFACE));
|
||||
CBrush brushBlack(RGB(0, 0, 0));
|
||||
|
||||
CBrush *pBackBrush = IsWindowEnabled() ? &brushBlack : &brushWindow;
|
||||
|
||||
CRect r;
|
||||
GetClientRect(r);
|
||||
|
||||
//
|
||||
// Fill with the window color.
|
||||
//
|
||||
pDC->FillRect(&r, &brushWindow);
|
||||
|
||||
//
|
||||
// Draw a 3D circle.
|
||||
//
|
||||
m_ptClientCenter = r.CenterPoint();
|
||||
|
||||
pDC->SelectStockObject(NULL_PEN);
|
||||
pDC->SelectObject(pBackBrush);
|
||||
pDC->Ellipse(r);
|
||||
|
||||
CPen hi(PS_SOLID, 2, GetSysColor(COLOR_3DSHADOW));
|
||||
CPen lo(PS_SOLID, 2, GetSysColor(COLOR_3DHILIGHT));
|
||||
|
||||
pDC->SelectObject(hi);
|
||||
pDC->Arc(r, CPoint(r.right, r.top), CPoint(r.left, r.bottom));
|
||||
pDC->SelectObject(lo);
|
||||
pDC->Arc(r, CPoint(r.left, r.bottom), CPoint(r.right, r.top));
|
||||
|
||||
//
|
||||
// Draw center point.
|
||||
//
|
||||
pDC->SetPixel(m_ptClientCenter, RGB(0xff, 0xff, 0xff));
|
||||
|
||||
//
|
||||
// Draw line indicating angles direction.
|
||||
//
|
||||
if (IsWindowEnabled())
|
||||
{
|
||||
DrawAngleLine(pDC);
|
||||
}
|
||||
|
||||
EndPaint(&ps);
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Enables or disables the angles controls.
|
||||
//-----------------------------------------------------------------------------
|
||||
void CAngleBox::Enable(bool bEnable)
|
||||
{
|
||||
if (bEnable)
|
||||
{
|
||||
EnableWindow(TRUE);
|
||||
|
||||
if (m_pEdit)
|
||||
{
|
||||
m_pEdit->EnableWindow(TRUE);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
EnableWindow(FALSE);
|
||||
|
||||
if (m_pEdit)
|
||||
{
|
||||
m_pEdit->EnableWindow(FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
Invalidate(FALSE);
|
||||
UpdateWindow();
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Hides or shows the angles controls.
|
||||
//-----------------------------------------------------------------------------
|
||||
void CAngleBox::Show(bool bShow)
|
||||
{
|
||||
if (bShow)
|
||||
{
|
||||
ShowWindow(SW_SHOW);
|
||||
|
||||
if (m_pEdit)
|
||||
{
|
||||
m_pEdit->ShowWindow(SW_SHOW);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ShowWindow(SW_HIDE);
|
||||
|
||||
if (m_pEdit)
|
||||
{
|
||||
m_pEdit->ShowWindow(SW_HIDE);
|
||||
}
|
||||
}
|
||||
|
||||
Invalidate(FALSE);
|
||||
UpdateWindow();
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Updates the text in the angle combo to reflect the current angles
|
||||
// in the angles control.
|
||||
//-----------------------------------------------------------------------------
|
||||
void CAngleBox::UpdateAngleEditText(void)
|
||||
{
|
||||
if (m_pEdit)
|
||||
{
|
||||
char szBuf[20];
|
||||
GetAngleEditText(szBuf);
|
||||
m_pEdit->SetAnglesInternal(szBuf);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
BEGIN_MESSAGE_MAP(CAngleCombo, CWnd)
|
||||
//{{AFX_MSG_MAP(CAngleBox)
|
||||
ON_CONTROL_REFLECT(CBN_EDITCHANGE, OnChangeAngleEdit)
|
||||
ON_CONTROL_REFLECT(CBN_SELENDOK, OnSelChangeAngleEdit)
|
||||
//}}AFX_MSG_MAP
|
||||
END_MESSAGE_MAP()
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Construktor.
|
||||
//-----------------------------------------------------------------------------
|
||||
CAngleCombo::CAngleCombo()
|
||||
: CComboBox()
|
||||
{
|
||||
m_pBox = NULL;
|
||||
m_bEnableUpdate = true;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : *szAngles -
|
||||
//-----------------------------------------------------------------------------
|
||||
void CAngleCombo::SetAnglesInternal(const char *szAngles)
|
||||
{
|
||||
m_bEnableUpdate = false;
|
||||
SetWindowText(szAngles);
|
||||
m_bEnableUpdate = true;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Handles a change in the contents of the angle edit control.
|
||||
//-----------------------------------------------------------------------------
|
||||
void CAngleCombo::OnChangeAngleEdit(void)
|
||||
{
|
||||
if (m_bEnableUpdate)
|
||||
{
|
||||
char buf[64];
|
||||
GetWindowText(buf, 64);
|
||||
UpdateAngleBox(buf);
|
||||
|
||||
GetParent()->PostMessage(ABN_CHANGED, GetDlgCtrlID(), 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Handles a change in the current selection of the angle edit combo.
|
||||
//-----------------------------------------------------------------------------
|
||||
void CAngleCombo::OnSelChangeAngleEdit(void)
|
||||
{
|
||||
char buf[64];
|
||||
int nSel = GetCurSel();
|
||||
GetLBText(nSel, buf);
|
||||
UpdateAngleBox(buf);
|
||||
|
||||
GetParent()->PostMessage(ABN_CHANGED, GetDlgCtrlID(), 0);
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Updates angle box with the settings from the combo box. Call the
|
||||
// internal functions so we don't get a reflected notification, mucking
|
||||
// up our state.
|
||||
//-----------------------------------------------------------------------------
|
||||
void CAngleCombo::UpdateAngleBox(char *szText)
|
||||
{
|
||||
if (m_pBox)
|
||||
{
|
||||
m_pBox->SetDifferentInternal(false);
|
||||
|
||||
if (V_isdigit(szText[0]))
|
||||
{
|
||||
QAngle vecAngles(0, atoi(szText), 0);
|
||||
m_pBox->SetAnglesInternal(vecAngles, true);
|
||||
}
|
||||
else if (!stricmp(szText, "down"))
|
||||
{
|
||||
m_pBox->SetAnglesInternal(QAngle(90, 0, 0), true);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_pBox->SetAnglesInternal(QAngle(-90, 0, 0), true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
130
hammer/anglebox.h
Normal file
130
hammer/anglebox.h
Normal file
@@ -0,0 +1,130 @@
|
||||
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef ANGLEBOX_H
|
||||
#define ANGLEBOX_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include "mathlib/vector.h"
|
||||
|
||||
|
||||
class CAngleCombo;
|
||||
|
||||
|
||||
class CAngleBox : public CWnd
|
||||
{
|
||||
public:
|
||||
CAngleBox();
|
||||
virtual ~CAngleBox();
|
||||
|
||||
bool GetAngles(QAngle &vecAngles);
|
||||
char *GetAngles(char *szAngles);
|
||||
|
||||
void SetAngles(const QAngle &vecAngles, bool bRedraw = true);
|
||||
void SetAngles(const char *szAngles, bool bRedraw = true);
|
||||
|
||||
void SetDifferent(bool bDifferent, bool bRedraw = true);
|
||||
inline void SetEditControl(CAngleCombo *pEdit);
|
||||
|
||||
char *GetAngleEditText(char *szBuf);
|
||||
|
||||
void Enable(bool bEnable);
|
||||
void Show(bool bShow);
|
||||
|
||||
// ClassWizard generated virtual function overrides
|
||||
//{{AFX_VIRTUAL(CAngleBox)
|
||||
public:
|
||||
//}}AFX_VIRTUAL
|
||||
|
||||
protected:
|
||||
|
||||
void UpdateAngleEditText(void);
|
||||
void UpdateLine(void);
|
||||
void DrawAngleLine(CDC *pDC);
|
||||
|
||||
bool m_bDifferent; // Set to true when we have multiselected objects with different angles.
|
||||
|
||||
CDC m_DragDC; // When dragging w/mouse.
|
||||
CPoint m_ptClientCenter;
|
||||
bool m_bDragging;
|
||||
|
||||
QAngle m_vecAngles;
|
||||
|
||||
CAngleCombo *m_pEdit; // The linked angle edit box, NULL if none.
|
||||
|
||||
// Generated message map functions
|
||||
//{{AFX_MSG(CAngleBox)
|
||||
afx_msg void OnMouseMove(UINT nFlags, CPoint point);
|
||||
afx_msg void OnLButtonUp(UINT nFlags, CPoint point);
|
||||
afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
|
||||
afx_msg void OnPaint();
|
||||
//}}AFX_MSG
|
||||
|
||||
DECLARE_MESSAGE_MAP()
|
||||
|
||||
private:
|
||||
|
||||
friend class CAngleCombo;
|
||||
|
||||
// Functions called by the angle combo to set our state without notification
|
||||
// back to the angle combo.
|
||||
void SetAnglesInternal(const QAngle &vecAngles, bool bRedraw = true);
|
||||
void SetDifferentInternal(bool bDifferent, bool bRedraw = true);
|
||||
};
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CAngleBox::SetEditControl(CAngleCombo *pEdit)
|
||||
{
|
||||
m_pEdit = pEdit;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
class CAngleCombo : public CComboBox
|
||||
{
|
||||
public:
|
||||
|
||||
CAngleCombo();
|
||||
|
||||
inline void SetAngleBox(CAngleBox *pBox);
|
||||
|
||||
protected:
|
||||
|
||||
void UpdateAngleBox(char *szText);
|
||||
|
||||
// Generated message map functions
|
||||
//{{AFX_MSG(CAngleBox)
|
||||
afx_msg void OnChangeAngleEdit();
|
||||
afx_msg void OnSelChangeAngleEdit();
|
||||
//}}AFX_MSG
|
||||
|
||||
DECLARE_MESSAGE_MAP()
|
||||
|
||||
private:
|
||||
|
||||
friend class CAngleBox;
|
||||
|
||||
void SetAnglesInternal(const char *szAngles);
|
||||
|
||||
CAngleBox *m_pBox; // The linked angle box control.
|
||||
bool m_bEnableUpdate; // Whether we forward update notifications to the linked angle box control.
|
||||
};
|
||||
|
||||
|
||||
void CAngleCombo::SetAngleBox(CAngleBox *pBox)
|
||||
{
|
||||
m_pBox = pBox;
|
||||
}
|
||||
|
||||
|
||||
#endif // ANGLEBOX_H
|
||||
291
hammer/archdlg.cpp
Normal file
291
hammer/archdlg.cpp
Normal file
@@ -0,0 +1,291 @@
|
||||
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ====
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "hammer.h"
|
||||
#include "hammer_mathlib.h"
|
||||
#include "ArchDlg.h"
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include <tier0/memdbgon.h>
|
||||
|
||||
|
||||
static LPCTSTR pszSection = "Arch";
|
||||
|
||||
extern void MakeArc(float x1, float y1, float x2, float y2, int npoints,
|
||||
float start_ang, float fArc, float points[][2]);
|
||||
|
||||
|
||||
CArchDlg::CArchDlg(Vector& boxmins, Vector& boxmaxs, CWnd* pParent /*=NULL*/)
|
||||
: CDialog(CArchDlg::IDD, pParent)
|
||||
{
|
||||
bmins = boxmins;
|
||||
bmaxs = boxmaxs;
|
||||
|
||||
//{{AFX_DATA_INIT(CArchDlg)
|
||||
m_iSides = 0;
|
||||
m_iWallWidth = 0;
|
||||
m_iAddHeight = 0;
|
||||
m_fArc = 0.0f;
|
||||
m_fAngle = 0.0f;
|
||||
//}}AFX_DATA_INIT
|
||||
|
||||
// load up old defaults
|
||||
CString str;
|
||||
m_iWallWidth = AfxGetApp()->GetProfileInt(pszSection, "Wall Width", 32);
|
||||
str = AfxGetApp()->GetProfileString(pszSection, "Arc_", "180");
|
||||
m_fArc = atof(str);
|
||||
m_iSides = AfxGetApp()->GetProfileInt(pszSection, "Sides", 8);
|
||||
str = AfxGetApp()->GetProfileString(pszSection, "Start Angle_", "0");
|
||||
m_fAngle = atof(str);
|
||||
m_iAddHeight = AfxGetApp()->GetProfileInt(pszSection, "Add Height", 0);
|
||||
}
|
||||
|
||||
|
||||
void CArchDlg::SaveValues()
|
||||
{
|
||||
CString str;
|
||||
AfxGetApp()->WriteProfileInt(pszSection, "Wall Width", m_iWallWidth);
|
||||
str.Format("%f", m_fArc);
|
||||
AfxGetApp()->WriteProfileString(pszSection, "Arc_", str);
|
||||
AfxGetApp()->WriteProfileInt(pszSection, "Sides", m_iSides);
|
||||
str.Format("%f", m_fAngle);
|
||||
AfxGetApp()->WriteProfileString(pszSection, "Start Angle_", str);
|
||||
AfxGetApp()->WriteProfileInt(pszSection, "Add Height", m_iAddHeight);
|
||||
}
|
||||
|
||||
|
||||
void CArchDlg::DoDataExchange(CDataExchange* pDX)
|
||||
{
|
||||
CDialog::DoDataExchange(pDX);
|
||||
|
||||
//{{AFX_DATA_MAP(CArchDlg)
|
||||
DDX_Control(pDX, IDC_ANGLESPIN, m_cStartAngleSpin);
|
||||
DDX_Control(pDX, IDC_WALLWIDTHSPIN, m_cWallWidthSpin);
|
||||
DDX_Control(pDX, IDC_WALLWIDTH, m_cWallWidth);
|
||||
DDX_Control(pDX, IDC_SIDESSPIN, m_cSidesSpin);
|
||||
DDX_Control(pDX, IDC_SIDES, m_cSides);
|
||||
DDX_Control(pDX, IDC_ARCSPIN, m_cArcSpin);
|
||||
DDX_Control(pDX, IDC_ARC, m_cArc);
|
||||
DDX_Control(pDX, IDC_PREVIEW, m_cPreview);
|
||||
|
||||
DDX_Text(pDX, IDC_WALLWIDTH, m_iWallWidth);
|
||||
DDX_Text(pDX, IDC_SIDES, m_iSides);
|
||||
DDV_MinMaxInt(pDX, m_iSides, 3, 2048);
|
||||
|
||||
DDX_Text(pDX, IDC_ADDHEIGHT, m_iAddHeight);
|
||||
DDX_Text(pDX, IDC_ARC, m_fArc);
|
||||
DDV_MinMaxFloat(pDX, m_fArc, 8.f, 360.f);
|
||||
DDX_Text(pDX, IDC_ANGLE, m_fAngle);
|
||||
DDV_MinMaxFloat(pDX, m_fAngle, 0.f, 360.f);
|
||||
//}}AFX_DATA_MAP
|
||||
}
|
||||
|
||||
|
||||
BEGIN_MESSAGE_MAP(CArchDlg, CDialog)
|
||||
//{{AFX_MSG_MAP(CArchDlg)
|
||||
ON_EN_CHANGE(IDC_ARC, OnChangeArc)
|
||||
ON_BN_CLICKED(IDC_CIRCLE, OnCircle)
|
||||
ON_EN_UPDATE(IDC_SIDES, OnUpdateSides)
|
||||
ON_EN_UPDATE(IDC_WALLWIDTH, OnUpdateWallwidth)
|
||||
ON_WM_PAINT()
|
||||
ON_BN_CLICKED(IDC_ARCH_PREVIEW, OnArchPreview)
|
||||
//}}AFX_MSG_MAP
|
||||
END_MESSAGE_MAP()
|
||||
|
||||
|
||||
void CArchDlg::OnChangeArc()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void CArchDlg::OnCircle()
|
||||
{
|
||||
m_cArcSpin.SetPos(360);
|
||||
}
|
||||
|
||||
|
||||
void CArchDlg::OnUpdateSides()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void CArchDlg::OnUpdateWallwidth()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
BOOL CArchDlg::OnInitDialog()
|
||||
{
|
||||
CDialog::OnInitDialog();
|
||||
|
||||
m_cArcSpin.SetRange(8, 360);
|
||||
m_cSidesSpin.SetRange(3, 100);
|
||||
m_cWallWidthSpin.SetRange(2, m_iMaxWallWidth);
|
||||
m_cStartAngleSpin.SetRange(0, 360);
|
||||
|
||||
m_cPreview.ShowWindow(SW_HIDE);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
void CArchDlg::OnPaint()
|
||||
{
|
||||
CPaintDC dc(this); // device context for painting
|
||||
|
||||
// Do not call CDialog::OnPaint() for painting messages
|
||||
CBrush black(RGB(0,0,0));
|
||||
CBrush grey(RGB(128,128,128));
|
||||
|
||||
CRect rcPreview;
|
||||
m_cPreview.GetWindowRect(&rcPreview);
|
||||
ScreenToClient(&rcPreview);
|
||||
dc.FillRect(rcPreview, &black);
|
||||
|
||||
DrawArch(&dc);
|
||||
rcPreview.InflateRect(1,1);
|
||||
dc.FrameRect(rcPreview, &grey);
|
||||
|
||||
ValidateRect(rcPreview);
|
||||
}
|
||||
|
||||
|
||||
void CArchDlg::OnArchPreview()
|
||||
{
|
||||
//
|
||||
// Build preview.
|
||||
//
|
||||
UpdateData(TRUE);
|
||||
InvalidateRect(NULL);
|
||||
UpdateWindow();
|
||||
}
|
||||
|
||||
|
||||
CArchDlg::~CArchDlg()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void CArchDlg::DrawArch(CDC* pDC)
|
||||
{
|
||||
int i;
|
||||
float fOuterPoints[ARC_MAX_POINTS][2];
|
||||
float fInnerPoints[ARC_MAX_POINTS][2];
|
||||
|
||||
float fScaleX;
|
||||
float fScaleY;
|
||||
|
||||
CPen m_hPen, *pOldPen;
|
||||
|
||||
m_hPen.CreatePen(PS_SOLID, 1, RGB(255,255,255));
|
||||
|
||||
pOldPen = pDC->SelectObject(&m_hPen);
|
||||
|
||||
CRect rcItem;
|
||||
m_cPreview.GetWindowRect(&rcItem);
|
||||
ScreenToClient(&rcItem);
|
||||
|
||||
CPoint pt;
|
||||
pt.x = rcItem.left + rcItem.Width() / 2;
|
||||
pt.y = rcItem.top + rcItem.Height() / 2;
|
||||
|
||||
if (bmaxs[0] - bmins[0])
|
||||
fScaleX = rcItem.Width()/(bmaxs[0] - bmins[0]);
|
||||
else
|
||||
fScaleX = 1.0f;
|
||||
|
||||
if (bmaxs[1] - bmins[1])
|
||||
fScaleY = rcItem.Height()/(bmaxs[1] - bmins[1]);
|
||||
else
|
||||
fScaleY = 1.0f;
|
||||
|
||||
int iSides, iWallWidth;
|
||||
float fArc, fStartAngle;
|
||||
|
||||
fArc = m_fArc;
|
||||
fStartAngle = m_fAngle;
|
||||
iSides = m_iSides;
|
||||
iWallWidth = m_iWallWidth;
|
||||
|
||||
|
||||
MakeArc(bmins[0], bmins[1],
|
||||
bmaxs[0], bmaxs[1], iSides,
|
||||
fStartAngle, fArc, fOuterPoints);
|
||||
|
||||
MakeArc(bmins[0] + iWallWidth,
|
||||
bmins[1] + iWallWidth,
|
||||
bmaxs[0] - iWallWidth,
|
||||
bmaxs[1] - iWallWidth, iSides,
|
||||
fStartAngle, fArc, fInnerPoints);
|
||||
|
||||
|
||||
// check wall width - if it's half or more of the total,
|
||||
// set the inner poinst to the center point of the box
|
||||
// and turn off the CreateSouthFace flag
|
||||
|
||||
BOOL bCreateSouthFace = TRUE;
|
||||
float fCenter[3];
|
||||
for (i = 0; i < 3; i++)
|
||||
fCenter[i] = (bmins[i] + bmaxs[i])/2.0;
|
||||
|
||||
if((iWallWidth*2+8) >= (bmaxs[0] - bmins[0]) ||
|
||||
(iWallWidth*2+8) >= (bmaxs[1] - bmins[1]))
|
||||
{
|
||||
for(int i = 0; i < ARC_MAX_POINTS; i++)
|
||||
{
|
||||
fInnerPoints[i][0] = fCenter[0];
|
||||
fInnerPoints[i][1] = fCenter[1];
|
||||
}
|
||||
bCreateSouthFace = FALSE;
|
||||
}
|
||||
|
||||
for (i = 0; i < iSides; i++)
|
||||
{
|
||||
int iNextPoint = i+1;
|
||||
if (iNextPoint >= iSides + 1)
|
||||
iNextPoint = 0;
|
||||
|
||||
Vector points[4];
|
||||
|
||||
points[0][0] = fOuterPoints[i][0];
|
||||
points[0][1] = fOuterPoints[i][1];
|
||||
|
||||
points[1][0] = fOuterPoints[iNextPoint][0];
|
||||
points[1][1] = fOuterPoints[iNextPoint][1];
|
||||
|
||||
points[2][0] = fInnerPoints[iNextPoint][0];
|
||||
points[2][1] = fInnerPoints[iNextPoint][1];
|
||||
|
||||
points[3][0] = fInnerPoints[i][0];
|
||||
points[3][1] = fInnerPoints[i][1];
|
||||
|
||||
for (int j = 0; j < 4; j++)
|
||||
{
|
||||
points[j][0] = fScaleX * (points[j][0] - fCenter[0]);
|
||||
points[j][1] = fScaleY * (points[j][1] - fCenter[1]);
|
||||
}
|
||||
|
||||
pDC->MoveTo(pt.x + (int)points[0][0], pt.y - (int)points[0][1]);
|
||||
pDC->LineTo(pt.x + (int)points[1][0], pt.y - (int)points[1][1]);
|
||||
pDC->LineTo(pt.x + (int)points[2][0], pt.y - (int)points[2][1]);
|
||||
pDC->LineTo(pt.x + (int)points[3][0], pt.y - (int)points[3][1]);
|
||||
}
|
||||
|
||||
// Draw the bbox
|
||||
/*CPen hPen2;
|
||||
hPen2.CreatePen(PS_SOLID, 1, RGB(255,255,0));
|
||||
|
||||
pDC->SelectObject(&hPen2);
|
||||
|
||||
pDC->MoveTo(pt.x + (int)((bmins[0] - fCenter[0])*fScaleX), pt.y - (int)((bmins[1] - fCenter[1])*fScaleY));
|
||||
pDC->LineTo(pt.x + (int)((bmins[0] - fCenter[0])*fScaleX), pt.y - (int)((bmaxs[1] - fCenter[1])*fScaleY));
|
||||
pDC->LineTo(pt.x + (int)((bmaxs[0] - fCenter[0])*fScaleX), pt.y - (int)((bmaxs[1] - fCenter[1])*fScaleY));
|
||||
pDC->LineTo(pt.x + (int)((bmaxs[0] - fCenter[0])*fScaleX), pt.y - (int)((bmins[1] - fCenter[1])*fScaleY));
|
||||
*/
|
||||
pDC->SelectObject(pOldPen);
|
||||
|
||||
}
|
||||
77
hammer/archdlg.h
Normal file
77
hammer/archdlg.h
Normal file
@@ -0,0 +1,77 @@
|
||||
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ====
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================
|
||||
#if !defined(AFX_ARCHDLG_H__C146AA5D_38FE_11D1_AFC9_0060979D2F4E__INCLUDED_)
|
||||
#define AFX_ARCHDLG_H__C146AA5D_38FE_11D1_AFC9_0060979D2F4E__INCLUDED_
|
||||
|
||||
#if _MSC_VER >= 1000
|
||||
#pragma once
|
||||
#endif // _MSC_VER >= 1000
|
||||
|
||||
#define ARC_MAX_POINTS 4096
|
||||
|
||||
class CArchDlg : public CDialog
|
||||
{
|
||||
// Construction
|
||||
public:
|
||||
CArchDlg(Vector& bmins, Vector& bmaxs, CWnd* pParent = NULL); // standard constructor
|
||||
~CArchDlg(); // standard constructor
|
||||
|
||||
void DrawArch(CDC *pDC);
|
||||
|
||||
float fOuterPoints[ARC_MAX_POINTS][2];
|
||||
float fInnerPoints[ARC_MAX_POINTS][2];
|
||||
Vector bmins, bmaxs;
|
||||
|
||||
// Dialog Data
|
||||
//{{AFX_DATA(CArchDlg)
|
||||
enum { IDD = IDD_ARCH };
|
||||
CSpinButtonCtrl m_cStartAngleSpin;
|
||||
CSpinButtonCtrl m_cWallWidthSpin;
|
||||
CEdit m_cWallWidth;
|
||||
CSpinButtonCtrl m_cSidesSpin;
|
||||
CEdit m_cSides;
|
||||
CSpinButtonCtrl m_cArcSpin;
|
||||
CEdit m_cArc;
|
||||
CStatic m_cPreview;
|
||||
int m_iSides;
|
||||
int m_iWallWidth;
|
||||
int m_iAddHeight;
|
||||
float m_fArc;
|
||||
float m_fAngle;
|
||||
//}}AFX_DATA
|
||||
|
||||
void SetMaxWallWidth(int iMaxWallWidth) { m_iMaxWallWidth = iMaxWallWidth; }
|
||||
void SaveValues();
|
||||
|
||||
// Overrides
|
||||
// ClassWizard generated virtual function overrides
|
||||
//{{AFX_VIRTUAL(CArchDlg)
|
||||
protected:
|
||||
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
|
||||
//}}AFX_VIRTUAL
|
||||
|
||||
// Implementation
|
||||
protected:
|
||||
|
||||
int m_iMaxWallWidth;
|
||||
|
||||
// Generated message map functions
|
||||
//{{AFX_MSG(CArchDlg)
|
||||
afx_msg void OnChangeArc();
|
||||
afx_msg void OnCircle();
|
||||
afx_msg void OnUpdateSides();
|
||||
afx_msg void OnUpdateWallwidth();
|
||||
virtual BOOL OnInitDialog();
|
||||
afx_msg void OnPaint();
|
||||
afx_msg void OnArchPreview();
|
||||
//}}AFX_MSG
|
||||
DECLARE_MESSAGE_MAP()
|
||||
};
|
||||
|
||||
//{{AFX_INSERT_LOCATION}}
|
||||
// Microsoft Developer Studio will insert additional declarations immediately before the previous line.
|
||||
|
||||
#endif // !defined(AFX_ARCHDLG_H__C146AA5D_38FE_11D1_AFC9_0060979D2F4E__INCLUDED_)
|
||||
188
hammer/autoselcombo.cpp
Normal file
188
hammer/autoselcombo.cpp
Normal file
@@ -0,0 +1,188 @@
|
||||
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: Implements a combo box that autoselects items from the list as the
|
||||
// user types in the edit control. It has the additional feature of
|
||||
// being able to easily set the text color.
|
||||
//
|
||||
//=============================================================================//
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "AutoSelCombo.h"
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
|
||||
BEGIN_MESSAGE_MAP(CAutoSelComboBox, CComboBox)
|
||||
//{{AFX_MSG_MAP(CAutoSelComboBox)
|
||||
ON_WM_CTLCOLOR()
|
||||
ON_CONTROL_REFLECT_EX(CBN_EDITUPDATE, OnEditUpdate)
|
||||
//}}AFX_MSG_MAP
|
||||
END_MESSAGE_MAP()
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Constructor.
|
||||
//-----------------------------------------------------------------------------
|
||||
CAutoSelComboBox::CAutoSelComboBox(void)
|
||||
{
|
||||
m_szLastText[0] = '\0';
|
||||
m_dwTextColor = RGB(0, 0, 0);
|
||||
m_bNotifyParent = true;
|
||||
m_nLastSel = -1;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Attaches this object to the given dialog item.
|
||||
//-----------------------------------------------------------------------------
|
||||
void CAutoSelComboBox::SubclassDlgItem(UINT nID, CWnd *pParent)
|
||||
{
|
||||
//
|
||||
// Disable parent notifications for CControlBar-derived classes. This is
|
||||
// necessary because these classes result in multiple message reflections
|
||||
// unless we return TRUE from our message handler.
|
||||
//
|
||||
if (pParent->IsKindOf(RUNTIME_CLASS(CControlBar)))
|
||||
{
|
||||
m_bNotifyParent = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_bNotifyParent = true;
|
||||
}
|
||||
|
||||
BaseClass::SubclassDlgItem(nID, pParent);
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Automatically selects the first matching combo box item when the
|
||||
// edit control's text changes.
|
||||
//-----------------------------------------------------------------------------
|
||||
void CAutoSelComboBox::OnUpdateText(void)
|
||||
{
|
||||
int nCurSel = GetCurSel();
|
||||
int nNewSel = nCurSel;
|
||||
|
||||
DWORD dwEditSel = GetEditSel();
|
||||
int nEditStart = LOWORD(dwEditSel);
|
||||
int nEditEnd = HIWORD(dwEditSel);
|
||||
|
||||
char szTypedText[MAX_PATH];
|
||||
GetWindowText(szTypedText, sizeof(szTypedText));
|
||||
|
||||
//
|
||||
// Select the first match in the list if what they typed is different from
|
||||
// the current selection. This won't do anything if they are deleting characters
|
||||
// from the end of the text.
|
||||
//
|
||||
int nTypedLen = strlen(szTypedText);
|
||||
int nLastLen = strlen(m_szLastText);
|
||||
|
||||
bool bSearched = false;
|
||||
int nIndex = CB_ERR;
|
||||
if (strnicmp(szTypedText, m_szLastText, nTypedLen))
|
||||
{
|
||||
nIndex = FindString(-1, szTypedText);
|
||||
bSearched = true;
|
||||
}
|
||||
else if (nTypedLen < nLastLen)
|
||||
{
|
||||
// They deleted characters, try to match the shorter string exactly.
|
||||
nIndex = FindStringExact(-1, szTypedText);
|
||||
bSearched = true;
|
||||
}
|
||||
|
||||
if (bSearched)
|
||||
{
|
||||
if (nCurSel != nIndex)
|
||||
{
|
||||
SetCurSel(nIndex);
|
||||
nNewSel = nIndex;
|
||||
}
|
||||
|
||||
if (nIndex != CB_ERR)
|
||||
{
|
||||
// Found a match.
|
||||
if ((nEditEnd == -1) || (nEditEnd == (int)strlen(szTypedText)))
|
||||
{
|
||||
SetEditSel(strlen(szTypedText), -1);
|
||||
}
|
||||
else
|
||||
{
|
||||
SetEditSel(nEditStart, nEditEnd);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// No match found.
|
||||
SetWindowText(szTypedText);
|
||||
SetEditSel(nEditStart, nEditEnd);
|
||||
}
|
||||
}
|
||||
|
||||
strcpy(m_szLastText, szTypedText);
|
||||
|
||||
if (nNewSel != m_nLastSel)
|
||||
{
|
||||
GetParent()->SendMessage(WM_COMMAND, MAKEWPARAM(GetDlgCtrlID(), CBN_SELCHANGE), (LPARAM)m_hWnd);
|
||||
m_nLastSel = nNewSel;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
BOOL CAutoSelComboBox::OnEditUpdate(void)
|
||||
{
|
||||
OnUpdateText();
|
||||
|
||||
//
|
||||
// Despite MSDN's lies, returning FALSE here allows the parent
|
||||
// window to hook the notification message as well, not TRUE.
|
||||
//
|
||||
return m_bNotifyParent ? FALSE : TRUE;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Resets the 'last typed text' buffer every time we gain/lose focus.
|
||||
//-----------------------------------------------------------------------------
|
||||
void CAutoSelComboBox::OnSetFocus(CWnd *pOldWnd)
|
||||
{
|
||||
m_szLastText[0] = '\0';
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : dwColor -
|
||||
//-----------------------------------------------------------------------------
|
||||
void CAutoSelComboBox::SetTextColor(COLORREF dwColor)
|
||||
{
|
||||
m_dwTextColor = dwColor;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Called before painting to override default colors.
|
||||
// Input : pDC - DEvice context being painted into.
|
||||
// pWnd - Control asking for color.
|
||||
// nCtlColor - Type of control asking for color.
|
||||
// Output : Returns the handle of a brush to use as the background color.
|
||||
//-----------------------------------------------------------------------------
|
||||
HBRUSH CAutoSelComboBox::OnCtlColor(CDC *pDC, CWnd *pWnd, UINT nCtlColor)
|
||||
{
|
||||
HBRUSH hBrush = CComboBox::OnCtlColor(pDC, pWnd, nCtlColor);
|
||||
|
||||
if (nCtlColor == CTLCOLOR_EDIT)
|
||||
{
|
||||
pDC->SetTextColor(m_dwTextColor);
|
||||
}
|
||||
|
||||
return(hBrush);
|
||||
}
|
||||
|
||||
|
||||
47
hammer/autoselcombo.h
Normal file
47
hammer/autoselcombo.h
Normal file
@@ -0,0 +1,47 @@
|
||||
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef AUTOSELCOMBO_H
|
||||
#define AUTOSELCOMBO_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
|
||||
class CAutoSelComboBox : public CComboBox
|
||||
{
|
||||
typedef CComboBox BaseClass;
|
||||
|
||||
public:
|
||||
|
||||
CAutoSelComboBox(void);
|
||||
|
||||
void SetTextColor(COLORREF dwColor);
|
||||
void SubclassDlgItem(UINT nID, CWnd *pParent);
|
||||
|
||||
protected:
|
||||
|
||||
// Called by OnEditUpdate when the user types in the edit box
|
||||
virtual void OnUpdateText(void);
|
||||
|
||||
protected:
|
||||
|
||||
void OnSetFocus(CWnd *pOldWnd);
|
||||
afx_msg HBRUSH OnCtlColor(CDC *pDC, CWnd *pWnd, UINT nCtlColor);
|
||||
afx_msg BOOL OnEditUpdate(void);
|
||||
|
||||
DWORD m_dwTextColor; // RGB color of edit box text.
|
||||
char m_szLastText[256]; // Last text typed by the user, for autocomplete code.
|
||||
int m_nLastSel; // Index of last item we autoselected.
|
||||
|
||||
bool m_bNotifyParent; // Whether we allow our parent to hook our notification messages.
|
||||
// This is necessary because CControlBar-derived classes result in multiple
|
||||
// message reflections unless we disable parent notification.
|
||||
|
||||
DECLARE_MESSAGE_MAP()
|
||||
};
|
||||
|
||||
#endif // AUTOSELCOMBO_H
|
||||
39
hammer/axes2.cpp
Normal file
39
hammer/axes2.cpp
Normal file
@@ -0,0 +1,39 @@
|
||||
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "Axes2.h"
|
||||
#include "mathlib/vector.h"
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
void Axes2::SetAxes(int h, bool bInvertH, int v, bool bInvertV)
|
||||
{
|
||||
bInvertHorz = bInvertH;
|
||||
bInvertVert = bInvertV;
|
||||
|
||||
axHorz = h;
|
||||
axVert = v;
|
||||
|
||||
if(h != AXIS_X && v != AXIS_X)
|
||||
axThird = AXIS_X;
|
||||
if(h != AXIS_Y && v != AXIS_Y)
|
||||
axThird = AXIS_Y;
|
||||
if(h != AXIS_Z && v != AXIS_Z)
|
||||
axThird = AXIS_Z;
|
||||
}
|
||||
|
||||
void Axes2::SetAxes(Axes2 &axes)
|
||||
{
|
||||
*this = axes;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
40
hammer/axes2.h
Normal file
40
hammer/axes2.h
Normal file
@@ -0,0 +1,40 @@
|
||||
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: Defines a base set of services for operations in an orthorgraphic
|
||||
// projection. This is used as a base class for the 2D view and for
|
||||
// the tools that work in the 2D views.
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef AXES2_H
|
||||
#define AXES2_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include "hammer_mathlib.h"
|
||||
|
||||
class Axes2
|
||||
{
|
||||
public:
|
||||
Axes2()
|
||||
{
|
||||
bInvertHorz = bInvertVert = false;
|
||||
axHorz = AXIS_X;
|
||||
axVert = AXIS_Y;
|
||||
axThird = AXIS_Z;
|
||||
}
|
||||
|
||||
void SetAxes(int h, bool bInvertH, int v, bool bInvertV);
|
||||
void SetAxes(Axes2 &axes);
|
||||
|
||||
bool bInvertHorz; // Whether the horizontal axis is inverted.
|
||||
bool bInvertVert; // Whether the vertical axis is inverted.
|
||||
|
||||
int axHorz; // Index of the horizontal axis (x=0, y=1, z=2)
|
||||
int axVert; // Index of the vertical axis (x=0, y=1, z=2)
|
||||
int axThird; // Index of the "out of the screen" axis (x=0, y=1, z=2)
|
||||
};
|
||||
|
||||
#endif // AXES2_H
|
||||
111
hammer/blockarray.cpp
Normal file
111
hammer/blockarray.cpp
Normal file
@@ -0,0 +1,111 @@
|
||||
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//
|
||||
//=============================================================================//
|
||||
|
||||
#include <windows.h>
|
||||
#include <stdio.h>
|
||||
|
||||
template <class T, int nBlockSize, int nMaxBlocks>
|
||||
class BlockArray
|
||||
{
|
||||
public:
|
||||
BlockArray()
|
||||
{
|
||||
nCount = nBlocks = 0;
|
||||
}
|
||||
~BlockArray()
|
||||
{
|
||||
GetBlocks(0);
|
||||
}
|
||||
|
||||
T& operator[] (int iIndex);
|
||||
|
||||
void SetCount(int nObjects);
|
||||
int GetCount() { return nCount; }
|
||||
|
||||
private:
|
||||
T * Blocks[nMaxBlocks+1];
|
||||
short nCount;
|
||||
short nBlocks;
|
||||
void GetBlocks(int nNewBlocks);
|
||||
};
|
||||
|
||||
/*
|
||||
template <class T, int nBlockSize, int nMaxBlocks>
|
||||
BlockArray<T,BlockSize,nMaxBlocks>::BlockArray()
|
||||
{
|
||||
nCount = nBlocks = 0;
|
||||
}
|
||||
|
||||
template <class T, int nBlockSize, int nMaxBlocks>
|
||||
BlockArray<T,BlockSize,nMaxBlocks>::~BlockArray()
|
||||
{
|
||||
GetBlocks(0); // free blocks
|
||||
}
|
||||
*/
|
||||
|
||||
template <class T, int nBlockSize, int nMaxBlocks>
|
||||
void BlockArray<T,nBlockSize,nMaxBlocks>::
|
||||
GetBlocks(int nNewBlocks)
|
||||
{
|
||||
for(int i = nBlocks; i < nNewBlocks; i++)
|
||||
{
|
||||
Blocks[i] = new T[nBlockSize];
|
||||
}
|
||||
for(i = nNewBlocks; i < nBlocks; i++)
|
||||
{
|
||||
delete[] Blocks[i];
|
||||
}
|
||||
|
||||
nBlocks = nNewBlocks;
|
||||
}
|
||||
|
||||
template <class T, int nBlockSize, int nMaxBlocks>
|
||||
void BlockArray<T,nBlockSize,nMaxBlocks>::
|
||||
SetCount(int nObjects)
|
||||
{
|
||||
if(nObjects == nCount)
|
||||
return;
|
||||
|
||||
// find the number of blocks required by nObjects
|
||||
int nNewBlocks = (nObjects / nBlockSize) + 1;
|
||||
if(nNewBlocks != nBlocks)
|
||||
GetBlocks(nNewBlocks);
|
||||
nCount = nObjects;
|
||||
}
|
||||
|
||||
template <class T, int nBlockSize, int nMaxBlocks>
|
||||
T& BlockArray<T,nBlockSize,nMaxBlocks>::operator[] (int iIndex)
|
||||
{
|
||||
if(iIndex >= nCount)
|
||||
SetCount(iIndex+1);
|
||||
return Blocks[iIndex / nBlockSize][iIndex % nBlockSize];
|
||||
}
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char Name[128];
|
||||
int iValue;
|
||||
} Buffy;
|
||||
|
||||
void main(void)
|
||||
{
|
||||
BlockArray<Buffy, 16, 16> Buffies;
|
||||
|
||||
for(int i = 0; i < 256; i++)
|
||||
{
|
||||
Buffies[i].iValue = i;
|
||||
strcpy(Buffies[i].Name, "Buk bUk buK");
|
||||
}
|
||||
|
||||
for(i = 0; i < 256; i++)
|
||||
{
|
||||
printf("%d: %s\n", Buffies[i].iValue, Buffies[i].Name);
|
||||
}
|
||||
|
||||
Buffies.SetCount(10);
|
||||
}
|
||||
99
hammer/blockarray.h
Normal file
99
hammer/blockarray.h
Normal file
@@ -0,0 +1,99 @@
|
||||
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef _BLOCKARRAY_H
|
||||
#define _BLOCKARRAY_H
|
||||
|
||||
#include "tier0/dbg.h"
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include <tier0/memdbgon.h>
|
||||
|
||||
template <class T, int nBlockSize, int nMaxBlocks>
|
||||
class BlockArray
|
||||
{
|
||||
public:
|
||||
BlockArray()
|
||||
{
|
||||
nCount = nBlocks = 0;
|
||||
}
|
||||
~BlockArray()
|
||||
{
|
||||
GetBlocks(0);
|
||||
}
|
||||
|
||||
T& operator[] (int iIndex);
|
||||
|
||||
void SetCount(int nObjects);
|
||||
int GetCount() { return nCount; }
|
||||
|
||||
private:
|
||||
T * Blocks[nMaxBlocks+1];
|
||||
short nCount;
|
||||
short nBlocks;
|
||||
void GetBlocks(int nNewBlocks);
|
||||
};
|
||||
|
||||
template <class T, int nBlockSize, int nMaxBlocks>
|
||||
void BlockArray<T,nBlockSize,nMaxBlocks>::
|
||||
GetBlocks(int nNewBlocks)
|
||||
{
|
||||
for(int i = nBlocks; i < nNewBlocks; i++)
|
||||
{
|
||||
Blocks[i] = new T[nBlockSize];
|
||||
}
|
||||
for(int i = nNewBlocks; i < nBlocks; i++)
|
||||
{
|
||||
delete[] Blocks[i];
|
||||
}
|
||||
|
||||
nBlocks = nNewBlocks;
|
||||
}
|
||||
|
||||
template <class T, int nBlockSize, int nMaxBlocks>
|
||||
void BlockArray<T,nBlockSize,nMaxBlocks>::
|
||||
SetCount(int nObjects)
|
||||
{
|
||||
if(nObjects == nCount)
|
||||
return;
|
||||
|
||||
// find the number of blocks required by nObjects, checking for
|
||||
// integer rounding error
|
||||
int nNewBlocks = (nObjects / nBlockSize);
|
||||
if ((nNewBlocks * nBlockSize) < nObjects)
|
||||
{
|
||||
nNewBlocks++;
|
||||
}
|
||||
|
||||
if(nNewBlocks != nBlocks)
|
||||
{
|
||||
// Make sure we don't get an overrun.
|
||||
if ( nNewBlocks > ARRAYSIZE( Blocks ) )
|
||||
{
|
||||
Error( "BlockArray< ?, %d, %d > - too many blocks needed.", nBlockSize, nMaxBlocks );
|
||||
}
|
||||
|
||||
GetBlocks(nNewBlocks);
|
||||
}
|
||||
nCount = nObjects;
|
||||
}
|
||||
|
||||
template <class T, int nBlockSize, int nMaxBlocks>
|
||||
T& BlockArray<T,nBlockSize,nMaxBlocks>::operator[] (int iIndex)
|
||||
{
|
||||
if(iIndex >= nCount)
|
||||
{
|
||||
Error( "BlockArray< %d, %d > - invalid block index.", iIndex, nCount );
|
||||
SetCount(iIndex+1);
|
||||
}
|
||||
return Blocks[iIndex / nBlockSize][iIndex % nBlockSize];
|
||||
}
|
||||
|
||||
#include <tier0/memdbgoff.h>
|
||||
|
||||
#endif // _BLOCKARRAY_H
|
||||
275
hammer/boundbox.cpp
Normal file
275
hammer/boundbox.cpp
Normal file
@@ -0,0 +1,275 @@
|
||||
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "BoundBox.h"
|
||||
#include "hammer_mathlib.h"
|
||||
#include "MapDefs.h"
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
BoundBox::BoundBox(void)
|
||||
{
|
||||
ResetBounds();
|
||||
}
|
||||
|
||||
BoundBox::BoundBox(const Vector &mins, const Vector &maxs)
|
||||
{
|
||||
bmins = mins;
|
||||
bmaxs = maxs;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Sets the box to an uninitialized state, so that calls to UpdateBounds
|
||||
// will properly set the mins and maxs.
|
||||
//-----------------------------------------------------------------------------
|
||||
void BoundBox::ResetBounds(void)
|
||||
{
|
||||
bmins[0] = bmins[1] = bmins[2] = COORD_NOTINIT;
|
||||
bmaxs[0] = bmaxs[1] = bmaxs[2] = -COORD_NOTINIT;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : pt -
|
||||
//-----------------------------------------------------------------------------
|
||||
void BoundBox::UpdateBounds(const Vector& pt)
|
||||
{
|
||||
if(pt[0] < bmins[0])
|
||||
bmins[0] = pt[0];
|
||||
if(pt[1] < bmins[1])
|
||||
bmins[1] = pt[1];
|
||||
if(pt[2] < bmins[2])
|
||||
bmins[2] = pt[2];
|
||||
|
||||
if(pt[0] > bmaxs[0])
|
||||
bmaxs[0] = pt[0];
|
||||
if(pt[1] > bmaxs[1])
|
||||
bmaxs[1] = pt[1];
|
||||
if(pt[2] > bmaxs[2])
|
||||
bmaxs[2] = pt[2];
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : bmins -
|
||||
// bmaxs -
|
||||
//-----------------------------------------------------------------------------
|
||||
void BoundBox::UpdateBounds(const Vector& mins, const Vector& maxs)
|
||||
{
|
||||
if(mins[0] < bmins[0])
|
||||
bmins[0] = mins[0];
|
||||
if(mins[1] < bmins[1])
|
||||
bmins[1] = mins[1];
|
||||
if(mins[2] < bmins[2])
|
||||
bmins[2] = mins[2];
|
||||
|
||||
if(maxs[0] > bmaxs[0])
|
||||
bmaxs[0] = maxs[0];
|
||||
if(maxs[1] > bmaxs[1])
|
||||
bmaxs[1] = maxs[1];
|
||||
if(maxs[2] > bmaxs[2])
|
||||
bmaxs[2] = maxs[2];
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : pBox -
|
||||
//-----------------------------------------------------------------------------
|
||||
void BoundBox::UpdateBounds(const BoundBox *pBox)
|
||||
{
|
||||
UpdateBounds(pBox->bmins, pBox->bmaxs);
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : ptdest -
|
||||
//-----------------------------------------------------------------------------
|
||||
void BoundBox::GetBoundsCenter(Vector& ptdest)
|
||||
{
|
||||
ptdest = (bmins + bmaxs)/2.0f;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : pt -
|
||||
// Output : Returns true on success, false on failure.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool BoundBox::ContainsPoint(const Vector& pt) const
|
||||
{
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
if (pt[i] < bmins[i] || pt[i] > bmaxs[i])
|
||||
{
|
||||
return(false);
|
||||
}
|
||||
}
|
||||
return(true);
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : pfMins -
|
||||
// pfMaxs -
|
||||
// Output : Returns true on success, false on failure.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool BoundBox::IsIntersectingBox(const Vector& pfMins, const Vector& pfMaxs) const
|
||||
{
|
||||
if ((bmins[0] >= pfMaxs[0]) || (bmaxs[0] <= pfMins[0]))
|
||||
{
|
||||
return(false);
|
||||
|
||||
}
|
||||
if ((bmins[1] >= pfMaxs[1]) || (bmaxs[1] <= pfMins[1]))
|
||||
{
|
||||
return(false);
|
||||
}
|
||||
|
||||
if ((bmins[2] >= pfMaxs[2]) || (bmaxs[2] <= pfMins[2]))
|
||||
{
|
||||
return(false);
|
||||
}
|
||||
|
||||
return(true);
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : pfMins -
|
||||
// pfMaxs -
|
||||
// Output : Returns true on success, false on failure.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool BoundBox::IsInsideBox(const Vector& pfMins, const Vector& pfMaxs) const
|
||||
{
|
||||
if ((bmins[0] < pfMins[0]) || (bmaxs[0] > pfMaxs[0]))
|
||||
{
|
||||
return(false);
|
||||
}
|
||||
|
||||
if ((bmins[1] < pfMins[1]) || (bmaxs[1] > pfMaxs[1]))
|
||||
{
|
||||
return(false);
|
||||
}
|
||||
|
||||
if ((bmins[2] < pfMins[2]) || (bmaxs[2] > pfMaxs[2]))
|
||||
{
|
||||
return(false);
|
||||
}
|
||||
|
||||
return(true);
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Returns whether this bounding box is valid, ie maxs >= mins.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool BoundBox::IsValidBox(void) const
|
||||
{
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
if (bmins[i] > bmaxs[i])
|
||||
{
|
||||
return(false);
|
||||
}
|
||||
}
|
||||
|
||||
return(true);
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : size -
|
||||
//-----------------------------------------------------------------------------
|
||||
void BoundBox::GetBoundsSize(Vector& size)
|
||||
{
|
||||
size[0] = bmaxs[0] - bmins[0];
|
||||
size[1] = bmaxs[1] - bmins[1];
|
||||
size[2] = bmaxs[2] - bmins[2];
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : iValue -
|
||||
// iGridSize -
|
||||
// Output :
|
||||
//-----------------------------------------------------------------------------
|
||||
static int Snap(/*int*/ float iValue, int iGridSize)
|
||||
{
|
||||
return (int)(rint(iValue/iGridSize) * iGridSize);
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : iGridSize -
|
||||
//-----------------------------------------------------------------------------
|
||||
void BoundBox::SnapToGrid(int iGridSize)
|
||||
{
|
||||
// does not alter the size of the box .. snaps its minimal coordinates
|
||||
// to the grid size specified in iGridSize
|
||||
Vector size;
|
||||
GetBoundsSize(size);
|
||||
|
||||
for(int i = 0; i < 3; i++)
|
||||
{
|
||||
bmins[i] = (float)Snap(/* YWB (int)*/bmins[i], iGridSize);
|
||||
bmaxs[i] = bmins[i] + size[i];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : axis -
|
||||
//-----------------------------------------------------------------------------
|
||||
void BoundBox::Rotate90(int axis)
|
||||
{
|
||||
int e1 = AXIS_X, e2 = AXIS_Y;
|
||||
|
||||
// get bounds center first
|
||||
Vector center;
|
||||
GetBoundsCenter(center);
|
||||
|
||||
switch(axis)
|
||||
{
|
||||
case AXIS_Z:
|
||||
e1 = AXIS_X;
|
||||
e2 = AXIS_Y;
|
||||
break;
|
||||
case AXIS_X:
|
||||
e1 = AXIS_Y;
|
||||
e2 = AXIS_Z;
|
||||
break;
|
||||
case AXIS_Y:
|
||||
e1 = AXIS_X;
|
||||
e2 = AXIS_Z;
|
||||
break;
|
||||
}
|
||||
|
||||
float tmp1, tmp2;
|
||||
tmp1 = bmins[e1] - center[e1] + center[e2];
|
||||
tmp2 = bmaxs[e1] - center[e1] + center[e2];
|
||||
bmins[e1] = bmins[e2] - center[e2] + center[e1];
|
||||
bmaxs[e1] = bmaxs[e2] - center[e2] + center[e1];
|
||||
bmins[e2] = tmp1;
|
||||
bmaxs[e2] = tmp2;
|
||||
}
|
||||
|
||||
71
hammer/boundbox.h
Normal file
71
hammer/boundbox.h
Normal file
@@ -0,0 +1,71 @@
|
||||
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: An axis aligned bounding box class.
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef BOUNDBOX_H
|
||||
#define BOUNDBOX_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
|
||||
#include "mathlib/vector.h"
|
||||
|
||||
|
||||
class BoundBox
|
||||
{
|
||||
public:
|
||||
|
||||
BoundBox(void);
|
||||
BoundBox(const Vector &mins, const Vector &maxs);
|
||||
|
||||
void ResetBounds(void);
|
||||
inline void SetBounds(const Vector &mins, const Vector &maxs);
|
||||
|
||||
void UpdateBounds(const Vector& bmins, const Vector& bmaxs);
|
||||
void UpdateBounds(const Vector& pt);
|
||||
void UpdateBounds(const BoundBox *pBox);
|
||||
void GetBoundsCenter(Vector& ptdest);
|
||||
inline void GetBounds(Vector& Mins, Vector& Maxs) const;
|
||||
|
||||
virtual bool IsIntersectingBox(const Vector& pfMins, const Vector& pfMaxs) const;
|
||||
bool IsInsideBox(const Vector& pfMins, const Vector& pfMaxs) const;
|
||||
bool ContainsPoint(const Vector& pt) const;
|
||||
bool IsValidBox(void) const;
|
||||
void GetBoundsSize(Vector& size);
|
||||
void SnapToGrid(int iGridSize);
|
||||
void Rotate90(int axis);
|
||||
|
||||
Vector bmins;
|
||||
Vector bmaxs;
|
||||
};
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Gets the bounding box as two vectors, a min and a max.
|
||||
// Input : Mins - Receives the box's minima.
|
||||
// Maxs - Receives the box's maxima.
|
||||
//-----------------------------------------------------------------------------
|
||||
void BoundBox::GetBounds(Vector &Mins, Vector &Maxs) const
|
||||
{
|
||||
Mins = bmins;
|
||||
Maxs = bmaxs;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Sets the box outright, equivalent to ResetBounds + UpdateBounds.
|
||||
// Input : mins - Minima to set.
|
||||
// maxs - Maxima to set.
|
||||
//-----------------------------------------------------------------------------
|
||||
void BoundBox::SetBounds(const Vector &mins, const Vector &maxs)
|
||||
{
|
||||
bmins = mins;
|
||||
bmaxs = maxs;
|
||||
}
|
||||
|
||||
|
||||
#endif // BOUNDBOX_H
|
||||
1179
hammer/box3d.cpp
Normal file
1179
hammer/box3d.cpp
Normal file
File diff suppressed because it is too large
Load Diff
150
hammer/box3d.h
Normal file
150
hammer/box3d.h
Normal file
@@ -0,0 +1,150 @@
|
||||
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef BOX3D_H
|
||||
#define BOX3D_H
|
||||
#pragma once
|
||||
|
||||
|
||||
#include "Tool3D.h"
|
||||
#include "BoundBox.h"
|
||||
|
||||
|
||||
class CMapView2D;
|
||||
class CRender3D;
|
||||
|
||||
|
||||
//
|
||||
// Formats for displaying world units.
|
||||
//
|
||||
enum WorldUnits_t
|
||||
{
|
||||
Units_None,
|
||||
Units_Inches,
|
||||
Units_Feet_Inches,
|
||||
};
|
||||
|
||||
|
||||
class Box3D : public Tool3D, public BoundBox
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
Box3D(void);
|
||||
|
||||
static inline void SetWorldUnits(WorldUnits_t eWorldUnits);
|
||||
static inline WorldUnits_t GetWorldUnits(void);
|
||||
|
||||
//
|
||||
// CBaseTool implementation.
|
||||
//
|
||||
virtual void SetEmpty();
|
||||
virtual void RenderTool2D(CRender2D *pRender);
|
||||
virtual void RenderTool3D(CRender3D *pRender);
|
||||
|
||||
virtual void UpdateStatusBar();
|
||||
|
||||
protected:
|
||||
|
||||
enum
|
||||
{
|
||||
expandbox = 0x01,
|
||||
thicklines = 0x04,
|
||||
boundstext = 0x08,
|
||||
};
|
||||
|
||||
enum TransformMode_t
|
||||
{
|
||||
modeNone = 0,
|
||||
modeMove,
|
||||
modeScale,
|
||||
modeRotate,
|
||||
modeShear,
|
||||
modeLast,
|
||||
};
|
||||
|
||||
void StartNew( CMapView *pView, const Vector2D &vPoint, const Vector &vecStart, const Vector &vecSize);
|
||||
|
||||
inline int GetTranslateMode() { return m_TranslateMode; }
|
||||
|
||||
virtual void ToggleTranslateMode(void);
|
||||
void EnableHandles(bool bEnable);
|
||||
|
||||
void SetDrawFlags(DWORD dwFlags);
|
||||
DWORD GetDrawFlags() { return m_dwDrawFlags; }
|
||||
void SetDrawColors(COLORREF dwHandleColor, COLORREF dwBoxColor);
|
||||
|
||||
virtual void GetStatusString(char *pszBuf);
|
||||
unsigned long UpdateCursor(CMapView *pView, const Vector &vHandleHit, TransformMode_t eTransformMode);
|
||||
|
||||
void HandleToWorld( Vector &vWorld, const Vector &vHandle, const Vector *pCustomHandleBox = NULL);
|
||||
const Vector NearestCorner(const Vector2D &vPoint, CMapView *pView, const Vector *pCustomHandleBox = NULL);
|
||||
int GetVisibleHandles( Vector *handles, CMapView *, int nMode );
|
||||
|
||||
void RenderHandles2D(CRender2D *pRender, const Vector &mins, const Vector &maxs );
|
||||
void RenderHandles3D(CRender3D *pRender, const Vector &mins, const Vector &maxs);
|
||||
|
||||
|
||||
//
|
||||
// Tool3D implementation.
|
||||
//
|
||||
|
||||
public:
|
||||
virtual int HitTest(CMapView *pView, const Vector2D &ptClient, bool bTestHandles = false);
|
||||
|
||||
// If pCustomHandleBox is non-null, it points at an array 2 vectors (min and max), and
|
||||
// it will use those bounds to figure out the corners that it will align to the grid.
|
||||
virtual void StartTranslation( CMapView *pView, const Vector2D &vPoint, const Vector &vHandleOrigin, const Vector *pRefPoint = NULL, const Vector *pCustomHandleBox = NULL );
|
||||
|
||||
virtual bool UpdateTranslation(const Vector &vUpdate, UINT uConstraints);
|
||||
virtual void FinishTranslation(bool bSave);
|
||||
virtual void TranslatePoint(Vector& pt);
|
||||
void TranslateBox(Vector& mins, Vector& maxs);
|
||||
virtual const VMatrix& GetTransformMatrix();
|
||||
|
||||
protected:
|
||||
|
||||
void UpdateTransformMatrix();
|
||||
|
||||
static WorldUnits_t m_eWorldUnits;
|
||||
|
||||
COLORREF m_clrHandle;
|
||||
COLORREF m_clrBox;
|
||||
|
||||
TransformMode_t m_TranslateMode; // current translation mode
|
||||
Vector m_TranslateHandle; // current translation handle/corner
|
||||
Vector m_vTranslationFixPoint; // fix point, meaning it remains unchanged by translation, eg rotation center etc.
|
||||
VMatrix m_TransformMatrix;
|
||||
|
||||
bool m_bEnableHandles; // check/show handles yes/no
|
||||
Vector m_LastHitTestHandle; // handle hit by last HitTest call
|
||||
TransformMode_t m_LastTranslateMode; // last translate mode
|
||||
|
||||
bool m_bPreventOverlap;
|
||||
DWORD m_dwDrawFlags;
|
||||
};
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
WorldUnits_t Box3D::GetWorldUnits(void)
|
||||
{
|
||||
return(m_eWorldUnits);
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void Box3D::SetWorldUnits(WorldUnits_t eWorldUnits)
|
||||
{
|
||||
m_eWorldUnits = eWorldUnits;
|
||||
}
|
||||
|
||||
|
||||
#endif // BOX3D_H
|
||||
353
hammer/brushops.cpp
Normal file
353
hammer/brushops.cpp
Normal file
@@ -0,0 +1,353 @@
|
||||
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#include "stdafx.h"
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
#include "hammer.h"
|
||||
#include "MapEntity.h"
|
||||
#include "MapDefs.h"
|
||||
#include "MapFace.h"
|
||||
#include "hammer_mathlib.h"
|
||||
#include "history.h"
|
||||
#include "Error3d.h"
|
||||
#include "BrushOps.h"
|
||||
#include "GlobalFunctions.h"
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
|
||||
#pragma warning( disable : 4244 ) // Disable warning messages
|
||||
|
||||
|
||||
#define SIDE_FRONT 0
|
||||
#define SIDE_BACK 1
|
||||
#define SIDE_ON 2
|
||||
|
||||
#define BOGUS_RANGE ( MAX_COORD_INTEGER * 4 )
|
||||
|
||||
|
||||
float lightaxis[3] = {1, 0.6f, 0.75f};
|
||||
|
||||
const int MAX_POINTS_ON_WINDING = 128;
|
||||
|
||||
|
||||
void Error(char* fmt, ...)
|
||||
{
|
||||
char str[300];
|
||||
sprintf(str, fmt, (&fmt)+1);
|
||||
Msg(mwError, str);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
=============================================================================
|
||||
|
||||
TURN PLANES INTO GROUPS OF FACES
|
||||
|
||||
=============================================================================
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
==================
|
||||
NewWinding
|
||||
==================
|
||||
*/
|
||||
winding_t *NewWinding (int points)
|
||||
{
|
||||
winding_t *w;
|
||||
|
||||
if (points > MAX_POINTS_ON_WINDING)
|
||||
Error ("NewWinding: %i points", points);
|
||||
|
||||
w = (winding_t *)malloc(sizeof(*w));
|
||||
w->numpoints = 0; // None are occupied yet even though allocated.
|
||||
w->p = (Vector *)calloc( points, sizeof(Vector) );
|
||||
|
||||
return w;
|
||||
}
|
||||
|
||||
void FreeWinding (winding_t *w)
|
||||
{
|
||||
if (*(unsigned *)w == 0xdeaddead)
|
||||
Error ("FreeWinding: freed a freed winding");
|
||||
*(unsigned *)w = 0xdeaddead;
|
||||
|
||||
if (w->p)
|
||||
{
|
||||
free (w->p);
|
||||
w->p = NULL;
|
||||
}
|
||||
free (w);
|
||||
}
|
||||
|
||||
size_t WindingSize(int points)
|
||||
{
|
||||
return (size_t)(&((winding_t *)0)->p[points]);
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Removes points that are withing a given distance from each other
|
||||
// from the winding.
|
||||
// Input : pWinding - The winding to remove duplicates from.
|
||||
// fMinDist - The minimum distance two points must be from one another
|
||||
// to be considered different. If this is zero, the points must be
|
||||
// identical to be considered duplicates.
|
||||
//-----------------------------------------------------------------------------
|
||||
void RemoveDuplicateWindingPoints(winding_t *pWinding, float fMinDist)
|
||||
{
|
||||
for (int i = 0; i < pWinding->numpoints; i++)
|
||||
{
|
||||
for (int j = i + 1; j < pWinding->numpoints; j++)
|
||||
{
|
||||
Vector edge;
|
||||
VectorSubtract(pWinding->p[i], pWinding->p[j], edge);
|
||||
|
||||
if (VectorLength(edge) < fMinDist)
|
||||
{
|
||||
if (j + 1 < pWinding->numpoints)
|
||||
{
|
||||
memmove(&pWinding->p[j], &pWinding->p[j + 1], (pWinding->numpoints - (j + 1)) * sizeof(pWinding->p[0]));
|
||||
}
|
||||
|
||||
pWinding->numpoints--;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
==================
|
||||
CopyWinding
|
||||
==================
|
||||
*/
|
||||
winding_t *CopyWinding (winding_t *w)
|
||||
{
|
||||
int size;
|
||||
winding_t *c;
|
||||
|
||||
c = NewWinding (w->numpoints);
|
||||
c->numpoints = w->numpoints;
|
||||
size = w->numpoints*sizeof(w->p[0]);
|
||||
memcpy (c->p, w->p, size);
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
==================
|
||||
ClipWinding
|
||||
|
||||
Clips the winding to the plane, returning the new winding on the positive side
|
||||
Frees the input winding.
|
||||
==================
|
||||
*/
|
||||
// YWB ADDED SPLIT EPS to match qcsg splitting
|
||||
#define SPLIT_EPSILON 0.01
|
||||
winding_t *ClipWinding (winding_t *in, PLANE *split)
|
||||
{
|
||||
float dists[MAX_POINTS_ON_WINDING];
|
||||
int sides[MAX_POINTS_ON_WINDING];
|
||||
int counts[3];
|
||||
float dot;
|
||||
int i, j;
|
||||
Vector *p1, *p2, *mid;
|
||||
winding_t *neww;
|
||||
int maxpts;
|
||||
|
||||
counts[0] = counts[1] = counts[2] = 0;
|
||||
|
||||
// determine sides for each point
|
||||
for (i=0 ; i<in->numpoints ; i++)
|
||||
{
|
||||
dot = DotProduct (in->p[i], split->normal);
|
||||
dot -= split->dist;
|
||||
dists[i] = dot;
|
||||
if (dot > SPLIT_EPSILON)
|
||||
sides[i] = SIDE_FRONT;
|
||||
else if (dot < -SPLIT_EPSILON)
|
||||
sides[i] = SIDE_BACK;
|
||||
else
|
||||
{
|
||||
sides[i] = SIDE_ON;
|
||||
}
|
||||
counts[sides[i]]++;
|
||||
}
|
||||
sides[i] = sides[0];
|
||||
dists[i] = dists[0];
|
||||
|
||||
if (!counts[0] && !counts[1])
|
||||
return in;
|
||||
|
||||
if (!counts[0])
|
||||
{
|
||||
free (in);
|
||||
return NULL;
|
||||
}
|
||||
if (!counts[1])
|
||||
return in;
|
||||
|
||||
maxpts = in->numpoints+4; // can't use counts[0]+2 because
|
||||
// of fp grouping errors
|
||||
neww = NewWinding (maxpts);
|
||||
|
||||
for (i=0 ; i<in->numpoints ; i++)
|
||||
{
|
||||
p1 = &in->p[i];
|
||||
|
||||
mid = &neww->p[neww->numpoints];
|
||||
|
||||
if (sides[i] == SIDE_FRONT || sides[i] == SIDE_ON)
|
||||
{
|
||||
*mid = *p1;
|
||||
neww->numpoints++;
|
||||
if (sides[i] == SIDE_ON)
|
||||
continue;
|
||||
mid = &neww->p[neww->numpoints];
|
||||
}
|
||||
|
||||
if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i])
|
||||
continue;
|
||||
|
||||
// generate a split point
|
||||
if (i == in->numpoints - 1)
|
||||
p2 = &in->p[0];
|
||||
else
|
||||
p2 = p1 + 1;
|
||||
|
||||
neww->numpoints++;
|
||||
|
||||
dot = dists[i] / (dists[i]-dists[i+1]);
|
||||
for (j=0 ; j<3 ; j++)
|
||||
{ // avoid round off error when possible
|
||||
if (split->normal[j] == 1)
|
||||
mid[0][j] = split->dist;
|
||||
else if (split->normal[j] == -1)
|
||||
mid[0][j] = -split->dist;
|
||||
mid[0][j] = p1[0][j] + dot*(p2[0][j]-p1[0][j]);
|
||||
}
|
||||
// mid[3] = p1[3] + dot*(p2[3]-p1[3]);
|
||||
// mid[4] = p1[4] + dot*(p2[4]-p1[4]);
|
||||
}
|
||||
|
||||
if (neww->numpoints > maxpts)
|
||||
Error ("ClipWinding: points exceeded estimate");
|
||||
|
||||
// free the original winding
|
||||
FreeWinding (in);
|
||||
|
||||
return neww;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Creates a huge quadrilateral winding given a plane.
|
||||
// Input : pPlane - Plane normal and distance to use when creating the winding.
|
||||
// Output : Returns a winding with 4 points.
|
||||
//-----------------------------------------------------------------------------
|
||||
// dvs: read through this and clean it up
|
||||
winding_t *CreateWindingFromPlane(PLANE *pPlane)
|
||||
{
|
||||
int i, x;
|
||||
float max, v;
|
||||
Vector org, vright, vup;
|
||||
winding_t *w;
|
||||
|
||||
// find the major axis
|
||||
max = -BOGUS_RANGE;
|
||||
x = -1;
|
||||
for (i=0 ; i<3; i++)
|
||||
{
|
||||
v = fabs(pPlane->normal[i]);
|
||||
if (v > max)
|
||||
{
|
||||
x = i;
|
||||
max = v;
|
||||
}
|
||||
}
|
||||
if (x==-1)
|
||||
Error ("BasePolyForPlane: no axis found");
|
||||
|
||||
vup = vec3_origin;
|
||||
switch (x)
|
||||
{
|
||||
case 0:
|
||||
case 1:
|
||||
vup[2] = 1;
|
||||
break;
|
||||
case 2:
|
||||
vup[0] = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
v = DotProduct (vup, pPlane->normal);
|
||||
VectorMA (vup, -v, pPlane->normal, vup);
|
||||
VectorNormalize (vup);
|
||||
|
||||
org = pPlane->normal * pPlane->dist;
|
||||
|
||||
CrossProduct (vup, pPlane->normal, vright);
|
||||
|
||||
vup = vup * MAX_TRACE_LENGTH;
|
||||
vright = vright * MAX_TRACE_LENGTH;
|
||||
|
||||
// project a really big axis aligned box onto the plane
|
||||
w = NewWinding (4);
|
||||
w->numpoints = 4;
|
||||
|
||||
VectorSubtract (org, vright, w->p[0]);
|
||||
VectorAdd (w->p[0], vup, w->p[0]);
|
||||
|
||||
VectorAdd (org, vright, w->p[1]);
|
||||
VectorAdd (w->p[1], vup, w->p[1]);
|
||||
|
||||
VectorAdd (org, vright, w->p[2]);
|
||||
VectorSubtract (w->p[2], vup, w->p[2]);
|
||||
|
||||
VectorSubtract (org, vright, w->p[3]);
|
||||
VectorSubtract (w->p[3], vup, w->p[3]);
|
||||
|
||||
return w;
|
||||
}
|
||||
|
||||
|
||||
static CArray<error3d, error3d&> Errors;
|
||||
static int nErrors;
|
||||
|
||||
void Add3dError(DWORD dwObjectID, LPCTSTR pszReason, PVOID pInfo)
|
||||
{
|
||||
error3d err;
|
||||
err.dwObjectID = dwObjectID;
|
||||
err.pszReason = pszReason;
|
||||
err.pInfo = pInfo;
|
||||
Errors.Add(err);
|
||||
++nErrors;
|
||||
}
|
||||
|
||||
int Get3dErrorCount()
|
||||
{
|
||||
return nErrors;
|
||||
}
|
||||
|
||||
error3d * Enum3dErrors(BOOL bStart)
|
||||
{
|
||||
static int iCurrent = 0;
|
||||
|
||||
if(bStart)
|
||||
iCurrent = 0;
|
||||
|
||||
if(iCurrent == nErrors)
|
||||
return NULL;
|
||||
|
||||
return & Errors.GetData()[iCurrent++];
|
||||
}
|
||||
|
||||
|
||||
33
hammer/brushops.h
Normal file
33
hammer/brushops.h
Normal file
@@ -0,0 +1,33 @@
|
||||
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef BRUSHOPS_H
|
||||
#define BRUSHOPS_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include "MapFace.h"
|
||||
|
||||
|
||||
#define ON_PLANE_EPSILON 0.5f // Vertices must be within this many units of the plane to be considered on the plane.
|
||||
#define MIN_EDGE_LENGTH_EPSILON 0.1f // Edges shorter than this are considered degenerate.
|
||||
#define ROUND_VERTEX_EPSILON 0.01f // Vertices within this many units of an integer value will be rounded to an integer value.
|
||||
|
||||
|
||||
void Add3dError(DWORD dwObjectID, LPCTSTR pszReason, PVOID pInfo);
|
||||
|
||||
|
||||
winding_t *ClipWinding(winding_t *in, PLANE *split);
|
||||
winding_t *CopyWinding(winding_t *w);
|
||||
winding_t *NewWinding(int points);
|
||||
void FreeWinding (winding_t *w);
|
||||
winding_t *CreateWindingFromPlane(PLANE *pPlane);
|
||||
size_t WindingSize(int points);
|
||||
void RemoveDuplicateWindingPoints(winding_t *pWinding, float fMinDist = 0);
|
||||
|
||||
|
||||
#endif // BRUSHOPS_H
|
||||
969
hammer/bsplighting.cpp
Normal file
969
hammer/bsplighting.cpp
Normal file
@@ -0,0 +1,969 @@
|
||||
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "materialsystem/imaterialsystem.h"
|
||||
#include "istudiorender.h"
|
||||
#include "material.h"
|
||||
#include "materialsystem/imesh.h"
|
||||
#include "disp_common.h"
|
||||
#include "bsplighting.h"
|
||||
#include "interface.h"
|
||||
#include "filesystem.h"
|
||||
#include "hammer.h"
|
||||
#include "tier0/dbg.h"
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
|
||||
bool SurfHasBumpedLightmaps( int flags )
|
||||
{
|
||||
return ( flags & SURF_BUMPLIGHT ) &&
|
||||
( !( flags & SURF_NOLIGHT ) );
|
||||
}
|
||||
|
||||
|
||||
void InitLMSamples( Vector4D *pSamples, int nSamples, float value )
|
||||
{
|
||||
for( int i=0; i < nSamples; i++ )
|
||||
{
|
||||
pSamples[i][0] = pSamples[i][1] = pSamples[i][2] = value;
|
||||
pSamples[i][3] = 1.0f;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void InitLMSamplesRed( Vector4D *pSamples, int nSamples )
|
||||
{
|
||||
for( int i=0; i < nSamples; i++ )
|
||||
{
|
||||
pSamples[i][0] = 1;
|
||||
pSamples[i][1] = pSamples[i][2] = 0;
|
||||
pSamples[i][3] = 1.0f;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
CBSPLighting::CMaterialBuf::CMaterialBuf()
|
||||
{
|
||||
m_nVerts = m_nIndices = 0;
|
||||
m_pMesh = NULL;
|
||||
}
|
||||
|
||||
|
||||
CBSPLighting::CMaterialBuf::~CMaterialBuf()
|
||||
{
|
||||
if( m_pMesh )
|
||||
{
|
||||
CMatRenderContextPtr pRenderContext( MaterialSystemInterface() );
|
||||
pRenderContext->DestroyStaticMesh( m_pMesh );
|
||||
}
|
||||
|
||||
m_DrawCommands.PurgeAndDeleteElements();
|
||||
}
|
||||
|
||||
|
||||
CBSPLighting::CFaceMaterial::~CFaceMaterial()
|
||||
{
|
||||
m_MaterialBufs.PurgeAndDeleteElements();
|
||||
m_Faces.PurgeAndDeleteElements();
|
||||
}
|
||||
|
||||
|
||||
CBSPLighting::CBSPLighting()
|
||||
{
|
||||
m_nTotalTris = 0;
|
||||
m_hVRadDLL = 0;
|
||||
m_pVRadDLL = 0;
|
||||
m_pBSPLightingThread = 0;
|
||||
m_bLightingInProgress = false;
|
||||
}
|
||||
|
||||
|
||||
CBSPLighting::~CBSPLighting()
|
||||
{
|
||||
Term();
|
||||
}
|
||||
|
||||
|
||||
void CBSPLighting::Release()
|
||||
{
|
||||
delete this;
|
||||
}
|
||||
|
||||
|
||||
bool CBSPLighting::Load( char const *pFilename )
|
||||
{
|
||||
// Free everything.
|
||||
Term();
|
||||
|
||||
|
||||
// Load VRAD's DLL (and load the BSP file).
|
||||
if( !LoadVRADDLL( pFilename ) )
|
||||
return false;
|
||||
|
||||
|
||||
// Create the lighting thread.
|
||||
m_pBSPLightingThread = CreateBSPLightingThread( m_pVRadDLL );
|
||||
if( !m_pBSPLightingThread )
|
||||
return false;
|
||||
|
||||
|
||||
// Get the BSP file information from VRAD.
|
||||
CBSPInfo file;
|
||||
m_pVRadDLL->GetBSPInfo( &file );
|
||||
|
||||
|
||||
// Allocate faces and verts.
|
||||
CUtlVector<char> usedFaces;
|
||||
usedFaces.SetSize( file.numfaces );
|
||||
|
||||
int nFaces = 0;
|
||||
int nVerts = 0;
|
||||
for( int iCountFace=0; iCountFace < file.numfaces; iCountFace++ )
|
||||
{
|
||||
usedFaces[iCountFace] = 0;
|
||||
|
||||
if( file.dfaces[iCountFace].m_LightmapTextureSizeInLuxels[0] != 0 ||
|
||||
file.dfaces[iCountFace].m_LightmapTextureSizeInLuxels[0] != 0 )
|
||||
{
|
||||
texinfo_t *pTexInfo = &file.texinfo[ file.dfaces[iCountFace].texinfo ];
|
||||
|
||||
if( !(pTexInfo->flags & SURF_NODRAW) )
|
||||
{
|
||||
++nFaces;
|
||||
nVerts += file.dfaces[iCountFace].numedges;
|
||||
usedFaces[iCountFace] = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
CUtlVector<CFace> faces;
|
||||
faces.SetSize( nFaces );
|
||||
|
||||
CUtlVector<CVert> verts;
|
||||
verts.SetSize( nVerts );
|
||||
|
||||
m_StoredFaces.SetSize( nFaces );
|
||||
|
||||
|
||||
InitMaterialLUT( file );
|
||||
|
||||
|
||||
// Make lightmaps and translate the map faces over..
|
||||
IMaterialSystem *pMatSys = MaterialSystemInterface();
|
||||
|
||||
// Add the BSP file as a search path so our FindMaterial calls will get
|
||||
// VMFs embedded in the BSP file.
|
||||
g_pFullFileSystem->AddSearchPath( pFilename, "GAME" );
|
||||
|
||||
m_nTotalTris = 0;
|
||||
int iOutVert = 0;
|
||||
int iOutFace = 0;
|
||||
for( int iFace=0; iFace < file.numfaces; iFace++ )
|
||||
{
|
||||
dface_t *pIn = &file.dfaces[iFace];
|
||||
|
||||
if( !usedFaces[iFace] )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
CFace *pOut = &faces[iOutFace];
|
||||
CStoredFace *pStoredFace = &m_StoredFaces[iOutFace];
|
||||
|
||||
++iOutFace;
|
||||
|
||||
pStoredFace->m_iMapFace = iFace;
|
||||
pStoredFace->m_pFace = pOut;
|
||||
|
||||
pOut->m_pDFace = pIn;
|
||||
pOut->m_pStoredFace = pStoredFace;
|
||||
|
||||
// Get its material.
|
||||
texinfo_t *pTexInfo = &file.texinfo[pIn->texinfo];
|
||||
dtexdata_t *pTexData = &file.dtexdata[pTexInfo->texdata];
|
||||
pStoredFace->m_pMaterial = FindOrAddMaterial( file, pTexData->nameStringTableID );
|
||||
if( pStoredFace->m_pMaterial )
|
||||
pStoredFace->m_pMaterial->m_Faces.AddToTail( pStoredFace );
|
||||
|
||||
// Setup its lightmap.
|
||||
memcpy( pOut->m_LightmapVecs, file.texinfo[pIn->texinfo].lightmapVecsLuxelsPerWorldUnits, sizeof(pOut->m_LightmapVecs) );
|
||||
memcpy( pOut->m_LightmapTextureMinsInLuxels, pIn->m_LightmapTextureMinsInLuxels, sizeof(pOut->m_LightmapTextureMinsInLuxels) );
|
||||
|
||||
pStoredFace->m_LightmapSize[0] = pIn->m_LightmapTextureSizeInLuxels[0]+1;
|
||||
pStoredFace->m_LightmapSize[1] = pIn->m_LightmapTextureSizeInLuxels[1]+1;
|
||||
|
||||
// Setup the verts.
|
||||
pOut->m_iVertStart = iOutVert;
|
||||
pOut->m_nVerts = pIn->numedges;
|
||||
for( int iEdge=0; iEdge < pIn->numedges; iEdge++ )
|
||||
{
|
||||
int edgeVal = file.dsurfedges[ pIn->firstedge + iEdge ];
|
||||
if( edgeVal < 0 )
|
||||
verts[pOut->m_iVertStart+iEdge].m_vPos = file.dvertexes[ file.dedges[-edgeVal].v[1] ].point;
|
||||
else
|
||||
verts[pOut->m_iVertStart+iEdge].m_vPos = file.dvertexes[ file.dedges[edgeVal].v[0] ].point;
|
||||
}
|
||||
m_nTotalTris += pOut->m_nVerts - 2;
|
||||
|
||||
iOutVert += pOut->m_nVerts;
|
||||
pOut->m_iDispInfo = pIn->dispinfo;
|
||||
}
|
||||
|
||||
g_pFullFileSystem->RemoveSearchPath( pFilename, "GAME" );
|
||||
|
||||
|
||||
// Allocate lightmaps.. must be grouped by material.
|
||||
pMatSys->ResetMaterialLightmapPageInfo();
|
||||
|
||||
pMatSys->BeginLightmapAllocation();
|
||||
|
||||
FOR_EACH_LL( m_FaceMaterials, iMat )
|
||||
{
|
||||
CFaceMaterial *pMat = m_FaceMaterials[iMat];
|
||||
bool bNeedsBumpmap = pMat->m_pMaterial->GetPropertyFlag( MATERIAL_PROPERTY_NEEDS_BUMPED_LIGHTMAPS );
|
||||
|
||||
FOR_EACH_LL( pMat->m_Faces, iFace )
|
||||
{
|
||||
CStoredFace *pStoredFace = pMat->m_Faces[iFace];
|
||||
CFace *pOut = pStoredFace->m_pFace;
|
||||
|
||||
int bumpedSize = pStoredFace->m_LightmapSize[0];
|
||||
if( bNeedsBumpmap )
|
||||
bumpedSize *= 4;
|
||||
|
||||
pOut->m_LightmapSortID = pMatSys->AllocateLightmap(
|
||||
bumpedSize,
|
||||
pStoredFace->m_LightmapSize[1],
|
||||
pStoredFace->m_OffsetIntoLightmapPage,
|
||||
pMat->m_pMaterial );
|
||||
}
|
||||
}
|
||||
|
||||
pMatSys->EndLightmapAllocation();
|
||||
|
||||
|
||||
// Get sort IDs from the material system.
|
||||
CUtlVector<MaterialSystem_SortInfo_t> sortInfos;
|
||||
sortInfos.SetSize( pMatSys->GetNumSortIDs() );
|
||||
pMatSys->GetSortInfo( sortInfos.Base() );
|
||||
|
||||
for( int iFace=0; iFace < faces.Count(); iFace++ )
|
||||
{
|
||||
m_StoredFaces[iFace].m_LightmapPageID = sortInfos[faces[iFace].m_LightmapSortID].lightmapPageID;
|
||||
}
|
||||
|
||||
// Setup the gamma table.
|
||||
BuildGammaTable( 2.2f, 2.2f, 0, 1 );
|
||||
|
||||
|
||||
// Set lightmap texture coordinates.
|
||||
for( int iFace=0; iFace < faces.Count(); iFace++ )
|
||||
{
|
||||
CFace *pFace = &faces[iFace];
|
||||
CStoredFace *pStoredFace = &m_StoredFaces[iFace];
|
||||
texinfo_t *pTexInfo = &file.texinfo[pFace->m_pDFace->texinfo];
|
||||
|
||||
int lightmapPageSize[2];
|
||||
pMatSys->GetLightmapPageSize( pFace->m_pStoredFace->m_LightmapPageID, &lightmapPageSize[0], &lightmapPageSize[1] );
|
||||
|
||||
pStoredFace->m_BumpSTexCoordOffset = (float)pStoredFace->m_LightmapSize[0] / lightmapPageSize[0];
|
||||
|
||||
// Set its texture coordinates.
|
||||
for( int iVert=0; iVert < pFace->m_nVerts; iVert++ )
|
||||
{
|
||||
CVert *pVert = &verts[ pFace->m_iVertStart + iVert ];
|
||||
Vector &vPos = pVert->m_vPos;
|
||||
|
||||
for( int iCoord=0; iCoord < 2; iCoord++ )
|
||||
{
|
||||
float *lmVec = pFace->m_LightmapVecs[iCoord];
|
||||
float flVal = lmVec[0]*vPos[0] + lmVec[1]*vPos[1] + lmVec[2]*vPos[2] + lmVec[3] - pFace->m_LightmapTextureMinsInLuxels[iCoord];
|
||||
|
||||
flVal += pFace->m_pStoredFace->m_OffsetIntoLightmapPage[iCoord];
|
||||
flVal += 0.5f; // bilinear...
|
||||
flVal /= lightmapPageSize[iCoord];
|
||||
Assert( _finite(flVal) );
|
||||
pVert->m_vLightCoords[iCoord] = flVal;
|
||||
|
||||
pVert->m_vTexCoords[iCoord] =
|
||||
DotProduct( vPos, *((Vector*)pTexInfo->textureVecsTexelsPerWorldUnits[iCoord]) ) +
|
||||
pTexInfo->textureVecsTexelsPerWorldUnits[iCoord][3];
|
||||
|
||||
if( pStoredFace->m_pMaterial )
|
||||
{
|
||||
if( iCoord == 0 )
|
||||
pVert->m_vTexCoords[iCoord] /= pStoredFace->m_pMaterial->m_pMaterial->GetMappingWidth();
|
||||
else
|
||||
pVert->m_vTexCoords[iCoord] /= pStoredFace->m_pMaterial->m_pMaterial->GetMappingHeight();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Create displacements.
|
||||
CUtlVector<CDispInfoFaces> dispInfos;
|
||||
CreateDisplacements( file, faces, dispInfos );
|
||||
|
||||
BuildLMGroups( file, faces, verts, dispInfos );
|
||||
BuildDrawCommands();
|
||||
|
||||
ReloadLightmaps();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void CBSPLighting::Term()
|
||||
{
|
||||
if( m_pBSPLightingThread )
|
||||
{
|
||||
m_pBSPLightingThread->Release();
|
||||
m_pBSPLightingThread = 0;
|
||||
}
|
||||
|
||||
m_nTotalTris = 0;
|
||||
|
||||
if( m_hVRadDLL )
|
||||
{
|
||||
if( m_pVRadDLL )
|
||||
{
|
||||
// Save the .r0 and .bsp files.
|
||||
m_pVRadDLL->Serialize();
|
||||
|
||||
m_pVRadDLL->Release();
|
||||
m_pVRadDLL = 0;
|
||||
}
|
||||
|
||||
Sys_UnloadModule( m_hVRadDLL );
|
||||
m_hVRadDLL = 0;
|
||||
}
|
||||
|
||||
m_StoredFaces.Purge();
|
||||
}
|
||||
|
||||
|
||||
bool CBSPLighting::Serialize()
|
||||
{
|
||||
if( m_pBSPLightingThread )
|
||||
{
|
||||
// Only serialize if we're not currently in the middle of lighting.
|
||||
if( m_pBSPLightingThread->GetCurrentState() == IBSPLightingThread::STATE_FINISHED )
|
||||
return m_pVRadDLL->Serialize();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void CBSPLighting::StartLighting( char const *pVMFFileWithEnts )
|
||||
{
|
||||
if( m_pBSPLightingThread )
|
||||
{
|
||||
m_pBSPLightingThread->StartLighting( pVMFFileWithEnts );
|
||||
m_bLightingInProgress = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
float CBSPLighting::GetPercentComplete()
|
||||
{
|
||||
if( m_bLightingInProgress && m_pBSPLightingThread )
|
||||
return m_pBSPLightingThread->GetPercentComplete();
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
void CBSPLighting::Interrupt()
|
||||
{
|
||||
if( m_pBSPLightingThread )
|
||||
m_pBSPLightingThread->Interrupt();
|
||||
}
|
||||
|
||||
|
||||
bool CBSPLighting::CheckForNewLightmaps()
|
||||
{
|
||||
if( !m_pBSPLightingThread )
|
||||
return false;
|
||||
|
||||
// Has it finished lighting?
|
||||
int curState = m_pBSPLightingThread->GetCurrentState();
|
||||
if( m_bLightingInProgress )
|
||||
{
|
||||
if( curState == IBSPLightingThread::STATE_FINISHED )
|
||||
{
|
||||
m_bLightingInProgress = false;
|
||||
ReloadLightmaps();
|
||||
return true;
|
||||
}
|
||||
else if( curState == IBSPLightingThread::STATE_IDLE )
|
||||
{
|
||||
m_bLightingInProgress = false;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
#define DRAWLIGHTMAPPAGE
|
||||
#if defined( DRAWLIGHTMAPPAGE )
|
||||
void DrawLightmapPage( IMaterialSystem *materialSystemInterface, int lightmapPageID )
|
||||
{
|
||||
IMaterial *g_materialDebugLightmap = materialSystemInterface->FindMaterial( "debug/debuglightmap", TEXTURE_GROUP_OTHER );
|
||||
|
||||
// assumes that we are already in ortho mode.
|
||||
int lightmapPageWidth, lightmapPageHeight;
|
||||
|
||||
CMatRenderContextPtr pRenderContext( materialSystemInterface );
|
||||
IMesh* pMesh = pRenderContext->GetDynamicMesh( true, NULL, NULL, g_materialDebugLightmap );
|
||||
|
||||
materialSystemInterface->GetLightmapPageSize( lightmapPageID, &lightmapPageWidth, &lightmapPageHeight );
|
||||
pRenderContext->BindLightmapPage( lightmapPageID );
|
||||
|
||||
CMeshBuilder meshBuilder;
|
||||
meshBuilder.Begin( pMesh, MATERIAL_QUADS, 1 );
|
||||
|
||||
// texcoord 1 is lightmaptexcoord for fixed function.
|
||||
static int yOffset = 30;
|
||||
|
||||
meshBuilder.TexCoord2f( 1, 0.0f, 0.0f );
|
||||
meshBuilder.Position3f( 0.0f, yOffset, 0.0f );
|
||||
meshBuilder.AdvanceVertex();
|
||||
|
||||
meshBuilder.TexCoord2f( 1, 1.0f, 0.0f );
|
||||
meshBuilder.Position3f( lightmapPageWidth, yOffset, 0.0f );
|
||||
meshBuilder.AdvanceVertex();
|
||||
|
||||
meshBuilder.TexCoord2f( 1, 1.0f, 1.0f );
|
||||
meshBuilder.Position3f( lightmapPageWidth, yOffset+lightmapPageHeight, 0.0f );
|
||||
meshBuilder.AdvanceVertex();
|
||||
|
||||
meshBuilder.TexCoord2f( 1, 0.0f, 1.0f );
|
||||
meshBuilder.Position3f( 0.0f, yOffset+lightmapPageHeight, 0.0f );
|
||||
meshBuilder.AdvanceVertex();
|
||||
|
||||
|
||||
meshBuilder.End();
|
||||
pMesh->Draw();
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
void CBSPLighting::Draw()
|
||||
{
|
||||
if( m_FaceMaterials.Count() == 0 )
|
||||
return;
|
||||
|
||||
IMaterialSystem *pMatSys = MaterialSystemInterface();
|
||||
if( !pMatSys )
|
||||
return;
|
||||
|
||||
CMatRenderContextPtr pRenderContext( pMatSys );
|
||||
|
||||
CheckForNewLightmaps();
|
||||
|
||||
pRenderContext->Flush();
|
||||
|
||||
#if defined( DRAWLIGHTMAPPAGE )
|
||||
static bool bDrawIt = false;
|
||||
if( bDrawIt )
|
||||
{
|
||||
pRenderContext->MatrixMode( MATERIAL_VIEW );
|
||||
pRenderContext->PushMatrix();
|
||||
pRenderContext->LoadIdentity();
|
||||
|
||||
pRenderContext->MatrixMode( MATERIAL_MODEL );
|
||||
pRenderContext->PushMatrix();
|
||||
pRenderContext->LoadIdentity();
|
||||
|
||||
pRenderContext->MatrixMode( MATERIAL_PROJECTION );
|
||||
pRenderContext->PushMatrix();
|
||||
pRenderContext->LoadIdentity();
|
||||
pRenderContext->Ortho( 0, 0, 300, 300, -99999, 99999 );
|
||||
|
||||
static int iPageToDraw = 0;
|
||||
DrawLightmapPage( MaterialSystemInterface(), iPageToDraw );
|
||||
|
||||
pRenderContext->MatrixMode( MATERIAL_VIEW );
|
||||
pRenderContext->PopMatrix();
|
||||
|
||||
pRenderContext->MatrixMode( MATERIAL_MODEL );
|
||||
pRenderContext->PopMatrix();
|
||||
|
||||
pRenderContext->MatrixMode( MATERIAL_PROJECTION );
|
||||
pRenderContext->PopMatrix();
|
||||
}
|
||||
#endif
|
||||
|
||||
// Draw everything from each material.
|
||||
FOR_EACH_LL( m_FaceMaterials, iMat )
|
||||
{
|
||||
CFaceMaterial *pMat = m_FaceMaterials[iMat];
|
||||
|
||||
pRenderContext->Bind( pMat->m_pMaterial );
|
||||
|
||||
FOR_EACH_LL( pMat->m_MaterialBufs, iBuf )
|
||||
{
|
||||
CMaterialBuf *pBuf = pMat->m_MaterialBufs[iBuf];
|
||||
|
||||
for( int iCmd=0; iCmd < pBuf->m_DrawCommands.Count(); iCmd++ )
|
||||
{
|
||||
CDrawCommand *pCmd = pBuf->m_DrawCommands[iCmd];
|
||||
|
||||
pRenderContext->BindLightmapPage( pCmd->m_LightmapPageID );
|
||||
pBuf->m_pMesh->Draw( pCmd->m_PrimLists.Base(), pCmd->m_PrimLists.Count() );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pRenderContext->Flush();
|
||||
}
|
||||
|
||||
|
||||
void CBSPLighting::AssignFaceMaterialCounts(
|
||||
CBSPInfo &file,
|
||||
CUtlVector<CFace> &faces )
|
||||
{
|
||||
FOR_EACH_LL( m_FaceMaterials, i )
|
||||
{
|
||||
CFaceMaterial *pMat = m_FaceMaterials[i];
|
||||
|
||||
// Start off an initial CMaterialBuf to dump the faces in.
|
||||
CMaterialBuf *pBuf = new CMaterialBuf;
|
||||
pMat->m_MaterialBufs.AddToTail( pBuf );
|
||||
|
||||
FOR_EACH_LL( pMat->m_Faces, iFace )
|
||||
{
|
||||
CStoredFace *pStoredFace = pMat->m_Faces[iFace];
|
||||
CFace *pFace = pStoredFace->m_pFace;
|
||||
|
||||
pStoredFace->m_iFirstIndex = pBuf->m_nIndices;
|
||||
|
||||
if( pFace->m_iDispInfo == -1 )
|
||||
{
|
||||
pStoredFace->m_nIndices = (pFace->m_nVerts - 2) * 3;
|
||||
|
||||
pBuf->m_nIndices += (pFace->m_nVerts - 2) * 3;
|
||||
pBuf->m_nVerts += pFace->m_nVerts;
|
||||
}
|
||||
else
|
||||
{
|
||||
ddispinfo_t *pDisp = &file.g_dispinfo[pFace->m_iDispInfo];
|
||||
|
||||
int nTris = Square( 1 << pDisp->power ) * 2;
|
||||
int nVerts = Square( (1 << pDisp->power) + 1 );
|
||||
|
||||
pStoredFace->m_nIndices = nTris * 3;
|
||||
|
||||
pBuf->m_nIndices += nTris * 3;
|
||||
pBuf->m_nVerts += nVerts;
|
||||
}
|
||||
|
||||
pBuf->m_Faces.AddToTail( pStoredFace );
|
||||
|
||||
// Don't make the buffers too big..
|
||||
if( pBuf->m_nIndices > (16*1024) || pBuf->m_nVerts > (16*1024) )
|
||||
{
|
||||
pBuf = new CMaterialBuf;
|
||||
pMat->m_MaterialBufs.AddToTail( pBuf );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Determines the appropriate vertex format for LMGroup meshes
|
||||
//-----------------------------------------------------------------------------
|
||||
VertexFormat_t CBSPLighting::ComputeLMGroupVertexFormat( IMaterial * pMaterial )
|
||||
{
|
||||
VertexFormat_t vertexFormat = pMaterial->GetVertexFormat();
|
||||
|
||||
// FIXME: set VERTEX_FORMAT_COMPRESSED if there are no artifacts and if it saves enough memory (use 'mem_dumpvballocs')
|
||||
vertexFormat &= ~VERTEX_FORMAT_COMPRESSED;
|
||||
// FIXME: check for and strip unused vertex elements (bone weights+indices, TANGENT_S/T?) - requires reliable material vertex formats first
|
||||
|
||||
return vertexFormat;
|
||||
}
|
||||
|
||||
void CBSPLighting::BuildLMGroups(
|
||||
CBSPInfo &file,
|
||||
CUtlVector<CFace> &faces,
|
||||
CUtlVector<CVert> &verts,
|
||||
CUtlVector<CDispInfoFaces> &dispInfos
|
||||
)
|
||||
{
|
||||
// Count everything in each CFaceMaterial.
|
||||
AssignFaceMaterialCounts( file, faces );
|
||||
|
||||
|
||||
IMaterialSystem *pMatSys = MaterialSystemInterface();
|
||||
if( !pMatSys )
|
||||
return;
|
||||
|
||||
CMatRenderContextPtr pRenderContext( pMatSys );
|
||||
|
||||
// Now create the static buffers.
|
||||
FOR_EACH_LL( m_FaceMaterials, iMat )
|
||||
{
|
||||
CFaceMaterial *pMat = m_FaceMaterials[iMat];
|
||||
|
||||
FOR_EACH_LL( pMat->m_MaterialBufs, iBuf )
|
||||
{
|
||||
CMaterialBuf *pBuf = pMat->m_MaterialBufs[iBuf];
|
||||
|
||||
VertexFormat_t vertexFormat = ComputeLMGroupVertexFormat( pMat->m_pMaterial );
|
||||
pBuf->m_pMesh = pRenderContext->CreateStaticMesh( vertexFormat, "terd", pMat->m_pMaterial );
|
||||
if( !pBuf->m_pMesh )
|
||||
continue;
|
||||
|
||||
bool bNeedsBumpmap = pMat->m_pMaterial->GetPropertyFlag( MATERIAL_PROPERTY_NEEDS_BUMPED_LIGHTMAPS );
|
||||
|
||||
CMeshBuilder mb;
|
||||
mb.Begin( pBuf->m_pMesh, MATERIAL_TRIANGLES, pBuf->m_nVerts, pBuf->m_nIndices );
|
||||
|
||||
// Write all the faces in.
|
||||
int iCurBaseVert = 0;
|
||||
|
||||
FOR_EACH_LL( pBuf->m_Faces, iFace )
|
||||
{
|
||||
CStoredFace *pStoredFace = pBuf->m_Faces[iFace];
|
||||
CFace *pFace = pStoredFace->m_pFace;
|
||||
|
||||
if( pFace->m_iDispInfo == -1 )
|
||||
{
|
||||
// It's a regular face.
|
||||
CVert *pVerts = &verts[pFace->m_iVertStart];
|
||||
|
||||
for( int iVert=0; iVert < pFace->m_nVerts; iVert++ )
|
||||
{
|
||||
mb.Position3fv( (float*)&pVerts[iVert].m_vPos );
|
||||
|
||||
mb.TexCoord2fv( 0, pVerts[iVert].m_vTexCoords.Base() );
|
||||
mb.TexCoord2fv( 1, pVerts[iVert].m_vLightCoords.Base() );
|
||||
if( bNeedsBumpmap )
|
||||
mb.TexCoord2f ( 2, pStoredFace->m_BumpSTexCoordOffset, 0 );
|
||||
|
||||
mb.Color3f( 1,1,1 );
|
||||
mb.AdvanceVertex();
|
||||
}
|
||||
|
||||
// Write the indices.
|
||||
for( int iTri=0; iTri < pFace->m_nVerts-2; iTri++ )
|
||||
{
|
||||
mb.Index( iCurBaseVert ); mb.AdvanceIndex();
|
||||
mb.Index( iCurBaseVert+iTri+1 ); mb.AdvanceIndex();
|
||||
mb.Index( iCurBaseVert+iTri+2 ); mb.AdvanceIndex();
|
||||
}
|
||||
|
||||
iCurBaseVert += pFace->m_nVerts;
|
||||
}
|
||||
else
|
||||
{
|
||||
// It's a displacement.
|
||||
CDispInfoFaces *pDisp = &dispInfos[pFace->m_iDispInfo];
|
||||
|
||||
// Generate the index list.
|
||||
unsigned short indices[ (1<<MAX_MAP_DISP_POWER) * (1<<MAX_MAP_DISP_POWER) * 6 ];
|
||||
|
||||
int nRequired = DispCommon_GetNumTriIndices( pDisp->m_Power );
|
||||
Assert( nRequired <= sizeof(indices)/sizeof(indices[0]) );
|
||||
|
||||
DispCommon_GenerateTriIndices( pDisp->m_Power, indices );
|
||||
|
||||
for( int iIndex=0; iIndex < nRequired; iIndex++ )
|
||||
{
|
||||
mb.Index( indices[iIndex] + iCurBaseVert );
|
||||
mb.AdvanceIndex();
|
||||
}
|
||||
|
||||
// Generate the vert list.
|
||||
for( int iVert=0; iVert < pDisp->m_Verts.Count(); iVert++ )
|
||||
{
|
||||
mb.Position3fv( (float*)&pDisp->m_Verts[iVert].m_vPos );
|
||||
mb.TexCoord2fv( 0, (float*)&pDisp->m_Verts[iVert].m_vTexCoords );
|
||||
mb.TexCoord2fv( 1, (float*)&pDisp->m_Verts[iVert].m_vLightCoords );
|
||||
|
||||
if( bNeedsBumpmap )
|
||||
mb.TexCoord2f ( 2, pStoredFace->m_BumpSTexCoordOffset, 0 );
|
||||
|
||||
mb.AdvanceVertex();
|
||||
}
|
||||
|
||||
iCurBaseVert += pDisp->m_Verts.Count();;
|
||||
}
|
||||
}
|
||||
|
||||
mb.End();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool FindDrawCommand( CUtlVector<CBSPLighting::CDrawCommand*> &drawCommands, int lmPageID, int &index )
|
||||
{
|
||||
for( int i=0; i < drawCommands.Count(); i++ )
|
||||
{
|
||||
if( drawCommands[i]->m_LightmapPageID == lmPageID )
|
||||
{
|
||||
index = i;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void CBSPLighting::BuildDrawCommands()
|
||||
{
|
||||
FOR_EACH_LL( m_FaceMaterials, iMat )
|
||||
{
|
||||
CFaceMaterial *pMat = m_FaceMaterials[iMat];
|
||||
|
||||
FOR_EACH_LL( pMat->m_MaterialBufs, iBuf )
|
||||
{
|
||||
CMaterialBuf *pBuf = pMat->m_MaterialBufs[iBuf];
|
||||
|
||||
// Group by lightmap page IDs.
|
||||
FOR_EACH_LL( pBuf->m_Faces, iFace )
|
||||
{
|
||||
CStoredFace *pFace = pBuf->m_Faces[iFace];
|
||||
|
||||
int index;
|
||||
if( !FindDrawCommand( pBuf->m_DrawCommands, pFace->m_LightmapPageID, index ) )
|
||||
{
|
||||
index = pBuf->m_DrawCommands.AddToTail( new CDrawCommand );
|
||||
pBuf->m_DrawCommands[index]->m_LightmapPageID = pFace->m_LightmapPageID;
|
||||
}
|
||||
|
||||
CPrimList primList;
|
||||
primList.m_FirstIndex = pFace->m_iFirstIndex;
|
||||
primList.m_NumIndices = pFace->m_nIndices;
|
||||
pBuf->m_DrawCommands[index]->m_PrimLists.AddToTail( primList );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void CBSPLighting::ReloadLightmaps()
|
||||
{
|
||||
if( !m_pVRadDLL )
|
||||
return;
|
||||
|
||||
IMaterialSystem *pMatSys = MaterialSystemInterface();
|
||||
if( !pMatSys )
|
||||
return;
|
||||
|
||||
CBSPInfo bspInfo;
|
||||
m_pVRadDLL->GetBSPInfo( &bspInfo );
|
||||
|
||||
if( !bspInfo.lightdatasize )
|
||||
return;
|
||||
|
||||
Vector4D blocklights[4][MAX_LIGHTMAP_DIM_INCLUDING_BORDER * MAX_LIGHTMAP_DIM_INCLUDING_BORDER];
|
||||
|
||||
for( int iFace=0; iFace < m_StoredFaces.Count(); iFace++ )
|
||||
{
|
||||
CStoredFace *pFace = &m_StoredFaces[iFace];
|
||||
|
||||
// Avoid updating lightmaps in faces that weren't touched.
|
||||
if( bspInfo.m_pFacesTouched && !bspInfo.m_pFacesTouched[pFace->m_iMapFace] )
|
||||
continue;
|
||||
|
||||
dface_t *pIn = &bspInfo.dfaces[ pFace->m_iMapFace ];
|
||||
int nLuxels = pFace->m_LightmapSize[0] * pFace->m_LightmapSize[1];
|
||||
|
||||
bool bNeedsBumpmap = pFace->m_pMaterial->m_pMaterial->GetPropertyFlag( MATERIAL_PROPERTY_NEEDS_BUMPED_LIGHTMAPS );
|
||||
|
||||
texinfo_t *pTexInfo = &bspInfo.texinfo[ bspInfo.dfaces[pFace->m_iMapFace].texinfo ];
|
||||
bool bHasBumpmap = SurfHasBumpedLightmaps( pTexInfo->flags );
|
||||
|
||||
int nLightmaps = 1;
|
||||
if( bNeedsBumpmap && bHasBumpmap )
|
||||
nLightmaps = 4;
|
||||
|
||||
ColorRGBExp32 *pLightmap = (ColorRGBExp32 *)&bspInfo.dlightdata[pIn->lightofs];
|
||||
int iLightmap;
|
||||
for( iLightmap=0; iLightmap < nLightmaps; iLightmap++ )
|
||||
{
|
||||
for( int iLuxel=0; iLuxel < nLuxels; iLuxel++ )
|
||||
{
|
||||
blocklights[iLightmap][iLuxel][0] = TexLightToLinear( pLightmap->r, pLightmap->exponent );
|
||||
blocklights[iLightmap][iLuxel][1] = TexLightToLinear( pLightmap->g, pLightmap->exponent );
|
||||
blocklights[iLightmap][iLuxel][2] = TexLightToLinear( pLightmap->b, pLightmap->exponent );
|
||||
blocklights[iLightmap][iLuxel][3] = 1;
|
||||
++pLightmap;
|
||||
}
|
||||
}
|
||||
|
||||
// If it needs bumpmaps but doesn't have them in the file, then just copy
|
||||
// the lightmap data into the other lightmaps like the engine does.
|
||||
if( bNeedsBumpmap && !bHasBumpmap )
|
||||
{
|
||||
for( iLightmap=1; iLightmap < 4; iLightmap++ )
|
||||
{
|
||||
memcpy( blocklights[iLightmap], blocklights[0], nLuxels * sizeof( blocklights[0][0] ) );
|
||||
}
|
||||
}
|
||||
|
||||
if( bNeedsBumpmap )
|
||||
{
|
||||
pMatSys->UpdateLightmap(
|
||||
pFace->m_LightmapPageID,
|
||||
pFace->m_LightmapSize,
|
||||
pFace->m_OffsetIntoLightmapPage,
|
||||
(float*)blocklights[0], (float*)blocklights[1], (float*)blocklights[2], (float*)blocklights[3] );
|
||||
}
|
||||
else
|
||||
{
|
||||
pMatSys->UpdateLightmap(
|
||||
pFace->m_LightmapPageID,
|
||||
pFace->m_LightmapSize,
|
||||
pFace->m_OffsetIntoLightmapPage,
|
||||
(float*)blocklights[0], NULL, NULL, NULL );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool CBSPLighting::LoadVRADDLL( char const *pFilename )
|
||||
{
|
||||
// Load VRAD's DLL.
|
||||
m_hVRadDLL = Sys_LoadModule( "vrad_dll.dll" );
|
||||
if( !m_hVRadDLL )
|
||||
return false;
|
||||
|
||||
CreateInterfaceFn fn = Sys_GetFactory( m_hVRadDLL );
|
||||
if( !fn )
|
||||
return false;
|
||||
|
||||
int retCode = 0;
|
||||
m_pVRadDLL = (IVRadDLL*)fn( VRAD_INTERFACE_VERSION, &retCode );
|
||||
if( !m_pVRadDLL )
|
||||
return false;
|
||||
|
||||
// Tell VRAD to load the BSP file.
|
||||
if( !m_pVRadDLL->Init( pFilename ) )
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void CBSPLighting::CreateDisplacements( CBSPInfo &file, CUtlVector<CFace> &faces, CUtlVector<CDispInfoFaces> &dispInfos )
|
||||
{
|
||||
/*
|
||||
IMaterialSystem *pMatSys = MaterialSystemInterface();
|
||||
|
||||
dispInfos.SetSize( file.g_numdispinfo );
|
||||
for( int iFace=0; iFace < faces.Size(); iFace++ )
|
||||
{
|
||||
CFace *pFace = &faces[iFace];
|
||||
CStoredFace *pStoredFace = &m_StoredFaces[iFace];
|
||||
dface_t *pInFace = pFace->m_pDFace;
|
||||
|
||||
if( pInFace->dispinfo == -1 )
|
||||
continue;
|
||||
|
||||
ddispinfo_t *pInDisp = &file.g_dispinfo[pInFace->dispinfo];
|
||||
CDispInfoFaces *pOutDisp = &dispInfos[pInFace->dispinfo];
|
||||
|
||||
pOutDisp->m_Power = pInDisp->power;
|
||||
int nVertsPerSide = (1 << pInDisp->power) + 1;
|
||||
|
||||
pOutDisp->m_Verts.SetSize( pInDisp->m_LODs[0].m_nVerts );
|
||||
|
||||
int lightmapPageSize[2];
|
||||
pMatSys->GetLightmapPageSize( pFace->m_pStoredFace->m_LightmapPageID, &lightmapPageSize[0], &lightmapPageSize[1] );
|
||||
|
||||
for( int iVert=0; iVert < pInDisp->m_LODs[0].m_nVerts; iVert++ )
|
||||
{
|
||||
ddisp_lod_vert_t *pInVert = &file.ddispverts[ pInDisp->m_LODs[0].m_iVertStart + iVert ];
|
||||
CVert *pOutVert = &pOutDisp->m_Verts[iVert];
|
||||
|
||||
pOutVert->m_vPos = pInVert->m_vPos;
|
||||
for( int iCoord=0; iCoord < 2; iCoord++ )
|
||||
{
|
||||
float flVal = pInVert->m_LightCoords[iCoord];
|
||||
|
||||
flVal += pFace->m_pStoredFace->m_OffsetIntoLightmapPage[iCoord];
|
||||
flVal += 0.5f;
|
||||
flVal /= lightmapPageSize[iCoord];
|
||||
Assert( _finite(flVal) );
|
||||
pOutVert->m_vLightCoords[iCoord] = flVal;
|
||||
|
||||
pOutVert->m_vTexCoords[iCoord] = pInVert->m_TexCoords[iCoord];
|
||||
|
||||
if( iCoord == 0 )
|
||||
pOutVert->m_vTexCoords[iCoord] /= pStoredFace->m_pMaterial->m_pMaterial->GetMappingWidth();
|
||||
else
|
||||
pOutVert->m_vTexCoords[iCoord] /= pStoredFace->m_pMaterial->m_pMaterial->GetMappingHeight();
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
void CBSPLighting::InitMaterialLUT( CBSPInfo &file )
|
||||
{
|
||||
m_StringTableIDToMaterial.SetSize( file.nTexDataStringTable );
|
||||
for( int i=0; i < m_StringTableIDToMaterial.Count(); i++ )
|
||||
m_StringTableIDToMaterial[i] = 0;
|
||||
}
|
||||
|
||||
|
||||
CBSPLighting::CFaceMaterial* CBSPLighting::FindOrAddMaterial( CBSPInfo &file, int stringTableID )
|
||||
{
|
||||
if( stringTableID >= m_StringTableIDToMaterial.Count() )
|
||||
{
|
||||
Assert( false );
|
||||
return 0;
|
||||
}
|
||||
|
||||
if( m_StringTableIDToMaterial[stringTableID] )
|
||||
{
|
||||
return m_StringTableIDToMaterial[stringTableID];
|
||||
}
|
||||
else
|
||||
{
|
||||
IMaterial *pMaterial = 0;
|
||||
char *pMaterialName = &file.texDataStringData[ file.texDataStringTable[ stringTableID ] ];
|
||||
if( pMaterialName )
|
||||
pMaterial = MaterialSystemInterface()->FindMaterial( pMaterialName, TEXTURE_GROUP_OTHER );
|
||||
|
||||
// Don't add CFaceMaterials without a material.
|
||||
if( !pMaterial )
|
||||
return 0;
|
||||
|
||||
// This is lovely. We have to call this stuff to get it to precalculate the data it needs.
|
||||
pMaterial->GetMappingHeight();
|
||||
pMaterial->RecomputeStateSnapshots();
|
||||
|
||||
CFaceMaterial *pMat = new CFaceMaterial;
|
||||
if( pMaterial->IsTranslucent() )
|
||||
m_FaceMaterials.AddToTail( pMat );
|
||||
else
|
||||
m_FaceMaterials.AddToHead( pMat );
|
||||
|
||||
pMat->m_pMaterial = pMaterial;
|
||||
|
||||
m_StringTableIDToMaterial[stringTableID] = pMat;
|
||||
return pMat;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
IBSPLighting* CreateBSPLighting()
|
||||
{
|
||||
return new CBSPLighting;
|
||||
}
|
||||
186
hammer/bsplighting.h
Normal file
186
hammer/bsplighting.h
Normal file
@@ -0,0 +1,186 @@
|
||||
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef BSPLIGHTING_H
|
||||
#define BSPLIGHTING_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "ibsplighting.h"
|
||||
#include "utlvector.h"
|
||||
#include "utllinkedlist.h"
|
||||
#include "bspfile.h"
|
||||
#include "interface.h"
|
||||
#include "ivraddll.h"
|
||||
#include "ibsplightingthread.h"
|
||||
|
||||
|
||||
class CBSPLighting : public IBSPLighting
|
||||
{
|
||||
public:
|
||||
|
||||
CBSPLighting();
|
||||
virtual ~CBSPLighting();
|
||||
virtual void Release();
|
||||
|
||||
virtual bool Load( char const *pFilename );
|
||||
virtual void Term();
|
||||
virtual bool Serialize();
|
||||
virtual void StartLighting( char const *pVMFFileWithEnts );
|
||||
virtual float GetPercentComplete();
|
||||
virtual void Interrupt();
|
||||
virtual bool CheckForNewLightmaps();
|
||||
virtual void Draw();
|
||||
|
||||
|
||||
private:
|
||||
class CVert
|
||||
{
|
||||
public:
|
||||
Vector m_vPos;
|
||||
Vector2D m_vTexCoords;
|
||||
Vector2D m_vLightCoords;
|
||||
};
|
||||
|
||||
// This is the face data we store for each face. Just enough to
|
||||
// let us update the lightmaps in memory.
|
||||
class CFaceMaterial;
|
||||
class CFace;
|
||||
class CStoredFace
|
||||
{
|
||||
public:
|
||||
int m_iMapFace; // index into dfaces.
|
||||
int m_LightmapPageID;
|
||||
int m_OffsetIntoLightmapPage[2];
|
||||
int m_LightmapSize[2]; // This already has 1 added to it (unlike dface).
|
||||
CFaceMaterial *m_pMaterial;
|
||||
CFace *m_pFace; // only valid inside of Load
|
||||
float m_BumpSTexCoordOffset;
|
||||
|
||||
// Indices into CFaceMaterial::m_pMesh
|
||||
int m_iFirstIndex;
|
||||
int m_nIndices;
|
||||
};
|
||||
|
||||
class CDrawCommand
|
||||
{
|
||||
public:
|
||||
CUtlVector<CPrimList> m_PrimLists;
|
||||
int m_LightmapPageID;
|
||||
};
|
||||
|
||||
friend bool FindDrawCommand( CUtlVector<CDrawCommand*> &drawCommands, int lmPageID, int &index );
|
||||
|
||||
class CMaterialBuf
|
||||
{
|
||||
public:
|
||||
CMaterialBuf();
|
||||
~CMaterialBuf();
|
||||
|
||||
CUtlLinkedList<CStoredFace*, unsigned short> m_Faces;
|
||||
|
||||
// Commands to draw everything in this material as fast as possible.
|
||||
CUtlVector<CDrawCommand*> m_DrawCommands;
|
||||
|
||||
int m_nVerts;
|
||||
int m_nIndices;
|
||||
|
||||
IMesh *m_pMesh;
|
||||
};
|
||||
|
||||
|
||||
class CFaceMaterial
|
||||
{
|
||||
public:
|
||||
~CFaceMaterial();
|
||||
|
||||
IMaterial *m_pMaterial;
|
||||
|
||||
// Faces using this material.
|
||||
CUtlLinkedList<CStoredFace*, unsigned short> m_Faces;
|
||||
|
||||
// Static buffers to hold all the verts.
|
||||
CUtlLinkedList<CMaterialBuf*, unsigned short> m_MaterialBufs;
|
||||
};
|
||||
|
||||
class CFace
|
||||
{
|
||||
public:
|
||||
|
||||
int m_iDispInfo;
|
||||
dface_t *m_pDFace; // used while loading..
|
||||
|
||||
CStoredFace *m_pStoredFace;
|
||||
int m_LightmapSortID;
|
||||
|
||||
float m_LightmapVecs[2][4];
|
||||
int m_LightmapTextureMinsInLuxels[2];
|
||||
|
||||
int m_iVertStart; // Indexes CBSPLighting::m_Verts.
|
||||
int m_nVerts;
|
||||
};
|
||||
|
||||
class CDispInfoFaces
|
||||
{
|
||||
public:
|
||||
CUtlVector<CVert> m_Verts;
|
||||
int m_Power;
|
||||
};
|
||||
|
||||
private:
|
||||
|
||||
void AssignFaceMaterialCounts(
|
||||
CBSPInfo &file,
|
||||
CUtlVector<CFace> &faces );
|
||||
|
||||
VertexFormat_t ComputeLMGroupVertexFormat( IMaterial * pMaterial );
|
||||
|
||||
void BuildLMGroups(
|
||||
CBSPInfo &file,
|
||||
CUtlVector<CFace> &faces,
|
||||
CUtlVector<CVert> &verts,
|
||||
CUtlVector<CDispInfoFaces> &dispInfos
|
||||
);
|
||||
|
||||
void BuildDrawCommands();
|
||||
|
||||
void ReloadLightmaps();
|
||||
bool LoadVRADDLL( char const *pFilename );
|
||||
void CreateDisplacements( CBSPInfo &file, CUtlVector<CFace> &faces, CUtlVector<CDispInfoFaces> &dispInfos );
|
||||
|
||||
// Fast material ID to CFaceMaterial lookups..
|
||||
void InitMaterialLUT( CBSPInfo &file );
|
||||
CFaceMaterial* FindOrAddMaterial( CBSPInfo &file, int stringTableID );
|
||||
|
||||
|
||||
private:
|
||||
CUtlVector<CStoredFace> m_StoredFaces;
|
||||
CUtlLinkedList<CFaceMaterial*, unsigned short> m_FaceMaterials;
|
||||
|
||||
int m_nTotalTris;
|
||||
|
||||
// The VRAD DLL. This holds the level file.
|
||||
CSysModule *m_hVRadDLL;
|
||||
IVRadDLL *m_pVRadDLL;
|
||||
|
||||
// The lighting thread.
|
||||
IBSPLightingThread *m_pBSPLightingThread;
|
||||
|
||||
// Used to detect when lighting is finished so it can update the lightmaps
|
||||
// in the material system.
|
||||
bool m_bLightingInProgress;
|
||||
|
||||
// Maps string table IDs to materials.
|
||||
CUtlVector<CFaceMaterial*> m_StringTableIDToMaterial;
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif // BSPLIGHTING_H
|
||||
227
hammer/bsplightingthread.cpp
Normal file
227
hammer/bsplightingthread.cpp
Normal file
@@ -0,0 +1,227 @@
|
||||
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "bsplightingthread.h"
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
|
||||
|
||||
// --------------------------------------------------------------------------- //
|
||||
// Global functions.
|
||||
// --------------------------------------------------------------------------- //
|
||||
IBSPLightingThread* CreateBSPLightingThread( IVRadDLL *pDLL )
|
||||
{
|
||||
CBSPLightingThread *pRet = new CBSPLightingThread;
|
||||
|
||||
if( pRet->Init( pDLL ) )
|
||||
{
|
||||
return pRet;
|
||||
}
|
||||
else
|
||||
{
|
||||
delete pRet;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
DWORD WINAPI ThreadMainLoop_Static( LPVOID lpParameter )
|
||||
{
|
||||
return ((CBSPLightingThread*)lpParameter)->ThreadMainLoop();
|
||||
}
|
||||
|
||||
|
||||
// --------------------------------------------------------------------------- //
|
||||
// Static helpers.
|
||||
// --------------------------------------------------------------------------- //
|
||||
|
||||
class CCSLock
|
||||
{
|
||||
public:
|
||||
CCSLock( CRITICAL_SECTION *pCS )
|
||||
{
|
||||
EnterCriticalSection( pCS );
|
||||
m_pCS = pCS;
|
||||
}
|
||||
|
||||
~CCSLock()
|
||||
{
|
||||
LeaveCriticalSection( m_pCS );
|
||||
}
|
||||
|
||||
CRITICAL_SECTION *m_pCS;
|
||||
};
|
||||
|
||||
|
||||
|
||||
// --------------------------------------------------------------------------- //
|
||||
//
|
||||
// --------------------------------------------------------------------------- //
|
||||
|
||||
CBSPLightingThread::CBSPLightingThread()
|
||||
{
|
||||
InitializeCriticalSection( &m_CS );
|
||||
|
||||
m_hThread = 0;
|
||||
m_ThreadID = 0;
|
||||
|
||||
m_ThreadCmd = THREADCMD_NONE;
|
||||
m_ThreadState = STATE_IDLE;
|
||||
}
|
||||
|
||||
|
||||
CBSPLightingThread::~CBSPLightingThread()
|
||||
{
|
||||
if( m_hThread )
|
||||
{
|
||||
// Stop the current lighting process if one is going on.
|
||||
Interrupt();
|
||||
|
||||
// Tell the thread to exit.
|
||||
SetThreadCmd( THREADCMD_EXIT );
|
||||
|
||||
DWORD dwCode;
|
||||
while( 1 )
|
||||
{
|
||||
if( GetExitCodeThread( m_hThread, &dwCode ) && dwCode == 0 )
|
||||
break;
|
||||
|
||||
Sleep( 10 );
|
||||
}
|
||||
|
||||
CloseHandle( m_hThread );
|
||||
}
|
||||
|
||||
DeleteCriticalSection( &m_CS );
|
||||
}
|
||||
|
||||
|
||||
void CBSPLightingThread::Release()
|
||||
{
|
||||
delete this;
|
||||
}
|
||||
|
||||
|
||||
void CBSPLightingThread::StartLighting( char const *pVMFFileWithEntities )
|
||||
{
|
||||
// First, kill any lighting going on.
|
||||
Interrupt();
|
||||
|
||||
// Store the VMF file data for the thread.
|
||||
int len = strlen( pVMFFileWithEntities ) + 1;
|
||||
m_VMFFileWithEntities.CopyArray( pVMFFileWithEntities, len );
|
||||
|
||||
// Tell the thread to start lighting.
|
||||
SetThreadState( STATE_LIGHTING );
|
||||
SetThreadCmd( THREADCMD_LIGHT );
|
||||
}
|
||||
|
||||
|
||||
int CBSPLightingThread::GetCurrentState()
|
||||
{
|
||||
return GetThreadState();
|
||||
}
|
||||
|
||||
|
||||
void CBSPLightingThread::Interrupt()
|
||||
{
|
||||
if( GetThreadState() == STATE_LIGHTING )
|
||||
{
|
||||
m_pVRadDLL->Interrupt();
|
||||
|
||||
while( GetThreadState() == STATE_LIGHTING )
|
||||
Sleep( 10 );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
float CBSPLightingThread::GetPercentComplete()
|
||||
{
|
||||
return m_pVRadDLL->GetPercentComplete();
|
||||
}
|
||||
|
||||
|
||||
bool CBSPLightingThread::Init( IVRadDLL *pDLL )
|
||||
{
|
||||
m_pVRadDLL = pDLL;
|
||||
|
||||
m_hThread = CreateThread(
|
||||
NULL,
|
||||
0,
|
||||
ThreadMainLoop_Static,
|
||||
this,
|
||||
0,
|
||||
&m_ThreadID );
|
||||
|
||||
if( !m_hThread )
|
||||
return false;
|
||||
|
||||
SetThreadPriority( m_hThread, THREAD_PRIORITY_LOWEST );
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
DWORD CBSPLightingThread::ThreadMainLoop()
|
||||
{
|
||||
while( 1 )
|
||||
{
|
||||
int cmd = GetThreadCmd();
|
||||
|
||||
if( cmd == THREADCMD_NONE )
|
||||
{
|
||||
// Keep waiting for a new command.
|
||||
Sleep( 10 );
|
||||
}
|
||||
else if( cmd == THREADCMD_LIGHT )
|
||||
{
|
||||
if( m_pVRadDLL->DoIncrementalLight( m_VMFFileWithEntities.Base() ) )
|
||||
SetThreadState( STATE_FINISHED );
|
||||
else
|
||||
SetThreadState( STATE_IDLE );
|
||||
}
|
||||
else if( cmd == THREADCMD_EXIT )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int CBSPLightingThread::GetThreadCmd()
|
||||
{
|
||||
CCSLock lock( &m_CS );
|
||||
|
||||
int ret = m_ThreadCmd;
|
||||
m_ThreadCmd = THREADCMD_NONE;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
void CBSPLightingThread::SetThreadCmd( int cmd )
|
||||
{
|
||||
CCSLock lock( &m_CS );
|
||||
m_ThreadCmd = cmd;
|
||||
}
|
||||
|
||||
|
||||
int CBSPLightingThread::GetThreadState()
|
||||
{
|
||||
CCSLock lock( &m_CS );
|
||||
return m_ThreadState;
|
||||
}
|
||||
|
||||
|
||||
void CBSPLightingThread::SetThreadState( int state )
|
||||
{
|
||||
CCSLock lock( &m_CS );
|
||||
m_ThreadState = state;
|
||||
}
|
||||
|
||||
|
||||
87
hammer/bsplightingthread.h
Normal file
87
hammer/bsplightingthread.h
Normal file
@@ -0,0 +1,87 @@
|
||||
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef BSPLIGHTINGTHREAD_H
|
||||
#define BSPLIGHTINGTHREAD_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "ibsplightingthread.h"
|
||||
#include "utlvector.h"
|
||||
|
||||
|
||||
class CBSPLightingThread : public IBSPLightingThread
|
||||
{
|
||||
public:
|
||||
|
||||
CBSPLightingThread();
|
||||
|
||||
|
||||
// IBSPLightingThread functions.
|
||||
public:
|
||||
virtual ~CBSPLightingThread();
|
||||
virtual void Release();
|
||||
virtual void StartLighting( char const *pVMFFileWithEntities );
|
||||
virtual int GetCurrentState();
|
||||
virtual void Interrupt();
|
||||
virtual float GetPercentComplete();
|
||||
|
||||
|
||||
// Other functions.
|
||||
public:
|
||||
|
||||
// This is called immediately after the constructor. It creates the thread.
|
||||
bool Init( IVRadDLL *pDLL );
|
||||
|
||||
|
||||
|
||||
// Threadsafe functions.
|
||||
public:
|
||||
|
||||
enum
|
||||
{
|
||||
THREADCMD_NONE=0,
|
||||
THREADCMD_LIGHT=1,
|
||||
THREADCMD_EXIT=2
|
||||
};
|
||||
|
||||
// Get the current command to the thread. Resets to THREADCMD_NONE on exit.
|
||||
int GetThreadCmd();
|
||||
void SetThreadCmd( int cmd );
|
||||
|
||||
// Returns an IBSPLightingThread::STATE_ define.
|
||||
int GetThreadState();
|
||||
void SetThreadState( int state );
|
||||
|
||||
|
||||
public:
|
||||
|
||||
// The thread's run function.
|
||||
DWORD ThreadMainLoop();
|
||||
|
||||
|
||||
public:
|
||||
|
||||
int m_ThreadCmd; // Next command for the thread to run.
|
||||
int m_ThreadState; // Current state of the thread.
|
||||
|
||||
CUtlVector<char> m_VMFFileWithEntities;
|
||||
|
||||
|
||||
public:
|
||||
IVRadDLL *m_pVRadDLL;
|
||||
|
||||
HANDLE m_hThread;
|
||||
DWORD m_ThreadID;
|
||||
CRITICAL_SECTION m_CS;
|
||||
};
|
||||
|
||||
|
||||
#endif // BSPLIGHTINGTHREAD_H
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user