Modified source engine (2017) developed by valve and leaked in 2020. Not for commercial purporses
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

2090 lines
48 KiB

//========= 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;
}