Team Fortress 2 Source Code as on 22/4/2020
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.

2090 lines
48 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose: Rendering and mouse handling in the 2D view.
  4. //
  5. //============================================================================//
  6. #include "stdafx.h"
  7. #include "MapView2DBase.h"
  8. #include "hammer.h"
  9. #include "MapEntity.h"
  10. #include "MapFace.h"
  11. #include "MapSolid.h"
  12. #include "MapWorld.h"
  13. #include "MapDoc.h"
  14. #include "MapView2D.h"
  15. #include "MapViewLogical.h"
  16. #include "MapView3D.h"
  17. #include "tooldefs.h"
  18. #include "StockSolids.h"
  19. #include "statusbarids.h"
  20. #include "ObjectProperties.h"
  21. #include "Options.h"
  22. #include "History.h"
  23. #include "GlobalFunctions.h"
  24. #include "MapDefs.h" // dvs: For COORD_NOTINIT
  25. #include "Render2D.h"
  26. #include "TitleWnd.h"
  27. #include "ToolManager.h"
  28. #include "ToolMorph.h" // FIXME: remove
  29. #include "ToolInterface.h"
  30. #include "MapPlayerHullHandle.h"
  31. #include "vgui_controls/EditablePanel.h"
  32. #include "camera.h"
  33. #include "material.h"
  34. // memdbgon must be the last include file in a .cpp file!!!
  35. #include <tier0/memdbgon.h>
  36. #define SnapToGrid(line,grid) (line - (line % grid))
  37. #define ZOOM_MIN_DEFAULT 0.02125
  38. #define ZOOM_MAX 256.0
  39. static float s_fDragRestX, s_fDragRestY;
  40. IMPLEMENT_DYNCREATE(CMapView2DBase, CView)
  41. class CMapView2DBasePanel : public vgui::EditablePanel
  42. {
  43. public:
  44. CMapView2DBasePanel( CMapView2DBase *pMapView, const char *panelName ) :
  45. vgui::EditablePanel( NULL, panelName )
  46. {
  47. m_pMapView = pMapView;
  48. }
  49. virtual void OnSizeChanged(int newWide, int newTall)
  50. {
  51. // call Panel and not EditablePanel OnSizeChanged.
  52. Panel::OnSizeChanged(newWide, newTall);
  53. }
  54. virtual void Paint()
  55. {
  56. m_pMapView->Render();
  57. }
  58. CMapView2DBase *m_pMapView;
  59. };
  60. BEGIN_MESSAGE_MAP(CMapView2DBase, CView)
  61. //{{AFX_MSG_MAP(CMapView2DBase)
  62. ON_WM_KEYDOWN()
  63. ON_WM_LBUTTONDOWN()
  64. ON_WM_MOUSEMOVE()
  65. ON_WM_MOUSEWHEEL()
  66. ON_WM_LBUTTONUP()
  67. ON_WM_LBUTTONDBLCLK()
  68. ON_WM_HSCROLL()
  69. ON_WM_VSCROLL()
  70. ON_WM_RBUTTONDOWN()
  71. ON_WM_TIMER()
  72. ON_WM_SIZE()
  73. ON_COMMAND(ID_EDIT_PROPERTIES, OnEditProperties)
  74. ON_WM_KEYUP()
  75. ON_WM_CHAR()
  76. ON_WM_RBUTTONUP()
  77. ON_UPDATE_COMMAND_UI(ID_CREATEOBJECT, OnUpdateEditFunction)
  78. ON_WM_ERASEBKGND()
  79. ON_UPDATE_COMMAND_UI(ID_EDIT_PROPERTIES, OnUpdateEditFunction)
  80. //}}AFX_MSG_MAP
  81. END_MESSAGE_MAP()
  82. //-----------------------------------------------------------------------------
  83. // Purpose: Constructor. Initializes data members.
  84. // ---------------------------------------------------------------------------
  85. CMapView2DBase::CMapView2DBase(void)
  86. {
  87. //
  88. // Must initialize the title window pointer before calling SetDrawType!
  89. //
  90. m_pwndTitle = NULL;
  91. m_flMinZoom = ZOOM_MIN_DEFAULT;
  92. m_fZoom = -1; // make sure setzoom performs
  93. m_vViewOrigin.Init();
  94. m_ViewMin.Init();
  95. m_ViewMax.Init();
  96. m_xScroll = m_yScroll = 0;
  97. m_bActive = false;
  98. m_bMouseDrag = false;
  99. m_pCamera = new CCamera();
  100. m_pCamera->SetOrthographic( 0.25f, -99999, 99999 );
  101. m_pRender = new CRender2D();
  102. m_pRender->SetView( this );
  103. m_pRender->SetDefaultRenderMode( RENDER_MODE_FLAT_NOZ );
  104. }
  105. //-----------------------------------------------------------------------------
  106. // Purpose: Destructor. Frees dynamically allocated resources.
  107. //-----------------------------------------------------------------------------
  108. CMapView2DBase::~CMapView2DBase(void)
  109. {
  110. if (m_pwndTitle != NULL)
  111. {
  112. delete m_pwndTitle;
  113. }
  114. if ( m_pCamera )
  115. {
  116. delete m_pCamera;
  117. }
  118. if ( m_pRender )
  119. {
  120. delete m_pRender;
  121. }
  122. }
  123. //-----------------------------------------------------------------------------
  124. // Purpose:
  125. //-----------------------------------------------------------------------------
  126. void CMapView2DBase::UpdateTitleWindowPos(void)
  127. {
  128. if (m_pwndTitle != NULL)
  129. {
  130. if (!::IsWindow(m_pwndTitle->m_hWnd))
  131. {
  132. return;
  133. }
  134. m_pwndTitle->SetWindowPos(NULL, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
  135. m_pwndTitle->ShowWindow(SW_SHOW);
  136. }
  137. }
  138. //-----------------------------------------------------------------------------
  139. // Create a title window.
  140. //-----------------------------------------------------------------------------
  141. void CMapView2DBase::CreateTitleWindow(void)
  142. {
  143. m_pwndTitle = CTitleWnd::CreateTitleWnd(this, ID_2DTITLEWND);
  144. Assert(m_pwndTitle != NULL);
  145. UpdateTitleWindowPos();
  146. }
  147. //-----------------------------------------------------------------------------
  148. // Purpose: First-time initialization of this view.
  149. //-----------------------------------------------------------------------------
  150. void CMapView2DBase::OnInitialUpdate(void)
  151. {
  152. // CMainFrame::LoadWindowStates calls InitialUpdateFrame which causes us to get two
  153. // OnInitialUpdate messages! Check for a NULL renderer to avoid processing twice.
  154. if ( GetMainPanel() != NULL )
  155. return;
  156. CMapDoc *pDoc = GetMapDoc();
  157. m_pToolManager = pDoc->GetTools();
  158. CenterView();
  159. SetColorMode(Options.view2d.bWhiteOnBlack);
  160. ShowScrollBar(SB_HORZ, Options.view2d.bScrollbars);
  161. ShowScrollBar(SB_VERT, Options.view2d.bScrollbars);
  162. CView::OnInitialUpdate();
  163. vgui::EditablePanel *pMainPanel = new CMapView2DBasePanel( this, "MapView2DPanel" );
  164. SetParentWindow( this );
  165. SetMainPanel( pMainPanel );
  166. }
  167. //-----------------------------------------------------------------------------
  168. // Purpose: Called by the tools to scroll the 2D view so that a point is visible.
  169. // Sets a timer to do the scroll so that we don't much with the view state
  170. // while the tool is handling a mouse message.
  171. // Input : point - Point in client coordinates to make visible.
  172. //-----------------------------------------------------------------------------
  173. void CMapView2DBase::ToolScrollToPoint(const Vector2D &ptClient)
  174. {
  175. int nScrollSpeed = 10 / m_fZoom;
  176. if ((GetCapture() == this) &&
  177. ( ptClient.x < 0 || ptClient.y < 0 || ptClient.x >= m_ClientWidth || ptClient.y >= m_ClientHeight ) )
  178. {
  179. // reset these
  180. m_xScroll = m_yScroll = 0;
  181. if (ptClient.x < 0)
  182. {
  183. // scroll left
  184. m_xScroll = -nScrollSpeed;
  185. }
  186. else if (ptClient.x >= m_ClientWidth)
  187. {
  188. // scroll right
  189. m_xScroll = nScrollSpeed;
  190. }
  191. if (ptClient.y < 0)
  192. {
  193. // scroll up
  194. m_yScroll = nScrollSpeed;
  195. }
  196. else if (ptClient.y >= m_ClientHeight)
  197. {
  198. // scroll down
  199. m_yScroll = -nScrollSpeed;
  200. }
  201. SetTimer( TIMER_SCROLLVIEW, 10, NULL);
  202. }
  203. else
  204. {
  205. m_xScroll = m_yScroll = 0;
  206. KillTimer( TIMER_SCROLLVIEW );
  207. }
  208. }
  209. //-----------------------------------------------------------------------------
  210. // Purpose: Adjusts a color's intensity - will not overbrighten.
  211. // Input : ulColor - Color to adjust.
  212. // nIntensity - Percentage of original color intensity to keep (0 - 100).
  213. // bReverse - True ramps toward black, false ramps toward the given color.
  214. // Output : Returns the adjusted color.
  215. //-----------------------------------------------------------------------------
  216. void CMapView2DBase::AdjustColorIntensity(Color &color, int nIntensity)
  217. {
  218. if (!Options.view2d.bWhiteOnBlack)
  219. {
  220. nIntensity = 100 - nIntensity;
  221. }
  222. nIntensity = clamp(nIntensity, 0, 100);
  223. //
  224. // Adjust each component's intensity.
  225. //
  226. color.SetColor( min( (color.r() * nIntensity) / 100, 255 ),
  227. min( (color.g() * nIntensity) / 100, 255 ),
  228. min( (color.b() * nIntensity) / 100, 255 ),
  229. color.a() );
  230. }
  231. //-----------------------------------------------------------------------------
  232. // Purpose:
  233. // Input : bWhiteOnBlack -
  234. //-----------------------------------------------------------------------------
  235. void CMapView2DBase::SetColorMode(bool bWhiteOnBlack)
  236. {
  237. // Grid color.
  238. COLORREF clr = Options.colors.clrGrid;
  239. m_clrGrid.SetColor( GetRValue(clr), GetGValue(clr), GetBValue(clr), 255 );
  240. if (Options.colors.bScaleGridColor)
  241. {
  242. AdjustColorIntensity(m_clrGrid, Options.view2d.iGridIntensity);
  243. }
  244. // Grid highlight color.
  245. clr = Options.colors.clrGrid10;
  246. m_clrGridCustom.SetColor( GetRValue(clr), GetGValue(clr), GetBValue(clr), 255 );
  247. if (Options.colors.bScaleGrid10Color)
  248. {
  249. AdjustColorIntensity(m_clrGridCustom, 1.5 * Options.view2d.iGridIntensity);
  250. }
  251. // Grid 1024 highlight color.
  252. clr = Options.colors.clrGrid1024;
  253. m_clrGrid1024.SetColor( GetRValue(clr), GetGValue(clr), GetBValue(clr), 255 );
  254. if (Options.colors.bScaleGrid1024Color)
  255. {
  256. AdjustColorIntensity(m_clrGrid1024, Options.view2d.iGridIntensity);
  257. }
  258. // Dotted grid color. No need to create a pen since all we do is SetPixel with it.
  259. clr = Options.colors.clrGridDot;
  260. m_clrGridDot.SetColor( GetRValue(clr), GetGValue(clr), GetBValue(clr), 255 );
  261. if (Options.colors.bScaleGridDotColor)
  262. {
  263. AdjustColorIntensity(m_clrGridDot, Options.view2d.iGridIntensity + 20);
  264. }
  265. // Axis color.
  266. clr = Options.colors.clrAxis;
  267. m_clrAxis.SetColor( GetRValue(clr), GetGValue(clr), GetBValue(clr), 255 );
  268. if (Options.colors.bScaleAxisColor)
  269. {
  270. AdjustColorIntensity(m_clrAxis, Options.view2d.iGridIntensity);
  271. }
  272. clr = Options.colors.clrBackground;
  273. m_ClearColor.SetColor( GetRValue(clr), GetGValue(clr), GetBValue(clr), 255 );
  274. m_bClearZBuffer = false;
  275. }
  276. // quick & dirty:
  277. static bool s_bGridDots;
  278. static int s_iCustomGridSpacing;
  279. bool CMapView2DBase::HighlightGridLine( CRender2D *pRender, int nGridLine )
  280. {
  281. if (nGridLine == 0)
  282. {
  283. pRender->SetDrawColor( m_clrAxis );
  284. return true;
  285. }
  286. //
  287. // Optionally highlight every 1024.
  288. //
  289. if (Options.view2d.bGridHigh1024 && (!(nGridLine % 1024)))
  290. {
  291. pRender->SetDrawColor( m_clrGrid1024 );
  292. return true;
  293. }
  294. //
  295. // Optionally highlight every 64.
  296. //
  297. else if (Options.view2d.bGridHigh64 && (!(nGridLine % 64)))
  298. {
  299. if (!s_bGridDots)
  300. {
  301. pRender->SetDrawColor( m_clrGridCustom );
  302. return true;
  303. }
  304. }
  305. //
  306. // Optionally highlight every nth grid line.
  307. //
  308. if (Options.view2d.bGridHigh10 && (!(nGridLine % s_iCustomGridSpacing)))
  309. {
  310. if (!s_bGridDots)
  311. {
  312. pRender->SetDrawColor( m_clrGridCustom );
  313. return true;
  314. }
  315. }
  316. return false;
  317. }
  318. //-----------------------------------------------------------------------------
  319. // Purpose: Draws the grid, using dots or lines depending on the user setting.
  320. // Input : pDC - Device context to draw in.
  321. //-----------------------------------------------------------------------------
  322. void CMapView2DBase::DrawGrid(CRender2D *pRender, int xAxis, int yAxis, float depth, bool bNoSmallGrid )
  323. {
  324. CMapDoc *pDoc = GetMapDoc();
  325. if (pDoc == NULL)
  326. return;
  327. // Check for too small grid.
  328. int nGridSpacing = pDoc->GetGridSpacing();
  329. // never allow a grid spacing samller then 2 pixel
  330. while ( ((float)nGridSpacing * m_fZoom) < 2.0f )
  331. {
  332. nGridSpacing*=2;
  333. }
  334. if ((((float)nGridSpacing * m_fZoom) < 4.0f) && Options.view2d.bHideSmallGrid)
  335. {
  336. bNoSmallGrid = true;
  337. }
  338. // No dots if too close together.
  339. s_bGridDots = Options.view2d.bGridDots;
  340. s_iCustomGridSpacing = nGridSpacing * Options.view2d.iGridHighSpec;
  341. int xMin = SnapToGrid( (int)max( g_MIN_MAP_COORD, m_ViewMin[xAxis]-nGridSpacing ), nGridSpacing );
  342. int xMax = SnapToGrid( (int)min( g_MAX_MAP_COORD, m_ViewMax[xAxis]+nGridSpacing ), nGridSpacing );
  343. int yMin = SnapToGrid( (int)max( g_MIN_MAP_COORD, m_ViewMin[yAxis]-nGridSpacing ), nGridSpacing );
  344. int yMax = SnapToGrid( (int)min( g_MAX_MAP_COORD, m_ViewMax[yAxis]+nGridSpacing ), nGridSpacing );
  345. Assert( xMin < xMax );
  346. Assert( yMin < yMax );
  347. // Draw the vertical grid lines.
  348. Vector vPointMin(depth,depth,depth);
  349. Vector vPointMax(depth,depth,depth);
  350. vPointMin[xAxis] = xMin;
  351. vPointMax[xAxis] = xMax;
  352. // draw dots first, for the shake of speed do really ugly things
  353. if (s_bGridDots && !bNoSmallGrid)
  354. {
  355. pRender->BeginClientSpace();
  356. CMeshBuilder meshBuilder;
  357. CMatRenderContextPtr pRenderContext( MaterialSystemInterface() );
  358. IMesh* pMesh = pRenderContext->GetDynamicMesh();
  359. for (int y = yMin; y <= yMax; y += nGridSpacing )
  360. {
  361. Vector vPoint(depth,depth,depth);
  362. vPoint[yAxis] = y;
  363. vPoint[xAxis] = xMin;
  364. Vector2D v2D; WorldToClient( v2D, vPoint );
  365. v2D.y = (int)(v2D.y+0.5);
  366. // dot drawing isn't precise enough in world space
  367. // so we still do it in client space
  368. int nNumPoints = 1+abs(xMax-xMin)/nGridSpacing;
  369. meshBuilder.Begin( pMesh, MATERIAL_LINES, nNumPoints );
  370. float fOffset = nGridSpacing * m_fZoom;
  371. while( nNumPoints > 0)
  372. {
  373. float roundfx = (int)(v2D.x+0.5);
  374. v2D.x += fOffset;
  375. meshBuilder.Position3f( roundfx, v2D.y, 0 );
  376. meshBuilder.Color4ubv( (byte*)&m_clrGridDot );
  377. meshBuilder.AdvanceVertex();
  378. meshBuilder.Position3f( roundfx+1, v2D.y+1, 0 );
  379. meshBuilder.Color4ubv( (byte*)&m_clrGridDot );
  380. meshBuilder.AdvanceVertex();
  381. nNumPoints--;
  382. }
  383. meshBuilder.End();
  384. pMesh->Draw();
  385. }
  386. pRender->EndClientSpace();
  387. }
  388. for (int y = yMin; y <= yMax; y += nGridSpacing )
  389. {
  390. pRender->SetDrawColor( m_clrGrid );
  391. int bHighligh = HighlightGridLine( pRender, y );
  392. // Don't draw the base grid if it is too small.
  393. if (!bHighligh && bNoSmallGrid)
  394. continue;
  395. // Always draw lines for the axes and map boundaries.
  396. if ((!s_bGridDots) || (bHighligh) || (y == g_MAX_MAP_COORD) || (y == g_MIN_MAP_COORD))
  397. {
  398. vPointMin[yAxis] = vPointMax[yAxis] = y;
  399. pRender->DrawLine( vPointMin, vPointMax );
  400. }
  401. }
  402. vPointMin[yAxis] = yMin;
  403. vPointMax[yAxis] = yMax;
  404. for (int x = xMin; x <= xMax; x += nGridSpacing )
  405. {
  406. pRender->SetDrawColor( m_clrGrid );
  407. int bHighligh = HighlightGridLine( pRender, x );
  408. // Don't draw the base grid if it is too small.
  409. if ( !bHighligh && bNoSmallGrid )
  410. continue;
  411. // Always draw lines for the axes and map boundaries.
  412. if ((!s_bGridDots) || (bHighligh) || (x == g_MAX_MAP_COORD) || (x == g_MIN_MAP_COORD))
  413. {
  414. vPointMin[xAxis] = vPointMax[xAxis] = x;
  415. pRender->DrawLine( vPointMin, vPointMax );
  416. }
  417. }
  418. }
  419. void CMapView2DBase::DrawGridLogical( CRender2D *pRender )
  420. {
  421. CMapDoc *pDoc = GetMapDoc();
  422. if (pDoc == NULL)
  423. return;
  424. // Grid in logical view is always 1024
  425. int nGridSpacing = 1024;
  426. s_iCustomGridSpacing = nGridSpacing;
  427. s_bGridDots = false;
  428. int xAxis = 0;
  429. int yAxis = 1;
  430. int xMin = SnapToGrid( (int)max( g_MIN_MAP_COORD, m_ViewMin[xAxis]-nGridSpacing ), nGridSpacing );
  431. int xMax = SnapToGrid( (int)min( g_MAX_MAP_COORD, m_ViewMax[xAxis]+nGridSpacing ), nGridSpacing );
  432. int yMin = SnapToGrid( (int)max( g_MIN_MAP_COORD, m_ViewMin[yAxis]-nGridSpacing ), nGridSpacing );
  433. int yMax = SnapToGrid( (int)min( g_MAX_MAP_COORD, m_ViewMax[yAxis]+nGridSpacing ), nGridSpacing );
  434. Assert( xMin < xMax );
  435. Assert( yMin < yMax );
  436. // Draw the vertical grid lines.
  437. float depth = 0.0f;
  438. Vector vPointMin(depth,depth,depth);
  439. Vector vPointMax(depth,depth,depth);
  440. vPointMin[xAxis] = xMin;
  441. vPointMax[xAxis] = xMax;
  442. for (int y = yMin; y <= yMax; y += nGridSpacing )
  443. {
  444. pRender->SetDrawColor( m_clrGrid );
  445. HighlightGridLine( pRender, y );
  446. vPointMin[yAxis] = vPointMax[yAxis] = y;
  447. pRender->DrawLine( vPointMin, vPointMax );
  448. }
  449. vPointMin[yAxis] = yMin;
  450. vPointMax[yAxis] = yMax;
  451. for (int x = xMin; x <= xMax; x += nGridSpacing )
  452. {
  453. pRender->SetDrawColor( m_clrGrid );
  454. HighlightGridLine( pRender, x );
  455. vPointMin[xAxis] = vPointMax[xAxis] = x;
  456. pRender->DrawLine( vPointMin, vPointMax );
  457. }
  458. }
  459. //-----------------------------------------------------------------------------
  460. // Purpose:
  461. // Input : pointCheck -
  462. // pointRef -
  463. // nDist -
  464. // Output : Returns true on success, false on failure.
  465. //-----------------------------------------------------------------------------
  466. bool CMapView2DBase::CheckDistance(const Vector2D &vecCheck, const Vector2D &vecRef, int nDist)
  467. {
  468. if ((fabs(vecRef.x - vecCheck.x) <= nDist) &&
  469. (fabs(vecRef.y - vecCheck.y) <= nDist))
  470. {
  471. return true;
  472. }
  473. return false;
  474. }
  475. //-----------------------------------------------------------------------------
  476. // Purpose: Gets the center point of the view in world coordinates.
  477. // Input : pt - Receives the center point. Only dimensions initialized with
  478. // COORD_NOTINIT will be filled out.
  479. //-----------------------------------------------------------------------------
  480. void CMapView2DBase::GetCenterPoint(Vector &pt)
  481. {
  482. Vector2D ptCenter( m_ClientWidth/2, m_ClientHeight/2);
  483. Vector vCenter;
  484. ClientToWorld(vCenter, ptCenter );
  485. if (pt[axHorz] == COORD_NOTINIT)
  486. {
  487. pt[axHorz] = vCenter[axHorz];
  488. }
  489. if (pt[axVert] == COORD_NOTINIT)
  490. {
  491. pt[axVert] = vCenter[axVert];
  492. }
  493. }
  494. void CMapView2DBase::SetViewOrigin( float fHorz, float fVert, bool bRelative )
  495. {
  496. Vector vCurPos;
  497. m_pCamera->GetViewPoint( vCurPos );
  498. if ( bRelative )
  499. {
  500. if ( fHorz == 0 && fVert == 0 )
  501. return;
  502. vCurPos[axHorz] += fHorz;
  503. vCurPos[axVert] += fVert;
  504. }
  505. else
  506. {
  507. if ( fHorz == vCurPos[axHorz] && fVert == vCurPos[axVert] )
  508. return;
  509. vCurPos[axHorz] = fHorz;
  510. vCurPos[axVert] = fVert;
  511. }
  512. if ( axThird == 1 )
  513. {
  514. vCurPos[axThird] = g_MIN_MAP_COORD;
  515. }
  516. else
  517. {
  518. vCurPos[axThird] = g_MAX_MAP_COORD;
  519. }
  520. m_pCamera->SetViewPoint( vCurPos );
  521. // Msg("SetViewOrigin: (%i,%i) %s (%i,%i) \n", x, y, bRelative?"rel":"abs", m_ptViewOrigin.x, m_ptViewOrigin.y );
  522. UpdateClientView();
  523. }
  524. //-----------------------------------------------------------------------------
  525. // Purpose: Calculates all viewport related variables
  526. //-----------------------------------------------------------------------------
  527. void CMapView2DBase::UpdateClientView(void)
  528. {
  529. if (!::IsWindow(m_hWnd))
  530. return;
  531. m_fZoom = m_pCamera->GetZoom();
  532. m_pCamera->GetViewPoint( m_vViewOrigin );
  533. CRect rectClient;
  534. GetClientRect( &rectClient );
  535. m_ClientWidth = rectClient.Width();
  536. m_ClientHeight = rectClient.Height();
  537. float viewWidth = (float)m_ClientWidth / m_fZoom;
  538. float viewHeight = (float)m_ClientHeight / m_fZoom;
  539. m_fClientWidthHalf = (float)m_ClientWidth / 2;
  540. m_fClientHeightHalf = (float)m_ClientHeight / 2;
  541. float flMaxExtents = fabs(g_MIN_MAP_COORD) + fabs(g_MAX_MAP_COORD);
  542. m_flMinZoom = min(m_ClientWidth / flMaxExtents, m_ClientHeight / flMaxExtents);
  543. if ( Options.view2d.bScrollbars )
  544. {
  545. SCROLLINFO si;
  546. si.cbSize = sizeof(si);
  547. si.fMask = SIF_PAGE | SIF_RANGE | SIF_POS;
  548. si.nMin = g_MIN_MAP_COORD - m_fClientWidthHalf;
  549. si.nMax = g_MAX_MAP_COORD + m_fClientWidthHalf;
  550. si.nPage = viewWidth;
  551. si.nPos = m_vViewOrigin[axHorz];
  552. if ( bInvertHorz )
  553. si.nPos = -si.nPos;
  554. SetScrollInfo(SB_HORZ, &si);
  555. si.nMin = g_MIN_MAP_COORD-m_fClientHeightHalf;
  556. si.nMax = g_MAX_MAP_COORD+m_fClientHeightHalf;
  557. si.nPage = viewHeight;
  558. si.nPos = m_vViewOrigin[axVert];
  559. if ( bInvertVert )
  560. si.nPos = -si.nPos;
  561. SetScrollInfo(SB_VERT, &si);
  562. }
  563. else
  564. {
  565. ShowScrollBar(SB_HORZ, FALSE);
  566. ShowScrollBar(SB_VERT, FALSE);
  567. }
  568. // calc view axis
  569. m_vViewAxis.Init();
  570. m_vViewAxis[axThird] = 1;
  571. if ( bInvertHorz && bInvertVert )
  572. m_vViewAxis = -m_vViewAxis;
  573. m_pCamera->SetViewPort( m_ClientWidth, m_ClientHeight );
  574. m_pCamera->SetYaw( 0 );
  575. m_pCamera->SetPitch( 0 );
  576. m_pCamera->SetRoll( 0 );
  577. switch ( axThird )
  578. {
  579. case 0 : m_pCamera->SetYaw( -90 );
  580. break;
  581. case 1 : m_pCamera->SetRoll( 0 );
  582. break;
  583. case 2 : m_pCamera->SetPitch( 90 );
  584. break;
  585. }
  586. // update 3D world bounding box for 2D client view
  587. int xmin = 0;
  588. int xmax = m_ClientWidth;
  589. int ymin = 0;
  590. int ymax = m_ClientHeight;
  591. Vector2D ptViewMin(xmin, ymin);
  592. Vector2D ptViewMax(xmax, ymax);
  593. ClientToWorld( m_ViewMin, ptViewMin );
  594. ClientToWorld( m_ViewMax, ptViewMax );
  595. m_ViewMin[axThird] = g_MIN_MAP_COORD;
  596. m_ViewMax[axThird] = g_MAX_MAP_COORD;
  597. NormalizeBox( m_ViewMin, m_ViewMax );
  598. Assert( m_ViewMin.x <= m_ViewMax.x );
  599. Assert( m_ViewMin.y <= m_ViewMax.y );
  600. Assert( m_ViewMin.z <= m_ViewMax.z );
  601. OnRenderListDirty();
  602. m_bUpdateView = true;
  603. UpdateStatusBar();
  604. }
  605. //-----------------------------------------------------------------------------
  606. // Purpose:
  607. //-----------------------------------------------------------------------------
  608. void CMapView2DBase::UpdateStatusBar()
  609. {
  610. if(!IsWindow(m_hWnd))
  611. return;
  612. char szBuf[128];
  613. sprintf(szBuf, " Zoom: %.2f ", m_fZoom);
  614. SetStatusText(SBI_GRIDZOOM, szBuf);
  615. }
  616. //-----------------------------------------------------------------------------
  617. // Purpose:
  618. // Input : fNewZoom -
  619. //-----------------------------------------------------------------------------
  620. void CMapView2DBase::SetZoom(float fNewZoom)
  621. {
  622. float fOldZoom = m_pCamera->GetZoom();
  623. fNewZoom = clamp( fNewZoom, m_flMinZoom, ZOOM_MAX );
  624. if (fOldZoom == fNewZoom)
  625. {
  626. return;
  627. }
  628. if (IsWindow(m_hWnd))
  629. {
  630. // zoom in on cursor position
  631. POINT ptClient;
  632. GetCursorPos(&ptClient);
  633. ScreenToClient(&ptClient);
  634. Vector2D newOrigin,vecClient(ptClient.x,ptClient.y);
  635. if (!PointInClientRect(vecClient))
  636. {
  637. // cursor is not in window; zoom on center instead
  638. vecClient.x = m_fClientWidthHalf;
  639. vecClient.y = m_fClientHeightHalf;
  640. }
  641. Vector vecWorld;
  642. ClientToWorld( vecWorld, vecClient );
  643. vecClient.x -= m_fClientWidthHalf;
  644. vecClient.y -= m_fClientHeightHalf;
  645. vecClient.x /= fNewZoom;
  646. vecClient.y /= fNewZoom;
  647. if (bInvertVert)
  648. {
  649. vecClient.y = -vecClient.y;
  650. }
  651. if (bInvertHorz)
  652. {
  653. vecClient.x = -vecClient.x;
  654. }
  655. newOrigin.x = vecWorld[axHorz] - vecClient.x;
  656. newOrigin.y = vecWorld[axVert] - vecClient.y;
  657. m_pCamera->SetZoom( fNewZoom );
  658. SetViewOrigin( newOrigin.x, newOrigin.y );
  659. UpdateClientView();
  660. }
  661. }
  662. #ifdef _DEBUG
  663. void CMapView2DBase::AssertValid() const
  664. {
  665. CView::AssertValid();
  666. }
  667. void CMapView2DBase::Dump(CDumpContext& dc) const
  668. {
  669. CView::Dump(dc);
  670. }
  671. #endif //_DEBUG
  672. //-----------------------------------------------------------------------------
  673. // Purpose:
  674. // Input : cs -
  675. // Output : Returns TRUE on success, FALSE on failure.
  676. //-----------------------------------------------------------------------------
  677. BOOL CMapView2DBase::PreCreateWindow(CREATESTRUCT& cs)
  678. {
  679. static CString className;
  680. if(className.IsEmpty())
  681. {
  682. className = AfxRegisterWndClass(CS_BYTEALIGNCLIENT | CS_DBLCLKS,
  683. AfxGetApp()->LoadStandardCursor(IDC_ARROW), HBRUSH(NULL));
  684. }
  685. cs.lpszClass = className;
  686. return CView::PreCreateWindow(cs);
  687. }
  688. //-----------------------------------------------------------------------------
  689. // Purpose:
  690. // Input : nChar -
  691. // nRepCnt -
  692. // nFlags -
  693. //-----------------------------------------------------------------------------
  694. void CMapView2DBase::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
  695. {
  696. CMapDoc *pDoc = GetMapDoc();
  697. if ( !pDoc || !m_pToolManager )
  698. return;
  699. if (nChar == VK_SPACE)
  700. {
  701. // Switch the cursor to the hand. We'll start panning the view
  702. // on the left button down event.
  703. if ( m_bMouseDrag )
  704. SetCursor("Resource/ifm_grab.cur");
  705. else
  706. SetCursor("Resource/ifm_move.cur");
  707. return;
  708. }
  709. // Pass the message to the active tool.
  710. CBaseTool *pTool = m_pToolManager->GetActiveTool();
  711. if (pTool)
  712. {
  713. if ( IsLogical() )
  714. {
  715. if ( pTool->OnKeyDownLogical( static_cast<CMapViewLogical*>( this ), nChar, nRepCnt, nFlags ) )
  716. return;
  717. }
  718. else
  719. {
  720. if ( pTool->OnKeyDown2D( static_cast<CMapView2D*>( this ), nChar, nRepCnt, nFlags ) )
  721. return;
  722. }
  723. }
  724. // The tool didn't handle the key. Perform default handling for this view.
  725. // bool bShift = nFlags & MK_SHIFT;
  726. bool bCtrl = nFlags & MK_CONTROL;
  727. switch (nChar)
  728. {
  729. //
  730. // Zoom in.
  731. //
  732. case '+':
  733. case VK_ADD:
  734. {
  735. ZoomIn(bCtrl);
  736. break;
  737. }
  738. //
  739. // Zoom out.
  740. //
  741. case '-':
  742. case VK_SUBTRACT:
  743. {
  744. ZoomOut(bCtrl);
  745. break;
  746. }
  747. case VK_UP:
  748. {
  749. // scroll up
  750. OnVScroll(SB_LINEUP, 0, NULL);
  751. break;
  752. }
  753. case VK_DOWN:
  754. {
  755. // scroll down
  756. OnVScroll(SB_LINEDOWN, 0, NULL);
  757. break;
  758. }
  759. case VK_LEFT:
  760. {
  761. // scroll up
  762. OnHScroll(SB_LINELEFT, 0, NULL);
  763. break;
  764. }
  765. case VK_RIGHT:
  766. {
  767. // scroll up
  768. OnHScroll(SB_LINERIGHT, 0, NULL);
  769. break;
  770. }
  771. //
  772. // 1-9 +0 shortcuts to various zoom levels.
  773. //
  774. case '1':
  775. case '2':
  776. case '3':
  777. case '4':
  778. case '5':
  779. case '6':
  780. case '7':
  781. case '8':
  782. case '9':
  783. case '0':
  784. {
  785. int iZoom = nChar - '1';
  786. if (nChar == '0')
  787. {
  788. iZoom = 9;
  789. }
  790. SetZoom(m_flMinZoom * (1 << iZoom));
  791. break;
  792. }
  793. }
  794. CView::OnKeyDown(nChar, nRepCnt, nFlags);
  795. }
  796. //-----------------------------------------------------------------------------
  797. // Purpose:
  798. // Input : Per CWnd::OnKeyUp.
  799. //-----------------------------------------------------------------------------
  800. void CMapView2DBase::OnKeyUp(UINT nChar, UINT nRepCnt, UINT nFlags)
  801. {
  802. if ( !m_pToolManager )
  803. return;
  804. if (nChar == VK_SPACE)
  805. {
  806. //
  807. // Releasing the space bar stops panning the view.
  808. //
  809. SetCursor( vgui::dc_arrow );
  810. }
  811. else
  812. {
  813. //
  814. // Pass the message to the active tool.
  815. //
  816. CBaseTool *pTool = m_pToolManager->GetActiveTool();
  817. if (pTool)
  818. {
  819. if ( IsLogical() )
  820. {
  821. if ( pTool->OnKeyUpLogical( static_cast<CMapViewLogical*>( this ), nChar, nRepCnt, nFlags ) )
  822. return;
  823. }
  824. else
  825. {
  826. if ( pTool->OnKeyUp2D( static_cast<CMapView2D*>( this ), nChar, nRepCnt, nFlags ) )
  827. return;
  828. }
  829. }
  830. }
  831. CView::OnKeyUp(nChar, nRepCnt, nFlags);
  832. }
  833. //-----------------------------------------------------------------------------
  834. // Purpose:
  835. //-----------------------------------------------------------------------------
  836. void CMapView2DBase::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags)
  837. {
  838. if ( !m_pToolManager )
  839. return;
  840. // Pass the message to the active tool.
  841. CBaseTool *pTool = m_pToolManager->GetActiveTool();
  842. if ( pTool )
  843. {
  844. if ( IsLogical() )
  845. {
  846. if ( pTool->OnCharLogical( static_cast<CMapViewLogical*>( this ), nChar, nRepCnt, nFlags ) )
  847. return;
  848. }
  849. else
  850. {
  851. if ( pTool->OnChar2D( static_cast<CMapView2D*>( this ), nChar, nRepCnt, nFlags ) )
  852. return;
  853. }
  854. }
  855. CView::OnChar( nChar, nRepCnt, nFlags );
  856. }
  857. //-----------------------------------------------------------------------------
  858. // Hit test
  859. //-----------------------------------------------------------------------------
  860. bool CMapView2DBase::HitTest( const Vector2D &vPoint, const Vector& mins, const Vector& maxs)
  861. {
  862. Vector2D vecMinClient,vecMaxClient;
  863. WorldToClient(vecMinClient, mins);
  864. WorldToClient(vecMaxClient, maxs);
  865. CRect rect(vecMinClient.x, vecMinClient.y, vecMaxClient.x, vecMaxClient.y);
  866. rect.NormalizeRect();
  867. return rect.PtInRect( CPoint( vPoint.x, vPoint.y) );
  868. }
  869. //-----------------------------------------------------------------------------
  870. // Purpose:
  871. // Input : point - Point in client coordinates.
  872. // bMakeFirst -
  873. // Output : Returns true on success, false on failure.
  874. //-----------------------------------------------------------------------------
  875. int CMapView2DBase::ObjectsAt( const Vector2D &vPoint, HitInfo_t *pHitData, int nMaxObjects, unsigned int nFlags )
  876. {
  877. CMapDoc *pDoc = GetMapDoc();
  878. CMapWorld *pWorld = pDoc->GetMapWorld();
  879. return ObjectsAt( pWorld, vPoint, pHitData, nMaxObjects, nFlags );
  880. }
  881. //-----------------------------------------------------------------------------
  882. // Purpose:
  883. // Input : point - Point in client coordinates.
  884. // bMakeFirst -
  885. // Output : Returns true on success, false on failure.
  886. //-----------------------------------------------------------------------------
  887. int CMapView2DBase::ObjectsAt( CMapWorld *pWorld, const Vector2D &vPoint, HitInfo_t *pHitData, int nMaxObjects, unsigned int nFlags )
  888. {
  889. int nIndex = 0;
  890. const CMapObjectList *pChildren = pWorld->GetChildren();
  891. FOR_EACH_OBJ( *pChildren, pos )
  892. {
  893. CMapClass *pChild = pChildren->Element(pos);
  894. CMapWorld *pWorldChild = dynamic_cast< CMapWorld * >( pChild );
  895. if ( pWorldChild )
  896. {
  897. nIndex += ObjectsAt( pWorldChild, vPoint, &pHitData[ nIndex ], nMaxObjects - nIndex );
  898. }
  899. else if ( IsLogical() )
  900. {
  901. if ( pChild->HitTestLogical( static_cast<CMapViewLogical*>(this), vPoint, pHitData[nIndex] ) )
  902. {
  903. nIndex++;
  904. }
  905. }
  906. else
  907. {
  908. if ( pChild->HitTest2D( static_cast<CMapView2D*>(this), vPoint, pHitData[nIndex] ) )
  909. {
  910. nIndex++;
  911. }
  912. }
  913. }
  914. return nIndex;
  915. }
  916. //-----------------------------------------------------------------------------
  917. // Purpose:
  918. // Input : nFlags -
  919. // point -
  920. //-----------------------------------------------------------------------------
  921. void CMapView2DBase::OnLButtonDown(UINT nFlags, CPoint point)
  922. {
  923. if ( !m_pToolManager )
  924. return;
  925. // Check for view-specific keyboard overrides.
  926. if (GetAsyncKeyState(VK_SPACE) & 0x8000)
  927. {
  928. //
  929. // Space bar + mouse move scrolls the view.
  930. //
  931. m_bMouseDrag = true;
  932. m_ptLDownClient = point;
  933. s_fDragRestX = s_fDragRestY = 0;
  934. SetCapture();
  935. SetCursor( "Resource/ifm_grab.cur" );
  936. return;
  937. }
  938. //
  939. // Pass the message to the active tool.
  940. //
  941. CBaseTool *pTool = m_pToolManager->GetActiveTool();
  942. if (pTool)
  943. {
  944. if ( IsLogical() )
  945. {
  946. if ( pTool->OnLMouseDownLogical( static_cast<CMapViewLogical*>( this ), nFlags, Vector2D( point.x, point.y ) ) )
  947. return;
  948. }
  949. else
  950. {
  951. if ( pTool->OnLMouseDown2D( static_cast<CMapView2D*>( this ), nFlags, Vector2D( point.x, point.y ) ) )
  952. return;
  953. }
  954. }
  955. m_ptLDownClient = point;
  956. CView::OnLButtonDown(nFlags, point);
  957. }
  958. //-----------------------------------------------------------------------------
  959. // Purpose:
  960. // Input : nFlags -
  961. // point -
  962. //-----------------------------------------------------------------------------
  963. void CMapView2DBase::OnMouseMove(UINT nFlags, CPoint point)
  964. {
  965. //
  966. // Make sure we are the active view.
  967. //
  968. CMapDoc *pDoc = GetMapDoc();
  969. if ( !pDoc || !m_pToolManager )
  970. return;
  971. if ( !IsActive() )
  972. {
  973. pDoc->SetActiveView(this);
  974. }
  975. //
  976. // If we are the active application, make sure this view has the input focus.
  977. //
  978. if (APP()->IsActiveApp() && !IsRunningInEngine() )
  979. {
  980. if (GetFocus() != this)
  981. {
  982. SetFocus();
  983. }
  984. }
  985. //
  986. // Panning the view with the mouse, just exit.
  987. //
  988. if ( m_bMouseDrag )
  989. {
  990. if ( point == m_ptLDownClient )
  991. return;
  992. float fdx = point.x - m_ptLDownClient.x;
  993. float fdy = point.y - m_ptLDownClient.y;
  994. fdx /= m_fZoom;
  995. fdy /= m_fZoom;
  996. if ( bInvertHorz )
  997. fdy = -fdy;
  998. if ( bInvertVert )
  999. fdx = -fdx;
  1000. fdx += s_fDragRestX;
  1001. fdy += s_fDragRestY;
  1002. int idx = fdx;
  1003. int idy = fdy;
  1004. if ( idy == 0 && idx == 0 )
  1005. return;
  1006. s_fDragRestX = fdx - idx;
  1007. s_fDragRestY = fdy - idy;
  1008. SetViewOrigin( idx, idy, true );
  1009. SetCursor( "Resource/ifm_grab.cur" );
  1010. // reset mouse pos
  1011. m_ptLDownClient = point;
  1012. return;
  1013. }
  1014. // Pass the message to the active tool.
  1015. CBaseTool *pTool = m_pToolManager->GetActiveTool();
  1016. if (pTool)
  1017. {
  1018. Vector2D vPoint( point.x, point.y );
  1019. if ( IsLogical() )
  1020. {
  1021. if ( pTool->OnMouseMoveLogical( static_cast<CMapViewLogical*>( this ), nFlags, vPoint ) )
  1022. return;
  1023. }
  1024. else
  1025. {
  1026. if ( pTool->OnMouseMove2D( static_cast<CMapView2D*>( this ), nFlags, vPoint ) )
  1027. return;
  1028. }
  1029. }
  1030. //
  1031. // The tool didn't handle the message. Make sure the cursor is set.
  1032. //
  1033. if (GetAsyncKeyState(VK_SPACE) & 0x8000)
  1034. {
  1035. SetCursor( "Resource/ifm_move.cur" );
  1036. }
  1037. else
  1038. {
  1039. SetCursor( vgui::dc_arrow );
  1040. }
  1041. CView::OnMouseMove(nFlags, point);
  1042. }
  1043. //-----------------------------------------------------------------------------
  1044. // Purpose: Handles mouse wheel events. The mouse wheel is used to zoom the 2D
  1045. // view in and out.
  1046. // Input : Per CWnd::OnMouseWheel.
  1047. //-----------------------------------------------------------------------------
  1048. BOOL CMapView2DBase::OnMouseWheel(UINT nFlags, short zDelta, CPoint point)
  1049. {
  1050. if ( !m_pToolManager )
  1051. return TRUE;
  1052. // Pass the message to the active tool.
  1053. //
  1054. CBaseTool *pTool = m_pToolManager->GetActiveTool();
  1055. if (pTool)
  1056. {
  1057. if ( IsLogical() )
  1058. {
  1059. if ( pTool->OnMouseWheelLogical( static_cast<CMapViewLogical*>( this ), nFlags, zDelta, Vector2D(point.x,point.y) ) )
  1060. return TRUE;
  1061. }
  1062. else
  1063. {
  1064. if ( pTool->OnMouseWheel2D( static_cast<CMapView2D*>( this ), nFlags, zDelta, Vector2D(point.x,point.y) ) )
  1065. return TRUE;
  1066. }
  1067. }
  1068. if (zDelta < 0)
  1069. {
  1070. ZoomOut(nFlags & MK_CONTROL);
  1071. }
  1072. else
  1073. {
  1074. ZoomIn(nFlags & MK_CONTROL);
  1075. }
  1076. return(TRUE);
  1077. }
  1078. //-----------------------------------------------------------------------------
  1079. // Purpose: Scrolls the view to make sure that the position in world space is visible.
  1080. // Input : vecPos -
  1081. //-----------------------------------------------------------------------------
  1082. void CMapView2DBase::EnsureVisible(Vector &vecPos, float flMargin)
  1083. {
  1084. Vector2D pt;
  1085. WorldToClient(pt, vecPos);
  1086. // check to see if it's in the client
  1087. if (pt.x < 0)
  1088. {
  1089. pt.x = -pt.x + flMargin;
  1090. }
  1091. else if (pt.x > m_ClientWidth )
  1092. {
  1093. pt.x = m_ClientWidth - pt.x - flMargin;
  1094. }
  1095. else
  1096. {
  1097. pt.x = 0;
  1098. }
  1099. if (pt.y < 0)
  1100. {
  1101. pt.y = -pt.y + flMargin;
  1102. }
  1103. else if (pt.y > m_ClientHeight)
  1104. {
  1105. pt.y = m_ClientHeight - pt.y - flMargin;
  1106. }
  1107. else
  1108. {
  1109. pt.y = 0;
  1110. }
  1111. // if it's not in the client, scroll
  1112. if (pt.x || pt.y)
  1113. {
  1114. SetViewOrigin( pt.x, pt.y, true );
  1115. }
  1116. }
  1117. //-----------------------------------------------------------------------------
  1118. // Purpose:
  1119. // Input : nFlags -
  1120. // point -
  1121. //-----------------------------------------------------------------------------
  1122. void CMapView2DBase::OnLButtonUp(UINT nFlags, CPoint point)
  1123. {
  1124. CMapDoc *pDoc = GetMapDoc();
  1125. if ( !pDoc || !m_pToolManager )
  1126. return;
  1127. ReleaseCapture();
  1128. if ( m_bMouseDrag )
  1129. {
  1130. m_bMouseDrag = false;
  1131. // KillTimer(TIMER_MOUSEDRAG);
  1132. OnMouseMove(nFlags, point);
  1133. return;
  1134. }
  1135. //
  1136. // Pass the message to the active tool.
  1137. //
  1138. CBaseTool *pTool = m_pToolManager->GetActiveTool();
  1139. if (pTool)
  1140. {
  1141. if ( IsLogical() )
  1142. {
  1143. if ( pTool->OnLMouseUpLogical( static_cast<CMapViewLogical*>( this ), nFlags, Vector2D(point.x,point.y) ) )
  1144. return;
  1145. }
  1146. else
  1147. {
  1148. if ( pTool->OnLMouseUp2D( static_cast<CMapView2D*>( this ), nFlags, Vector2D(point.x,point.y) ) )
  1149. return;
  1150. }
  1151. }
  1152. // we might have removed some stuff that was relevant:
  1153. pDoc->UpdateStatusbar();
  1154. CView::OnLButtonUp(nFlags, point);
  1155. }
  1156. //-----------------------------------------------------------------------------
  1157. // Purpose: Handles the left mouse button double click event.
  1158. //-----------------------------------------------------------------------------
  1159. void CMapView2DBase::OnLButtonDblClk(UINT nFlags, CPoint point)
  1160. {
  1161. //
  1162. // Don't forward message if we are controlling the camera.
  1163. //
  1164. if ((GetAsyncKeyState(VK_SPACE) & 0x8000) != 0)
  1165. return;
  1166. if ( !m_pToolManager )
  1167. return;
  1168. // Pass the message to the active tool.
  1169. CBaseTool *pTool = m_pToolManager->GetActiveTool();
  1170. if (pTool != NULL)
  1171. {
  1172. Vector2D vPoint( point.x, point.y );
  1173. if ( IsLogical() )
  1174. {
  1175. pTool->OnLMouseDblClkLogical( static_cast<CMapViewLogical*>( this ), nFlags, vPoint );
  1176. pTool->OnLMouseDownLogical( static_cast<CMapViewLogical*>( this ), nFlags, vPoint );
  1177. }
  1178. else
  1179. {
  1180. pTool->OnLMouseDblClk2D( static_cast<CMapView2D*>( this ), nFlags, vPoint );
  1181. pTool->OnLMouseDown2D( static_cast<CMapView2D*>( this ), nFlags, vPoint );
  1182. }
  1183. }
  1184. }
  1185. //-----------------------------------------------------------------------------
  1186. // Purpose:
  1187. // Input : bActivate -
  1188. // pActivateView -
  1189. // pDeactiveView -
  1190. //-----------------------------------------------------------------------------
  1191. void CMapView2DBase::ActivateView(bool bActivate)
  1192. {
  1193. CMapView::ActivateView( bActivate );
  1194. if ( bActivate )
  1195. {
  1196. CMapDoc *pDoc = GetMapDoc();
  1197. CMapDoc::SetActiveMapDoc( pDoc );
  1198. pDoc->UpdateTitle( this );
  1199. UpdateStatusBar();
  1200. }
  1201. else
  1202. {
  1203. m_xScroll = m_yScroll = 0;
  1204. }
  1205. }
  1206. //-----------------------------------------------------------------------------
  1207. // Purpose:
  1208. //-----------------------------------------------------------------------------
  1209. void CMapView2DBase::UpdateView( int nFlags )
  1210. {
  1211. if ( nFlags & MAPVIEW_UPDATE_ONLY_3D )
  1212. return;
  1213. if ( IsLogical() )
  1214. {
  1215. if ( nFlags & MAPVIEW_UPDATE_ONLY_2D )
  1216. return;
  1217. }
  1218. else
  1219. {
  1220. if ( nFlags & MAPVIEW_UPDATE_ONLY_LOGICAL )
  1221. return;
  1222. }
  1223. if(nFlags & MAPVIEW_OPTIONS_CHANGED)
  1224. {
  1225. ShowScrollBar(SB_HORZ, Options.view2d.bScrollbars);
  1226. ShowScrollBar(SB_VERT, Options.view2d.bScrollbars);
  1227. SetColorMode(Options.view2d.bWhiteOnBlack);
  1228. UpdateClientView();
  1229. }
  1230. // Render the world if the flag is specified.
  1231. if ( nFlags & (MAPVIEW_UPDATE_OBJECTS|MAPVIEW_UPDATE_VISGROUP_STATE|MAPVIEW_UPDATE_VISGROUP_ALL) )
  1232. {
  1233. // rebuild render list since objects or visiblity was changed
  1234. OnRenderListDirty();
  1235. }
  1236. if ( m_pwndTitle != NULL )
  1237. {
  1238. m_pwndTitle->Invalidate(false);
  1239. }
  1240. CMapView::UpdateView( nFlags );
  1241. }
  1242. //-----------------------------------------------------------------------------
  1243. // Purpose:
  1244. // Input : pt3 -
  1245. //-----------------------------------------------------------------------------
  1246. void CMapView2DBase::CenterView(Vector *pCenter)
  1247. {
  1248. CMapWorld *pWorld = GetMapDoc()->GetMapWorld();
  1249. float fPointX, fPointY;
  1250. if( pCenter )
  1251. {
  1252. // use provided point
  1253. fPointX = (*pCenter)[axHorz];
  1254. fPointY = (*pCenter)[axVert];
  1255. }
  1256. else
  1257. {
  1258. //
  1259. // Use center of map.
  1260. //
  1261. Vector vecMins;
  1262. Vector vecMaxs;
  1263. pWorld->GetRender2DBox(vecMins, vecMaxs);
  1264. fPointX = (vecMaxs[axHorz] + vecMins[axHorz]) / 2;
  1265. fPointY = (vecMaxs[axVert] + vecMins[axVert]) / 2;
  1266. }
  1267. SetViewOrigin( fPointX, fPointY );
  1268. }
  1269. //-----------------------------------------------------------------------------
  1270. // Purpose:
  1271. // Input : nSBCode -
  1272. // nPos -
  1273. // pScrollBar -
  1274. //-----------------------------------------------------------------------------
  1275. void CMapView2DBase::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar *pScrollBar)
  1276. {
  1277. int iPos = int(nPos);
  1278. float viewWidth = (float)m_ClientWidth / m_fZoom;
  1279. switch (nSBCode)
  1280. {
  1281. case SB_LINELEFT:
  1282. {
  1283. iPos = -int(viewWidth / 4);
  1284. break;
  1285. }
  1286. case SB_LINERIGHT:
  1287. {
  1288. iPos = int(viewWidth / 4);
  1289. break;
  1290. }
  1291. case SB_PAGELEFT:
  1292. {
  1293. iPos = -int(viewWidth / 2);
  1294. break;
  1295. }
  1296. case SB_PAGERIGHT:
  1297. {
  1298. iPos = int(viewWidth / 2);
  1299. break;
  1300. }
  1301. case SB_THUMBTRACK:
  1302. case SB_THUMBPOSITION:
  1303. {
  1304. if ( bInvertHorz )
  1305. iPos = -iPos;
  1306. SetViewOrigin( iPos, m_vViewOrigin[axVert] );
  1307. return;
  1308. }
  1309. }
  1310. if ( bInvertHorz )
  1311. iPos = -iPos;
  1312. SetViewOrigin( iPos, 0, true );
  1313. }
  1314. //-----------------------------------------------------------------------------
  1315. // Purpose:
  1316. // Input : nSBCode -
  1317. // nPos -
  1318. // pScrollBar -
  1319. //-----------------------------------------------------------------------------
  1320. void CMapView2DBase::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar *pScrollBar)
  1321. {
  1322. int iPos = int(nPos);
  1323. float viewHeight = (float)m_ClientHeight / m_fZoom;
  1324. switch (nSBCode)
  1325. {
  1326. case SB_LINEUP:
  1327. {
  1328. iPos = -int(viewHeight / 4);
  1329. break;
  1330. }
  1331. case SB_LINEDOWN:
  1332. {
  1333. iPos = int(viewHeight / 4);
  1334. break;
  1335. }
  1336. case SB_PAGEUP:
  1337. {
  1338. iPos = -int(viewHeight / 2);
  1339. break;
  1340. }
  1341. case SB_PAGEDOWN:
  1342. {
  1343. iPos = int(viewHeight / 2);
  1344. break;
  1345. }
  1346. case SB_THUMBTRACK:
  1347. case SB_THUMBPOSITION:
  1348. {
  1349. if ( bInvertVert )
  1350. iPos = -iPos;
  1351. SetViewOrigin( m_vViewOrigin[axHorz], iPos );
  1352. return;
  1353. }
  1354. }
  1355. if ( bInvertVert )
  1356. iPos = -iPos;
  1357. SetViewOrigin( 0, iPos, true );
  1358. }
  1359. //-----------------------------------------------------------------------------
  1360. // Purpose:
  1361. // Input : nFlags -
  1362. // point -
  1363. //-----------------------------------------------------------------------------
  1364. void CMapView2DBase::OnRButtonDown(UINT nFlags, CPoint point)
  1365. {
  1366. // Pass the message to the active tool.
  1367. if ( !m_pToolManager )
  1368. return;
  1369. CBaseTool *pTool = m_pToolManager->GetActiveTool();
  1370. if (pTool)
  1371. {
  1372. if ( IsLogical() )
  1373. {
  1374. if ( pTool->OnRMouseDownLogical( static_cast<CMapViewLogical*>( this ), nFlags, Vector2D(point.x,point.y) ) )
  1375. return;
  1376. }
  1377. else
  1378. {
  1379. if ( pTool->OnRMouseDown2D( static_cast<CMapView2D*>( this ), nFlags, Vector2D(point.x,point.y) ) )
  1380. return;
  1381. }
  1382. }
  1383. CView::OnRButtonDown(nFlags, point);
  1384. }
  1385. //-----------------------------------------------------------------------------
  1386. // Purpose:
  1387. // Input : nIDEvent -
  1388. //-----------------------------------------------------------------------------
  1389. void CMapView2DBase::OnTimer(UINT nIDEvent)
  1390. {
  1391. if ( nIDEvent == TIMER_SCROLLVIEW )
  1392. {
  1393. KillTimer( TIMER_SCROLLVIEW );
  1394. if (m_xScroll || m_yScroll)
  1395. {
  1396. SetViewOrigin(m_xScroll, m_yScroll, true);
  1397. // force mousemove event
  1398. CPoint pt;
  1399. GetCursorPos(&pt);
  1400. ScreenToClient(&pt);
  1401. OnMouseMove(0, pt);
  1402. }
  1403. }
  1404. CView::OnTimer(nIDEvent);
  1405. }
  1406. //-----------------------------------------------------------------------------
  1407. // Purpose:
  1408. // Input : pWnd -
  1409. // point -
  1410. //-----------------------------------------------------------------------------
  1411. void CMapView2DBase::OnContextMenu(UINT nFlags, const Vector2D &vPoint)
  1412. {
  1413. if ( m_bMouseDrag || !m_pToolManager )
  1414. {
  1415. return;
  1416. }
  1417. //
  1418. // Pass the message to the active tool.
  1419. //
  1420. CBaseTool *pTool = m_pToolManager->GetActiveTool();
  1421. if (pTool)
  1422. {
  1423. if ( IsLogical() )
  1424. {
  1425. if ( pTool->OnContextMenuLogical( static_cast<CMapViewLogical*>( this ), nFlags, vPoint ) )
  1426. return;
  1427. }
  1428. else
  1429. {
  1430. if ( pTool->OnContextMenu2D( static_cast<CMapView2D*>( this ), nFlags, vPoint ) )
  1431. return;
  1432. }
  1433. }
  1434. static CMenu menu, menuDefault;
  1435. static bool bInit = false;
  1436. if(!bInit)
  1437. {
  1438. bInit = true;
  1439. menu.LoadMenu(IDR_POPUPS);
  1440. menuDefault.Attach(::GetSubMenu(menu.m_hMenu, 2));
  1441. }
  1442. if(!PointInClientRect( vPoint ) )
  1443. return;
  1444. CPoint ptScreen( vPoint.x, vPoint.y );
  1445. ClientToScreen( &ptScreen );
  1446. menuDefault.TrackPopupMenu(TPM_LEFTBUTTON | TPM_RIGHTBUTTON | TPM_LEFTALIGN, ptScreen.x, ptScreen.y, this);
  1447. }
  1448. //-----------------------------------------------------------------------------
  1449. // Purpose: Called whenever the view is resized.
  1450. // Input : nType -
  1451. // cx -
  1452. // cy -
  1453. //-----------------------------------------------------------------------------
  1454. void CMapView2DBase::OnSize(UINT nType, int cx, int cy)
  1455. {
  1456. CView::OnSize(nType, cx, cy);
  1457. UpdateClientView();
  1458. }
  1459. //-----------------------------------------------------------------------------
  1460. // Purpose:
  1461. //-----------------------------------------------------------------------------
  1462. void CMapView2DBase::OnEditProperties()
  1463. {
  1464. // kludge for trackpopupmenu()
  1465. GetMainWnd()->pObjectProperties->ShowWindow(SW_SHOW);
  1466. }
  1467. //-----------------------------------------------------------------------------
  1468. // Purpose:
  1469. // Input : nFlags -
  1470. // point -
  1471. //-----------------------------------------------------------------------------
  1472. void CMapView2DBase::OnRButtonUp(UINT nFlags, CPoint point)
  1473. {
  1474. if ( !m_pToolManager )
  1475. return;
  1476. // Pass the message to the active tool.
  1477. CBaseTool *pTool = m_pToolManager->GetActiveTool();
  1478. if (pTool)
  1479. {
  1480. if ( IsLogical() )
  1481. {
  1482. pTool->OnRMouseUpLogical( static_cast<CMapViewLogical*>( this ), nFlags, Vector2D(point.x,point.y) );
  1483. }
  1484. else
  1485. {
  1486. pTool->OnRMouseUp2D( static_cast<CMapView2D*>( this ), nFlags, Vector2D(point.x,point.y) );
  1487. }
  1488. }
  1489. OnContextMenu( nFlags, Vector2D(point.x,point.y) );
  1490. CView::OnRButtonUp(nFlags, point);
  1491. }
  1492. //-----------------------------------------------------------------------------
  1493. // Purpose:
  1494. // Input : pCmdUI -
  1495. //-----------------------------------------------------------------------------
  1496. void CMapView2DBase::OnUpdateEditFunction(CCmdUI *pCmdUI)
  1497. {
  1498. pCmdUI->Enable((m_pToolManager->GetActiveToolID() != TOOL_FACEEDIT_MATERIAL) &&
  1499. !GetMainWnd()->IsShellSessionActive());
  1500. }
  1501. //-----------------------------------------------------------------------------
  1502. // Purpose:
  1503. // Input : pDC -
  1504. // Output : Returns TRUE on success, FALSE on failure.
  1505. //-----------------------------------------------------------------------------
  1506. BOOL CMapView2DBase::OnEraseBkgnd(CDC* pDC)
  1507. {
  1508. return TRUE;
  1509. }
  1510. void CMapView2DBase::WorldToClient(Vector2D &ptClient, const Vector &vecWorld)
  1511. {
  1512. Assert(!bInvertHorz);
  1513. Assert(bInvertVert);
  1514. ptClient.x = (m_fZoom * ( vecWorld[axHorz] - m_vViewOrigin[axHorz] )) + m_fClientWidthHalf;
  1515. ptClient.y = (m_fZoom * ( m_vViewOrigin[axVert] - vecWorld[axVert] )) + m_fClientHeightHalf;
  1516. /* if (bInvertHorz)
  1517. {
  1518. ptClient.x = -ptClient.x;
  1519. }
  1520. if ( bInvertVert )
  1521. {
  1522. ptClient.y = -ptClient.y;
  1523. }
  1524. // Also valid:
  1525. Vector2D vClient;
  1526. m_pCamera->WorldToView( vecWorld, vClient );
  1527. ptClient.x = vClient.x;
  1528. ptClient.y = vClient.y; */
  1529. }
  1530. //-----------------------------------------------------------------------------
  1531. // Purpose: Converts a 2D client coordinate into 3D world coordinates.
  1532. // Input : vecWorld -
  1533. // ptClient -
  1534. //-----------------------------------------------------------------------------
  1535. void CMapView2DBase::ClientToWorld(Vector &vecWorld, const Vector2D &ptClient)
  1536. {
  1537. vecWorld[axHorz] = ptClient.x - m_fClientWidthHalf;
  1538. vecWorld[axVert] = ptClient.y - m_fClientHeightHalf;
  1539. vecWorld[axThird] = 0;
  1540. vecWorld[axHorz] /= m_fZoom;
  1541. vecWorld[axVert] /= m_fZoom;
  1542. if (bInvertHorz)
  1543. {
  1544. vecWorld[axHorz] = -vecWorld[axHorz];
  1545. }
  1546. if (bInvertVert)
  1547. {
  1548. vecWorld[axVert] = -vecWorld[axVert];
  1549. }
  1550. vecWorld += m_vViewOrigin;
  1551. }
  1552. void CMapView2DBase::BuildRay( const Vector2D &ptClient, Vector& vStart, Vector& vEnd )
  1553. {
  1554. ClientToWorld( vStart, ptClient );
  1555. vEnd = vStart;
  1556. vStart[axThird] = -99999;
  1557. vEnd[axThird] = 99999;
  1558. }
  1559. void CMapView2DBase::GetBestTransformPlane( Vector &horzAxis, Vector &vertAxis, Vector &thirdAxis)
  1560. {
  1561. horzAxis.Init(); horzAxis[axHorz] = 1;
  1562. vertAxis.Init(); vertAxis[axVert] = 1;
  1563. thirdAxis.Init(); thirdAxis[axThird] = 1;
  1564. }
  1565. //-----------------------------------------------------------------------------
  1566. // Purpose: Zooms the 2D view in.
  1567. // Input : bAllViews - Whether to set all 2D views to this zoom level.
  1568. //-----------------------------------------------------------------------------
  1569. void CMapView2DBase::ZoomIn(BOOL bAllViews)
  1570. {
  1571. float newZoom = m_fZoom * 1.2;
  1572. SetZoom( newZoom );
  1573. //
  1574. // Set all doc 2d view zooms to this zoom level.
  1575. //
  1576. if (bAllViews)
  1577. {
  1578. VIEW2DINFO vi;
  1579. vi.wFlags = VI_ZOOM;
  1580. vi.fZoom = newZoom;
  1581. CMapDoc *pDoc = GetMapDoc();
  1582. if (pDoc != NULL)
  1583. {
  1584. pDoc->SetView2dInfo(vi);
  1585. }
  1586. }
  1587. }
  1588. //-----------------------------------------------------------------------------
  1589. // Purpose: Zooms the 2D view out.
  1590. // Input : bAllViews - Whether to set all 2D views to this zoom level.
  1591. //-----------------------------------------------------------------------------
  1592. void CMapView2DBase::ZoomOut(BOOL bAllViews)
  1593. {
  1594. SetZoom(m_fZoom / 1.2);
  1595. //
  1596. // Set all doc 2d view zooms to this zoom level.
  1597. //
  1598. if (bAllViews)
  1599. {
  1600. VIEW2DINFO vi;
  1601. vi.wFlags = VI_ZOOM;
  1602. vi.fZoom = m_fZoom;
  1603. CMapDoc *pDoc = GetMapDoc();
  1604. if (pDoc != NULL)
  1605. {
  1606. pDoc->SetView2dInfo(vi);
  1607. }
  1608. }
  1609. }
  1610. //-----------------------------------------------------------------------------
  1611. // Purpose: Returns true if the entire 3D box is visible in this 2D view.
  1612. //-----------------------------------------------------------------------------
  1613. bool CMapView2DBase::IsBoxFullyVisible(const Vector &minsWorld, const Vector &maxsWorld)
  1614. {
  1615. Vector2D minsClient;
  1616. Vector2D maxsClient;
  1617. WorldToClient(minsClient, minsWorld);
  1618. WorldToClient(maxsClient, maxsWorld);
  1619. return (PointInClientRect( minsClient ) &&
  1620. PointInClientRect( maxsClient ) );
  1621. }
  1622. //-----------------------------------------------------------------------------
  1623. // Purpose: Returns true if the entire 3D box is visible in this 2D view.
  1624. //-----------------------------------------------------------------------------
  1625. bool CMapView2DBase::CanBoxFitInView(const Vector &minsWorld, const Vector &maxsWorld)
  1626. {
  1627. Vector2D minsClient;
  1628. Vector2D maxsClient;
  1629. WorldToClient(minsClient, minsWorld);
  1630. WorldToClient(maxsClient, maxsWorld);
  1631. return ((m_ClientWidth > maxsClient.x - minsClient.x) &&
  1632. (m_ClientHeight > maxsClient.y - minsClient.y));
  1633. }
  1634. void CMapView2DBase::RenderView()
  1635. {
  1636. DrawVGuiPanel();
  1637. m_bUpdateView = false;
  1638. }
  1639. LRESULT CMapView2DBase::WindowProc( UINT message, WPARAM wParam, LPARAM lParam )
  1640. {
  1641. switch ( message )
  1642. {
  1643. case WM_KEYDOWN:
  1644. case WM_SYSKEYDOWN:
  1645. case WM_SYSCHAR:
  1646. case WM_CHAR:
  1647. case WM_KEYUP:
  1648. case WM_SYSKEYUP:
  1649. {
  1650. // don't invalidate window on these events, too much
  1651. return CView::WindowProc( message, wParam, lParam ) ;
  1652. }
  1653. case WM_PAINT:
  1654. {
  1655. CWnd *focusWnd = GetForegroundWindow();
  1656. if ( focusWnd && focusWnd->ContinueModal() )
  1657. {
  1658. // render the view now since were not running the main loop
  1659. RenderView();
  1660. }
  1661. else
  1662. {
  1663. // just flag view to be update with next main loop
  1664. m_bUpdateView = true;
  1665. }
  1666. return CView::WindowProc( message, wParam, lParam ) ;
  1667. }
  1668. }
  1669. if ( !WindowProcVGui( message, wParam, lParam ) )
  1670. {
  1671. return CView::WindowProc( message, wParam, lParam ) ;
  1672. }
  1673. return 1;
  1674. }
  1675. bool CMapView2DBase::IsInClientView( const Vector &vecMin, const Vector &vecMax )
  1676. {
  1677. // check render view bounds in world space, dont translate every object
  1678. if ( (vecMin.x > m_ViewMax.x) || (vecMax.x < m_ViewMin.x) )
  1679. return false;
  1680. if ( (vecMin.y > m_ViewMax.y) || (vecMax.y < m_ViewMin.y) )
  1681. return false;
  1682. if ( (vecMin.z > m_ViewMax.z) || (vecMax.z < m_ViewMin.z) )
  1683. return false;
  1684. return true;
  1685. }
  1686. bool CMapView2DBase::IsInClientView( const Vector2D &vecMin, const Vector2D &vecMax )
  1687. {
  1688. // check render view bounds in world space, dont translate every object
  1689. if ( (vecMin.x > m_ViewMax.x) || (vecMax.x < m_ViewMin.x) )
  1690. return false;
  1691. if ( (vecMin.y > m_ViewMax.y) || (vecMax.y < m_ViewMin.y) )
  1692. return false;
  1693. return true;
  1694. }
  1695. const Vector& CMapView2DBase::GetViewAxis()
  1696. {
  1697. return m_vViewAxis;
  1698. }