//========= Copyright Valve Corporation, All rights reserved. ============// // // Purpose: Rendering and mouse handling in the 2D view. // //============================================================================// #include "stdafx.h" #include "MapView2DBase.h" #include "hammer.h" #include "MapEntity.h" #include "MapFace.h" #include "MapSolid.h" #include "MapWorld.h" #include "MapDoc.h" #include "MapView2D.h" #include "MapViewLogical.h" #include "MapView3D.h" #include "tooldefs.h" #include "StockSolids.h" #include "statusbarids.h" #include "ObjectProperties.h" #include "Options.h" #include "History.h" #include "GlobalFunctions.h" #include "MapDefs.h" // dvs: For COORD_NOTINIT #include "Render2D.h" #include "TitleWnd.h" #include "ToolManager.h" #include "ToolMorph.h" // FIXME: remove #include "ToolInterface.h" #include "MapPlayerHullHandle.h" #include "vgui_controls/EditablePanel.h" #include "camera.h" #include "material.h" // memdbgon must be the last include file in a .cpp file!!! #include #define SnapToGrid(line,grid) (line - (line % grid)) #define ZOOM_MIN_DEFAULT 0.02125 #define ZOOM_MAX 256.0 static float s_fDragRestX, s_fDragRestY; IMPLEMENT_DYNCREATE(CMapView2DBase, CView) class CMapView2DBasePanel : public vgui::EditablePanel { public: CMapView2DBasePanel( CMapView2DBase *pMapView, const char *panelName ) : vgui::EditablePanel( NULL, panelName ) { m_pMapView = pMapView; } virtual void OnSizeChanged(int newWide, int newTall) { // call Panel and not EditablePanel OnSizeChanged. Panel::OnSizeChanged(newWide, newTall); } virtual void Paint() { m_pMapView->Render(); } CMapView2DBase *m_pMapView; }; BEGIN_MESSAGE_MAP(CMapView2DBase, CView) //{{AFX_MSG_MAP(CMapView2DBase) ON_WM_KEYDOWN() ON_WM_LBUTTONDOWN() ON_WM_MOUSEMOVE() ON_WM_MOUSEWHEEL() ON_WM_LBUTTONUP() ON_WM_LBUTTONDBLCLK() ON_WM_HSCROLL() ON_WM_VSCROLL() ON_WM_RBUTTONDOWN() ON_WM_TIMER() ON_WM_SIZE() ON_COMMAND(ID_EDIT_PROPERTIES, OnEditProperties) ON_WM_KEYUP() ON_WM_CHAR() ON_WM_RBUTTONUP() ON_UPDATE_COMMAND_UI(ID_CREATEOBJECT, OnUpdateEditFunction) ON_WM_ERASEBKGND() ON_UPDATE_COMMAND_UI(ID_EDIT_PROPERTIES, OnUpdateEditFunction) //}}AFX_MSG_MAP END_MESSAGE_MAP() //----------------------------------------------------------------------------- // Purpose: Constructor. Initializes data members. // --------------------------------------------------------------------------- CMapView2DBase::CMapView2DBase(void) { // // Must initialize the title window pointer before calling SetDrawType! // m_pwndTitle = NULL; m_flMinZoom = ZOOM_MIN_DEFAULT; m_fZoom = -1; // make sure setzoom performs m_vViewOrigin.Init(); m_ViewMin.Init(); m_ViewMax.Init(); m_xScroll = m_yScroll = 0; m_bActive = false; m_bMouseDrag = false; m_pCamera = new CCamera(); m_pCamera->SetOrthographic( 0.25f, -99999, 99999 ); m_pRender = new CRender2D(); m_pRender->SetView( this ); m_pRender->SetDefaultRenderMode( RENDER_MODE_FLAT_NOZ ); } //----------------------------------------------------------------------------- // Purpose: Destructor. Frees dynamically allocated resources. //----------------------------------------------------------------------------- CMapView2DBase::~CMapView2DBase(void) { if (m_pwndTitle != NULL) { delete m_pwndTitle; } if ( m_pCamera ) { delete m_pCamera; } if ( m_pRender ) { delete m_pRender; } } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CMapView2DBase::UpdateTitleWindowPos(void) { if (m_pwndTitle != NULL) { if (!::IsWindow(m_pwndTitle->m_hWnd)) { return; } m_pwndTitle->SetWindowPos(NULL, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOZORDER); m_pwndTitle->ShowWindow(SW_SHOW); } } //----------------------------------------------------------------------------- // Create a title window. //----------------------------------------------------------------------------- void CMapView2DBase::CreateTitleWindow(void) { m_pwndTitle = CTitleWnd::CreateTitleWnd(this, ID_2DTITLEWND); Assert(m_pwndTitle != NULL); UpdateTitleWindowPos(); } //----------------------------------------------------------------------------- // Purpose: First-time initialization of this view. //----------------------------------------------------------------------------- void CMapView2DBase::OnInitialUpdate(void) { // CMainFrame::LoadWindowStates calls InitialUpdateFrame which causes us to get two // OnInitialUpdate messages! Check for a NULL renderer to avoid processing twice. if ( GetMainPanel() != NULL ) return; CMapDoc *pDoc = GetMapDoc(); m_pToolManager = pDoc->GetTools(); CenterView(); SetColorMode(Options.view2d.bWhiteOnBlack); ShowScrollBar(SB_HORZ, Options.view2d.bScrollbars); ShowScrollBar(SB_VERT, Options.view2d.bScrollbars); CView::OnInitialUpdate(); vgui::EditablePanel *pMainPanel = new CMapView2DBasePanel( this, "MapView2DPanel" ); SetParentWindow( this ); SetMainPanel( pMainPanel ); } //----------------------------------------------------------------------------- // Purpose: Called by the tools to scroll the 2D view so that a point is visible. // Sets a timer to do the scroll so that we don't much with the view state // while the tool is handling a mouse message. // Input : point - Point in client coordinates to make visible. //----------------------------------------------------------------------------- void CMapView2DBase::ToolScrollToPoint(const Vector2D &ptClient) { int nScrollSpeed = 10 / m_fZoom; if ((GetCapture() == this) && ( ptClient.x < 0 || ptClient.y < 0 || ptClient.x >= m_ClientWidth || ptClient.y >= m_ClientHeight ) ) { // reset these m_xScroll = m_yScroll = 0; if (ptClient.x < 0) { // scroll left m_xScroll = -nScrollSpeed; } else if (ptClient.x >= m_ClientWidth) { // scroll right m_xScroll = nScrollSpeed; } if (ptClient.y < 0) { // scroll up m_yScroll = nScrollSpeed; } else if (ptClient.y >= m_ClientHeight) { // scroll down m_yScroll = -nScrollSpeed; } SetTimer( TIMER_SCROLLVIEW, 10, NULL); } else { m_xScroll = m_yScroll = 0; KillTimer( TIMER_SCROLLVIEW ); } } //----------------------------------------------------------------------------- // Purpose: Adjusts a color's intensity - will not overbrighten. // Input : ulColor - Color to adjust. // nIntensity - Percentage of original color intensity to keep (0 - 100). // bReverse - True ramps toward black, false ramps toward the given color. // Output : Returns the adjusted color. //----------------------------------------------------------------------------- void CMapView2DBase::AdjustColorIntensity(Color &color, int nIntensity) { if (!Options.view2d.bWhiteOnBlack) { nIntensity = 100 - nIntensity; } nIntensity = clamp(nIntensity, 0, 100); // // Adjust each component's intensity. // color.SetColor( min( (color.r() * nIntensity) / 100, 255 ), min( (color.g() * nIntensity) / 100, 255 ), min( (color.b() * nIntensity) / 100, 255 ), color.a() ); } //----------------------------------------------------------------------------- // Purpose: // Input : bWhiteOnBlack - //----------------------------------------------------------------------------- void CMapView2DBase::SetColorMode(bool bWhiteOnBlack) { // Grid color. COLORREF clr = Options.colors.clrGrid; m_clrGrid.SetColor( GetRValue(clr), GetGValue(clr), GetBValue(clr), 255 ); if (Options.colors.bScaleGridColor) { AdjustColorIntensity(m_clrGrid, Options.view2d.iGridIntensity); } // Grid highlight color. clr = Options.colors.clrGrid10; m_clrGridCustom.SetColor( GetRValue(clr), GetGValue(clr), GetBValue(clr), 255 ); if (Options.colors.bScaleGrid10Color) { AdjustColorIntensity(m_clrGridCustom, 1.5 * Options.view2d.iGridIntensity); } // Grid 1024 highlight color. clr = Options.colors.clrGrid1024; m_clrGrid1024.SetColor( GetRValue(clr), GetGValue(clr), GetBValue(clr), 255 ); if (Options.colors.bScaleGrid1024Color) { AdjustColorIntensity(m_clrGrid1024, Options.view2d.iGridIntensity); } // Dotted grid color. No need to create a pen since all we do is SetPixel with it. clr = Options.colors.clrGridDot; m_clrGridDot.SetColor( GetRValue(clr), GetGValue(clr), GetBValue(clr), 255 ); if (Options.colors.bScaleGridDotColor) { AdjustColorIntensity(m_clrGridDot, Options.view2d.iGridIntensity + 20); } // Axis color. clr = Options.colors.clrAxis; m_clrAxis.SetColor( GetRValue(clr), GetGValue(clr), GetBValue(clr), 255 ); if (Options.colors.bScaleAxisColor) { AdjustColorIntensity(m_clrAxis, Options.view2d.iGridIntensity); } clr = Options.colors.clrBackground; m_ClearColor.SetColor( GetRValue(clr), GetGValue(clr), GetBValue(clr), 255 ); m_bClearZBuffer = false; } // quick & dirty: static bool s_bGridDots; static int s_iCustomGridSpacing; bool CMapView2DBase::HighlightGridLine( CRender2D *pRender, int nGridLine ) { if (nGridLine == 0) { pRender->SetDrawColor( m_clrAxis ); return true; } // // Optionally highlight every 1024. // if (Options.view2d.bGridHigh1024 && (!(nGridLine % 1024))) { pRender->SetDrawColor( m_clrGrid1024 ); return true; } // // Optionally highlight every 64. // else if (Options.view2d.bGridHigh64 && (!(nGridLine % 64))) { if (!s_bGridDots) { pRender->SetDrawColor( m_clrGridCustom ); return true; } } // // Optionally highlight every nth grid line. // if (Options.view2d.bGridHigh10 && (!(nGridLine % s_iCustomGridSpacing))) { if (!s_bGridDots) { pRender->SetDrawColor( m_clrGridCustom ); return true; } } return false; } //----------------------------------------------------------------------------- // Purpose: Draws the grid, using dots or lines depending on the user setting. // Input : pDC - Device context to draw in. //----------------------------------------------------------------------------- void CMapView2DBase::DrawGrid(CRender2D *pRender, int xAxis, int yAxis, float depth, bool bNoSmallGrid ) { CMapDoc *pDoc = GetMapDoc(); if (pDoc == NULL) return; // Check for too small grid. int nGridSpacing = pDoc->GetGridSpacing(); // never allow a grid spacing samller then 2 pixel while ( ((float)nGridSpacing * m_fZoom) < 2.0f ) { nGridSpacing*=2; } if ((((float)nGridSpacing * m_fZoom) < 4.0f) && Options.view2d.bHideSmallGrid) { bNoSmallGrid = true; } // No dots if too close together. s_bGridDots = Options.view2d.bGridDots; s_iCustomGridSpacing = nGridSpacing * Options.view2d.iGridHighSpec; int xMin = SnapToGrid( (int)max( g_MIN_MAP_COORD, m_ViewMin[xAxis]-nGridSpacing ), nGridSpacing ); int xMax = SnapToGrid( (int)min( g_MAX_MAP_COORD, m_ViewMax[xAxis]+nGridSpacing ), nGridSpacing ); int yMin = SnapToGrid( (int)max( g_MIN_MAP_COORD, m_ViewMin[yAxis]-nGridSpacing ), nGridSpacing ); int yMax = SnapToGrid( (int)min( g_MAX_MAP_COORD, m_ViewMax[yAxis]+nGridSpacing ), nGridSpacing ); Assert( xMin < xMax ); Assert( yMin < yMax ); // Draw the vertical grid lines. Vector vPointMin(depth,depth,depth); Vector vPointMax(depth,depth,depth); vPointMin[xAxis] = xMin; vPointMax[xAxis] = xMax; // draw dots first, for the shake of speed do really ugly things if (s_bGridDots && !bNoSmallGrid) { pRender->BeginClientSpace(); CMeshBuilder meshBuilder; CMatRenderContextPtr pRenderContext( MaterialSystemInterface() ); IMesh* pMesh = pRenderContext->GetDynamicMesh(); for (int y = yMin; y <= yMax; y += nGridSpacing ) { Vector vPoint(depth,depth,depth); vPoint[yAxis] = y; vPoint[xAxis] = xMin; Vector2D v2D; WorldToClient( v2D, vPoint ); v2D.y = (int)(v2D.y+0.5); // dot drawing isn't precise enough in world space // so we still do it in client space int nNumPoints = 1+abs(xMax-xMin)/nGridSpacing; meshBuilder.Begin( pMesh, MATERIAL_LINES, nNumPoints ); float fOffset = nGridSpacing * m_fZoom; while( nNumPoints > 0) { float roundfx = (int)(v2D.x+0.5); v2D.x += fOffset; meshBuilder.Position3f( roundfx, v2D.y, 0 ); meshBuilder.Color4ubv( (byte*)&m_clrGridDot ); meshBuilder.AdvanceVertex(); meshBuilder.Position3f( roundfx+1, v2D.y+1, 0 ); meshBuilder.Color4ubv( (byte*)&m_clrGridDot ); meshBuilder.AdvanceVertex(); nNumPoints--; } meshBuilder.End(); pMesh->Draw(); } pRender->EndClientSpace(); } for (int y = yMin; y <= yMax; y += nGridSpacing ) { pRender->SetDrawColor( m_clrGrid ); int bHighligh = HighlightGridLine( pRender, y ); // Don't draw the base grid if it is too small. if (!bHighligh && bNoSmallGrid) continue; // Always draw lines for the axes and map boundaries. if ((!s_bGridDots) || (bHighligh) || (y == g_MAX_MAP_COORD) || (y == g_MIN_MAP_COORD)) { vPointMin[yAxis] = vPointMax[yAxis] = y; pRender->DrawLine( vPointMin, vPointMax ); } } vPointMin[yAxis] = yMin; vPointMax[yAxis] = yMax; for (int x = xMin; x <= xMax; x += nGridSpacing ) { pRender->SetDrawColor( m_clrGrid ); int bHighligh = HighlightGridLine( pRender, x ); // Don't draw the base grid if it is too small. if ( !bHighligh && bNoSmallGrid ) continue; // Always draw lines for the axes and map boundaries. if ((!s_bGridDots) || (bHighligh) || (x == g_MAX_MAP_COORD) || (x == g_MIN_MAP_COORD)) { vPointMin[xAxis] = vPointMax[xAxis] = x; pRender->DrawLine( vPointMin, vPointMax ); } } } void CMapView2DBase::DrawGridLogical( CRender2D *pRender ) { CMapDoc *pDoc = GetMapDoc(); if (pDoc == NULL) return; // Grid in logical view is always 1024 int nGridSpacing = 1024; s_iCustomGridSpacing = nGridSpacing; s_bGridDots = false; int xAxis = 0; int yAxis = 1; int xMin = SnapToGrid( (int)max( g_MIN_MAP_COORD, m_ViewMin[xAxis]-nGridSpacing ), nGridSpacing ); int xMax = SnapToGrid( (int)min( g_MAX_MAP_COORD, m_ViewMax[xAxis]+nGridSpacing ), nGridSpacing ); int yMin = SnapToGrid( (int)max( g_MIN_MAP_COORD, m_ViewMin[yAxis]-nGridSpacing ), nGridSpacing ); int yMax = SnapToGrid( (int)min( g_MAX_MAP_COORD, m_ViewMax[yAxis]+nGridSpacing ), nGridSpacing ); Assert( xMin < xMax ); Assert( yMin < yMax ); // Draw the vertical grid lines. float depth = 0.0f; Vector vPointMin(depth,depth,depth); Vector vPointMax(depth,depth,depth); vPointMin[xAxis] = xMin; vPointMax[xAxis] = xMax; for (int y = yMin; y <= yMax; y += nGridSpacing ) { pRender->SetDrawColor( m_clrGrid ); HighlightGridLine( pRender, y ); vPointMin[yAxis] = vPointMax[yAxis] = y; pRender->DrawLine( vPointMin, vPointMax ); } vPointMin[yAxis] = yMin; vPointMax[yAxis] = yMax; for (int x = xMin; x <= xMax; x += nGridSpacing ) { pRender->SetDrawColor( m_clrGrid ); HighlightGridLine( pRender, x ); vPointMin[xAxis] = vPointMax[xAxis] = x; pRender->DrawLine( vPointMin, vPointMax ); } } //----------------------------------------------------------------------------- // Purpose: // Input : pointCheck - // pointRef - // nDist - // Output : Returns true on success, false on failure. //----------------------------------------------------------------------------- bool CMapView2DBase::CheckDistance(const Vector2D &vecCheck, const Vector2D &vecRef, int nDist) { if ((fabs(vecRef.x - vecCheck.x) <= nDist) && (fabs(vecRef.y - vecCheck.y) <= nDist)) { return true; } return false; } //----------------------------------------------------------------------------- // Purpose: Gets the center point of the view in world coordinates. // Input : pt - Receives the center point. Only dimensions initialized with // COORD_NOTINIT will be filled out. //----------------------------------------------------------------------------- void CMapView2DBase::GetCenterPoint(Vector &pt) { Vector2D ptCenter( m_ClientWidth/2, m_ClientHeight/2); Vector vCenter; ClientToWorld(vCenter, ptCenter ); if (pt[axHorz] == COORD_NOTINIT) { pt[axHorz] = vCenter[axHorz]; } if (pt[axVert] == COORD_NOTINIT) { pt[axVert] = vCenter[axVert]; } } void CMapView2DBase::SetViewOrigin( float fHorz, float fVert, bool bRelative ) { Vector vCurPos; m_pCamera->GetViewPoint( vCurPos ); if ( bRelative ) { if ( fHorz == 0 && fVert == 0 ) return; vCurPos[axHorz] += fHorz; vCurPos[axVert] += fVert; } else { if ( fHorz == vCurPos[axHorz] && fVert == vCurPos[axVert] ) return; vCurPos[axHorz] = fHorz; vCurPos[axVert] = fVert; } if ( axThird == 1 ) { vCurPos[axThird] = g_MIN_MAP_COORD; } else { vCurPos[axThird] = g_MAX_MAP_COORD; } m_pCamera->SetViewPoint( vCurPos ); // Msg("SetViewOrigin: (%i,%i) %s (%i,%i) \n", x, y, bRelative?"rel":"abs", m_ptViewOrigin.x, m_ptViewOrigin.y ); UpdateClientView(); } //----------------------------------------------------------------------------- // Purpose: Calculates all viewport related variables //----------------------------------------------------------------------------- void CMapView2DBase::UpdateClientView(void) { if (!::IsWindow(m_hWnd)) return; m_fZoom = m_pCamera->GetZoom(); m_pCamera->GetViewPoint( m_vViewOrigin ); CRect rectClient; GetClientRect( &rectClient ); m_ClientWidth = rectClient.Width(); m_ClientHeight = rectClient.Height(); float viewWidth = (float)m_ClientWidth / m_fZoom; float viewHeight = (float)m_ClientHeight / m_fZoom; m_fClientWidthHalf = (float)m_ClientWidth / 2; m_fClientHeightHalf = (float)m_ClientHeight / 2; float flMaxExtents = fabs(g_MIN_MAP_COORD) + fabs(g_MAX_MAP_COORD); m_flMinZoom = min(m_ClientWidth / flMaxExtents, m_ClientHeight / flMaxExtents); if ( Options.view2d.bScrollbars ) { SCROLLINFO si; si.cbSize = sizeof(si); si.fMask = SIF_PAGE | SIF_RANGE | SIF_POS; si.nMin = g_MIN_MAP_COORD - m_fClientWidthHalf; si.nMax = g_MAX_MAP_COORD + m_fClientWidthHalf; si.nPage = viewWidth; si.nPos = m_vViewOrigin[axHorz]; if ( bInvertHorz ) si.nPos = -si.nPos; SetScrollInfo(SB_HORZ, &si); si.nMin = g_MIN_MAP_COORD-m_fClientHeightHalf; si.nMax = g_MAX_MAP_COORD+m_fClientHeightHalf; si.nPage = viewHeight; si.nPos = m_vViewOrigin[axVert]; if ( bInvertVert ) si.nPos = -si.nPos; SetScrollInfo(SB_VERT, &si); } else { ShowScrollBar(SB_HORZ, FALSE); ShowScrollBar(SB_VERT, FALSE); } // calc view axis m_vViewAxis.Init(); m_vViewAxis[axThird] = 1; if ( bInvertHorz && bInvertVert ) m_vViewAxis = -m_vViewAxis; m_pCamera->SetViewPort( m_ClientWidth, m_ClientHeight ); m_pCamera->SetYaw( 0 ); m_pCamera->SetPitch( 0 ); m_pCamera->SetRoll( 0 ); switch ( axThird ) { case 0 : m_pCamera->SetYaw( -90 ); break; case 1 : m_pCamera->SetRoll( 0 ); break; case 2 : m_pCamera->SetPitch( 90 ); break; } // update 3D world bounding box for 2D client view int xmin = 0; int xmax = m_ClientWidth; int ymin = 0; int ymax = m_ClientHeight; Vector2D ptViewMin(xmin, ymin); Vector2D ptViewMax(xmax, ymax); ClientToWorld( m_ViewMin, ptViewMin ); ClientToWorld( m_ViewMax, ptViewMax ); m_ViewMin[axThird] = g_MIN_MAP_COORD; m_ViewMax[axThird] = g_MAX_MAP_COORD; NormalizeBox( m_ViewMin, m_ViewMax ); Assert( m_ViewMin.x <= m_ViewMax.x ); Assert( m_ViewMin.y <= m_ViewMax.y ); Assert( m_ViewMin.z <= m_ViewMax.z ); OnRenderListDirty(); m_bUpdateView = true; UpdateStatusBar(); } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CMapView2DBase::UpdateStatusBar() { if(!IsWindow(m_hWnd)) return; char szBuf[128]; sprintf(szBuf, " Zoom: %.2f ", m_fZoom); SetStatusText(SBI_GRIDZOOM, szBuf); } //----------------------------------------------------------------------------- // Purpose: // Input : fNewZoom - //----------------------------------------------------------------------------- void CMapView2DBase::SetZoom(float fNewZoom) { float fOldZoom = m_pCamera->GetZoom(); fNewZoom = clamp( fNewZoom, m_flMinZoom, ZOOM_MAX ); if (fOldZoom == fNewZoom) { return; } if (IsWindow(m_hWnd)) { // zoom in on cursor position POINT ptClient; GetCursorPos(&ptClient); ScreenToClient(&ptClient); Vector2D newOrigin,vecClient(ptClient.x,ptClient.y); if (!PointInClientRect(vecClient)) { // cursor is not in window; zoom on center instead vecClient.x = m_fClientWidthHalf; vecClient.y = m_fClientHeightHalf; } Vector vecWorld; ClientToWorld( vecWorld, vecClient ); vecClient.x -= m_fClientWidthHalf; vecClient.y -= m_fClientHeightHalf; vecClient.x /= fNewZoom; vecClient.y /= fNewZoom; if (bInvertVert) { vecClient.y = -vecClient.y; } if (bInvertHorz) { vecClient.x = -vecClient.x; } newOrigin.x = vecWorld[axHorz] - vecClient.x; newOrigin.y = vecWorld[axVert] - vecClient.y; m_pCamera->SetZoom( fNewZoom ); SetViewOrigin( newOrigin.x, newOrigin.y ); UpdateClientView(); } } #ifdef _DEBUG void CMapView2DBase::AssertValid() const { CView::AssertValid(); } void CMapView2DBase::Dump(CDumpContext& dc) const { CView::Dump(dc); } #endif //_DEBUG //----------------------------------------------------------------------------- // Purpose: // Input : cs - // Output : Returns TRUE on success, FALSE on failure. //----------------------------------------------------------------------------- BOOL CMapView2DBase::PreCreateWindow(CREATESTRUCT& cs) { static CString className; if(className.IsEmpty()) { className = AfxRegisterWndClass(CS_BYTEALIGNCLIENT | CS_DBLCLKS, AfxGetApp()->LoadStandardCursor(IDC_ARROW), HBRUSH(NULL)); } cs.lpszClass = className; return CView::PreCreateWindow(cs); } //----------------------------------------------------------------------------- // Purpose: // Input : nChar - // nRepCnt - // nFlags - //----------------------------------------------------------------------------- void CMapView2DBase::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) { CMapDoc *pDoc = GetMapDoc(); if ( !pDoc || !m_pToolManager ) return; if (nChar == VK_SPACE) { // Switch the cursor to the hand. We'll start panning the view // on the left button down event. if ( m_bMouseDrag ) SetCursor("Resource/ifm_grab.cur"); else SetCursor("Resource/ifm_move.cur"); return; } // Pass the message to the active tool. CBaseTool *pTool = m_pToolManager->GetActiveTool(); if (pTool) { if ( IsLogical() ) { if ( pTool->OnKeyDownLogical( static_cast( this ), nChar, nRepCnt, nFlags ) ) return; } else { if ( pTool->OnKeyDown2D( static_cast( this ), nChar, nRepCnt, nFlags ) ) return; } } // The tool didn't handle the key. Perform default handling for this view. // bool bShift = nFlags & MK_SHIFT; bool bCtrl = nFlags & MK_CONTROL; switch (nChar) { // // Zoom in. // case '+': case VK_ADD: { ZoomIn(bCtrl); break; } // // Zoom out. // case '-': case VK_SUBTRACT: { ZoomOut(bCtrl); break; } case VK_UP: { // scroll up OnVScroll(SB_LINEUP, 0, NULL); break; } case VK_DOWN: { // scroll down OnVScroll(SB_LINEDOWN, 0, NULL); break; } case VK_LEFT: { // scroll up OnHScroll(SB_LINELEFT, 0, NULL); break; } case VK_RIGHT: { // scroll up OnHScroll(SB_LINERIGHT, 0, NULL); break; } // // 1-9 +0 shortcuts to various zoom levels. // case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': case '0': { int iZoom = nChar - '1'; if (nChar == '0') { iZoom = 9; } SetZoom(m_flMinZoom * (1 << iZoom)); break; } } CView::OnKeyDown(nChar, nRepCnt, nFlags); } //----------------------------------------------------------------------------- // Purpose: // Input : Per CWnd::OnKeyUp. //----------------------------------------------------------------------------- void CMapView2DBase::OnKeyUp(UINT nChar, UINT nRepCnt, UINT nFlags) { if ( !m_pToolManager ) return; if (nChar == VK_SPACE) { // // Releasing the space bar stops panning the view. // SetCursor( vgui::dc_arrow ); } else { // // Pass the message to the active tool. // CBaseTool *pTool = m_pToolManager->GetActiveTool(); if (pTool) { if ( IsLogical() ) { if ( pTool->OnKeyUpLogical( static_cast( this ), nChar, nRepCnt, nFlags ) ) return; } else { if ( pTool->OnKeyUp2D( static_cast( this ), nChar, nRepCnt, nFlags ) ) return; } } } CView::OnKeyUp(nChar, nRepCnt, nFlags); } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CMapView2DBase::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags) { if ( !m_pToolManager ) return; // Pass the message to the active tool. CBaseTool *pTool = m_pToolManager->GetActiveTool(); if ( pTool ) { if ( IsLogical() ) { if ( pTool->OnCharLogical( static_cast( this ), nChar, nRepCnt, nFlags ) ) return; } else { if ( pTool->OnChar2D( static_cast( this ), nChar, nRepCnt, nFlags ) ) return; } } CView::OnChar( nChar, nRepCnt, nFlags ); } //----------------------------------------------------------------------------- // Hit test //----------------------------------------------------------------------------- bool CMapView2DBase::HitTest( const Vector2D &vPoint, const Vector& mins, const Vector& maxs) { Vector2D vecMinClient,vecMaxClient; WorldToClient(vecMinClient, mins); WorldToClient(vecMaxClient, maxs); CRect rect(vecMinClient.x, vecMinClient.y, vecMaxClient.x, vecMaxClient.y); rect.NormalizeRect(); return rect.PtInRect( CPoint( vPoint.x, vPoint.y) ); } //----------------------------------------------------------------------------- // Purpose: // Input : point - Point in client coordinates. // bMakeFirst - // Output : Returns true on success, false on failure. //----------------------------------------------------------------------------- int CMapView2DBase::ObjectsAt( const Vector2D &vPoint, HitInfo_t *pHitData, int nMaxObjects, unsigned int nFlags ) { CMapDoc *pDoc = GetMapDoc(); CMapWorld *pWorld = pDoc->GetMapWorld(); return ObjectsAt( pWorld, vPoint, pHitData, nMaxObjects, nFlags ); } //----------------------------------------------------------------------------- // Purpose: // Input : point - Point in client coordinates. // bMakeFirst - // Output : Returns true on success, false on failure. //----------------------------------------------------------------------------- int CMapView2DBase::ObjectsAt( CMapWorld *pWorld, const Vector2D &vPoint, HitInfo_t *pHitData, int nMaxObjects, unsigned int nFlags ) { int nIndex = 0; const CMapObjectList *pChildren = pWorld->GetChildren(); FOR_EACH_OBJ( *pChildren, pos ) { CMapClass *pChild = pChildren->Element(pos); CMapWorld *pWorldChild = dynamic_cast< CMapWorld * >( pChild ); if ( pWorldChild ) { nIndex += ObjectsAt( pWorldChild, vPoint, &pHitData[ nIndex ], nMaxObjects - nIndex ); } else if ( IsLogical() ) { if ( pChild->HitTestLogical( static_cast(this), vPoint, pHitData[nIndex] ) ) { nIndex++; } } else { if ( pChild->HitTest2D( static_cast(this), vPoint, pHitData[nIndex] ) ) { nIndex++; } } } return nIndex; } //----------------------------------------------------------------------------- // Purpose: // Input : nFlags - // point - //----------------------------------------------------------------------------- void CMapView2DBase::OnLButtonDown(UINT nFlags, CPoint point) { if ( !m_pToolManager ) return; // Check for view-specific keyboard overrides. if (GetAsyncKeyState(VK_SPACE) & 0x8000) { // // Space bar + mouse move scrolls the view. // m_bMouseDrag = true; m_ptLDownClient = point; s_fDragRestX = s_fDragRestY = 0; SetCapture(); SetCursor( "Resource/ifm_grab.cur" ); return; } // // Pass the message to the active tool. // CBaseTool *pTool = m_pToolManager->GetActiveTool(); if (pTool) { if ( IsLogical() ) { if ( pTool->OnLMouseDownLogical( static_cast( this ), nFlags, Vector2D( point.x, point.y ) ) ) return; } else { if ( pTool->OnLMouseDown2D( static_cast( this ), nFlags, Vector2D( point.x, point.y ) ) ) return; } } m_ptLDownClient = point; CView::OnLButtonDown(nFlags, point); } //----------------------------------------------------------------------------- // Purpose: // Input : nFlags - // point - //----------------------------------------------------------------------------- void CMapView2DBase::OnMouseMove(UINT nFlags, CPoint point) { // // Make sure we are the active view. // CMapDoc *pDoc = GetMapDoc(); if ( !pDoc || !m_pToolManager ) return; if ( !IsActive() ) { pDoc->SetActiveView(this); } // // If we are the active application, make sure this view has the input focus. // if (APP()->IsActiveApp() && !IsRunningInEngine() ) { if (GetFocus() != this) { SetFocus(); } } // // Panning the view with the mouse, just exit. // if ( m_bMouseDrag ) { if ( point == m_ptLDownClient ) return; float fdx = point.x - m_ptLDownClient.x; float fdy = point.y - m_ptLDownClient.y; fdx /= m_fZoom; fdy /= m_fZoom; if ( bInvertHorz ) fdy = -fdy; if ( bInvertVert ) fdx = -fdx; fdx += s_fDragRestX; fdy += s_fDragRestY; int idx = fdx; int idy = fdy; if ( idy == 0 && idx == 0 ) return; s_fDragRestX = fdx - idx; s_fDragRestY = fdy - idy; SetViewOrigin( idx, idy, true ); SetCursor( "Resource/ifm_grab.cur" ); // reset mouse pos m_ptLDownClient = point; return; } // Pass the message to the active tool. CBaseTool *pTool = m_pToolManager->GetActiveTool(); if (pTool) { Vector2D vPoint( point.x, point.y ); if ( IsLogical() ) { if ( pTool->OnMouseMoveLogical( static_cast( this ), nFlags, vPoint ) ) return; } else { if ( pTool->OnMouseMove2D( static_cast( this ), nFlags, vPoint ) ) return; } } // // The tool didn't handle the message. Make sure the cursor is set. // if (GetAsyncKeyState(VK_SPACE) & 0x8000) { SetCursor( "Resource/ifm_move.cur" ); } else { SetCursor( vgui::dc_arrow ); } CView::OnMouseMove(nFlags, point); } //----------------------------------------------------------------------------- // Purpose: Handles mouse wheel events. The mouse wheel is used to zoom the 2D // view in and out. // Input : Per CWnd::OnMouseWheel. //----------------------------------------------------------------------------- BOOL CMapView2DBase::OnMouseWheel(UINT nFlags, short zDelta, CPoint point) { if ( !m_pToolManager ) return TRUE; // Pass the message to the active tool. // CBaseTool *pTool = m_pToolManager->GetActiveTool(); if (pTool) { if ( IsLogical() ) { if ( pTool->OnMouseWheelLogical( static_cast( this ), nFlags, zDelta, Vector2D(point.x,point.y) ) ) return TRUE; } else { if ( pTool->OnMouseWheel2D( static_cast( this ), nFlags, zDelta, Vector2D(point.x,point.y) ) ) return TRUE; } } if (zDelta < 0) { ZoomOut(nFlags & MK_CONTROL); } else { ZoomIn(nFlags & MK_CONTROL); } return(TRUE); } //----------------------------------------------------------------------------- // Purpose: Scrolls the view to make sure that the position in world space is visible. // Input : vecPos - //----------------------------------------------------------------------------- void CMapView2DBase::EnsureVisible(Vector &vecPos, float flMargin) { Vector2D pt; WorldToClient(pt, vecPos); // check to see if it's in the client if (pt.x < 0) { pt.x = -pt.x + flMargin; } else if (pt.x > m_ClientWidth ) { pt.x = m_ClientWidth - pt.x - flMargin; } else { pt.x = 0; } if (pt.y < 0) { pt.y = -pt.y + flMargin; } else if (pt.y > m_ClientHeight) { pt.y = m_ClientHeight - pt.y - flMargin; } else { pt.y = 0; } // if it's not in the client, scroll if (pt.x || pt.y) { SetViewOrigin( pt.x, pt.y, true ); } } //----------------------------------------------------------------------------- // Purpose: // Input : nFlags - // point - //----------------------------------------------------------------------------- void CMapView2DBase::OnLButtonUp(UINT nFlags, CPoint point) { CMapDoc *pDoc = GetMapDoc(); if ( !pDoc || !m_pToolManager ) return; ReleaseCapture(); if ( m_bMouseDrag ) { m_bMouseDrag = false; // KillTimer(TIMER_MOUSEDRAG); OnMouseMove(nFlags, point); return; } // // Pass the message to the active tool. // CBaseTool *pTool = m_pToolManager->GetActiveTool(); if (pTool) { if ( IsLogical() ) { if ( pTool->OnLMouseUpLogical( static_cast( this ), nFlags, Vector2D(point.x,point.y) ) ) return; } else { if ( pTool->OnLMouseUp2D( static_cast( this ), nFlags, Vector2D(point.x,point.y) ) ) return; } } // we might have removed some stuff that was relevant: pDoc->UpdateStatusbar(); CView::OnLButtonUp(nFlags, point); } //----------------------------------------------------------------------------- // Purpose: Handles the left mouse button double click event. //----------------------------------------------------------------------------- void CMapView2DBase::OnLButtonDblClk(UINT nFlags, CPoint point) { // // Don't forward message if we are controlling the camera. // if ((GetAsyncKeyState(VK_SPACE) & 0x8000) != 0) return; if ( !m_pToolManager ) return; // Pass the message to the active tool. CBaseTool *pTool = m_pToolManager->GetActiveTool(); if (pTool != NULL) { Vector2D vPoint( point.x, point.y ); if ( IsLogical() ) { pTool->OnLMouseDblClkLogical( static_cast( this ), nFlags, vPoint ); pTool->OnLMouseDownLogical( static_cast( this ), nFlags, vPoint ); } else { pTool->OnLMouseDblClk2D( static_cast( this ), nFlags, vPoint ); pTool->OnLMouseDown2D( static_cast( this ), nFlags, vPoint ); } } } //----------------------------------------------------------------------------- // Purpose: // Input : bActivate - // pActivateView - // pDeactiveView - //----------------------------------------------------------------------------- void CMapView2DBase::ActivateView(bool bActivate) { CMapView::ActivateView( bActivate ); if ( bActivate ) { CMapDoc *pDoc = GetMapDoc(); CMapDoc::SetActiveMapDoc( pDoc ); pDoc->UpdateTitle( this ); UpdateStatusBar(); } else { m_xScroll = m_yScroll = 0; } } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CMapView2DBase::UpdateView( int nFlags ) { if ( nFlags & MAPVIEW_UPDATE_ONLY_3D ) return; if ( IsLogical() ) { if ( nFlags & MAPVIEW_UPDATE_ONLY_2D ) return; } else { if ( nFlags & MAPVIEW_UPDATE_ONLY_LOGICAL ) return; } if(nFlags & MAPVIEW_OPTIONS_CHANGED) { ShowScrollBar(SB_HORZ, Options.view2d.bScrollbars); ShowScrollBar(SB_VERT, Options.view2d.bScrollbars); SetColorMode(Options.view2d.bWhiteOnBlack); UpdateClientView(); } // Render the world if the flag is specified. if ( nFlags & (MAPVIEW_UPDATE_OBJECTS|MAPVIEW_UPDATE_VISGROUP_STATE|MAPVIEW_UPDATE_VISGROUP_ALL) ) { // rebuild render list since objects or visiblity was changed OnRenderListDirty(); } if ( m_pwndTitle != NULL ) { m_pwndTitle->Invalidate(false); } CMapView::UpdateView( nFlags ); } //----------------------------------------------------------------------------- // Purpose: // Input : pt3 - //----------------------------------------------------------------------------- void CMapView2DBase::CenterView(Vector *pCenter) { CMapWorld *pWorld = GetMapDoc()->GetMapWorld(); float fPointX, fPointY; if( pCenter ) { // use provided point fPointX = (*pCenter)[axHorz]; fPointY = (*pCenter)[axVert]; } else { // // Use center of map. // Vector vecMins; Vector vecMaxs; pWorld->GetRender2DBox(vecMins, vecMaxs); fPointX = (vecMaxs[axHorz] + vecMins[axHorz]) / 2; fPointY = (vecMaxs[axVert] + vecMins[axVert]) / 2; } SetViewOrigin( fPointX, fPointY ); } //----------------------------------------------------------------------------- // Purpose: // Input : nSBCode - // nPos - // pScrollBar - //----------------------------------------------------------------------------- void CMapView2DBase::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar *pScrollBar) { int iPos = int(nPos); float viewWidth = (float)m_ClientWidth / m_fZoom; switch (nSBCode) { case SB_LINELEFT: { iPos = -int(viewWidth / 4); break; } case SB_LINERIGHT: { iPos = int(viewWidth / 4); break; } case SB_PAGELEFT: { iPos = -int(viewWidth / 2); break; } case SB_PAGERIGHT: { iPos = int(viewWidth / 2); break; } case SB_THUMBTRACK: case SB_THUMBPOSITION: { if ( bInvertHorz ) iPos = -iPos; SetViewOrigin( iPos, m_vViewOrigin[axVert] ); return; } } if ( bInvertHorz ) iPos = -iPos; SetViewOrigin( iPos, 0, true ); } //----------------------------------------------------------------------------- // Purpose: // Input : nSBCode - // nPos - // pScrollBar - //----------------------------------------------------------------------------- void CMapView2DBase::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar *pScrollBar) { int iPos = int(nPos); float viewHeight = (float)m_ClientHeight / m_fZoom; switch (nSBCode) { case SB_LINEUP: { iPos = -int(viewHeight / 4); break; } case SB_LINEDOWN: { iPos = int(viewHeight / 4); break; } case SB_PAGEUP: { iPos = -int(viewHeight / 2); break; } case SB_PAGEDOWN: { iPos = int(viewHeight / 2); break; } case SB_THUMBTRACK: case SB_THUMBPOSITION: { if ( bInvertVert ) iPos = -iPos; SetViewOrigin( m_vViewOrigin[axHorz], iPos ); return; } } if ( bInvertVert ) iPos = -iPos; SetViewOrigin( 0, iPos, true ); } //----------------------------------------------------------------------------- // Purpose: // Input : nFlags - // point - //----------------------------------------------------------------------------- void CMapView2DBase::OnRButtonDown(UINT nFlags, CPoint point) { // Pass the message to the active tool. if ( !m_pToolManager ) return; CBaseTool *pTool = m_pToolManager->GetActiveTool(); if (pTool) { if ( IsLogical() ) { if ( pTool->OnRMouseDownLogical( static_cast( this ), nFlags, Vector2D(point.x,point.y) ) ) return; } else { if ( pTool->OnRMouseDown2D( static_cast( this ), nFlags, Vector2D(point.x,point.y) ) ) return; } } CView::OnRButtonDown(nFlags, point); } //----------------------------------------------------------------------------- // Purpose: // Input : nIDEvent - //----------------------------------------------------------------------------- void CMapView2DBase::OnTimer(UINT nIDEvent) { if ( nIDEvent == TIMER_SCROLLVIEW ) { KillTimer( TIMER_SCROLLVIEW ); if (m_xScroll || m_yScroll) { SetViewOrigin(m_xScroll, m_yScroll, true); // force mousemove event CPoint pt; GetCursorPos(&pt); ScreenToClient(&pt); OnMouseMove(0, pt); } } CView::OnTimer(nIDEvent); } //----------------------------------------------------------------------------- // Purpose: // Input : pWnd - // point - //----------------------------------------------------------------------------- void CMapView2DBase::OnContextMenu(UINT nFlags, const Vector2D &vPoint) { if ( m_bMouseDrag || !m_pToolManager ) { return; } // // Pass the message to the active tool. // CBaseTool *pTool = m_pToolManager->GetActiveTool(); if (pTool) { if ( IsLogical() ) { if ( pTool->OnContextMenuLogical( static_cast( this ), nFlags, vPoint ) ) return; } else { if ( pTool->OnContextMenu2D( static_cast( this ), nFlags, vPoint ) ) return; } } static CMenu menu, menuDefault; static bool bInit = false; if(!bInit) { bInit = true; menu.LoadMenu(IDR_POPUPS); menuDefault.Attach(::GetSubMenu(menu.m_hMenu, 2)); } if(!PointInClientRect( vPoint ) ) return; CPoint ptScreen( vPoint.x, vPoint.y ); ClientToScreen( &ptScreen ); menuDefault.TrackPopupMenu(TPM_LEFTBUTTON | TPM_RIGHTBUTTON | TPM_LEFTALIGN, ptScreen.x, ptScreen.y, this); } //----------------------------------------------------------------------------- // Purpose: Called whenever the view is resized. // Input : nType - // cx - // cy - //----------------------------------------------------------------------------- void CMapView2DBase::OnSize(UINT nType, int cx, int cy) { CView::OnSize(nType, cx, cy); UpdateClientView(); } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CMapView2DBase::OnEditProperties() { // kludge for trackpopupmenu() GetMainWnd()->pObjectProperties->ShowWindow(SW_SHOW); } //----------------------------------------------------------------------------- // Purpose: // Input : nFlags - // point - //----------------------------------------------------------------------------- void CMapView2DBase::OnRButtonUp(UINT nFlags, CPoint point) { if ( !m_pToolManager ) return; // Pass the message to the active tool. CBaseTool *pTool = m_pToolManager->GetActiveTool(); if (pTool) { if ( IsLogical() ) { pTool->OnRMouseUpLogical( static_cast( this ), nFlags, Vector2D(point.x,point.y) ); } else { pTool->OnRMouseUp2D( static_cast( this ), nFlags, Vector2D(point.x,point.y) ); } } OnContextMenu( nFlags, Vector2D(point.x,point.y) ); CView::OnRButtonUp(nFlags, point); } //----------------------------------------------------------------------------- // Purpose: // Input : pCmdUI - //----------------------------------------------------------------------------- void CMapView2DBase::OnUpdateEditFunction(CCmdUI *pCmdUI) { pCmdUI->Enable((m_pToolManager->GetActiveToolID() != TOOL_FACEEDIT_MATERIAL) && !GetMainWnd()->IsShellSessionActive()); } //----------------------------------------------------------------------------- // Purpose: // Input : pDC - // Output : Returns TRUE on success, FALSE on failure. //----------------------------------------------------------------------------- BOOL CMapView2DBase::OnEraseBkgnd(CDC* pDC) { return TRUE; } void CMapView2DBase::WorldToClient(Vector2D &ptClient, const Vector &vecWorld) { Assert(!bInvertHorz); Assert(bInvertVert); ptClient.x = (m_fZoom * ( vecWorld[axHorz] - m_vViewOrigin[axHorz] )) + m_fClientWidthHalf; ptClient.y = (m_fZoom * ( m_vViewOrigin[axVert] - vecWorld[axVert] )) + m_fClientHeightHalf; /* if (bInvertHorz) { ptClient.x = -ptClient.x; } if ( bInvertVert ) { ptClient.y = -ptClient.y; } // Also valid: Vector2D vClient; m_pCamera->WorldToView( vecWorld, vClient ); ptClient.x = vClient.x; ptClient.y = vClient.y; */ } //----------------------------------------------------------------------------- // Purpose: Converts a 2D client coordinate into 3D world coordinates. // Input : vecWorld - // ptClient - //----------------------------------------------------------------------------- void CMapView2DBase::ClientToWorld(Vector &vecWorld, const Vector2D &ptClient) { vecWorld[axHorz] = ptClient.x - m_fClientWidthHalf; vecWorld[axVert] = ptClient.y - m_fClientHeightHalf; vecWorld[axThird] = 0; vecWorld[axHorz] /= m_fZoom; vecWorld[axVert] /= m_fZoom; if (bInvertHorz) { vecWorld[axHorz] = -vecWorld[axHorz]; } if (bInvertVert) { vecWorld[axVert] = -vecWorld[axVert]; } vecWorld += m_vViewOrigin; } void CMapView2DBase::BuildRay( const Vector2D &ptClient, Vector& vStart, Vector& vEnd ) { ClientToWorld( vStart, ptClient ); vEnd = vStart; vStart[axThird] = -99999; vEnd[axThird] = 99999; } void CMapView2DBase::GetBestTransformPlane( Vector &horzAxis, Vector &vertAxis, Vector &thirdAxis) { horzAxis.Init(); horzAxis[axHorz] = 1; vertAxis.Init(); vertAxis[axVert] = 1; thirdAxis.Init(); thirdAxis[axThird] = 1; } //----------------------------------------------------------------------------- // Purpose: Zooms the 2D view in. // Input : bAllViews - Whether to set all 2D views to this zoom level. //----------------------------------------------------------------------------- void CMapView2DBase::ZoomIn(BOOL bAllViews) { float newZoom = m_fZoom * 1.2; SetZoom( newZoom ); // // Set all doc 2d view zooms to this zoom level. // if (bAllViews) { VIEW2DINFO vi; vi.wFlags = VI_ZOOM; vi.fZoom = newZoom; CMapDoc *pDoc = GetMapDoc(); if (pDoc != NULL) { pDoc->SetView2dInfo(vi); } } } //----------------------------------------------------------------------------- // Purpose: Zooms the 2D view out. // Input : bAllViews - Whether to set all 2D views to this zoom level. //----------------------------------------------------------------------------- void CMapView2DBase::ZoomOut(BOOL bAllViews) { SetZoom(m_fZoom / 1.2); // // Set all doc 2d view zooms to this zoom level. // if (bAllViews) { VIEW2DINFO vi; vi.wFlags = VI_ZOOM; vi.fZoom = m_fZoom; CMapDoc *pDoc = GetMapDoc(); if (pDoc != NULL) { pDoc->SetView2dInfo(vi); } } } //----------------------------------------------------------------------------- // Purpose: Returns true if the entire 3D box is visible in this 2D view. //----------------------------------------------------------------------------- bool CMapView2DBase::IsBoxFullyVisible(const Vector &minsWorld, const Vector &maxsWorld) { Vector2D minsClient; Vector2D maxsClient; WorldToClient(minsClient, minsWorld); WorldToClient(maxsClient, maxsWorld); return (PointInClientRect( minsClient ) && PointInClientRect( maxsClient ) ); } //----------------------------------------------------------------------------- // Purpose: Returns true if the entire 3D box is visible in this 2D view. //----------------------------------------------------------------------------- bool CMapView2DBase::CanBoxFitInView(const Vector &minsWorld, const Vector &maxsWorld) { Vector2D minsClient; Vector2D maxsClient; WorldToClient(minsClient, minsWorld); WorldToClient(maxsClient, maxsWorld); return ((m_ClientWidth > maxsClient.x - minsClient.x) && (m_ClientHeight > maxsClient.y - minsClient.y)); } void CMapView2DBase::RenderView() { DrawVGuiPanel(); m_bUpdateView = false; } LRESULT CMapView2DBase::WindowProc( UINT message, WPARAM wParam, LPARAM lParam ) { switch ( message ) { case WM_KEYDOWN: case WM_SYSKEYDOWN: case WM_SYSCHAR: case WM_CHAR: case WM_KEYUP: case WM_SYSKEYUP: { // don't invalidate window on these events, too much return CView::WindowProc( message, wParam, lParam ) ; } case WM_PAINT: { CWnd *focusWnd = GetForegroundWindow(); if ( focusWnd && focusWnd->ContinueModal() ) { // render the view now since were not running the main loop RenderView(); } else { // just flag view to be update with next main loop m_bUpdateView = true; } return CView::WindowProc( message, wParam, lParam ) ; } } if ( !WindowProcVGui( message, wParam, lParam ) ) { return CView::WindowProc( message, wParam, lParam ) ; } return 1; } bool CMapView2DBase::IsInClientView( const Vector &vecMin, const Vector &vecMax ) { // check render view bounds in world space, dont translate every object if ( (vecMin.x > m_ViewMax.x) || (vecMax.x < m_ViewMin.x) ) return false; if ( (vecMin.y > m_ViewMax.y) || (vecMax.y < m_ViewMin.y) ) return false; if ( (vecMin.z > m_ViewMax.z) || (vecMax.z < m_ViewMin.z) ) return false; return true; } bool CMapView2DBase::IsInClientView( const Vector2D &vecMin, const Vector2D &vecMax ) { // check render view bounds in world space, dont translate every object if ( (vecMin.x > m_ViewMax.x) || (vecMax.x < m_ViewMin.x) ) return false; if ( (vecMin.y > m_ViewMax.y) || (vecMax.y < m_ViewMin.y) ) return false; return true; } const Vector& CMapView2DBase::GetViewAxis() { return m_vViewAxis; }