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.

400 lines
11 KiB

  1. //========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose: Implements the cordon tool. The cordon tool defines a rectangular
  4. // volume that acts as a visibility filter. Only objects that intersect
  5. // the cordon are rendered in the views. When saving the MAP file while
  6. // the cordon tool is active, only brushes that intersect the cordon
  7. // bounds are saved. The cordon box is replaced by brushes in order to
  8. // seal the map.
  9. //
  10. //=============================================================================//
  11. #include "stdafx.h"
  12. #include "ChunkFile.h"
  13. #include "ToolCordon.h"
  14. #include "History.h"
  15. #include "GlobalFunctions.h"
  16. #include "MainFrm.h"
  17. #include "MapDoc.h"
  18. #include "MapDefs.h"
  19. #include "MapSolid.h"
  20. #include "MapView2D.h"
  21. #include "MapView3D.h"
  22. #include "MapWorld.h"
  23. #include "render2d.h"
  24. #include "StatusBarIDs.h"
  25. #include "ToolManager.h"
  26. #include "Options.h"
  27. #include "WorldSize.h"
  28. #include "vgui/Cursor.h"
  29. // memdbgon must be the last include file in a .cpp file!!!
  30. #include <tier0/memdbgon.h>
  31. Vector Cordon3D::m_vecLastMins; // Last mins & maxs the user dragged out with this tool;
  32. Vector Cordon3D::m_vecLastMaxs; // used to fill in the third axis when starting a new box.
  33. //-----------------------------------------------------------------------------
  34. // Purpose: Constructor.
  35. //-----------------------------------------------------------------------------
  36. Cordon3D::Cordon3D(void)
  37. {
  38. SetDrawColors(RGB(0, 255, 255), RGB(255, 0, 0));
  39. m_vecLastMins.Init( COORD_NOTINIT, COORD_NOTINIT, COORD_NOTINIT );
  40. m_vecLastMaxs.Init( COORD_NOTINIT, COORD_NOTINIT, COORD_NOTINIT );
  41. }
  42. //-----------------------------------------------------------------------------
  43. // Purpose: Called when the tool is activated.
  44. // Input : eOldTool - The ID of the previously active tool.
  45. //-----------------------------------------------------------------------------
  46. void Cordon3D::OnActivate()
  47. {
  48. RefreshToolState();
  49. }
  50. //-----------------------------------------------------------------------------
  51. // Fetch data from the document and update our internal state.
  52. //-----------------------------------------------------------------------------
  53. void Cordon3D::RefreshToolState()
  54. {
  55. Vector mins( COORD_NOTINIT, COORD_NOTINIT, COORD_NOTINIT );
  56. Vector maxs( COORD_NOTINIT, COORD_NOTINIT, COORD_NOTINIT );
  57. if ( m_pDocument->Cordon_GetCount() > 0 )
  58. {
  59. m_pDocument->Cordon_GetEditCordon( mins, maxs );
  60. m_vecLastMins = mins;
  61. m_vecLastMaxs = maxs;
  62. }
  63. SetBounds( mins, maxs );
  64. m_bEmpty = !IsValidBox();
  65. EnableHandles( true );
  66. }
  67. //-----------------------------------------------------------------------------
  68. // Return true of the boxes intersect (but not if they just touch).
  69. //-----------------------------------------------------------------------------
  70. inline bool BoxesIntersect2D( const Vector2D &vBox1Min, const Vector2D &vBox1Max, const Vector2D &vBox2Min, const Vector2D &vBox2Max )
  71. {
  72. return ( vBox1Min.x < vBox2Max.x ) && ( vBox1Max.x > vBox2Min.x ) &&
  73. ( vBox1Min.y < vBox2Max.y ) && ( vBox1Max.y > vBox2Min.y );
  74. }
  75. //-----------------------------------------------------------------------------
  76. // Purpose: Handles left mouse button down events in the 2D view.
  77. // Input : Per CWnd::OnLButtonDown.
  78. // Output : Returns true if the message was handled, false if not.
  79. //-----------------------------------------------------------------------------
  80. bool Cordon3D::OnLMouseDown2D(CMapView2D *pView, UINT nFlags, const Vector2D &vPoint)
  81. {
  82. Tool3D::OnLMouseDown2D(pView, nFlags, vPoint);
  83. Vector vecWorld;
  84. pView->ClientToWorld(vecWorld, vPoint);
  85. unsigned int uConstraints = GetConstraints( nFlags );
  86. if ( HitTest(pView, vPoint, true) )
  87. {
  88. StartTranslation( pView, vPoint, m_LastHitTestHandle );
  89. }
  90. else
  91. {
  92. //
  93. // Test against all active cordons
  94. //
  95. CMapDoc *pDoc = pView->GetMapDoc();
  96. if ( !pDoc )
  97. return true;
  98. // Make a little box around the cursor to test against.
  99. const int iSelUnits = 2;
  100. Vector2D selMins( vPoint.x - iSelUnits, vPoint.y - iSelUnits );
  101. Vector2D selMaxs( vPoint.x + iSelUnits, vPoint.y + iSelUnits );
  102. for ( int i = 0; i < pDoc->Cordon_GetCount(); i++ )
  103. {
  104. Cordon_t *cordon = pDoc->Cordon_GetCordon( i );
  105. if ( !cordon->m_bActive )
  106. continue;
  107. for ( int j = 0; j < cordon->m_Boxes.Count(); j++ )
  108. {
  109. BoundBox *box = &cordon->m_Boxes[j];
  110. Vector2D vecClientMins;
  111. Vector2D vecClientMaxs;
  112. pView->WorldToClient( vecClientMins, box->bmins );
  113. pView->WorldToClient( vecClientMaxs, box->bmaxs );
  114. // 2D projection can flip Y
  115. NormalizeBox( vecClientMins, vecClientMaxs );
  116. if ( BoxesIntersect2D( vecClientMins, vecClientMaxs, selMins, selMaxs ) )
  117. {
  118. pDoc->Cordon_SelectCordonForEditing( cordon, box, SELECT_CORDON_FROM_TOOL );
  119. RefreshToolState();
  120. return true;
  121. }
  122. }
  123. }
  124. // getvisiblepoint fills in any coord that's still set to COORD_NOTINIT:
  125. vecWorld[pView->axThird] = m_vecLastMins[pView->axThird];
  126. m_pDocument->GetBestVisiblePoint(vecWorld);
  127. // snap starting position to grid
  128. if ( uConstraints & constrainSnap )
  129. m_pDocument->Snap(vecWorld,uConstraints);
  130. // Create a new box
  131. // Add it to the current edit cordon
  132. // Set the edit cordon to current edit cordon and the new box
  133. Cordon_t *cordon = m_pDocument->Cordon_GetSelectedCordonForEditing();
  134. BoundBox *box = NULL;
  135. if ( !cordon )
  136. {
  137. // No cordon, we need a new one.
  138. cordon = m_pDocument->Cordon_CreateNewCordon( DEFAULT_CORDON_NAME, &box );
  139. }
  140. else
  141. {
  142. // Just add a box to the current cordon.
  143. box = m_pDocument->Cordon_AddBox( cordon );
  144. }
  145. box->bmins = box->bmaxs = vecWorld;
  146. Vector vecSize( 0, 0, 0 );
  147. if ( ( m_vecLastMins[pView->axThird] == COORD_NOTINIT ) || ( m_vecLastMaxs[pView->axThird] == COORD_NOTINIT ) )
  148. {
  149. vecSize[pView->axThird] = pDoc->GetGridSpacing();
  150. }
  151. else
  152. {
  153. vecSize[pView->axThird] = m_vecLastMaxs[pView->axThird] - m_vecLastMins[pView->axThird];
  154. }
  155. StartNew( pView, vPoint, vecWorld, vecSize );
  156. m_pDocument->Cordon_SelectCordonForEditing( cordon, box, SELECT_CORDON_FROM_TOOL );
  157. if ( pDoc->Cordon_IsCordoning() )
  158. {
  159. pDoc->UpdateVisibilityAll();
  160. }
  161. pDoc->SetModifiedFlag( true );
  162. }
  163. return true;
  164. }
  165. //-----------------------------------------------------------------------------
  166. // Purpose: Handles left mouse button up events in the 2D view.
  167. // Input : Per CWnd::OnLButtonUp.
  168. // Output : Returns true if the message was handled, false if not.
  169. //-----------------------------------------------------------------------------
  170. bool Cordon3D::OnLMouseUp2D(CMapView2D *pView, UINT nFlags, const Vector2D &vPoint)
  171. {
  172. bool bShift = ( nFlags & MK_SHIFT ) != 0;
  173. Tool3D::OnLMouseUp2D(pView, nFlags, vPoint) ;
  174. if ( IsTranslating() )
  175. {
  176. if ( bShift )
  177. {
  178. }
  179. FinishTranslation( true );
  180. if ( bShift )
  181. {
  182. // Clone the selected cordon
  183. Cordon_t *cordon = m_pDocument->Cordon_GetSelectedCordonForEditing();
  184. BoundBox *box = m_pDocument->Cordon_AddBox( cordon );
  185. box->bmins = bmins;
  186. box->bmaxs = bmaxs;
  187. m_pDocument->Cordon_SelectCordonForEditing( cordon, box, SELECT_CORDON_FROM_TOOL );
  188. RefreshToolState();
  189. }
  190. else
  191. {
  192. m_pDocument->Cordon_SetEditCordon( bmins, bmaxs );
  193. // Remember these bounds for the next time we start dragging out a new cordon.
  194. m_vecLastMins = bmins;
  195. m_vecLastMaxs = bmaxs;
  196. }
  197. }
  198. m_pDocument->UpdateStatusbar();
  199. return true;
  200. }
  201. //-----------------------------------------------------------------------------
  202. // Purpose: Handles mouse move events in the 2D view.
  203. // Input : Per CWnd::OnMouseMove.
  204. // Output : Returns true if the message was handled, false if not.
  205. //-----------------------------------------------------------------------------
  206. bool Cordon3D::OnMouseMove2D(CMapView2D *pView, UINT nFlags, const Vector2D &vPoint)
  207. {
  208. vgui::HCursor hCursor = vgui::dc_arrow;
  209. Tool3D::OnMouseMove2D(pView, nFlags, vPoint) ;
  210. unsigned int uConstraints = GetConstraints( nFlags );
  211. // Convert to world coords.
  212. Vector vecWorld;
  213. pView->ClientToWorld(vecWorld, vPoint);
  214. // Update status bar position display.
  215. //
  216. char szBuf[128];
  217. m_pDocument->Snap(vecWorld,uConstraints);
  218. sprintf(szBuf, " @%.0f, %.0f ", vecWorld[pView->axHorz], vecWorld[pView->axVert]);
  219. SetStatusText(SBI_COORDS, szBuf);
  220. if ( IsTranslating() )
  221. {
  222. // cursor is cross here
  223. Tool3D::UpdateTranslation( pView, vPoint, uConstraints );
  224. hCursor = vgui::dc_none;
  225. }
  226. else if ( HitTest(pView, vPoint, true) )
  227. {
  228. hCursor = UpdateCursor( pView, m_LastHitTestHandle, m_TranslateMode );
  229. }
  230. if ( hCursor != vgui::dc_none )
  231. pView->SetCursor( hCursor );
  232. return true;
  233. }
  234. //-----------------------------------------------------------------------------
  235. // Purpose: Handles the escape key in the 2D or 3D views.
  236. //-----------------------------------------------------------------------------
  237. void Cordon3D::OnEscape(void)
  238. {
  239. if ( IsTranslating() )
  240. {
  241. FinishTranslation( false );
  242. }
  243. else
  244. {
  245. m_pDocument->GetTools()->SetTool(TOOL_POINTER);
  246. }
  247. }
  248. //-----------------------------------------------------------------------------
  249. // Deletes the currently selected cordon in response to the user hitting DELETE
  250. //-----------------------------------------------------------------------------
  251. void Cordon3D::OnDelete()
  252. {
  253. BoundBox *pBox = NULL;
  254. Cordon_t *pCordon = m_pDocument->Cordon_GetSelectedCordonForEditing( &pBox );
  255. if ( !pCordon || !pBox )
  256. return;
  257. if ( !pBox || ( pCordon->m_Boxes.Count() <= 1 ) )
  258. {
  259. m_pDocument->Cordon_RemoveCordon( pCordon );
  260. }
  261. else
  262. {
  263. m_pDocument->Cordon_RemoveBox( pCordon, pBox );
  264. }
  265. m_pDocument->UpdateVisibilityAll();
  266. m_pDocument->SetModifiedFlag( true );
  267. }
  268. //-----------------------------------------------------------------------------
  269. //-----------------------------------------------------------------------------
  270. bool Cordon3D::OnKeyDown2D(CMapView2D *pView, UINT nChar, UINT nRepCnt, UINT nFlags)
  271. {
  272. if (nChar == VK_ESCAPE)
  273. {
  274. OnEscape();
  275. return true;
  276. }
  277. if ( nChar == VK_DELETE )
  278. {
  279. OnDelete();
  280. }
  281. return false;
  282. }
  283. //-----------------------------------------------------------------------------
  284. //-----------------------------------------------------------------------------
  285. bool Cordon3D::OnKeyDown3D(CMapView3D *pView, UINT nChar, UINT nRepCnt, UINT nFlags)
  286. {
  287. if (nChar == VK_ESCAPE)
  288. {
  289. OnEscape();
  290. return true;
  291. }
  292. if ( nChar == VK_DELETE )
  293. {
  294. OnDelete();
  295. }
  296. return false;
  297. }
  298. //-----------------------------------------------------------------------------
  299. //-----------------------------------------------------------------------------
  300. void Cordon3D::RenderTool2D( CRender2D *pRender )
  301. {
  302. pRender->PushRenderMode( RENDER_MODE_DOTTED );
  303. pRender->SetDrawColor( 255, 255, 0 );
  304. // If cordoning is active, the document's rendering code handles drawing the cordons.
  305. if ( !m_pDocument->Cordon_IsCordoning() )
  306. {
  307. int nCount = m_pDocument->Cordon_GetCount();
  308. for ( int i = 0; i < nCount; i++ )
  309. {
  310. Cordon_t *pCordon = m_pDocument->Cordon_GetCordon( i );
  311. if ( pCordon->m_bActive )
  312. {
  313. for ( int j = 0; j < pCordon->m_Boxes.Count(); j++ )
  314. {
  315. // draw simple rectangle
  316. pRender->DrawRectangle( pCordon->m_Boxes[j].bmins, pCordon->m_Boxes[j].bmaxs, false, 0 );
  317. }
  318. }
  319. }
  320. }
  321. pRender->PopRenderMode();
  322. BaseClass::RenderTool2D( pRender );
  323. }