csgo-2018-source/hammer/mapview3d.cpp
2021-07-24 21:11:47 -07:00

2112 lines
53 KiB
C++

//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
//
// Purpose: Implements the 3D view message handling. This class is responsible
// for 3D camera control, activating tools in the 3D view, calling
// into the renderer when necessary, and synchronizing the 2D camera
// information with the 3D camera.
//
//=============================================================================//
#include "stdafx.h"
#include <oleauto.h>
#include <oaidl.h>
#if _MSC_VER < 1300
#include <afxpriv.h>
#endif
#include <mmsystem.h>
#include "Camera.h"
#include "GlobalFunctions.h"
#include "Gizmo.h"
#include "History.h"
#include "Keyboard.h"
#include "MainFrm.h"
#include "MapDoc.h"
#include "MapDecal.h"
#include "MapEntity.h"
#include "MapSolid.h"
#include "MapStudioModel.h"
#include "MapWorld.h"
#include "MapView3D.h"
#include "MapView2D.h"
#include "ObjectBar.h"
#include "Options.h"
#include "StatusBarIDs.h"
#include "TitleWnd.h"
#include "ToolManager.h"
#include "hammer.h"
#include "mathlib/vector.h"
#include "MapOverlay.h"
#include "engine_launcher_api.h"
#include "vgui/Cursor.h"
#include "ToolCamera.h"
#include "HammerVGui.h"
// memdbgon must be the last include file in a .cpp file!!!
#include <tier0/memdbgon.h>
#pragma warning(disable:4244 4305)
typedef struct
{
CMapObjectList *pList;
POINT pt;
CMapWorld *pWorld;
} SELECT3DINFO;
int g_nClipPoints = 0;
Vector g_ClipPoints[4];
//
// Defines the logical keys.
//
#define LOGICAL_KEY_FORWARD 0
#define LOGICAL_KEY_BACK 1
#define LOGICAL_KEY_LEFT 2
#define LOGICAL_KEY_RIGHT 3
#define LOGICAL_KEY_UP 4
#define LOGICAL_KEY_DOWN 5
#define LOGICAL_KEY_PITCH_UP 6
#define LOGICAL_KEY_PITCH_DOWN 7
#define LOGICAL_KEY_YAW_LEFT 8
#define LOGICAL_KEY_YAW_RIGHT 9
//
// Rotation speeds, in degrees per second.
//
#define YAW_SPEED 180
#define PITCH_SPEED 180
#define ROLL_SPEED 180
IMPLEMENT_DYNCREATE(CMapView3D, CView)
BEGIN_MESSAGE_MAP(CMapView3D, CView)
//{{AFX_MSG_MAP(CMapView3D)
ON_WM_KILLFOCUS()
ON_WM_TIMER()
ON_WM_KEYDOWN()
ON_WM_KEYUP()
ON_WM_SIZE()
ON_WM_CONTEXTMENU()
ON_WM_LBUTTONDOWN()
ON_WM_LBUTTONUP()
ON_WM_LBUTTONDBLCLK()
ON_WM_RBUTTONDOWN()
ON_WM_MOUSEMOVE()
ON_WM_MOUSEWHEEL()
ON_WM_RBUTTONUP()
ON_WM_CHAR()
ON_WM_SETFOCUS()
ON_WM_NCPAINT()
ON_COMMAND(ID_FILE_PRINT, CView::OnFilePrint)
ON_COMMAND(ID_FILE_PRINT_DIRECT, CView::OnFilePrint)
ON_COMMAND(ID_FILE_PRINT_PREVIEW, CView::OnFilePrintPreview)
ON_COMMAND(ID_VIEW_3DWIREFRAME, OnView3dWireframe)
ON_COMMAND(ID_VIEW_3DPOLYGON, OnView3dPolygon)
ON_COMMAND(ID_VIEW_3DTEXTURED, OnView3dTextured)
ON_COMMAND(ID_VIEW_3DLIGHTMAP_GRID, OnView3dLightmapGrid)
ON_COMMAND(ID_VIEW_LIGHTINGPREVIEW, OnView3dLightingPreview)
ON_COMMAND(ID_VIEW_LIGHTINGPREVIEW_RAYTRACED, OnView3dLightingPreviewRayTraced)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
//-----------------------------------------------------------------------------
// Purpose: Constructor. Initializes data members to default values.
//-----------------------------------------------------------------------------
CMapView3D::CMapView3D(void)
{
m_eDrawType = VIEW3D_WIREFRAME;
m_pRender = NULL;
m_pCamera = NULL;
m_dwTimeLastInputSample = 0;
m_fForwardSpeed = 0;
m_fStrafeSpeed = 0;
m_fVerticalSpeed = 0;
m_pwndTitle = NULL;
m_bLightingPreview = false;
m_bMouseLook = false;
m_bStrafing = false;
m_bRotating = false;
m_ptLastMouseMovement.x = 0;
m_ptLastMouseMovement.y = 0;
m_nLastRaytracedBitmapRenderTimeStamp = -1;
m_bCameraPosChanged = false;
m_bClippingChanged = false;
}
//-----------------------------------------------------------------------------
// Purpose: Destructor. Releases dynamically allocated resources.
//-----------------------------------------------------------------------------
CMapView3D::~CMapView3D(void)
{
if (m_pCamera != NULL)
{
delete m_pCamera;
}
if (m_pRender != NULL)
{
m_pRender->ShutDown();
delete m_pRender;
}
if (m_pwndTitle != NULL)
{
delete m_pwndTitle;
}
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : cs -
// Output : Returns TRUE on success, FALSE on failure.
//-----------------------------------------------------------------------------
BOOL CMapView3D::PreCreateWindow(CREATESTRUCT& cs)
{
static CString className;
if(className.IsEmpty())
{
//
// We need the CS_OWNDC bit so that we don't need to call GetDC every time we render. That fixes the flicker under Win98.
//
className = AfxRegisterWndClass(CS_BYTEALIGNCLIENT | CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW | CS_OWNDC, NULL, HBRUSH(GetStockObject(BLACK_BRUSH)));
}
cs.lpszClass = className;
return CView::PreCreateWindow(cs);
}
//-----------------------------------------------------------------------------
// Purpose: Disables mouselook when the view loses focus. This ensures that the
// cursor is shown and not locked in the center of the 3D view.
// Input : pNewWnd - The window getting focus.
//-----------------------------------------------------------------------------
void CMapView3D::OnKillFocus(CWnd *pNewWnd)
{
EnableMouseLook(false);
EnableRotating(false);
EnableStrafing(false);
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : nDrawType -
//-----------------------------------------------------------------------------
void CMapView3D::SetDrawType(DrawType_t eDrawType)
{
EditorRenderMode_t eRenderMode;
// Turn off the dialog.
if ( m_eDrawType == VIEW3D_SMOOTHING_GROUP )
{
CMainFrame *pMainFrame = GetMainWnd();
if ( pMainFrame )
{
CFaceSmoothingVisualDlg *pSmoothDlg = pMainFrame->GetSmoothingGroupDialog();
pSmoothDlg->ShowWindow( SW_HIDE );
}
}
if (m_pwndTitle != NULL)
{
m_pwndTitle->SetTitle("camera");
}
m_bLightingPreview = false;
switch (eDrawType)
{
case VIEW3D_WIREFRAME:
{
eRenderMode = RENDER_MODE_WIREFRAME;
break;
}
case VIEW3D_POLYGON:
{
eRenderMode = RENDER_MODE_FLAT;
break;
}
case VIEW3D_TEXTURED:
{
eRenderMode = RENDER_MODE_TEXTURED;
break;
}
case VIEW3D_TEXTURED_SHADED:
{
eRenderMode = RENDER_MODE_TEXTURED_SHADED;
break;
}
case VIEW3D_LIGHTMAP_GRID:
{
eRenderMode = RENDER_MODE_LIGHTMAP_GRID;
break;
}
case VIEW3D_LIGHTING_PREVIEW2:
{
eRenderMode = RENDER_MODE_LIGHT_PREVIEW2;
break;
}
case VIEW3D_LIGHTING_PREVIEW_RAYTRACED:
{
eRenderMode = RENDER_MODE_LIGHT_PREVIEW_RAYTRACED;
break;
}
case VIEW3D_SMOOTHING_GROUP:
{
CMainFrame *pMainFrame = GetMainWnd();
if ( pMainFrame )
{
CFaceSmoothingVisualDlg *pSmoothDlg = pMainFrame->GetSmoothingGroupDialog();
pSmoothDlg->ShowWindow( SW_SHOW );
}
// Always set the initial group to visualize (zero).
CMapDoc *pDoc = GetMapDoc();
pDoc->SetSmoothingGroupVisual( 0 );
eRenderMode = RENDER_MODE_SMOOTHING_GROUP;
break;
}
//case VIEW3D_ENGINE:
//{
// eRenderMode = RENDER_MODE_TEXTURED;
// if ( IsRunningInEngine() )
// {
// CMapDoc *pMapDoc = CMapDoc::GetActiveMapDoc();
// if ( pMapDoc )
// {
// const char *pFullPathName = pMapDoc->GetPathName();
// if ( pFullPathName && pFullPathName[0] )
// {
// char buf[MAX_PATH];
// Q_FileBase( pFullPathName, buf, MAX_PATH );
//
// // Don't do it if we're untitled
// //if ( !Q_stristr( buf, "untitled" ) )
// {
// g_pEngineAPI->SetEngineWindow( m_hWnd );
// //g_pEngineAPI->SetMap( buf );
// g_pEngineAPI->ActivateSimulation( true );
// }
// }
// }
// }
// if (m_pwndTitle != NULL)
// {
// m_pwndTitle->SetTitle("engine");
// }
// break;
//}
default:
{
Assert(FALSE);
eDrawType = VIEW3D_WIREFRAME;
eRenderMode = RENDER_MODE_WIREFRAME;
break;
}
}
m_eDrawType = eDrawType;
//
// Set renderer to use the new rendering mode.
//
if (m_pRender != NULL)
{
m_pRender->SetDefaultRenderMode(eRenderMode);
m_pRender->SetInLightingPreview( m_bLightingPreview );
// Somehow, this drop down box screws up MFC's notion
// of what we're supposed to be updating. This is a workaround.
m_pRender->ResetFocus();
}
}
//-----------------------------------------------------------------------------
// Purpose: Sets the position and direction of the camera for this view.
//-----------------------------------------------------------------------------
void CMapView3D::SetCamera(const Vector &vecPos, const Vector &vecLookAt)
{
m_pCamera->SetViewPoint(vecPos);
m_pCamera->SetViewTarget(vecLookAt);
}
//-----------------------------------------------------------------------------
// Purpose: Prepares to print.
// Input : Per CView::OnPreparePrinting.
// Output : Returns nonzero to begin printing, zero to cancel printing.
//-----------------------------------------------------------------------------
BOOL CMapView3D::OnPreparePrinting(CPrintInfo* pInfo)
{
return(DoPreparePrinting(pInfo));
}
//-----------------------------------------------------------------------------
// Purpose: Debugging functions.
//-----------------------------------------------------------------------------
#ifdef _DEBUG
void CMapView3D::AssertValid() const
{
CView::AssertValid();
}
void CMapView3D::Dump(CDumpContext& dc) const
{
CView::Dump(dc);
}
#endif //_DEBUG
//-----------------------------------------------------------------------------
// Purpose:
// Input : nIDEvent -
//-----------------------------------------------------------------------------
void CMapView3D::OnTimer(UINT nIDEvent)
{
static bool s_bPicking = false; // picking mutex
switch (nIDEvent)
{
case MVTIMER_PICKNEXT:
{
if ( !s_bPicking )
{
s_bPicking = true;
// set current document hit
GetMapDoc()->GetSelection()->SetCurrentHit(hitNext);
s_bPicking = false;
}
break;
}
}
CView::OnTimer(nIDEvent);
}
//-----------------------------------------------------------------------------
// Purpose: Called just before we are destroyed.
//-----------------------------------------------------------------------------
BOOL CMapView3D::DestroyWindow()
{
KillTimer(MVTIMER_PICKNEXT);
return CView::DestroyWindow();
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CMapView3D::UpdateStatusBar(void)
{
if (!IsWindow(m_hWnd))
{
return;
}
SetStatusText(SBI_GRIDZOOM, "");
SetStatusText(SBI_COORDS, "");
}
//-----------------------------------------------------------------------------
// Purpose: Sets up key bindings for the 3D view.
//-----------------------------------------------------------------------------
void CMapView3D::InitializeKeyMap(void)
{
m_Keyboard.RemoveAllKeyMaps();
if (!Options.view2d.bNudge)
{
m_Keyboard.AddKeyMap(VK_LEFT, 0, LOGICAL_KEY_YAW_LEFT);
m_Keyboard.AddKeyMap(VK_RIGHT, 0, LOGICAL_KEY_YAW_RIGHT);
m_Keyboard.AddKeyMap(VK_DOWN, 0, LOGICAL_KEY_PITCH_DOWN);
m_Keyboard.AddKeyMap(VK_UP, 0, LOGICAL_KEY_PITCH_UP);
m_Keyboard.AddKeyMap(VK_LEFT, KEY_MOD_SHIFT, LOGICAL_KEY_LEFT);
m_Keyboard.AddKeyMap(VK_RIGHT, KEY_MOD_SHIFT, LOGICAL_KEY_RIGHT);
m_Keyboard.AddKeyMap(VK_DOWN, KEY_MOD_SHIFT, LOGICAL_KEY_DOWN);
m_Keyboard.AddKeyMap(VK_UP, KEY_MOD_SHIFT, LOGICAL_KEY_UP);
}
if (Options.view3d.bUseMouseLook)
{
m_Keyboard.AddKeyMap('W', 0, LOGICAL_KEY_FORWARD);
m_Keyboard.AddKeyMap('A', 0, LOGICAL_KEY_LEFT);
m_Keyboard.AddKeyMap('D', 0, LOGICAL_KEY_RIGHT);
m_Keyboard.AddKeyMap('S', 0, LOGICAL_KEY_BACK);
}
else
{
m_Keyboard.AddKeyMap('D', 0, LOGICAL_KEY_FORWARD);
m_Keyboard.AddKeyMap('C', 0, LOGICAL_KEY_BACK);
}
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : pWnd -
// point -
//-----------------------------------------------------------------------------
void CMapView3D::OnContextMenu(CWnd *pWnd, CPoint point)
{
// Pass the message to the active tool.
if ( !m_pToolManager )
return;
CBaseTool *pTool = m_pToolManager->GetActiveTool();
if (pTool)
{
if ( pTool->OnContextMenu3D(this, 0, Vector2D(point.x, point.y) ) )
{
return;
}
}
}
//-----------------------------------------------------------------------------
// Purpose: Handles the key down event.
// Input : Per CWnd::OnKeyDown.
//-----------------------------------------------------------------------------
void CMapView3D::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
{
CMapDoc *pDoc = GetMapDoc();
if (pDoc == NULL)
{
return;
}
//
// 'z' toggles mouselook.
//
if (((char)tolower(nChar) == 'z') && !(nFlags & 0x4000) && (Options.view3d.bUseMouseLook))
{
CMapDoc *pDoc = GetMapDoc();
if (pDoc != NULL)
{
EnableMouseLook(!m_bMouseLook);
//
// If we just stopped mouse looking, update the camera variables.
//
if (!m_bMouseLook)
{
UpdateCameraVariables();
}
}
return;
}
// Got to check for m_pToolManager here because otherwise it can crash on startup if they have keys pressed.
if ( m_pToolManager )
{
//
// Pass the message to the active tool.
//
CBaseTool *pTool = m_pToolManager->GetActiveTool();
if (pTool)
{
if (pTool->OnKeyDown3D(this, nChar, nRepCnt, nFlags))
{
return;
}
}
}
m_Keyboard.OnKeyDown(nChar, nRepCnt, nFlags);
switch (nChar)
{
case VK_DELETE:
{
pDoc->OnCmdMsg(ID_EDIT_DELETE, CN_COMMAND, NULL, NULL);
break;
}
case VK_NEXT:
{
pDoc->OnCmdMsg(ID_EDIT_SELNEXT, CN_COMMAND, NULL, NULL);
break;
}
case VK_PRIOR:
{
pDoc->OnCmdMsg(ID_EDIT_SELPREV, CN_COMMAND, NULL, NULL);
break;
}
//
// Move the back clipping plane closer in.
//
case '1':
{
float fBack = m_pCamera->GetFarClip();
if (fBack >= 2000)
{
m_pCamera->SetFarClip(fBack - 1000);
Options.view3d.iBackPlane = fBack;
}
else if (fBack > 500)
{
m_pCamera->SetFarClip(fBack - 250);
Options.view3d.iBackPlane = fBack;
}
m_bUpdateView = true;
m_bClippingChanged = true;
break;
}
//
// Move the back clipping plane farther away.
//
case '2':
{
float fBack = m_pCamera->GetFarClip();
if ((fBack <= 9000) && (fBack > 1000))
{
m_pCamera->SetFarClip(fBack + 1000);
Options.view3d.iBackPlane = fBack;
}
else if (fBack < 10000)
{
m_pCamera->SetFarClip(fBack + 250);
Options.view3d.iBackPlane = fBack;
}
m_bUpdateView = true;
m_bClippingChanged = true;
break;
}
case 'O':
case 'o':
{
m_pRender->DebugHook1();
break;
}
case 'I':
case 'i':
{
m_pRender->DebugHook2();
break;
}
case 'P':
case 'p':
{
pDoc->OnToggle3DGrid();
break;
}
default:
{
break;
}
}
CView::OnKeyDown(nChar, nRepCnt, nFlags);
}
//-----------------------------------------------------------------------------
// Purpose: Handles key release events.
// Input : Per CWnd::OnKeyup
//-----------------------------------------------------------------------------
void CMapView3D::OnKeyUp(UINT nChar, UINT nRepCnt, UINT nFlags)
{
// Got to check for m_pToolManager here because otherwise it can crash on startup if they have keys pressed.
if ( m_pToolManager )
{
// Pass the message to the active tool.
CBaseTool *pTool = m_pToolManager->GetActiveTool();
if (pTool)
{
if (pTool->OnKeyUp3D(this, nChar, nRepCnt, nFlags))
{
return;
}
}
m_Keyboard.OnKeyUp(nChar, nRepCnt, nFlags);
UpdateCameraVariables();
}
CView::OnKeyUp(nChar, nRepCnt, nFlags);
}
//-----------------------------------------------------------------------------
// Purpose: Called when the view is resized.
// Input : nType -
// cx -
// cy -
//-----------------------------------------------------------------------------
void CMapView3D::OnSize(UINT nType, int cx, int cy)
{
if ( m_pCamera )
{
m_pCamera->SetViewPort( cx, cy );
}
CView::OnSize(nType, cx, cy);
}
//-----------------------------------------------------------------------------
// Purpose: Finds the axis that is most closely aligned with the given vector.
// Input : Vector - Vector to find closest axis to.
// Output : Returns an axis index as follows:
// 0 - Positive X axis.
// 1 - Positive Y axis.
// 2 - Positive Z axis.
// 3 - Negative X axis.
// 4 - Negative Y axis.
// 5 - Negative Z axis.
//-----------------------------------------------------------------------------
const Vector&ClosestAxis(const Vector& v)
{
static Vector vBestAxis;
float fBestDot = -1;
Vector vNormal = v;
VectorNormalize( vNormal );
vBestAxis.Init();
for (int i = 0; i < 6; i++)
{
Vector vTestAxis(0,0,0);
vTestAxis[i%3] = (i>=3)?-1:1;
float fTestDot = DotProduct(v, vTestAxis);
if (fTestDot > fBestDot)
{
fBestDot = fTestDot;
vBestAxis = vTestAxis;
}
}
return vBestAxis;
}
void CMapView3D::GetBestTransformPlane( Vector &horzAxis, Vector &vertAxis, Vector &thirdAxis)
{
Vector vAxis;
m_pCamera->GetViewRight( vAxis );
horzAxis = ClosestAxis( vAxis );
m_pCamera->GetViewUp( vAxis );
vertAxis = ClosestAxis( vAxis );
m_pCamera->GetViewForward( vAxis );
thirdAxis = ClosestAxis( vAxis );
}
//-----------------------------------------------------------------------------
// Purpose: Synchronizes the 2D camera information with the 3D view.
//-----------------------------------------------------------------------------
void CMapView3D::UpdateCameraVariables(void)
{
Camera3D *pCamTool = dynamic_cast<Camera3D*>(m_pToolManager->GetToolForID( TOOL_CAMERA ));
if (!m_pCamera || !pCamTool )
return;
Vector viewPoint,viewForward;
m_pCamera->GetViewPoint(viewPoint);
m_pCamera->GetViewForward(viewForward);
// tell camera tool to update active camera
pCamTool->UpdateActiveCamera( viewPoint, viewForward );
}
//-----------------------------------------------------------------------------
// Purpose: Handles the left mouse button double click event.
//-----------------------------------------------------------------------------
void CMapView3D::OnLButtonDblClk(UINT nFlags, CPoint point)
{
//
// Don't forward message if we are controlling the camera.
//
if ((GetAsyncKeyState(VK_SPACE) & 0x8000) != 0)
{
return;
}
//
// Pass the message to the active tool.
//
if ( !m_pToolManager )
return;
CBaseTool *pTool = m_pToolManager->GetActiveTool();
if (pTool != NULL)
{
Vector2D vPoint( point.x,point.y);
if (pTool->OnLMouseDblClk3D( this, nFlags, vPoint ))
{
return;
}
}
}
//-----------------------------------------------------------------------------
// Purpose: Handles the left mouse button down event.
//-----------------------------------------------------------------------------
void CMapView3D::OnLButtonDown(UINT nFlags, CPoint point)
{
if ((GetAsyncKeyState(VK_SPACE) & 0x8000) != 0)
{
EnableRotating(true);
return;
}
//
// Pass the message to the active tool.
//
if ( m_pToolManager != NULL )
{
CBaseTool *pTool = m_pToolManager->GetActiveTool();
if (pTool != NULL)
{
Vector2D vPoint( point.x,point.y);
if (pTool->OnLMouseDown3D(this, nFlags, vPoint))
{
return;
}
}
}
CView::OnLButtonDown(nFlags, point);
}
//-----------------------------------------------------------------------------
// Purpose: Called by the selection tool to begin timed selection by depth.
//-----------------------------------------------------------------------------
void CMapView3D::BeginPick(void)
{
SetTimer(MVTIMER_PICKNEXT, 500, NULL);
}
//-----------------------------------------------------------------------------
// Purpose: Called by the selection tool to end timed selection by depth.
//-----------------------------------------------------------------------------
void CMapView3D::EndPick(void)
{
//
// Kill pick timer.
//
KillTimer(MVTIMER_PICKNEXT);
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : nFlags -
// point -
//-----------------------------------------------------------------------------
void CMapView3D::OnLButtonUp(UINT nFlags, CPoint point)
{
if (m_bRotating)
{
EnableRotating(false);
UpdateCameraVariables();
return;
}
//
// Pass the message to the active tool.
//
if ( m_pToolManager != NULL )
{
CBaseTool *pTool = m_pToolManager->GetActiveTool();
if (pTool != NULL)
{
Vector2D vPoint( point.x,point.y);
if (pTool->OnLMouseUp3D(this, nFlags, vPoint))
{
return;
}
}
}
CView::OnLButtonUp(nFlags, point);
}
//-----------------------------------------------------------------------------
// Purpose: Creates the renderer and the camera and initializes them.
//-----------------------------------------------------------------------------
void CMapView3D::OnInitialUpdate(void)
{
InitializeKeyMap();
//
// Create a title window.
//
m_pwndTitle = CTitleWnd::CreateTitleWnd(this, ID_2DTITLEWND);
Assert(m_pwndTitle != NULL);
if (m_pwndTitle != NULL)
{
m_pwndTitle->SetTitle("camera");
}
//
// CMainFrame::LoadWindowStates calls InitialUpdateFrame which causes us to get two
// OnInitialUpdate messages! Check for a NULL renderer to avoid processing twice.
//
if (m_pRender != NULL)
{
return;
}
//
// Create and initialize the renderer.
//
m_pRender = new CRender3D();
CMapDoc *pDoc = GetMapDoc();
if (pDoc == NULL)
{
Assert(pDoc != NULL);
return;
}
m_pRender->SetView( this );
m_pToolManager = pDoc->GetTools();
SetDrawType(m_eDrawType);
//
// Create and initialize the camera.
//
m_pCamera = new CCamera();
Assert(m_pCamera != NULL);
if (m_pCamera == NULL)
{
return;
}
CRect rect;
GetClientRect( rect );
m_pCamera->SetViewPort( rect.Width(), rect.Height() );
m_fForwardSpeedMax = Options.view3d.nForwardSpeedMax;
m_fStrafeSpeedMax = Options.view3d.nForwardSpeedMax * 0.75f;
m_fVerticalSpeedMax = Options.view3d.nForwardSpeedMax * 0.5f;
//
// Calculate the acceleration based on max speed and the time to max speed.
//
if (Options.view3d.nTimeToMaxSpeed != 0)
{
m_fForwardAcceleration = m_fForwardSpeedMax / (Options.view3d.nTimeToMaxSpeed / 1000.0f);
m_fStrafeAcceleration = m_fStrafeSpeedMax / (Options.view3d.nTimeToMaxSpeed / 1000.0f);
m_fVerticalAcceleration = m_fVerticalSpeedMax / (Options.view3d.nTimeToMaxSpeed / 1000.0f);
}
else
{
m_fForwardAcceleration = 0;
m_fStrafeAcceleration = 0;
m_fVerticalAcceleration = 0;
}
//
// Set up the frustum. We set the vertical FOV to zero because the renderer
// only uses the horizontal FOV.
//
m_pCamera->SetPerspective( CMapEntity::GetShowDotACamera() ? 65.0f : Options.view3d.fFOV, CAMERA_FRONT_PLANE_DISTANCE, Options.view3d.iBackPlane);
//
// Set the distance at which studio models become bounding boxes.
//
CMapStudioModel::SetRenderDistance(Options.view3d.nModelDistance);
CMapStudioModel::EnableAnimation(Options.view3d.bAnimateModels);
//
// Enable or disable reverse selection.
//
m_pRender->RenderEnable(RENDER_REVERSE_SELECTION, (Options.view3d.bReverseSelection == TRUE));
//
// Enable or disable the 3D grid.
//
m_pRender->RenderEnable(RENDER_GRID, pDoc->Is3DGridEnabled());
//
// Enable or disable texture filtering.
//
m_pRender->RenderEnable(RENDER_FILTER_TEXTURES, (Options.view3d.bFilterTextures == TRUE));
// Get the initial viewpoint and view direction from the default camera in the document.
Camera3D *pCamTool = dynamic_cast<Camera3D*>(m_pToolManager->GetToolForID( TOOL_CAMERA ));
if ( pCamTool )
{
Vector vecPos,vecLookAt;
pCamTool->GetCameraPos( vecPos,vecLookAt );
SetCamera(vecPos, vecLookAt);
}
CView::OnInitialUpdate();
}
//-----------------------------------------------------------------------------
// Purpose: Turns on wireframe mode from the floating "Camera" menu.
//-----------------------------------------------------------------------------
void CMapView3D::OnView3dWireframe(void)
{
SetDrawType(VIEW3D_WIREFRAME);
}
//-----------------------------------------------------------------------------
// Purpose: Turns on flat shaded mode from the floating "Camera" menu.
//-----------------------------------------------------------------------------
void CMapView3D::OnView3dPolygon(void)
{
SetDrawType(VIEW3D_POLYGON);
}
//-----------------------------------------------------------------------------
// Purpose: Turns on textured mode from the floating "Camera" menu.
//-----------------------------------------------------------------------------
void CMapView3D::OnView3dTextured(void)
{
SetDrawType(VIEW3D_TEXTURED);
}
//-----------------------------------------------------------------------------
// Purpose: Turns on lightmap grid mode from the floating "Camera" menu.
//-----------------------------------------------------------------------------
void CMapView3D::OnView3dLightmapGrid(void)
{
SetDrawType(VIEW3D_LIGHTMAP_GRID);
}
//-----------------------------------------------------------------------------
// Purpose: Turns on lighting preview mode from the floating "Camera" menu.
//-----------------------------------------------------------------------------
void CMapView3D::OnView3dLightingPreview(void)
{
SetDrawType(VIEW3D_LIGHTING_PREVIEW2);
}
void CMapView3D::OnView3dLightingPreviewRayTraced(void)
{
SetDrawType(VIEW3D_LIGHTING_PREVIEW_RAYTRACED);
}
//-----------------------------------------------------------------------------
// Purpose: Turns on engine mode from the floating "Camera" menu.
//-----------------------------------------------------------------------------
//void CMapView3D::OnView3dEngine(void)
//{
// SetDrawType(VIEW3D_ENGINE);
//}
//-----------------------------------------------------------------------------
// Purpose:
// Input : bActivate -
// pActivateView -
// pDeactiveView -
//-----------------------------------------------------------------------------
void CMapView3D::ActivateView(bool bActivate)
{
CMapView::ActivateView(bActivate);
if (bActivate)
{
CMapDoc *pDoc = GetMapDoc();
CMapDoc::SetActiveMapDoc(pDoc);
UpdateStatusBar();
// tell doc to update title
pDoc->UpdateTitle(this);
m_Keyboard.ClearKeyStates();
//
// Reset the last input sample time.
//
m_dwTimeLastInputSample = 0;
}
}
void CMapView3D::OnDraw(CDC *pDC)
{
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;
}
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void CMapView3D::RenderView()
{
RenderView2( false );
}
void CMapView3D::RenderView2( bool bRenderingOverEngine )
{
Render( bRenderingOverEngine );
m_bUpdateView = false;
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
bool CMapView3D::ShouldRender()
{
if ( m_eDrawType == VIEW3D_LIGHTING_PREVIEW_RAYTRACED )
{
// check if we have new results from lpreview thread
// if ( m_nLastRaytracedBitmapRenderTimeStamp !=
// GetUpdateCounter( EVTYPE_BITMAP_RECEIVED_FROM_LPREVIEW ) )
// return true;
}
else
{
// don't animate ray traced displays
if ( Options.view3d.bAnimateModels )
{
DWORD dwTimeElapsed = timeGetTime() - m_dwTimeLastRender;
if ( (dwTimeElapsed/1000.0f) > 1.0f/20.0f)
{
m_bUpdateView = true;
}
}
}
return CMapView::ShouldRender();
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : pDC -
//-----------------------------------------------------------------------------
void CMapView3D::OnSetFocus(CWnd *pOldWnd)
{
// Make sure the whole window region is marked as invalid
m_bUpdateView = true;
}
//-----------------------------------------------------------------------------
// Purpose: Called to paint the non client area of the window.
//-----------------------------------------------------------------------------
void CMapView3D::OnNcPaint(void)
{
// Make sure the whole window region is marked as invalid
m_bUpdateView = true;
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : pSender -
// lHint -
// pHint -
//-----------------------------------------------------------------------------
void CMapView3D::UpdateView(int nFlags)
{
if ( !m_pRender )
return;
if (nFlags & ( MAPVIEW_UPDATE_ONLY_2D | MAPVIEW_UPDATE_ONLY_LOGICAL ) )
return;
//
// One of the options in the 3D options page is changing.
//
if (nFlags & MAPVIEW_OPTIONS_CHANGED)
{
InitializeKeyMap();
CMapStudioModel::SetRenderDistance(Options.view3d.nModelDistance);
CMapStudioModel::EnableAnimation(Options.view3d.bAnimateModels);
m_pRender->RenderEnable(RENDER_REVERSE_SELECTION, (Options.view3d.bReverseSelection == TRUE));
m_fForwardSpeedMax = Options.view3d.nForwardSpeedMax;
m_fStrafeSpeedMax = Options.view3d.nForwardSpeedMax * 0.75f;
m_fVerticalSpeedMax = Options.view3d.nForwardSpeedMax * 0.5f;
//
// Calculate the acceleration based on max speed and the time to max speed.
//
if (Options.view3d.nTimeToMaxSpeed != 0)
{
m_fForwardAcceleration = m_fForwardSpeedMax / (Options.view3d.nTimeToMaxSpeed / 1000.0f);
m_fStrafeAcceleration = m_fStrafeSpeedMax / (Options.view3d.nTimeToMaxSpeed / 1000.0f);
m_fVerticalAcceleration = m_fVerticalSpeedMax / (Options.view3d.nTimeToMaxSpeed / 1000.0f);
}
else
{
m_fForwardAcceleration = 0;
m_fStrafeAcceleration = 0;
m_fVerticalAcceleration = 0;
}
m_pCamera->SetPerspective( CMapEntity::GetShowDotACamera() ? 65.0f : Options.view3d.fFOV, CAMERA_FRONT_PLANE_DISTANCE, Options.view3d.iBackPlane);
CMapDoc *pDoc = GetMapDoc();
if ((pDoc != NULL) && (m_pRender != NULL))
{
m_pRender->RenderEnable(RENDER_GRID, pDoc->Is3DGridEnabled());
m_pRender->RenderEnable(RENDER_FILTER_TEXTURES, (Options.view3d.bFilterTextures == TRUE));
}
}
if (nFlags & MAPVIEW_UPDATE_OBJECTS)
{
// dvs: could use this hint to update the octree
}
CMapView::UpdateView( nFlags );
}
//-----------------------------------------------------------------------------
// Purpose: Determines the object at the point (point.x, point.y) in the 3D view.
// Input : point - Point to use for hit test.
// ulFace - Index of face in object that was hit.
// Output : Returns a pointer to the CMapClass object at the coordinates, NULL if none.
//-----------------------------------------------------------------------------
CMapClass *CMapView3D::NearestObjectAt( const Vector2D &vPoint, ULONG &ulFace, unsigned int nFlags, VMatrix *pLocalMatrix )
{
ulFace = 0;
if (m_pRender == NULL)
{
return(NULL);
}
HitInfo_t Hits;
if (m_pRender->ObjectsAt( vPoint.x, vPoint.y, 1, 1, &Hits, 1, nFlags ) != 0)
{
//
// If they clicked on a solid, the index of the face they clicked on is stored
// in array index [1].
//
CMapAtom *pObject = (CMapAtom *)Hits.pObject;
CMapSolid *pSolid = dynamic_cast<CMapSolid *>(pObject);
if ( pLocalMatrix != NULL )
{
*pLocalMatrix = Hits.m_LocalMatrix;
}
if (pSolid != NULL)
{
ulFace = Hits.uData;
return(pSolid);
}
return((CMapClass *)pObject);
}
return(NULL);
}
//-----------------------------------------------------------------------------
// Purpose: Casts a ray from the viewpoint through the given plane and determines
// the point of intersection of the ray on the plane.
// Input : point - Point in client screen coordinates.
// plane - Plane being 'clicked' on.
// pos - Returns the point on the plane that projects to the given point.
//-----------------------------------------------------------------------------
void CMapView3D::GetHitPos(const Vector2D &point, PLANE &plane, Vector &pos)
{
//
// Find the point they clicked on in world coordinates. It lies on the near
// clipping plane.
//
Vector ClickPoint;
ClientToWorld( ClickPoint, point );
//
// Build a ray from the viewpoint through the point on the near clipping plane.
//
Vector ViewPoint;
Vector Ray;
m_pCamera->GetViewPoint(ViewPoint);
VectorSubtract(ClickPoint, ViewPoint, Ray);
//
// Find the point of intersection of the ray with the given plane.
//
float t = DotProduct(plane.normal, ViewPoint) - plane.dist;
t = t / -DotProduct(plane.normal, Ray);
pos = ViewPoint + t * Ray;
}
bool CMapView3D::HitTest( const Vector2D &vPoint, const Vector& mins, const Vector& maxs)
{
Vector vStart, vEnd;
int nFace;
BuildRay( vPoint, vStart, vEnd );
return IntersectionLineAABBox( mins, maxs, vStart, vEnd, nFace ) >= 0.0f;
}
//-----------------------------------------------------------------------------
// Purpose: Finds all objects under the given rectangular region in the view.
// Input : x - Client x coordinate.
// y - Client y coordinate.
// fWidth - Width of region in client pixels.
// fHeight - Height of region in client pixels.
// pObjects - Receives objects in the given region.
// nMaxObjects - Size of the array pointed to by pObjects.
// Output : Returns the number of objects in the given region.
//-----------------------------------------------------------------------------
int CMapView3D::ObjectsAt( const Vector2D &vPoint, HitInfo_t *pObjects, int nMaxObjects, unsigned int nFlags )
{
if (m_pRender != NULL)
{
return m_pRender->ObjectsAt( vPoint.x, vPoint.y, 1, 1, pObjects, nMaxObjects, nFlags );
}
return 0;
}
//-----------------------------------------------------------------------------
// Purpose: Makes sure that this view has focus if the mouse moves over it.
//-----------------------------------------------------------------------------
void CMapView3D::OnMouseMove(UINT nFlags, CPoint point)
{
//
// Make sure we are the active view.
//
if (!IsActive())
{
CMapDoc *pDoc = GetMapDoc();
pDoc->SetActiveView(this);
}
//
// If we are the active application, make sure this view has the input focus.
//
if (APP()->IsActiveApp())
{
if (GetFocus() != this)
{
SetFocus();
}
}
CView::OnMouseMove(nFlags, point);
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CMapView3D::ProcessInput(void)
{
if (m_dwTimeLastInputSample == 0)
{
m_dwTimeLastInputSample = timeGetTime();
}
DWORD dwTimeNow = timeGetTime();
float fElapsedTime = (float)(dwTimeNow - m_dwTimeLastInputSample) / 1000.0f;
m_dwTimeLastInputSample = dwTimeNow;
// Clamp (can get really big when we cache textures in )
if (fElapsedTime > 0.3f)
{
fElapsedTime = 0.3f;
}
else if ( fElapsedTime <=0 )
{
return; // dont process input
}
ProcessKeys( fElapsedTime );
ProcessMouse();
if ( Options.general.bRadiusCulling )
{
ProcessCulling();
}
}
//-----------------------------------------------------------------------------
// Purpose: Applies an acceleration to a velocity, allowing instantaneous direction
// change and zeroing the velocity in the absence of acceleration.
// Input : fVelocity - Current velocity.
// fAccel - Amount of acceleration to apply.
// fTimeScale - The time for which the acceleration should be applied.
// fMaxVelocity - The maximum velocity to allow.
// Output : Returns the new velocity.
//-----------------------------------------------------------------------------
static float Accelerate(float fVelocity, float fAccel, float fAccelScale, float fTimeScale, float fVelocityMax)
{
//
// If we have a finite acceleration in this direction, apply it to the velocity.
//
if ((fAccel != 0) && (fAccelScale != 0))
{
//
// Check for direction reversal - zero velocity when reversing.
//
if (fAccelScale > 0)
{
if (fVelocity < 0)
{
fVelocity = 0;
}
}
else if (fAccelScale < 0)
{
if (fVelocity > 0)
{
fVelocity = 0;
}
}
//
// Apply the acceleration.
//
fVelocity += fAccel * fAccelScale * fTimeScale;
if (fVelocity > fVelocityMax)
{
fVelocity = fVelocityMax;
}
else if (fVelocity < -fVelocityMax)
{
fVelocity = -fVelocityMax;
}
}
//
// If we have infinite acceleration, go straight to maximum velocity.
//
else if (fAccelScale != 0)
{
fVelocity = fVelocityMax * fAccelScale;
}
//
// Else no velocity in this direction at all.
//
else
{
fVelocity = 0;
}
return(fVelocity);
}
//-----------------------------------------------------------------------------
// Purpose: Moves the camera based on the keyboard state.
//-----------------------------------------------------------------------------
void CMapView3D::ProcessMovementKeys(float fElapsedTime)
{
//
// Read the state of the camera movement keys.
//
float fBack = m_Keyboard.GetKeyScale(LOGICAL_KEY_BACK);
float fMoveForward = m_Keyboard.GetKeyScale(LOGICAL_KEY_FORWARD) - fBack;
float fLeft = m_Keyboard.GetKeyScale(LOGICAL_KEY_LEFT);
float fMoveRight = m_Keyboard.GetKeyScale(LOGICAL_KEY_RIGHT) - fLeft;
float fDown = m_Keyboard.GetKeyScale(LOGICAL_KEY_DOWN);
float fMoveUp = m_Keyboard.GetKeyScale(LOGICAL_KEY_UP) - fDown;
float fPitchUp = m_Keyboard.GetKeyScale(LOGICAL_KEY_PITCH_UP);
float fPitchDown = m_Keyboard.GetKeyScale(LOGICAL_KEY_PITCH_DOWN);
float fYawLeft = m_Keyboard.GetKeyScale(LOGICAL_KEY_YAW_LEFT);
float fYawRight = m_Keyboard.GetKeyScale(LOGICAL_KEY_YAW_RIGHT);
//
// Apply pitch and yaw if they are nonzero.
//
if ((fPitchDown - fPitchUp) != 0)
{
m_pCamera->Pitch((fPitchDown - fPitchUp) * fElapsedTime * PITCH_SPEED);
m_bUpdateView = true;
}
if ((fYawRight - fYawLeft) != 0)
{
m_pCamera->Yaw((fYawRight - fYawLeft) * fElapsedTime * YAW_SPEED);
m_bUpdateView = true;
}
//
// Apply the accelerations to the forward, strafe, and vertical speeds. They are actually
// velocities because they are signed values.
//
m_fForwardSpeed = Accelerate(m_fForwardSpeed, m_fForwardAcceleration, fMoveForward, fElapsedTime, m_fForwardSpeedMax);
m_fStrafeSpeed = Accelerate(m_fStrafeSpeed, m_fStrafeAcceleration, fMoveRight, fElapsedTime, m_fStrafeSpeedMax);
m_fVerticalSpeed = Accelerate(m_fVerticalSpeed, m_fVerticalAcceleration, fMoveUp, fElapsedTime, m_fVerticalSpeedMax);
if ( CMapEntity::GetShowDotACamera() )
{
CMapDoc *pDoc = (CMapDoc *)GetDocument();
Vector vForward;
m_pCamera->GetViewForward( vForward );
Vector vViewpoint;
m_pCamera->GetViewPoint( vViewpoint );
Vector vHitLoc;
bool bHit = pDoc->PickTrace( vViewpoint, vForward, &vHitLoc );
if ( !bHit )
{
vHitLoc = vViewpoint + ( vForward * 1500.0f );
}
Vector vDirection = vHitLoc - vViewpoint;
VectorNormalize( vDirection );
Vector vNewViewpoint = vHitLoc - vDirection * 1500.0f;
m_fForwardSpeed *= 2.0f;
m_fStrafeSpeed *= 2.0f;
m_pCamera->SetPitch( 65.0f );
m_pCamera->SetRoll( 0.0f );
m_pCamera->SetYaw( 0.0f );
m_pCamera->Move( Vector( m_fStrafeSpeed * fElapsedTime + ( vNewViewpoint.x - vViewpoint.x ), m_fForwardSpeed * fElapsedTime + ( vNewViewpoint.y - vViewpoint.y ), vNewViewpoint.z - vViewpoint.z ) );
m_bUpdateView = true;
m_bCameraPosChanged = true;
}
else
{
//
// Move the camera if any of the speeds are nonzero.
//
if (m_fForwardSpeed != 0)
{
m_pCamera->MoveForward(m_fForwardSpeed * fElapsedTime);
m_bUpdateView = true;
m_bCameraPosChanged = true;
}
if (m_fStrafeSpeed != 0)
{
m_pCamera->MoveRight(m_fStrafeSpeed * fElapsedTime);
m_bUpdateView = true;
m_bCameraPosChanged = true;
}
if (m_fVerticalSpeed != 0)
{
m_pCamera->MoveUp(m_fVerticalSpeed * fElapsedTime);
m_bUpdateView = true;
m_bCameraPosChanged = true;
}
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CMapView3D::ProcessKeys(float fElapsedTime)
{
ProcessMovementKeys(fElapsedTime);
m_Keyboard.ClearImpulseFlags();
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CMapView3D::ProcessCulling( void )
{
if ( m_bCameraPosChanged || m_bClippingChanged )
{
CMapDoc *pDoc = GetMapDoc();
pDoc->UpdateVisibilityAll();
m_bClippingChanged = false;
m_bCameraPosChanged = false;
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
bool CMapView3D::ControlCamera(const CPoint &point)
{
if (!m_bStrafing && !m_bRotating && !m_bMouseLook)
{
return false;
}
bool bShift = ((GetAsyncKeyState(VK_SHIFT) & 0x8000) != 0);
CRect rect;
GetClientRect(&rect);
// get mouse distance to client window center
CPoint WindowCenter = rect.CenterPoint();
CSize MouseLookDelta = point - WindowCenter;
// camera look is on, but no mouse changes
if ( MouseLookDelta.cx == 0 && MouseLookDelta.cy == 0 )
true;
//
// If strafing, left-right movement moves the camera from side to side.
// Up-down movement either moves the camera forward and back if the SHIFT
// key is held down, or up and down if the SHIFT key is not held down.
// If rotating and strafing simultaneously, the behavior is as if SHIFT is
// held down.
//
if (m_bStrafing)
{
if (bShift || m_bRotating)
{
MoveForward(-MouseLookDelta.cy * 2);
}
else
{
MoveUp(-MouseLookDelta.cy * 2);
}
MoveRight(MouseLookDelta.cx * 2);
m_bCameraPosChanged = true;
}
//
// If mouse looking, left-right movement controls yaw, and up-down
// movement controls pitch.
//
else
{
//
// Up-down mouse movement changes the camera pitch.
//
if (MouseLookDelta.cy)
{
float fTheta = MouseLookDelta.cy * 0.4;
if (Options.view3d.bReverseY)
{
fTheta = -fTheta;
}
Pitch(fTheta);
}
//
// Left-right mouse movement changes the camera yaw.
//
if (MouseLookDelta.cx)
{
float fTheta = MouseLookDelta.cx * 0.4;
Yaw(fTheta);
}
}
// move mouse back to center
CWnd::ClientToScreen(&WindowCenter);
SetCursorPos(WindowCenter.x, WindowCenter.y);
m_bUpdateView = true;
return true;
}
//-----------------------------------------------------------------------------
// Purpose: Called by RunFrame to tell this view to process mouse input. This
// function samples the cursor position and takes the appropriate
// action based on the current mode (camera, morphing).
//-----------------------------------------------------------------------------
void CMapView3D::ProcessMouse(void)
{
//
// Get the cursor position in client coordinates.
//
CPoint point;
GetCursorPos(&point);
ScreenToClient(&point);
if ( point == m_ptLastMouseMovement )
return;
m_ptLastMouseMovement = point;
if ( ControlCamera( point ) )
{
return;
}
// If not in mouselook mode, only process mouse messages if there
// is an active tool.
//
CBaseTool *pTool = m_pToolManager->GetActiveTool();
if (pTool != NULL)
{
//
// Pass the message to the tool.
//
int nFlags = 0;
if ((GetAsyncKeyState(VK_CONTROL) & 0x8000) != 0)
{
nFlags |= MK_CONTROL;
}
if ((GetAsyncKeyState(VK_SHIFT) & 0x8000) != 0)
{
nFlags |= MK_SHIFT;
}
Vector2D vPoint( point.x,point.y);
pTool->OnMouseMove3D(this, nFlags, vPoint);
}
}
//-----------------------------------------------------------------------------
// Purpose: Handles mouse wheel events. The mouse wheel is used in camera mode
// to dolly the camera forward and back.
// Input : Per CWnd::OnMouseWheel.
//-----------------------------------------------------------------------------
BOOL CMapView3D::OnMouseWheel(UINT nFlags, short zDelta, CPoint point)
{
//
// Pass the message to the active tool.
//
if ( m_pToolManager != NULL )
{
CBaseTool *pTool = m_pToolManager->GetActiveTool();
if (pTool != NULL)
{
Vector2D vPoint( point.x,point.y);
if (pTool->OnMouseWheel3D(this, nFlags, zDelta, vPoint))
{
return(TRUE);
}
}
}
m_pCamera->MoveForward(zDelta / 2);
//
// Render now to avoid an ugly lag between the 2D views and the 3D view
// when "center 2D views on camera" is enabled.
//
m_bUpdateView = true;
m_bCameraPosChanged = true;
UpdateCameraVariables();
return CView::OnMouseWheel(nFlags, zDelta, point);
}
//-----------------------------------------------------------------------------
// Purpose: Handles right mouse button down events.
// Input : Per CWnd::OnRButtonDown.
//-----------------------------------------------------------------------------
void CMapView3D::OnRButtonDown(UINT nFlags, CPoint point)
{
if ((GetAsyncKeyState(VK_SPACE) & 0x8000) != 0)
{
EnableStrafing(true);
return;
}
//
// Pass the message to the active tool.
//
if ( m_pToolManager != NULL )
{
CBaseTool *pTool = m_pToolManager->GetActiveTool();
if (pTool != NULL)
{
Vector2D vPoint( point.x,point.y);
if (pTool->OnRMouseDown3D( this, nFlags, vPoint ))
{
return;
}
}
}
CView::OnRButtonDown(nFlags, point);
}
//-----------------------------------------------------------------------------
// Purpose: Handles right mouse button up events.
// Input : Per CWnd::OnRButtonUp.
//-----------------------------------------------------------------------------
void CMapView3D::OnRButtonUp(UINT nFlags, CPoint point)
{
if (m_bStrafing)
{
//
// Turn off strafing and update the 2D views.
//
EnableStrafing(false);
UpdateCameraVariables();
return;
}
//
// Pass the message to the active tool.
//
if ( m_pToolManager != NULL )
{
CBaseTool *pTool = m_pToolManager->GetActiveTool();
if (pTool != NULL)
{
Vector2D vPoint( point.x,point.y);
if (pTool->OnRMouseUp3D( this, nFlags, vPoint ))
{
return;
}
}
}
CView::OnRButtonUp(nFlags, point);
}
//-----------------------------------------------------------------------------
// Purpose: Handles character events.
// Input : Per CWnd::OnChar.
//-----------------------------------------------------------------------------
void CMapView3D::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags)
{
// Got to check for m_pToolManager here because otherwise it can crash on startup if they have keys pressed.
if ( m_pToolManager )
{
//
// Pass the message to the active tool.
//
CBaseTool *pTool = m_pToolManager->GetActiveTool();
if (pTool != NULL)
{
if (pTool->OnChar3D(this, nChar, nRepCnt, nFlags))
{
return;
}
}
}
CView::OnChar(nChar, nRepCnt, nFlags);
}
//-----------------------------------------------------------------------------
// Purpose: Called when mouselook is enabled. The cursor is moved to the center
// of the screen and hidden.
// Input : bEnable - true to lock and hide the cursor, false to unlock and show it.
//-----------------------------------------------------------------------------
void CMapView3D::EnableCrosshair(bool bEnable)
{
CRect Rect;
CPoint Point;
GetClientRect(&Rect);
CWnd::ClientToScreen(&Rect);
Point = Rect.CenterPoint();
SetCursorPos(Point.x, Point.y);
if (bEnable)
{
ClipCursor(&Rect);
}
else
{
ClipCursor(NULL);
}
ShowCursor(bEnable ? FALSE : TRUE);
m_pRender->RenderEnable(RENDER_CENTER_CROSSHAIR, bEnable);
}
//-----------------------------------------------------------------------------
// Purpose: Enables or disables mouselook. When mouselooking, the cursor is hidden
// and a crosshair is rendered in the center of the view.
// Input : bEnable - TRUE to enable, FALSE to disable mouselook.
//-----------------------------------------------------------------------------
//void CMapView3D::EnableMouseLook(bool bEnable)
//{
// if (m_bMouseLook != bEnable)
// {
// CMapDoc *pDoc = GetDocument();
// if (pDoc != NULL)
// {
// EnableCrosshair(bEnable);
// m_bMouseLook = bEnable;
// }
// }
//}
//-----------------------------------------------------------------------------
// Purpose: Enables or disables mouselook. When mouselooking, the cursor is hidden
// and a crosshair is rendered in the center of the view.
//-----------------------------------------------------------------------------
void CMapView3D::EnableMouseLook(bool bEnable)
{
if (m_bMouseLook != bEnable)
{
if (!(m_bStrafing || m_bRotating))
{
EnableCrosshair(bEnable);
}
m_bMouseLook = bEnable;
}
}
//-----------------------------------------------------------------------------
// Purpose: Enables or disables camera rotating. When rotating, the cursor is hidden
// and a crosshair is rendered in the center of the view.
//-----------------------------------------------------------------------------
void CMapView3D::EnableRotating(bool bEnable)
{
if (m_bRotating != bEnable)
{
if (!(m_bStrafing || m_bMouseLook))
{
EnableCrosshair(bEnable);
}
m_bRotating = bEnable;
}
}
//-----------------------------------------------------------------------------
// Purpose: Enables or disables camera strafing. When strafing, the cursor is hidden
// and a crosshair is rendered in the center of the view.
//-----------------------------------------------------------------------------
void CMapView3D::EnableStrafing(bool bEnable)
{
if (m_bStrafing != bEnable)
{
if (!(m_bMouseLook || m_bRotating))
{
EnableCrosshair(bEnable);
}
m_bStrafing = bEnable;
}
}
//-----------------------------------------------------------------------------
// Purpose: Actually renders the 3D view. Called from the frame loop and from
// some mouse messages when timely updating is important.
//-----------------------------------------------------------------------------
void CMapView3D::Render( bool bRenderingOverEngine )
{
if ( m_pRender != NULL )
{
m_pRender->Render( bRenderingOverEngine );
}
if (m_pwndTitle != NULL)
{
m_pwndTitle->BringWindowToTop();
m_pwndTitle->Invalidate();
m_pwndTitle->UpdateWindow();
}
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : *pObject -
//-----------------------------------------------------------------------------
void CMapView3D::RenderPreloadObject(CMapAtom *pObject)
{
if ((pObject != NULL) && (m_pRender != NULL))
{
pObject->RenderPreload(m_pRender, false);
}
}
//-----------------------------------------------------------------------------
// Release all video memory.
//-----------------------------------------------------------------------------
void CMapView3D::ReleaseVideoMemory(void)
{
m_pRender->UncacheAllTextures();
}
void CMapView3D::Foundry_OnLButtonDown( int x, int y )
{
OnLButtonDown( 0, CPoint( x, y ) );
}
//-----------------------------------------------------------------------------
// Purpose: Moves the camera forward by flDistance units. Negative units move back.
//-----------------------------------------------------------------------------
void CMapView3D::MoveForward(float flDistance)
{
if (m_pCamera != NULL)
{
m_pCamera->MoveForward(flDistance);
}
}
//-----------------------------------------------------------------------------
// Purpose: Moves the camera up by flDistance units. Negative units move down.
//-----------------------------------------------------------------------------
void CMapView3D::MoveUp(float flDistance)
{
if (m_pCamera != NULL)
{
m_pCamera->MoveUp(flDistance);
}
}
//-----------------------------------------------------------------------------
// Purpose: Moves the camera right by flDistance units. Negative units move left.
//-----------------------------------------------------------------------------
void CMapView3D::MoveRight(float flDistance)
{
if (m_pCamera != NULL)
{
m_pCamera->MoveRight(flDistance);
}
}
//-----------------------------------------------------------------------------
// Purpose: Pitches the camera forward by flDegrees degrees. Negative units pitch back.
//-----------------------------------------------------------------------------
void CMapView3D::Pitch(float flDegrees)
{
if (m_pCamera != NULL)
{
m_pCamera->Pitch(flDegrees);
}
}
//-----------------------------------------------------------------------------
// Purpose: Yaws the camera left by flDegrees degrees. Negative units yaw right.
//-----------------------------------------------------------------------------
void CMapView3D::Yaw(float flDegrees)
{
if (m_pCamera != NULL)
{
m_pCamera->Yaw(flDegrees);
}
}
void CMapView3D::WorldToClient(Vector2D &vClient, const Vector &vWorld)
{
m_pCamera->WorldToView( vWorld, vClient );
}
void CMapView3D::ClientToWorld(Vector &vWorld, const Vector2D &vClient)
{
m_pCamera->ViewToWorld( vClient, vWorld );
}
void CMapView3D::SetCursor( vgui::HCursor hCursor )
{
// translate VGUI -> GDI cursors
switch( hCursor )
{
case vgui::dc_arrow : ::SetCursor(AfxGetApp()->LoadStandardCursor(IDC_ARROW)); break;
case vgui::dc_sizenwse : ::SetCursor(AfxGetApp()->LoadStandardCursor(IDC_SIZENWSE)); break;
case vgui::dc_sizenesw : ::SetCursor(AfxGetApp()->LoadStandardCursor(IDC_SIZENESW)); break;
case vgui::dc_sizewe : ::SetCursor(AfxGetApp()->LoadStandardCursor(IDC_SIZEWE)); break;
case vgui::dc_sizens : ::SetCursor(AfxGetApp()->LoadStandardCursor(IDC_SIZENS)); break;
case vgui::dc_sizeall : ::SetCursor(AfxGetApp()->LoadStandardCursor(IDC_SIZEALL)); break;
case vgui::dc_crosshair : ::SetCursor(AfxGetApp()->LoadStandardCursor(IDC_CROSS)); break;
default : ::SetCursor(AfxGetApp()->LoadStandardCursor(IDC_ARROW)); break;
}
}
LRESULT CMapView3D::WindowProc( UINT message, WPARAM wParam, LPARAM lParam )
{
switch ( message )
{
case WM_KILLFOCUS:
m_Keyboard.ClearKeyStates();
// Msg( mwStatus, "debug: lost focus, clearing key states\n");
break;
}
return CView::WindowProc( message, wParam, lParam ) ;
}