diff options
| author | FluorescentCIAAfricanAmerican <[email protected]> | 2020-04-22 12:56:21 -0400 |
|---|---|---|
| committer | FluorescentCIAAfricanAmerican <[email protected]> | 2020-04-22 12:56:21 -0400 |
| commit | 3bf9df6b2785fa6d951086978a3e66f49427166a (patch) | |
| tree | 2c0f1f0c63c4832882bc93814ebd2c2b1c6224e5 /hammer/ToolOverlay.cpp | |
| download | archived-source-engine-2018-hl2-src-master.tar.xz archived-source-engine-2018-hl2-src-master.zip | |
Diffstat (limited to 'hammer/ToolOverlay.cpp')
| -rw-r--r-- | hammer/ToolOverlay.cpp | 546 |
1 files changed, 546 insertions, 0 deletions
diff --git a/hammer/ToolOverlay.cpp b/hammer/ToolOverlay.cpp new file mode 100644 index 0000000..b0d5b40 --- /dev/null +++ b/hammer/ToolOverlay.cpp @@ -0,0 +1,546 @@ +//========= Copyright 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() +{ +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +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 ) + { + CMapOverlay *pOverlay = dynamic_cast<CMapOverlay*>( pChildren->Element(pos) ); + 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 ) + { + CMapOverlay *pOverlay = dynamic_cast<CMapOverlay*>( pChildren->Element(pos2) ); + 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 = pSelection->Element( iSelection ); + if ( pMapClass && pMapClass->IsMapClass( MAPCLASS_TYPE( CMapEntity ) ) ) + { + const CMapObjectList *pChildren = pMapClass->GetChildren(); + FOR_EACH_OBJ( *pChildren, pos ) + { + CMapOverlay *pOverlay = dynamic_cast<CMapOverlay*>( pChildren->Element(pos) ); + 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 = pSelection->Element( iSelection ); + if ( pMapClass && pMapClass->IsMapClass( MAPCLASS_TYPE( CMapEntity ) ) ) + { + const CMapObjectList *pChildren = pMapClass->GetChildren(); + FOR_EACH_OBJ( *pChildren, pos ) + { + CMapOverlay *pOverlay = dynamic_cast<CMapOverlay*>( pChildren->Element(pos) ); + 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 posWorld; + CMapClass *pChild = pWorld->GetFirstDescendent( posWorld ); + while ( pChild ) + { + CMapEntity *pEntity = dynamic_cast<CMapEntity*>( pChild ); + if ( pEntity ) + { + const CMapObjectList *pChildren = pEntity->GetChildren(); + FOR_EACH_OBJ( *pChildren, pos ) + { + CMapOverlay *pOverlay = dynamic_cast<CMapOverlay*>( pChildren->Element(pos) ); + 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( posWorld ); + } +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +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 ); + } + } +} |