summaryrefslogtreecommitdiff
path: root/hammer/mapview3d.cpp
diff options
context:
space:
mode:
authorFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
committerFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
commit3bf9df6b2785fa6d951086978a3e66f49427166a (patch)
tree2c0f1f0c63c4832882bc93814ebd2c2b1c6224e5 /hammer/mapview3d.cpp
downloadarchived-source-engine-2018-hl2-src-master.tar.xz
archived-source-engine-2018-hl2-src-master.zip
Diffstat (limited to 'hammer/mapview3d.cpp')
-rw-r--r--hammer/mapview3d.cpp2049
1 files changed, 2049 insertions, 0 deletions
diff --git a/hammer/mapview3d.cpp b/hammer/mapview3d.cpp
new file mode 100644
index 0000000..3a2edf3
--- /dev/null
+++ b/hammer/mapview3d.cpp
@@ -0,0 +1,2049 @@
+//========= Copyright 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.
+ 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))
+ {
+ 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.
+ //
+ 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.
+ //
+ 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.
+ //
+ 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.
+ //
+ if ( Options.general.bRadiusCulling )
+ {
+ // Hack! Don't use frustum culling when doing radial distance culling (slam the distance to 10K)
+ m_pCamera->SetPerspective( Options.view3d.fFOV, CAMERA_FRONT_PLANE_DISTANCE, 10000);
+ }
+ else
+ {
+ m_pCamera->SetPerspective( 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()
+{
+ Render();
+ 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( 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);
+
+ //
+ // 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.
+ //
+ 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.
+ //
+ 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.
+ //
+ 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(void)
+{
+ if ( m_pRender != NULL )
+ {
+ m_pRender->Render();
+ }
+
+ 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();
+}
+
+
+//-----------------------------------------------------------------------------
+// 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 ) ;
+} \ No newline at end of file