diff options
| author | FluorescentCIAAfricanAmerican <[email protected]> | 2020-04-22 12:56:21 -0400 |
|---|---|---|
| committer | FluorescentCIAAfricanAmerican <[email protected]> | 2020-04-22 12:56:21 -0400 |
| commit | 3bf9df6b2785fa6d951086978a3e66f49427166a (patch) | |
| tree | 2c0f1f0c63c4832882bc93814ebd2c2b1c6224e5 /hammer/mapview2dbase.cpp | |
| download | archived-source-engine-2018-hl2-src-master.tar.xz archived-source-engine-2018-hl2-src-master.zip | |
Diffstat (limited to 'hammer/mapview2dbase.cpp')
| -rw-r--r-- | hammer/mapview2dbase.cpp | 2090 |
1 files changed, 2090 insertions, 0 deletions
diff --git a/hammer/mapview2dbase.cpp b/hammer/mapview2dbase.cpp new file mode 100644 index 0000000..821c0a9 --- /dev/null +++ b/hammer/mapview2dbase.cpp @@ -0,0 +1,2090 @@ +//========= 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 <tier0/memdbgon.h> + + +#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<CMapViewLogical*>( this ), nChar, nRepCnt, nFlags ) ) + return; + } + else + { + if ( pTool->OnKeyDown2D( static_cast<CMapView2D*>( 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<CMapViewLogical*>( this ), nChar, nRepCnt, nFlags ) ) + return; + } + else + { + if ( pTool->OnKeyUp2D( static_cast<CMapView2D*>( 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<CMapViewLogical*>( this ), nChar, nRepCnt, nFlags ) ) + return; + } + else + { + if ( pTool->OnChar2D( static_cast<CMapView2D*>( 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<CMapViewLogical*>(this), vPoint, pHitData[nIndex] ) ) + { + nIndex++; + } + } + else + { + if ( pChild->HitTest2D( static_cast<CMapView2D*>(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<CMapViewLogical*>( this ), nFlags, Vector2D( point.x, point.y ) ) ) + return; + } + else + { + if ( pTool->OnLMouseDown2D( static_cast<CMapView2D*>( 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<CMapViewLogical*>( this ), nFlags, vPoint ) ) + return; + } + else + { + if ( pTool->OnMouseMove2D( static_cast<CMapView2D*>( 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<CMapViewLogical*>( this ), nFlags, zDelta, Vector2D(point.x,point.y) ) ) + return TRUE; + } + else + { + if ( pTool->OnMouseWheel2D( static_cast<CMapView2D*>( 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<CMapViewLogical*>( this ), nFlags, Vector2D(point.x,point.y) ) ) + return; + } + else + { + if ( pTool->OnLMouseUp2D( static_cast<CMapView2D*>( 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<CMapViewLogical*>( this ), nFlags, vPoint ); + pTool->OnLMouseDownLogical( static_cast<CMapViewLogical*>( this ), nFlags, vPoint ); + } + else + { + pTool->OnLMouseDblClk2D( static_cast<CMapView2D*>( this ), nFlags, vPoint ); + pTool->OnLMouseDown2D( static_cast<CMapView2D*>( 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<CMapViewLogical*>( this ), nFlags, Vector2D(point.x,point.y) ) ) + return; + } + else + { + if ( pTool->OnRMouseDown2D( static_cast<CMapView2D*>( 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<CMapViewLogical*>( this ), nFlags, vPoint ) ) + return; + } + else + { + if ( pTool->OnContextMenu2D( static_cast<CMapView2D*>( 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<CMapViewLogical*>( this ), nFlags, Vector2D(point.x,point.y) ); + } + else + { + pTool->OnRMouseUp2D( static_cast<CMapView2D*>( 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; +} |