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.

987 lines
26 KiB

  1. //========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================//
  7. #include "stdafx.h"
  8. #include "GlobalFunctions.h"
  9. #include "History.h"
  10. #include "MapDefs.h"
  11. #include "MapDoc.h"
  12. #include "MapFace.h"
  13. #include "MapSolid.h"
  14. #include "MapView2D.h"
  15. #include "MapWorld.h"
  16. #include "Options.h"
  17. #include "Render2D.h"
  18. #include "Render3D.h"
  19. #include "RenderUtils.h"
  20. #include "StatusBarIDs.h" // dvs: remove
  21. #include "ToolClipper.h"
  22. #include "ToolManager.h"
  23. #include "vgui/Cursor.h"
  24. #include "Selection.h"
  25. // memdbgon must be the last include file in a .cpp file!!!
  26. #include <tier0/memdbgon.h>
  27. #pragma warning( disable:4244 )
  28. //=============================================================================
  29. //
  30. // Friend Function (for MapClass->EnumChildren Callback)
  31. //
  32. //-----------------------------------------------------------------------------
  33. // Purpose: This function creates a new clip group with the given solid as
  34. // the original solid.
  35. // Input: pSolid - the original solid to put in the clip list
  36. // pClipper - the clipper tool
  37. // Output: successful?? (true/false)
  38. //-----------------------------------------------------------------------------
  39. BOOL AddToClipList( CMapSolid *pSolid, Clipper3D *pClipper )
  40. {
  41. CClipGroup *pClipGroup = new CClipGroup;
  42. if( !pClipGroup )
  43. return false;
  44. pClipGroup->SetOrigSolid( pSolid );
  45. pClipper->m_ClipResults.AddToTail( pClipGroup );
  46. return true;
  47. }
  48. //=============================================================================
  49. //
  50. // CClipGroup
  51. //
  52. //-----------------------------------------------------------------------------
  53. // Purpose: Destructor. Gets rid of the unnecessary clip solids.
  54. //-----------------------------------------------------------------------------
  55. CClipGroup::~CClipGroup()
  56. {
  57. delete m_pClipSolids[0];
  58. delete m_pClipSolids[1];
  59. }
  60. //-----------------------------------------------------------------------------
  61. // Purpose: constructor - initialize the clipper variables
  62. //-----------------------------------------------------------------------------
  63. Clipper3D::Clipper3D(void)
  64. {
  65. m_Mode = FRONT;
  66. m_ClipPlane.normal.Init();
  67. m_ClipPlane.dist = 0.0f;
  68. m_ClipPoints[0].Init();
  69. m_ClipPoints[1].Init();
  70. m_ClipPointHit = -1;
  71. m_pOrigObjects = NULL;
  72. m_bDrawMeasurements = false;
  73. SetEmpty();
  74. }
  75. //-----------------------------------------------------------------------------
  76. // Purpose: deconstructor
  77. //-----------------------------------------------------------------------------
  78. Clipper3D::~Clipper3D(void)
  79. {
  80. }
  81. //-----------------------------------------------------------------------------
  82. // Purpose: Called when the tool is activated.
  83. // Input : eOldTool - The ID of the previously active tool.
  84. //-----------------------------------------------------------------------------
  85. void Clipper3D::OnActivate()
  86. {
  87. if (IsActiveTool())
  88. {
  89. //
  90. // Already the active tool - toggle the mode.
  91. //
  92. IterateClipMode();
  93. }
  94. }
  95. //-----------------------------------------------------------------------------
  96. // Purpose: Called when the tool is deactivated.
  97. // Input : eNewTool - The ID of the tool that is being activated.
  98. //-----------------------------------------------------------------------------
  99. void Clipper3D::OnDeactivate()
  100. {
  101. SetEmpty();
  102. }
  103. //-----------------------------------------------------------------------------
  104. // Purpose: (virtual imp) This function handles the "dragging" of the mouse
  105. // while the left mouse button is depressed. It updates the position
  106. // of the clippoing plane point selected in the StartTranslation
  107. // function. This function rebuilds the clipping plane and updates
  108. // the clipping solids when necessary.
  109. // Input: pt - current location of the mouse in the 2DView
  110. // uFlags - constrained clipping plane point movement
  111. // *dragSize - not used in the virtual implementation
  112. // Output: success of translation (TRUE/FALSE)
  113. //-----------------------------------------------------------------------------
  114. bool Clipper3D::UpdateTranslation( const Vector &vUpdate, UINT uFlags )
  115. {
  116. // sanity check
  117. if( IsEmpty() )
  118. return false;
  119. Vector vNewPos = m_vOrgPos + vUpdate;
  120. // snap point if need be
  121. if ( uFlags & constrainSnap )
  122. m_pDocument->Snap( vNewPos, uFlags );
  123. //
  124. // update clipping point positions
  125. //
  126. if ( m_ClipPoints[m_ClipPointHit] == vNewPos )
  127. return false;
  128. if( uFlags & constrainMoveAll )
  129. {
  130. //
  131. // calculate the point and delta - to move both clip points simultaneously
  132. //
  133. Vector delta = vNewPos - m_ClipPoints[m_ClipPointHit];
  134. m_ClipPoints[(m_ClipPointHit+1)%2] += delta;
  135. }
  136. m_ClipPoints[m_ClipPointHit] = vNewPos;
  137. // build the new clip plane and update clip results
  138. BuildClipPlane();
  139. GetClipResults();
  140. m_pDocument->UpdateAllViews( MAPVIEW_UPDATE_TOOL );
  141. return true;
  142. }
  143. //-----------------------------------------------------------------------------
  144. // Purpose: (virtual imp) This function defines all finishing functionality
  145. // necessary at the end of a clipping action. Nothing really!!!
  146. // Input : bSave - passed along the the Tool finish translation call
  147. //-----------------------------------------------------------------------------
  148. void Clipper3D::FinishTranslation( bool bSave )
  149. {
  150. // get the clip results -- in case the update is a click and not a drag
  151. GetClipResults();
  152. Tool3D::FinishTranslation( bSave );
  153. }
  154. //-----------------------------------------------------------------------------
  155. // Purpose: iterate through the types of clipping modes, update after an
  156. // iteration takes place to visualize the new clip results
  157. //-----------------------------------------------------------------------------
  158. void Clipper3D::IterateClipMode( void )
  159. {
  160. //
  161. // increment the clipping mode (wrap when necessary)
  162. //
  163. m_Mode++;
  164. if( m_Mode > BOTH )
  165. {
  166. m_Mode = FRONT;
  167. }
  168. // update the clipped objects based on the mode
  169. GetClipResults();
  170. }
  171. //-----------------------------------------------------------------------------
  172. // Purpose: This resets the solids to clip (the original list) and calls the
  173. // CalcClipResults function to generate new "clip" solids
  174. //-----------------------------------------------------------------------------
  175. void Clipper3D::GetClipResults( void )
  176. {
  177. // reset the clip list to the original solid lsit
  178. SetClipObjects( m_pOrigObjects );
  179. // calculate the clipped objects based on the current "clip plane"
  180. CalcClipResults();
  181. }
  182. //-----------------------------------------------------------------------------
  183. // Purpose: This function allows one to specifically set the clipping plane
  184. // information, as opposed to building a clip plane during "translation"
  185. // Input: pPlane - the plane information used to create the clip plane
  186. //-----------------------------------------------------------------------------
  187. void Clipper3D::SetClipPlane( PLANE *pPlane )
  188. {
  189. //
  190. // copy the clipping plane info
  191. //
  192. m_ClipPlane.normal = pPlane->normal;
  193. m_ClipPlane.dist = pPlane->dist;
  194. }
  195. //-----------------------------------------------------------------------------
  196. // Purpose: This function builds a clipping plane based on the clip point
  197. // locations manipulated in the "translation" functions and the 2DView
  198. //-----------------------------------------------------------------------------
  199. void Clipper3D::BuildClipPlane( void )
  200. {
  201. // calculate the up vector
  202. Vector upVect = m_vPlaneNormal;
  203. // calculate the right vector
  204. Vector rightVect;
  205. VectorSubtract( m_ClipPoints[1], m_ClipPoints[0], rightVect );
  206. // calculate the forward (normal) vector
  207. Vector forwardVect;
  208. CrossProduct( upVect, rightVect, forwardVect );
  209. VectorNormalize( forwardVect );
  210. //
  211. // save the clip plane info
  212. //
  213. m_ClipPlane.normal = forwardVect;
  214. m_ClipPlane.dist = DotProduct( m_ClipPoints[0], forwardVect );
  215. }
  216. //-----------------------------------------------------------------------------
  217. // Purpose: This functions sets up the list of objects to be clipped.
  218. // Initially the list is passed in (typically a Selection set). On
  219. // subsequent "translation" updates the list is refreshed from the
  220. // m_pOrigObjects list.
  221. // Input: pList - the list of objects (solids) to be clipped
  222. //-----------------------------------------------------------------------------
  223. void Clipper3D::SetClipObjects( const CMapObjectList *pList )
  224. {
  225. // check for an empty list
  226. if( !pList )
  227. return;
  228. // save the original list
  229. m_pOrigObjects = pList;
  230. // clear the clip results list
  231. ResetClipResults();
  232. //
  233. // copy solids into the clip list
  234. //
  235. FOR_EACH_OBJ( *m_pOrigObjects, pos )
  236. {
  237. CMapClass *pObject = (CUtlReference< CMapClass >)m_pOrigObjects->Element( pos );
  238. if( !pObject )
  239. continue;
  240. if( pObject->IsMapClass( MAPCLASS_TYPE( CMapSolid ) ) )
  241. {
  242. AddToClipList( ( CMapSolid* )pObject, this );
  243. }
  244. pObject->EnumChildren( ENUMMAPCHILDRENPROC( AddToClipList ), DWORD( this ), MAPCLASS_TYPE( CMapSolid ) );
  245. }
  246. // the clipping list is not empty anymore
  247. m_bEmpty = false;
  248. }
  249. //-----------------------------------------------------------------------------
  250. // Purpose: This function calculates based on the defined or given clipping
  251. // plane and clipping mode the new clip solids.
  252. //-----------------------------------------------------------------------------
  253. void Clipper3D::CalcClipResults( void )
  254. {
  255. // sanity check
  256. if( IsEmpty() )
  257. return;
  258. //
  259. // iterate through and clip all of the solids in the clip list
  260. //
  261. FOR_EACH_OBJ( m_ClipResults, pos )
  262. {
  263. CClipGroup *pClipGroup = m_ClipResults.Element( pos );
  264. CMapSolid *pOrigSolid = pClipGroup->GetOrigSolid();
  265. if( !pOrigSolid )
  266. continue;
  267. //
  268. // check the modes for which solids to generate
  269. //
  270. CMapSolid *pFront = NULL;
  271. CMapSolid *pBack = NULL;
  272. if( m_Mode == FRONT )
  273. {
  274. pOrigSolid->Split( &m_ClipPlane, &pFront, NULL );
  275. }
  276. else if( m_Mode == BACK )
  277. {
  278. pOrigSolid->Split( &m_ClipPlane, NULL, &pBack );
  279. }
  280. else if( m_Mode == BOTH )
  281. {
  282. pOrigSolid->Split( &m_ClipPlane, &pFront, &pBack );
  283. }
  284. if( pFront )
  285. {
  286. pFront->SetTemporary(true);
  287. pClipGroup->SetClipSolid( pFront, FRONT );
  288. }
  289. if( pBack )
  290. {
  291. pBack->SetTemporary(true);
  292. pClipGroup->SetClipSolid( pBack, BACK );
  293. }
  294. }
  295. }
  296. //-----------------------------------------------------------------------------
  297. // Purpose: This function handles the removal of the "original" solid when it
  298. // has been clipped into new solid(s) or removed from the world (group
  299. // or entity) entirely. It handles this in an undo safe fashion.
  300. // Input: pOrigSolid - the solid to remove
  301. //-----------------------------------------------------------------------------
  302. void Clipper3D::RemoveOrigSolid( CMapSolid *pOrigSolid )
  303. {
  304. m_pDocument->DeleteObject(pOrigSolid);
  305. //
  306. // remove the solid from the selection set if in the seleciton set and
  307. // its parent is the world, or set the selection state to none parent is group
  308. // or entity in the selection set
  309. //
  310. CSelection *pSelection = m_pDocument->GetSelection();
  311. if ( pSelection->IsSelected( pOrigSolid ) )
  312. {
  313. pSelection->SelectObject( pOrigSolid, scUnselect );
  314. }
  315. else
  316. {
  317. pOrigSolid->SetSelectionState( SELECT_NONE );
  318. }
  319. }
  320. //-----------------------------------------------------------------------------
  321. // Purpose: This function handles the saving of newly clipped solids (derived
  322. // from an "original" solid). It handles them in an undo safe fashion.
  323. // Input: pSolid - the newly clipped solid
  324. // pOrigSolid - the "original" solid or solid the clipped solid was
  325. // derived from
  326. //-----------------------------------------------------------------------------
  327. void Clipper3D::SaveClipSolid( CMapSolid *pSolid, CMapSolid *pOrigSolid )
  328. {
  329. //
  330. // no longer a temporary solid
  331. //
  332. pSolid->SetTemporary( FALSE );
  333. //
  334. // Add the new solid to the original solid's parent (group, entity, world, etc.).
  335. //
  336. m_pDocument->AddObjectToWorld(pSolid, pOrigSolid->GetParent());
  337. //
  338. // handle linking solid into selection -- via selection set when parent is the world
  339. // and selected, or set the selection state if parent is group or entity in selection set
  340. //
  341. if( m_pDocument->GetSelection()->IsSelected( pOrigSolid ) )
  342. {
  343. m_pDocument->SelectObject( pSolid, scSelect );
  344. }
  345. else
  346. {
  347. pSolid->SetSelectionState( SELECT_NORMAL );
  348. }
  349. GetHistory()->KeepNew( pSolid );
  350. }
  351. //-----------------------------------------------------------------------------
  352. // Purpose: This function saves all the clipped solid information. If new solids
  353. // were generated from the original, they are saved and the original is
  354. // set for desctruciton. Otherwise, the original solid is kept.
  355. //-----------------------------------------------------------------------------
  356. void Clipper3D::SaveClipResults( void )
  357. {
  358. // sanity check!
  359. if( IsEmpty() )
  360. return;
  361. // mark this place in the history
  362. GetHistory()->MarkUndoPosition( NULL, "Clip Objects" );
  363. //
  364. // save all new objects into the selection list
  365. //
  366. FOR_EACH_OBJ( m_ClipResults, pos )
  367. {
  368. CClipGroup *pClipGroup = m_ClipResults.Element( pos );
  369. if( !pClipGroup )
  370. continue;
  371. CMapSolid *pOrigSolid = pClipGroup->GetOrigSolid();
  372. CMapSolid *pBackSolid = pClipGroup->GetClipSolid( CClipGroup::BACK );
  373. CMapSolid *pFrontSolid = pClipGroup->GetClipSolid( CClipGroup::FRONT );
  374. //
  375. // save the front clip solid and clear the clip results list of itself
  376. //
  377. if( pFrontSolid )
  378. {
  379. SaveClipSolid( pFrontSolid, pOrigSolid );
  380. pClipGroup->SetClipSolid( NULL, CClipGroup::FRONT );
  381. }
  382. //
  383. // save the front clip solid and clear the clip results list of itself
  384. //
  385. if( pBackSolid )
  386. {
  387. SaveClipSolid( pBackSolid, pOrigSolid );
  388. pClipGroup->SetClipSolid( NULL, CClipGroup::BACK );
  389. }
  390. // Send the notification that this solid as been clipped.
  391. pOrigSolid->PostUpdate( Notify_Clipped );
  392. // remove the original solid
  393. RemoveOrigSolid( pOrigSolid );
  394. }
  395. // set the the clipping results list as empty
  396. ResetClipResults();
  397. // update world and views
  398. m_pDocument->SetModifiedFlag();
  399. }
  400. //-----------------------------------------------------------------------------
  401. // Purpose: Draws the measurements of a brush in the 2D view.
  402. // Input : pRender -
  403. // pSolid -
  404. // nFlags -
  405. //-----------------------------------------------------------------------------
  406. void Clipper3D::DrawBrushExtents( CRender2D *pRender, CMapSolid *pSolid, int nFlags )
  407. {
  408. //
  409. // get the bounds of the solid
  410. //
  411. Vector Mins, Maxs;
  412. pSolid->GetRender2DBox( Mins, Maxs );
  413. //
  414. // Determine which side of the clipping plane this solid is on in screen
  415. // space. This tells us where to draw the extents.
  416. //
  417. if( ( m_ClipPlane.normal[0] == 0 ) && ( m_ClipPlane.normal[1] == 0 ) && ( m_ClipPlane.normal[2] == 0 ) )
  418. return;
  419. Vector normal = m_ClipPlane.normal;
  420. if( nFlags & DBT_BACK )
  421. {
  422. VectorNegate( normal );
  423. }
  424. Vector2D planeNormal;
  425. pRender->TransformNormal( planeNormal, normal );
  426. if( planeNormal.x <= 0 )
  427. {
  428. nFlags &= ~DBT_RIGHT;
  429. nFlags |= DBT_LEFT;
  430. }
  431. else if( planeNormal.x > 0 )
  432. {
  433. nFlags &= ~DBT_LEFT;
  434. nFlags |= DBT_RIGHT;
  435. }
  436. if( planeNormal.y <= 0 )
  437. {
  438. nFlags &= ~DBT_BOTTOM;
  439. nFlags |= DBT_TOP;
  440. }
  441. else if( planeNormal.y > 0 )
  442. {
  443. nFlags &= ~DBT_TOP;
  444. nFlags |= DBT_BOTTOM;
  445. }
  446. DrawBoundsText(pRender, Mins, Maxs, nFlags);
  447. }
  448. //-----------------------------------------------------------------------------
  449. // Purpose:
  450. // Input : *pRender -
  451. //-----------------------------------------------------------------------------
  452. void Clipper3D::RenderTool2D(CRender2D *pRender)
  453. {
  454. if ( IsEmpty() )
  455. return;
  456. // check flag for rendering vertices
  457. bool bDrawVerts = ( bool )( Options.view2d.bDrawVertices == TRUE );
  458. // setup the line to use
  459. pRender->SetDrawColor( 255, 255, 255 );
  460. //
  461. // render the clipped solids
  462. //
  463. FOR_EACH_OBJ( m_ClipResults, pos )
  464. {
  465. CClipGroup *pClipGroup = m_ClipResults.Element( pos );
  466. CMapSolid *pClipBack = pClipGroup->GetClipSolid( CClipGroup::BACK );
  467. CMapSolid *pClipFront = pClipGroup->GetClipSolid( CClipGroup::FRONT );
  468. if( !pClipBack && !pClipFront )
  469. continue;
  470. //
  471. // draw clip solids with the extents
  472. //
  473. if( pClipBack )
  474. {
  475. int faceCount = pClipBack->GetFaceCount();
  476. for( int i = 0; i < faceCount; i++ )
  477. {
  478. CMapFace *pFace = pClipBack->GetFace( i );
  479. // size 4
  480. pRender->DrawPolyLine( pFace->nPoints, pFace->Points );
  481. if ( bDrawVerts )
  482. {
  483. pRender->DrawHandles( pFace->nPoints, pFace->Points );
  484. }
  485. if( m_bDrawMeasurements )
  486. {
  487. DrawBrushExtents( pRender, pClipBack, DBT_TOP | DBT_LEFT | DBT_BACK );
  488. }
  489. }
  490. }
  491. if( pClipFront )
  492. {
  493. int faceCount = pClipFront->GetFaceCount();
  494. for( int i = 0; i < faceCount; i++ )
  495. {
  496. CMapFace *pFace = pClipFront->GetFace( i );
  497. pRender->DrawPolyLine( pFace->nPoints, pFace->Points );
  498. if ( bDrawVerts )
  499. {
  500. pRender->DrawHandles( pFace->nPoints, pFace->Points );
  501. }
  502. if( m_bDrawMeasurements )
  503. {
  504. DrawBrushExtents( pRender, pClipFront, DBT_BOTTOM | DBT_RIGHT );
  505. }
  506. }
  507. }
  508. }
  509. //
  510. // draw the clip-plane
  511. //
  512. pRender->SetDrawColor( 0, 255, 255 );
  513. pRender->DrawLine( m_ClipPoints[0], m_ClipPoints[1] );
  514. //
  515. // draw the clip-plane endpoints
  516. //
  517. pRender->SetHandleStyle( HANDLE_RADIUS, CRender::HANDLE_SQUARE );
  518. pRender->SetHandleColor( 255, 255, 255 );
  519. pRender->DrawHandle( m_ClipPoints[0] );
  520. pRender->DrawHandle( m_ClipPoints[1] );
  521. }
  522. //-----------------------------------------------------------------------------
  523. // Purpose: Renders the brushes that will be left by the clipper in white
  524. // wireframe.
  525. // Input : pRender - Rendering interface.
  526. //-----------------------------------------------------------------------------
  527. void Clipper3D::RenderTool3D( CRender3D *pRender )
  528. {
  529. // is there anything to render?
  530. if( m_bEmpty )
  531. return;
  532. //
  533. // setup the renderer
  534. //
  535. pRender->PushRenderMode( RENDER_MODE_WIREFRAME );
  536. FOR_EACH_OBJ( m_ClipResults, pos )
  537. {
  538. CClipGroup *pClipGroup = m_ClipResults.Element( pos );
  539. CMapSolid *pFrontSolid = pClipGroup->GetClipSolid( CClipGroup::FRONT );
  540. if( pFrontSolid )
  541. {
  542. color32 rgbColor = pFrontSolid->GetRenderColor();
  543. pFrontSolid->SetRenderColor(255, 255, 255);
  544. pFrontSolid->Render3D(pRender);
  545. pFrontSolid->SetRenderColor(rgbColor);
  546. }
  547. CMapSolid *pBackSolid = pClipGroup->GetClipSolid( CClipGroup::BACK );
  548. if( pBackSolid )
  549. {
  550. color32 rgbColor = pBackSolid->GetRenderColor();
  551. pBackSolid->SetRenderColor(255, 255, 255);
  552. pBackSolid->Render3D(pRender);
  553. pBackSolid->SetRenderColor(rgbColor);
  554. }
  555. }
  556. pRender->PopRenderMode();
  557. }
  558. //-----------------------------------------------------------------------------
  559. // Purpose: (virtual imp)
  560. // Input : pt -
  561. // BOOL -
  562. // Output : int
  563. //-----------------------------------------------------------------------------
  564. int Clipper3D::HitTest(CMapView *pView, const Vector2D &ptClient, bool bTestHandles)
  565. {
  566. // check points
  567. for ( int i=0; i<2;i++ )
  568. {
  569. if ( HitRect(pView, ptClient, m_ClipPoints[i], HANDLE_RADIUS) )
  570. {
  571. return i+1; // return clip point index + 1
  572. }
  573. }
  574. // neither point hit
  575. return 0;
  576. }
  577. //-----------------------------------------------------------------------------
  578. // Purpose: Reset (clear) the clip results.
  579. //-----------------------------------------------------------------------------
  580. void Clipper3D::ResetClipResults( void )
  581. {
  582. //
  583. // delete the clip solids held in the list -- originals are just pointers
  584. // to pre-existing objects
  585. //
  586. FOR_EACH_OBJ( m_ClipResults, pos )
  587. {
  588. CClipGroup *pClipGroup = m_ClipResults.Element(pos);
  589. if( pClipGroup )
  590. {
  591. delete pClipGroup;
  592. }
  593. }
  594. m_ClipResults.RemoveAll();
  595. // the clipping list is empty
  596. SetEmpty();
  597. }
  598. //-----------------------------------------------------------------------------
  599. // Purpose:
  600. // Input : nChar -
  601. // nRepCnt -
  602. // nFlags -
  603. //-----------------------------------------------------------------------------
  604. bool Clipper3D::OnKeyDown2D(CMapView2D *pView, UINT nChar, UINT nRepCnt, UINT nFlags)
  605. {
  606. switch (nChar)
  607. {
  608. case 'O':
  609. {
  610. //
  611. // Toggle the rendering of measurements.
  612. //
  613. ToggleMeasurements();
  614. return true;
  615. }
  616. case VK_RETURN:
  617. {
  618. //
  619. // Do the clip.
  620. //
  621. if (!IsEmpty() )
  622. {
  623. SaveClipResults();
  624. }
  625. return true;
  626. }
  627. case VK_ESCAPE:
  628. {
  629. OnEscape();
  630. return true;
  631. }
  632. }
  633. return false;
  634. }
  635. //-----------------------------------------------------------------------------
  636. // Purpose: Handles left mouse button down events in the 2D view.
  637. // Input : Per CWnd::OnLButtonDown.
  638. // Output : Returns true if the message was handled, false if not.
  639. //-----------------------------------------------------------------------------
  640. bool Clipper3D::OnLMouseDown2D(CMapView2D *pView, UINT nFlags, const Vector2D &vPoint)
  641. {
  642. Tool3D::OnLMouseDown2D(pView, nFlags, vPoint);
  643. unsigned int uConstraints = GetConstraints( nFlags );
  644. //
  645. // Convert point to world coords.
  646. //
  647. Vector vecWorld;
  648. pView->ClientToWorld(vecWorld, vPoint);
  649. vecWorld[pView->axThird] = COORD_NOTINIT;
  650. // getvisiblepoint fills in any coord that's still set to COORD_NOTINIT:
  651. m_pDocument->GetBestVisiblePoint(vecWorld);
  652. // snap starting position to grid
  653. if ( uConstraints & constrainSnap )
  654. m_pDocument->Snap(vecWorld, uConstraints);
  655. bool bStarting = false;
  656. // if the tool is not empty, and shift is not held down (to
  657. // start a new camera), don't do anything.
  658. if(!IsEmpty())
  659. {
  660. // test for clip point hit (result = {0, 1, 2}
  661. int hitPoint = HitTest( pView, vPoint );
  662. if ( hitPoint > 0 )
  663. {
  664. // test for clip point hit (result = {0, 1, -1})
  665. m_ClipPointHit = hitPoint-1; // convert back to index
  666. m_vOrgPos = m_ClipPoints[m_ClipPointHit];
  667. StartTranslation( pView, vPoint );
  668. }
  669. else if ( m_vPlaneNormal != pView->GetViewAxis() )
  670. {
  671. SetEmpty();
  672. bStarting = true;
  673. }
  674. else
  675. {
  676. if (nFlags & MK_SHIFT)
  677. {
  678. SetEmpty();
  679. bStarting = true;
  680. }
  681. else
  682. {
  683. return true; // do nothing;
  684. }
  685. }
  686. }
  687. else
  688. {
  689. bStarting = true;
  690. }
  691. SetClipObjects(m_pDocument->GetSelection()->GetList());
  692. if (bStarting)
  693. {
  694. // start the tools translation functionality
  695. StartTranslation( pView, vPoint );
  696. // set the initial clip points
  697. m_ClipPointHit = 0;
  698. m_ClipPoints[0] = vecWorld;
  699. m_ClipPoints[1] = vecWorld;
  700. m_vOrgPos = vecWorld;
  701. }
  702. return true;
  703. }
  704. //-----------------------------------------------------------------------------
  705. // Purpose: Handles left mouse button up events in the 2D view.
  706. // Input : Per CWnd::OnLButtonUp.
  707. // Output : Returns true if the message was handled, false if not.
  708. //-----------------------------------------------------------------------------
  709. bool Clipper3D::OnLMouseUp2D(CMapView2D *pView, UINT nFlags, const Vector2D &vPoint)
  710. {
  711. Tool3D::OnLMouseUp2D(pView, nFlags, vPoint);
  712. if ( IsTranslating() )
  713. {
  714. FinishTranslation(true);
  715. }
  716. m_pDocument->UpdateStatusbar();
  717. return true;
  718. }
  719. unsigned int Clipper3D::GetConstraints(unsigned int nKeyFlags)
  720. {
  721. unsigned int uConstraints = Tool3D::GetConstraints( nKeyFlags );
  722. if(nKeyFlags & MK_CONTROL)
  723. {
  724. uConstraints |= constrainMoveAll;
  725. }
  726. return uConstraints;
  727. }
  728. //-----------------------------------------------------------------------------
  729. // Purpose: Handles mouse move events in the 2D view.
  730. // Input : Per CWnd::OnMouseMove.
  731. // Output : Returns true if the message was handled, false if not.
  732. //-----------------------------------------------------------------------------
  733. bool Clipper3D::OnMouseMove2D(CMapView2D *pView, UINT nFlags, const Vector2D &vPoint)
  734. {
  735. vgui::HCursor hCursor = vgui::dc_arrow;
  736. unsigned int uConstraints = GetConstraints( nFlags );
  737. Tool3D::OnMouseMove2D(pView, nFlags, vPoint);
  738. //
  739. // Convert to world coords.
  740. //
  741. Vector vecWorld;
  742. pView->ClientToWorld(vecWorld, vPoint);
  743. //
  744. // Update status bar position display.
  745. //
  746. char szBuf[128];
  747. if ( uConstraints & constrainSnap )
  748. m_pDocument->Snap(vecWorld,uConstraints);
  749. sprintf(szBuf, " @%.0f, %.0f ", vecWorld[pView->axHorz], vecWorld[pView->axVert]);
  750. SetStatusText(SBI_COORDS, szBuf);
  751. if (IsTranslating())
  752. {
  753. // cursor is cross here
  754. Tool3D::UpdateTranslation( pView, vPoint, uConstraints);
  755. hCursor = vgui::dc_none;
  756. }
  757. else if (!IsEmpty())
  758. {
  759. //
  760. // If the cursor is on a handle, set it to a cross.
  761. //
  762. if (HitTest( pView, vPoint, true))
  763. {
  764. hCursor = vgui::dc_crosshair;
  765. }
  766. }
  767. if ( hCursor != vgui::dc_none )
  768. pView->SetCursor( hCursor );
  769. return true;
  770. }
  771. //-----------------------------------------------------------------------------
  772. // Purpose: Handles character events.
  773. // Input : Per CWnd::OnKeyDown.
  774. // Output : Returns true if the message was handled, false if not.
  775. //-----------------------------------------------------------------------------
  776. bool Clipper3D::OnKeyDown3D(CMapView3D *pView, UINT nChar, UINT nRepCnt, UINT nFlags)
  777. {
  778. switch (nChar)
  779. {
  780. case VK_RETURN:
  781. {
  782. if (!IsEmpty()) // dvs: what does isempty mean for the clipper?
  783. {
  784. SaveClipResults();
  785. }
  786. return true;
  787. }
  788. case VK_ESCAPE:
  789. {
  790. OnEscape();
  791. return true;
  792. }
  793. }
  794. return false;
  795. }
  796. //-----------------------------------------------------------------------------
  797. // Purpose: Handles the escape key in the 2D or 3D views.
  798. //-----------------------------------------------------------------------------
  799. void Clipper3D::OnEscape(void)
  800. {
  801. // If we're clipping, clear it
  802. if (!IsEmpty())
  803. {
  804. SetEmpty();
  805. }
  806. else
  807. {
  808. m_pDocument->GetTools()->SetTool(TOOL_POINTER);
  809. }
  810. }