Counter Strike : Global Offensive Source Code
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

592 lines
17 KiB

  1. //========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================//
  7. #include <stdafx.h>
  8. #include "MapWorld.h"
  9. #include "GlobalFunctions.h"
  10. #include "MainFrm.h"
  11. #include "ToolOverlay.h"
  12. #include "MapDoc.h"
  13. #include "History.h"
  14. #include "CollisionUtils.h"
  15. #include "cmodel.h"
  16. #include "MapView3D.h"
  17. #include "MapView2D.h"
  18. #include "MapSolid.h"
  19. #include "Camera.h"
  20. #include "ObjectProperties.h" // FIXME: For ObjectProperties::RefreshData
  21. #include "Selection.h"
  22. // memdbgon must be the last include file in a .cpp file!!!
  23. #include <tier0/memdbgon.h>
  24. #define OVERLAY_TOOL_SNAP_DISTANCE 35.0f
  25. //-----------------------------------------------------------------------------
  26. // Purpose: Constructor
  27. //-----------------------------------------------------------------------------
  28. CToolOverlay::CToolOverlay()
  29. {
  30. m_bDragging = false;
  31. m_pActiveOverlay = NULL;
  32. }
  33. //-----------------------------------------------------------------------------
  34. // Purpose: Destructor
  35. //-----------------------------------------------------------------------------
  36. CToolOverlay::~CToolOverlay()
  37. {
  38. }
  39. //-----------------------------------------------------------------------------
  40. //-----------------------------------------------------------------------------
  41. void CToolOverlay::OnActivate()
  42. {
  43. m_bDragging = false;
  44. m_pActiveOverlay = NULL;
  45. }
  46. //-----------------------------------------------------------------------------
  47. //-----------------------------------------------------------------------------
  48. void CToolOverlay::OnDeactivate()
  49. {
  50. }
  51. //-----------------------------------------------------------------------------
  52. // Purpose: Handles key down events in the 2D view.
  53. // Input : Per CWnd::OnKeyDown.
  54. // Output : Returns true if the message was handled, false if not.
  55. //-----------------------------------------------------------------------------
  56. bool CToolOverlay::OnKeyDown2D(CMapView2D *pView, UINT nChar, UINT nRepCnt, UINT nFlags)
  57. {
  58. switch (nChar)
  59. {
  60. case VK_ESCAPE:
  61. {
  62. ToolManager()->SetTool(TOOL_POINTER);
  63. return true;
  64. }
  65. }
  66. return false;
  67. }
  68. //-----------------------------------------------------------------------------
  69. // Purpose: Handles key down events in the 3D view.
  70. // Input : Per CWnd::OnKeyDown.
  71. // Output : Returns true if the message was handled, false if not.
  72. //-----------------------------------------------------------------------------
  73. bool CToolOverlay::OnKeyDown3D(CMapView3D *pView, UINT nChar, UINT nRepCnt, UINT nFlags)
  74. {
  75. switch (nChar)
  76. {
  77. case VK_ESCAPE:
  78. {
  79. ToolManager()->SetTool(TOOL_POINTER);
  80. return true;
  81. }
  82. }
  83. return false;
  84. }
  85. //-----------------------------------------------------------------------------
  86. //-----------------------------------------------------------------------------
  87. bool CToolOverlay::OnLMouseUp3D( CMapView3D *pView, UINT nFlags, const Vector2D &vPoint )
  88. {
  89. // Post drag events.
  90. PostDrag();
  91. // Update the entity properties dialog.
  92. GetMainWnd()->pObjectProperties->MarkDataDirty();
  93. return true;
  94. }
  95. //-----------------------------------------------------------------------------
  96. //-----------------------------------------------------------------------------
  97. bool CToolOverlay::OnLMouseDown3D( CMapView3D *pView, UINT nFlags, const Vector2D &vPoint )
  98. {
  99. // Handle the overlay "handle" selection.
  100. if ( HandleSelection( pView, vPoint ) )
  101. {
  102. PreDrag();
  103. return true;
  104. }
  105. // Handle adding and removing overlay entities from the selection list.
  106. OverlaySelection( pView, nFlags, vPoint );
  107. // Handle the overlay creation and placement (if we hit a solid).
  108. ULONG ulFace;
  109. CMapClass *pObject = NULL;
  110. if ( ( pObject = pView->NearestObjectAt( vPoint, ulFace ) ) != NULL )
  111. {
  112. CMapSolid *pSolid = dynamic_cast<CMapSolid*>( pObject );
  113. if ( pSolid )
  114. {
  115. return CreateOverlay( pSolid, ulFace, pView, vPoint );
  116. }
  117. }
  118. return true;
  119. }
  120. //-----------------------------------------------------------------------------
  121. //-----------------------------------------------------------------------------
  122. bool CToolOverlay::OnMouseMove3D( CMapView3D *pView, UINT nFlags, const Vector2D &vPoint )
  123. {
  124. if ( m_bDragging )
  125. {
  126. bool bShift = ( ( GetKeyState( VK_SHIFT ) & 0x8000 ) != 0 );
  127. // Build the ray and drag the overlay handle to the impact point.
  128. const CCamera *pCamera = pView->GetCamera();
  129. if ( pCamera )
  130. {
  131. Vector vecStart, vecEnd;
  132. pView->BuildRay( vPoint, vecStart, vecEnd );
  133. OnDrag( vecStart, vecEnd, bShift );
  134. }
  135. }
  136. return true;
  137. }
  138. //-----------------------------------------------------------------------------
  139. //-----------------------------------------------------------------------------
  140. bool CToolOverlay::CreateOverlay( CMapSolid *pSolid, ULONG iFace, CMapView3D *pView, Vector2D point )
  141. {
  142. // Build a ray to trace against the face that they clicked on to
  143. // find the point of intersection.
  144. Vector vecStart, vecEnd;
  145. pView->BuildRay( point, vecStart, vecEnd );
  146. Vector vecHitPos, vecHitNormal;
  147. CMapFace *pFace = pSolid->GetFace( iFace );
  148. if( pFace->TraceLine( vecHitPos, vecHitNormal, vecStart, vecEnd ) )
  149. {
  150. // Create and initialize the "entity" --> "overlay."
  151. CMapEntity *pEntity = new CMapEntity;
  152. pEntity->SetKeyValue( "material", GetDefaultTextureName() );
  153. pEntity->SetPlaceholder( TRUE );
  154. pEntity->SetOrigin( vecHitPos );
  155. pEntity->SetClass( "info_overlay" );
  156. // Add the entity to the world.
  157. m_pDocument->AddObjectToWorld( pEntity );
  158. // Setup "history."
  159. GetHistory()->MarkUndoPosition( NULL, "Create Overlay" );
  160. GetHistory()->KeepNew( pEntity );
  161. // Initialize the overlay.
  162. InitOverlay( pEntity, pFace );
  163. pEntity->CalcBounds( TRUE );
  164. // Add to selection list.
  165. m_pDocument->SelectObject( pEntity, scSelect );
  166. m_bEmpty = false;
  167. // Set modified and update views.
  168. m_pDocument->SetModifiedFlag();
  169. m_pShoreline = NULL;
  170. return true;
  171. }
  172. return false;
  173. }
  174. //-----------------------------------------------------------------------------
  175. // Purpose:
  176. //-----------------------------------------------------------------------------
  177. void CToolOverlay::InitOverlay( CMapEntity *pEntity, CMapFace *pFace )
  178. {
  179. // Valid face?
  180. if ( !pFace )
  181. return;
  182. const CMapObjectList *pChildren = pEntity->GetChildren();
  183. FOR_EACH_OBJ( *pChildren, pos )
  184. {
  185. CMapClass *pMapClassObj = (CUtlReference< CMapClass >)pChildren->Element(pos);
  186. CMapOverlay *pOverlay = dynamic_cast<CMapOverlay*>( pMapClassObj );
  187. if ( pOverlay )
  188. {
  189. pOverlay->Basis_Init( pFace );
  190. pOverlay->Handles_Init( pFace );
  191. pOverlay->SideList_Init( pFace );
  192. pOverlay->SetOverlayType( OVERLAY_TYPE_GENERIC );
  193. pOverlay->SetLoaded( true );
  194. pOverlay->CalcBounds( true );
  195. }
  196. }
  197. }
  198. //-----------------------------------------------------------------------------
  199. //-----------------------------------------------------------------------------
  200. void CToolOverlay::OverlaySelection( CMapView3D *pView, UINT nFlags, const Vector2D &vPoint )
  201. {
  202. CMapObjectList aSelectionList;
  203. m_pDocument->GetSelection()->ClearHitList();
  204. // Find out how many (and what) map objects are under the point clicked on.
  205. HitInfo_t Objects[MAX_PICK_HITS];
  206. int nHits = pView->ObjectsAt( vPoint, Objects, sizeof( Objects ) / sizeof( Objects[0] ) );
  207. if ( nHits != 0 )
  208. {
  209. // We now have an array of pointers to CMapAtoms. Any that can be upcast to CMapClass objects?
  210. for ( int iHit = 0; iHit < nHits; ++iHit )
  211. {
  212. CMapClass *pMapClass = dynamic_cast<CMapClass*>( Objects[iHit].pObject );
  213. if ( pMapClass )
  214. {
  215. aSelectionList.AddToTail( pMapClass );
  216. }
  217. }
  218. }
  219. // Did we hit anything?
  220. if ( !aSelectionList.Count() )
  221. {
  222. m_pDocument->SelectFace( NULL, 0, scClear );
  223. m_pDocument->SelectObject( NULL, scClear|scSaveChanges );
  224. SetEmpty();
  225. return;
  226. }
  227. // Find overlays.
  228. bool bUpdateViews = false;
  229. SelectMode_t eSelectMode = m_pDocument->GetSelection()->GetMode();
  230. FOR_EACH_OBJ( aSelectionList, pos )
  231. {
  232. CMapClass *pObject = aSelectionList.Element( pos );
  233. CMapClass *pHitObject = pObject->PrepareSelection( eSelectMode );
  234. if ( pHitObject )
  235. {
  236. if ( pHitObject->IsMapClass( MAPCLASS_TYPE( CMapEntity ) ) )
  237. {
  238. const CMapObjectList *pChildren = pHitObject->GetChildren();
  239. FOR_EACH_OBJ( *pChildren, pos2 )
  240. {
  241. CMapClass *pMapClassObj = (CUtlReference< CMapClass >)pChildren->Element(pos2);
  242. CMapOverlay *pOverlay = dynamic_cast<CMapOverlay*>( pMapClassObj );
  243. if ( pOverlay )
  244. {
  245. m_pDocument->GetSelection()->AddHit( pHitObject );
  246. m_bEmpty = false;
  247. UINT cmd = scClear | scSelect | scSaveChanges;
  248. if (nFlags & MK_CONTROL)
  249. {
  250. cmd = scToggle;
  251. }
  252. m_pDocument->SelectObject( pHitObject, cmd );
  253. bUpdateViews = true;
  254. }
  255. }
  256. }
  257. }
  258. }
  259. // Update the views.
  260. if ( bUpdateViews )
  261. {
  262. m_pDocument->UpdateAllViews( MAPVIEW_UPDATE_OBJECTS );
  263. }
  264. }
  265. //-----------------------------------------------------------------------------
  266. //-----------------------------------------------------------------------------
  267. bool CToolOverlay::OnContextMenu2D( CMapView2D *pView, UINT nFlags, const Vector2D &vPoint )
  268. {
  269. static CMenu menu, menuOverlay;
  270. static bool bInit = false;
  271. if ( !bInit )
  272. {
  273. // Create the menu.
  274. menu.LoadMenu( IDR_POPUPS );
  275. menuOverlay.Attach( ::GetSubMenu( menu.m_hMenu, 6 ) );
  276. bInit = true;
  277. }
  278. if ( !pView->PointInClientRect(vPoint) )
  279. return false;
  280. if (!IsEmpty())
  281. {
  282. if ( HitTest( pView, vPoint, false ) )
  283. {
  284. CPoint ptScreen( vPoint.x,vPoint.y);
  285. pView->ClientToScreen(&ptScreen);
  286. menuOverlay.TrackPopupMenu( TPM_LEFTBUTTON | TPM_RIGHTBUTTON | TPM_LEFTALIGN, ptScreen.x, ptScreen.y, pView );
  287. }
  288. }
  289. return true;
  290. }
  291. //-----------------------------------------------------------------------------
  292. //-----------------------------------------------------------------------------
  293. bool CToolOverlay::UpdateTranslation( const Vector &vUpdate, UINT nFlags)
  294. {
  295. // if( m_bBoxSelecting )
  296. // return Box3D::UpdateTranslation( pt, nFlags );
  297. return true;
  298. }
  299. //-----------------------------------------------------------------------------
  300. //-----------------------------------------------------------------------------
  301. void CToolOverlay::HandlesReset( void )
  302. {
  303. // Go through selection list and reset overlay handles.
  304. const CMapObjectList *pSelection = m_pDocument->GetSelection()->GetList();
  305. for( int iSelection = 0; iSelection < pSelection->Count(); ++iSelection )
  306. {
  307. CMapClass *pMapClass = (CUtlReference< CMapClass >)pSelection->Element( iSelection );
  308. if ( pMapClass && pMapClass->IsMapClass( MAPCLASS_TYPE( CMapEntity ) ) )
  309. {
  310. const CMapObjectList *pChildren = pMapClass->GetChildren();
  311. FOR_EACH_OBJ( *pChildren, pos )
  312. {
  313. CMapClass *pMapClassCast = (CUtlReference< CMapClass >)pChildren->Element( pos );
  314. CMapOverlay *pOverlay = dynamic_cast<CMapOverlay*>( pMapClassCast );
  315. if ( pOverlay )
  316. {
  317. pOverlay->HandlesReset();
  318. break;
  319. }
  320. }
  321. }
  322. }
  323. }
  324. //-----------------------------------------------------------------------------
  325. //-----------------------------------------------------------------------------
  326. bool CToolOverlay::HandleSelection( CMapView *pView, const Vector2D &vPoint )
  327. {
  328. // Reset the hit overlay.
  329. m_pActiveOverlay = NULL;
  330. // Go through selection list and test all overlay's handles and set the
  331. // "hit" overlay current.
  332. const CMapObjectList *pSelection = m_pDocument->GetSelection()->GetList();
  333. for ( int iSelection = 0; iSelection < pSelection->Count(); ++iSelection )
  334. {
  335. CMapClass *pMapClass = (CUtlReference< CMapClass >)pSelection->Element( iSelection );
  336. if ( pMapClass && pMapClass->IsMapClass( MAPCLASS_TYPE( CMapEntity ) ) )
  337. {
  338. const CMapObjectList *pChildren = pMapClass->GetChildren();
  339. FOR_EACH_OBJ( *pChildren, pos )
  340. {
  341. CMapClass *pMapClassCast = (CUtlReference< CMapClass >)pChildren->Element(pos);
  342. CMapOverlay *pOverlay = dynamic_cast<CMapOverlay*>( pMapClassCast );
  343. if ( pOverlay && pOverlay->IsSelected() )
  344. {
  345. if ( pOverlay->HandlesHitTest( pView, vPoint ) )
  346. {
  347. m_pActiveOverlay = pOverlay;
  348. break;
  349. }
  350. }
  351. }
  352. }
  353. }
  354. if ( !m_pActiveOverlay )
  355. return false;
  356. return true;
  357. }
  358. //-----------------------------------------------------------------------------
  359. //-----------------------------------------------------------------------------
  360. bool CToolOverlay::HandleSnap( CMapOverlay *pOverlay, Vector &vecHandlePt )
  361. {
  362. Vector vecTmp;
  363. for ( int i = 0; i < OVERLAY_HANDLES_COUNT; i++ )
  364. {
  365. pOverlay->GetHandlePos( i, vecTmp );
  366. vecTmp -= vecHandlePt;
  367. float flDist = vecTmp.Length();
  368. if ( flDist < OVERLAY_TOOL_SNAP_DISTANCE )
  369. {
  370. // Snap!
  371. pOverlay->GetHandlePos( i, vecHandlePt );
  372. return true;
  373. }
  374. }
  375. return false;
  376. }
  377. //-----------------------------------------------------------------------------
  378. //-----------------------------------------------------------------------------
  379. bool CToolOverlay::HandleInBBox( CMapOverlay *pOverlay, Vector const &vecHandlePt )
  380. {
  381. Vector vecMin, vecMax;
  382. pOverlay->GetCullBox( vecMin, vecMax );
  383. for ( int iAxis = 0; iAxis < 3; iAxis++ )
  384. {
  385. vecMin[iAxis] -= OVERLAY_TOOL_SNAP_DISTANCE;
  386. vecMax[iAxis] += OVERLAY_TOOL_SNAP_DISTANCE;
  387. if( ( vecHandlePt[iAxis] < vecMin[iAxis] ) || ( vecHandlePt[iAxis] > vecMax[iAxis] ) )
  388. return false;
  389. }
  390. return true;
  391. }
  392. //-----------------------------------------------------------------------------
  393. //-----------------------------------------------------------------------------
  394. void CToolOverlay::SnapHandle( Vector &vecHandlePt )
  395. {
  396. CMapWorld *pWorld = GetActiveWorld();
  397. if ( !pWorld )
  398. return;
  399. EnumChildrenPos_t pos;
  400. CMapClass *pChild = pWorld->GetFirstDescendent( pos );
  401. while ( pChild )
  402. {
  403. CMapEntity *pEntity = dynamic_cast<CMapEntity*>( pChild );
  404. if ( pEntity )
  405. {
  406. const CMapObjectList *pChildren = pEntity->GetChildren();
  407. FOR_EACH_OBJ( *pChildren, pos )
  408. {
  409. CMapClass *pMapClassCast = (CUtlReference< CMapClass >)pChildren->Element(pos);
  410. CMapOverlay *pOverlay = dynamic_cast<CMapOverlay*>( pMapClassCast );
  411. if ( pOverlay && pOverlay != m_pActiveOverlay && pOverlay->IsSelected() )
  412. {
  413. // Intersection test and attempt to snap
  414. if ( HandleInBBox( pOverlay, vecHandlePt ) )
  415. {
  416. if ( HandleSnap( pOverlay, vecHandlePt ) )
  417. return;
  418. }
  419. }
  420. }
  421. }
  422. pChild = pWorld->GetNextDescendent( pos );
  423. }
  424. }
  425. //-----------------------------------------------------------------------------
  426. //-----------------------------------------------------------------------------
  427. void CToolOverlay::OnDrag( Vector const &vecRayStart, Vector const &vecRayEnd, bool bShift )
  428. {
  429. // Get the current overlay.
  430. CMapOverlay *pOverlay = m_pActiveOverlay;
  431. if ( !pOverlay )
  432. return;
  433. // Get a list of faces and test for "impact."
  434. Vector vecImpact( 0.0f, 0.0f, 0.0f );
  435. Vector vecImpactNormal( 0.0f, 0.0f, 0.0f );
  436. CMapFace *pFace = NULL;
  437. int nFaceCount = pOverlay->GetFaceCount();
  438. int iFace;
  439. for ( iFace = 0; iFace < nFaceCount; iFace++ )
  440. {
  441. pFace = pOverlay->GetFace( iFace );
  442. if ( pFace )
  443. {
  444. if ( pFace->TraceLineInside( vecImpact, vecImpactNormal, vecRayStart, vecRayEnd ) )
  445. break;
  446. }
  447. }
  448. // Test for impact (face index = count mean no impact).
  449. if ( iFace == nFaceCount )
  450. return;
  451. if ( bShift )
  452. {
  453. SnapHandle( vecImpact );
  454. }
  455. // Pass the new handle position to the overlay.
  456. pOverlay->HandlesDragTo( vecImpact, pFace );
  457. m_pDocument->UpdateAllViews( MAPVIEW_UPDATE_ONLY_3D );
  458. }
  459. //-----------------------------------------------------------------------------
  460. //-----------------------------------------------------------------------------
  461. void CToolOverlay::PreDrag( void )
  462. {
  463. m_bDragging = true;
  464. SetupHandleDragUndo();
  465. }
  466. //-----------------------------------------------------------------------------
  467. // Purpose: Renders the cordon tool in the 3D view.
  468. //-----------------------------------------------------------------------------
  469. void CToolOverlay::RenderTool3D(CRender3D *pRender)
  470. {
  471. // TODO render tool handles here and not in overlay rendering code
  472. }
  473. //-----------------------------------------------------------------------------
  474. //-----------------------------------------------------------------------------
  475. void CToolOverlay::PostDrag( void )
  476. {
  477. if ( !m_bDragging )
  478. return;
  479. m_bDragging = false;
  480. // Get the current overlay.
  481. CMapOverlay *pOverlay = m_pActiveOverlay;
  482. if ( pOverlay )
  483. {
  484. pOverlay->DoClip();
  485. pOverlay->CenterEntity();
  486. pOverlay->PostUpdate( Notify_Changed );
  487. m_pDocument->UpdateAllViews( MAPVIEW_UPDATE_OBJECTS );
  488. }
  489. // Reset the overlay handles.
  490. HandlesReset();
  491. }
  492. //-----------------------------------------------------------------------------
  493. //-----------------------------------------------------------------------------
  494. void CToolOverlay::SetupHandleDragUndo( void )
  495. {
  496. // Get the current overlay.
  497. CMapOverlay *pOverlay = m_pActiveOverlay;
  498. if ( pOverlay )
  499. {
  500. CMapEntity *pEntity = ( CMapEntity* )pOverlay->GetParent();
  501. if ( pEntity )
  502. {
  503. // Setup for drag undo.
  504. GetHistory()->MarkUndoPosition( m_pDocument->GetSelection()->GetList(), "Drag Overlay Handle" );
  505. GetHistory()->Keep( ( CMapClass* )pEntity );
  506. }
  507. }
  508. }