Team Fortress 2 Source Code as on 22/4/2020
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2048 lines
51 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose: Implements the 3D view message handling. This class is responsible
  4. // for 3D camera control, activating tools in the 3D view, calling
  5. // into the renderer when necessary, and synchronizing the 2D camera
  6. // information with the 3D camera.
  7. //
  8. //=============================================================================//
  9. #include "stdafx.h"
  10. #include <oleauto.h>
  11. #include <oaidl.h>
  12. #if _MSC_VER < 1300
  13. #include <afxpriv.h>
  14. #endif
  15. #include <mmsystem.h>
  16. #include "Camera.h"
  17. #include "GlobalFunctions.h"
  18. #include "Gizmo.h"
  19. #include "History.h"
  20. #include "Keyboard.h"
  21. #include "MainFrm.h"
  22. #include "MapDoc.h"
  23. #include "MapDecal.h"
  24. #include "MapEntity.h"
  25. #include "MapSolid.h"
  26. #include "MapStudioModel.h"
  27. #include "MapWorld.h"
  28. #include "MapView3D.h"
  29. #include "MapView2D.h"
  30. #include "ObjectBar.h"
  31. #include "Options.h"
  32. #include "StatusBarIDs.h"
  33. #include "TitleWnd.h"
  34. #include "ToolManager.h"
  35. #include "hammer.h"
  36. #include "mathlib/vector.h"
  37. #include "MapOverlay.h"
  38. #include "engine_launcher_api.h"
  39. #include "vgui/Cursor.h"
  40. #include "ToolCamera.h"
  41. #include "HammerVGui.h"
  42. // memdbgon must be the last include file in a .cpp file!!!
  43. #include <tier0/memdbgon.h>
  44. #pragma warning(disable:4244 4305)
  45. typedef struct
  46. {
  47. CMapObjectList *pList;
  48. POINT pt;
  49. CMapWorld *pWorld;
  50. } SELECT3DINFO;
  51. int g_nClipPoints = 0;
  52. Vector g_ClipPoints[4];
  53. //
  54. // Defines the logical keys.
  55. //
  56. #define LOGICAL_KEY_FORWARD 0
  57. #define LOGICAL_KEY_BACK 1
  58. #define LOGICAL_KEY_LEFT 2
  59. #define LOGICAL_KEY_RIGHT 3
  60. #define LOGICAL_KEY_UP 4
  61. #define LOGICAL_KEY_DOWN 5
  62. #define LOGICAL_KEY_PITCH_UP 6
  63. #define LOGICAL_KEY_PITCH_DOWN 7
  64. #define LOGICAL_KEY_YAW_LEFT 8
  65. #define LOGICAL_KEY_YAW_RIGHT 9
  66. //
  67. // Rotation speeds, in degrees per second.
  68. //
  69. #define YAW_SPEED 180
  70. #define PITCH_SPEED 180
  71. #define ROLL_SPEED 180
  72. IMPLEMENT_DYNCREATE(CMapView3D, CView)
  73. BEGIN_MESSAGE_MAP(CMapView3D, CView)
  74. //{{AFX_MSG_MAP(CMapView3D)
  75. ON_WM_KILLFOCUS()
  76. ON_WM_TIMER()
  77. ON_WM_KEYDOWN()
  78. ON_WM_KEYUP()
  79. ON_WM_SIZE()
  80. ON_WM_CONTEXTMENU()
  81. ON_WM_LBUTTONDOWN()
  82. ON_WM_LBUTTONUP()
  83. ON_WM_LBUTTONDBLCLK()
  84. ON_WM_RBUTTONDOWN()
  85. ON_WM_MOUSEMOVE()
  86. ON_WM_MOUSEWHEEL()
  87. ON_WM_RBUTTONUP()
  88. ON_WM_CHAR()
  89. ON_WM_SETFOCUS()
  90. ON_WM_NCPAINT()
  91. ON_COMMAND(ID_FILE_PRINT, CView::OnFilePrint)
  92. ON_COMMAND(ID_FILE_PRINT_DIRECT, CView::OnFilePrint)
  93. ON_COMMAND(ID_FILE_PRINT_PREVIEW, CView::OnFilePrintPreview)
  94. ON_COMMAND(ID_VIEW_3DWIREFRAME, OnView3dWireframe)
  95. ON_COMMAND(ID_VIEW_3DPOLYGON, OnView3dPolygon)
  96. ON_COMMAND(ID_VIEW_3DTEXTURED, OnView3dTextured)
  97. ON_COMMAND(ID_VIEW_3DLIGHTMAP_GRID, OnView3dLightmapGrid)
  98. ON_COMMAND(ID_VIEW_LIGHTINGPREVIEW, OnView3dLightingPreview)
  99. ON_COMMAND(ID_VIEW_LIGHTINGPREVIEW_RAYTRACED, OnView3dLightingPreviewRayTraced)
  100. //}}AFX_MSG_MAP
  101. END_MESSAGE_MAP()
  102. //-----------------------------------------------------------------------------
  103. // Purpose: Constructor. Initializes data members to default values.
  104. //-----------------------------------------------------------------------------
  105. CMapView3D::CMapView3D(void)
  106. {
  107. m_eDrawType = VIEW3D_WIREFRAME;
  108. m_pRender = NULL;
  109. m_pCamera = NULL;
  110. m_dwTimeLastInputSample = 0;
  111. m_fForwardSpeed = 0;
  112. m_fStrafeSpeed = 0;
  113. m_fVerticalSpeed = 0;
  114. m_pwndTitle = NULL;
  115. m_bLightingPreview = false;
  116. m_bMouseLook = false;
  117. m_bStrafing = false;
  118. m_bRotating = false;
  119. m_ptLastMouseMovement.x = 0;
  120. m_ptLastMouseMovement.y = 0;
  121. m_nLastRaytracedBitmapRenderTimeStamp = -1;
  122. m_bCameraPosChanged = false;
  123. m_bClippingChanged = false;
  124. }
  125. //-----------------------------------------------------------------------------
  126. // Purpose: Destructor. Releases dynamically allocated resources.
  127. //-----------------------------------------------------------------------------
  128. CMapView3D::~CMapView3D(void)
  129. {
  130. if (m_pCamera != NULL)
  131. {
  132. delete m_pCamera;
  133. }
  134. if (m_pRender != NULL)
  135. {
  136. m_pRender->ShutDown();
  137. delete m_pRender;
  138. }
  139. if (m_pwndTitle != NULL)
  140. {
  141. delete m_pwndTitle;
  142. }
  143. }
  144. //-----------------------------------------------------------------------------
  145. // Purpose:
  146. // Input : cs -
  147. // Output : Returns TRUE on success, FALSE on failure.
  148. //-----------------------------------------------------------------------------
  149. BOOL CMapView3D::PreCreateWindow(CREATESTRUCT& cs)
  150. {
  151. static CString className;
  152. if(className.IsEmpty())
  153. {
  154. //
  155. // 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.
  156. //
  157. className = AfxRegisterWndClass(CS_BYTEALIGNCLIENT | CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW | CS_OWNDC, NULL, HBRUSH(GetStockObject(BLACK_BRUSH)));
  158. }
  159. cs.lpszClass = className;
  160. return CView::PreCreateWindow(cs);
  161. }
  162. //-----------------------------------------------------------------------------
  163. // Purpose: Disables mouselook when the view loses focus. This ensures that the
  164. // cursor is shown and not locked in the center of the 3D view.
  165. // Input : pNewWnd - The window getting focus.
  166. //-----------------------------------------------------------------------------
  167. void CMapView3D::OnKillFocus(CWnd *pNewWnd)
  168. {
  169. EnableMouseLook(false);
  170. EnableRotating(false);
  171. EnableStrafing(false);
  172. }
  173. //-----------------------------------------------------------------------------
  174. // Purpose:
  175. // Input : nDrawType -
  176. //-----------------------------------------------------------------------------
  177. void CMapView3D::SetDrawType(DrawType_t eDrawType)
  178. {
  179. EditorRenderMode_t eRenderMode;
  180. // Turn off the dialog.
  181. if ( m_eDrawType == VIEW3D_SMOOTHING_GROUP )
  182. {
  183. CMainFrame *pMainFrame = GetMainWnd();
  184. if ( pMainFrame )
  185. {
  186. CFaceSmoothingVisualDlg *pSmoothDlg = pMainFrame->GetSmoothingGroupDialog();
  187. pSmoothDlg->ShowWindow( SW_HIDE );
  188. }
  189. }
  190. if (m_pwndTitle != NULL)
  191. {
  192. m_pwndTitle->SetTitle("camera");
  193. }
  194. m_bLightingPreview = false;
  195. switch (eDrawType)
  196. {
  197. case VIEW3D_WIREFRAME:
  198. {
  199. eRenderMode = RENDER_MODE_WIREFRAME;
  200. break;
  201. }
  202. case VIEW3D_POLYGON:
  203. {
  204. eRenderMode = RENDER_MODE_FLAT;
  205. break;
  206. }
  207. case VIEW3D_TEXTURED:
  208. {
  209. eRenderMode = RENDER_MODE_TEXTURED;
  210. break;
  211. }
  212. case VIEW3D_TEXTURED_SHADED:
  213. {
  214. eRenderMode = RENDER_MODE_TEXTURED_SHADED;
  215. break;
  216. }
  217. case VIEW3D_LIGHTMAP_GRID:
  218. {
  219. eRenderMode = RENDER_MODE_LIGHTMAP_GRID;
  220. break;
  221. }
  222. case VIEW3D_LIGHTING_PREVIEW2:
  223. {
  224. eRenderMode = RENDER_MODE_LIGHT_PREVIEW2;
  225. break;
  226. }
  227. case VIEW3D_LIGHTING_PREVIEW_RAYTRACED:
  228. {
  229. eRenderMode = RENDER_MODE_LIGHT_PREVIEW_RAYTRACED;
  230. break;
  231. }
  232. case VIEW3D_SMOOTHING_GROUP:
  233. {
  234. CMainFrame *pMainFrame = GetMainWnd();
  235. if ( pMainFrame )
  236. {
  237. CFaceSmoothingVisualDlg *pSmoothDlg = pMainFrame->GetSmoothingGroupDialog();
  238. pSmoothDlg->ShowWindow( SW_SHOW );
  239. }
  240. // Always set the initial group to visualize (zero).
  241. CMapDoc *pDoc = GetMapDoc();
  242. pDoc->SetSmoothingGroupVisual( 0 );
  243. eRenderMode = RENDER_MODE_SMOOTHING_GROUP;
  244. break;
  245. }
  246. //case VIEW3D_ENGINE:
  247. //{
  248. // eRenderMode = RENDER_MODE_TEXTURED;
  249. // if ( IsRunningInEngine() )
  250. // {
  251. // CMapDoc *pMapDoc = CMapDoc::GetActiveMapDoc();
  252. // if ( pMapDoc )
  253. // {
  254. // const char *pFullPathName = pMapDoc->GetPathName();
  255. // if ( pFullPathName && pFullPathName[0] )
  256. // {
  257. // char buf[MAX_PATH];
  258. // Q_FileBase( pFullPathName, buf, MAX_PATH );
  259. //
  260. // // Don't do it if we're untitled
  261. // //if ( !Q_stristr( buf, "untitled" ) )
  262. // {
  263. // g_pEngineAPI->SetEngineWindow( m_hWnd );
  264. // //g_pEngineAPI->SetMap( buf );
  265. // g_pEngineAPI->ActivateSimulation( true );
  266. // }
  267. // }
  268. // }
  269. // }
  270. // if (m_pwndTitle != NULL)
  271. // {
  272. // m_pwndTitle->SetTitle("engine");
  273. // }
  274. // break;
  275. //}
  276. default:
  277. {
  278. Assert(FALSE);
  279. eDrawType = VIEW3D_WIREFRAME;
  280. eRenderMode = RENDER_MODE_WIREFRAME;
  281. break;
  282. }
  283. }
  284. m_eDrawType = eDrawType;
  285. //
  286. // Set renderer to use the new rendering mode.
  287. //
  288. if (m_pRender != NULL)
  289. {
  290. m_pRender->SetDefaultRenderMode(eRenderMode);
  291. m_pRender->SetInLightingPreview( m_bLightingPreview );
  292. // Somehow, this drop down box screws up MFC's notion
  293. // of what we're supposed to be updating. This is a workaround.
  294. m_pRender->ResetFocus();
  295. }
  296. }
  297. //-----------------------------------------------------------------------------
  298. // Purpose: Sets the position and direction of the camera for this view.
  299. //-----------------------------------------------------------------------------
  300. void CMapView3D::SetCamera(const Vector &vecPos, const Vector &vecLookAt)
  301. {
  302. m_pCamera->SetViewPoint(vecPos);
  303. m_pCamera->SetViewTarget(vecLookAt);
  304. }
  305. //-----------------------------------------------------------------------------
  306. // Purpose: Prepares to print.
  307. // Input : Per CView::OnPreparePrinting.
  308. // Output : Returns nonzero to begin printing, zero to cancel printing.
  309. //-----------------------------------------------------------------------------
  310. BOOL CMapView3D::OnPreparePrinting(CPrintInfo* pInfo)
  311. {
  312. return(DoPreparePrinting(pInfo));
  313. }
  314. //-----------------------------------------------------------------------------
  315. // Purpose: Debugging functions.
  316. //-----------------------------------------------------------------------------
  317. #ifdef _DEBUG
  318. void CMapView3D::AssertValid() const
  319. {
  320. CView::AssertValid();
  321. }
  322. void CMapView3D::Dump(CDumpContext& dc) const
  323. {
  324. CView::Dump(dc);
  325. }
  326. #endif //_DEBUG
  327. //-----------------------------------------------------------------------------
  328. // Purpose:
  329. // Input : nIDEvent -
  330. //-----------------------------------------------------------------------------
  331. void CMapView3D::OnTimer(UINT nIDEvent)
  332. {
  333. static bool s_bPicking = false; // picking mutex
  334. switch (nIDEvent)
  335. {
  336. case MVTIMER_PICKNEXT:
  337. {
  338. if ( !s_bPicking )
  339. {
  340. s_bPicking = true;
  341. // set current document hit
  342. GetMapDoc()->GetSelection()->SetCurrentHit(hitNext);
  343. s_bPicking = false;
  344. }
  345. break;
  346. }
  347. }
  348. CView::OnTimer(nIDEvent);
  349. }
  350. //-----------------------------------------------------------------------------
  351. // Purpose: Called just before we are destroyed.
  352. //-----------------------------------------------------------------------------
  353. BOOL CMapView3D::DestroyWindow()
  354. {
  355. KillTimer(MVTIMER_PICKNEXT);
  356. return CView::DestroyWindow();
  357. }
  358. //-----------------------------------------------------------------------------
  359. // Purpose:
  360. //-----------------------------------------------------------------------------
  361. void CMapView3D::UpdateStatusBar(void)
  362. {
  363. if (!IsWindow(m_hWnd))
  364. {
  365. return;
  366. }
  367. SetStatusText(SBI_GRIDZOOM, "");
  368. SetStatusText(SBI_COORDS, "");
  369. }
  370. //-----------------------------------------------------------------------------
  371. // Purpose: Sets up key bindings for the 3D view.
  372. //-----------------------------------------------------------------------------
  373. void CMapView3D::InitializeKeyMap(void)
  374. {
  375. m_Keyboard.RemoveAllKeyMaps();
  376. if (!Options.view2d.bNudge)
  377. {
  378. m_Keyboard.AddKeyMap(VK_LEFT, 0, LOGICAL_KEY_YAW_LEFT);
  379. m_Keyboard.AddKeyMap(VK_RIGHT, 0, LOGICAL_KEY_YAW_RIGHT);
  380. m_Keyboard.AddKeyMap(VK_DOWN, 0, LOGICAL_KEY_PITCH_DOWN);
  381. m_Keyboard.AddKeyMap(VK_UP, 0, LOGICAL_KEY_PITCH_UP);
  382. m_Keyboard.AddKeyMap(VK_LEFT, KEY_MOD_SHIFT, LOGICAL_KEY_LEFT);
  383. m_Keyboard.AddKeyMap(VK_RIGHT, KEY_MOD_SHIFT, LOGICAL_KEY_RIGHT);
  384. m_Keyboard.AddKeyMap(VK_DOWN, KEY_MOD_SHIFT, LOGICAL_KEY_DOWN);
  385. m_Keyboard.AddKeyMap(VK_UP, KEY_MOD_SHIFT, LOGICAL_KEY_UP);
  386. }
  387. if (Options.view3d.bUseMouseLook)
  388. {
  389. m_Keyboard.AddKeyMap('W', 0, LOGICAL_KEY_FORWARD);
  390. m_Keyboard.AddKeyMap('A', 0, LOGICAL_KEY_LEFT);
  391. m_Keyboard.AddKeyMap('D', 0, LOGICAL_KEY_RIGHT);
  392. m_Keyboard.AddKeyMap('S', 0, LOGICAL_KEY_BACK);
  393. }
  394. else
  395. {
  396. m_Keyboard.AddKeyMap('D', 0, LOGICAL_KEY_FORWARD);
  397. m_Keyboard.AddKeyMap('C', 0, LOGICAL_KEY_BACK);
  398. }
  399. }
  400. //-----------------------------------------------------------------------------
  401. // Purpose:
  402. // Input : pWnd -
  403. // point -
  404. //-----------------------------------------------------------------------------
  405. void CMapView3D::OnContextMenu(CWnd *pWnd, CPoint point)
  406. {
  407. // Pass the message to the active tool.
  408. CBaseTool *pTool = m_pToolManager->GetActiveTool();
  409. if (pTool)
  410. {
  411. if ( pTool->OnContextMenu3D(this, 0, Vector2D(point.x, point.y) ) )
  412. {
  413. return;
  414. }
  415. }
  416. }
  417. //-----------------------------------------------------------------------------
  418. // Purpose: Handles the key down event.
  419. // Input : Per CWnd::OnKeyDown.
  420. //-----------------------------------------------------------------------------
  421. void CMapView3D::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
  422. {
  423. CMapDoc *pDoc = GetMapDoc();
  424. if (pDoc == NULL)
  425. {
  426. return;
  427. }
  428. //
  429. // 'z' toggles mouselook.
  430. //
  431. if (((char)tolower(nChar) == 'z') && !(nFlags & 0x4000) && (Options.view3d.bUseMouseLook))
  432. {
  433. if (pDoc != NULL)
  434. {
  435. EnableMouseLook(!m_bMouseLook);
  436. //
  437. // If we just stopped mouse looking, update the camera variables.
  438. //
  439. if (!m_bMouseLook)
  440. {
  441. UpdateCameraVariables();
  442. }
  443. }
  444. return;
  445. }
  446. // Got to check for m_pToolManager here because otherwise it can crash on startup if they have keys pressed.
  447. if ( m_pToolManager )
  448. {
  449. //
  450. // Pass the message to the active tool.
  451. //
  452. CBaseTool *pTool = m_pToolManager->GetActiveTool();
  453. if (pTool)
  454. {
  455. if (pTool->OnKeyDown3D(this, nChar, nRepCnt, nFlags))
  456. {
  457. return;
  458. }
  459. }
  460. }
  461. m_Keyboard.OnKeyDown(nChar, nRepCnt, nFlags);
  462. switch (nChar)
  463. {
  464. case VK_DELETE:
  465. {
  466. pDoc->OnCmdMsg(ID_EDIT_DELETE, CN_COMMAND, NULL, NULL);
  467. break;
  468. }
  469. case VK_NEXT:
  470. {
  471. pDoc->OnCmdMsg(ID_EDIT_SELNEXT, CN_COMMAND, NULL, NULL);
  472. break;
  473. }
  474. case VK_PRIOR:
  475. {
  476. pDoc->OnCmdMsg(ID_EDIT_SELPREV, CN_COMMAND, NULL, NULL);
  477. break;
  478. }
  479. //
  480. // Move the back clipping plane closer in.
  481. //
  482. case '1':
  483. {
  484. float fBack = m_pCamera->GetFarClip();
  485. if (fBack >= 2000)
  486. {
  487. m_pCamera->SetFarClip(fBack - 1000);
  488. Options.view3d.iBackPlane = fBack;
  489. }
  490. else if (fBack > 500)
  491. {
  492. m_pCamera->SetFarClip(fBack - 250);
  493. Options.view3d.iBackPlane = fBack;
  494. }
  495. m_bUpdateView = true;
  496. m_bClippingChanged = true;
  497. break;
  498. }
  499. //
  500. // Move the back clipping plane farther away.
  501. //
  502. case '2':
  503. {
  504. float fBack = m_pCamera->GetFarClip();
  505. if ((fBack <= 9000) && (fBack > 1000))
  506. {
  507. m_pCamera->SetFarClip(fBack + 1000);
  508. Options.view3d.iBackPlane = fBack;
  509. }
  510. else if (fBack < 10000)
  511. {
  512. m_pCamera->SetFarClip(fBack + 250);
  513. Options.view3d.iBackPlane = fBack;
  514. }
  515. m_bUpdateView = true;
  516. m_bClippingChanged = true;
  517. break;
  518. }
  519. case 'O':
  520. case 'o':
  521. {
  522. m_pRender->DebugHook1();
  523. break;
  524. }
  525. case 'I':
  526. case 'i':
  527. {
  528. m_pRender->DebugHook2();
  529. break;
  530. }
  531. case 'P':
  532. case 'p':
  533. {
  534. pDoc->OnToggle3DGrid();
  535. break;
  536. }
  537. default:
  538. {
  539. break;
  540. }
  541. }
  542. CView::OnKeyDown(nChar, nRepCnt, nFlags);
  543. }
  544. //-----------------------------------------------------------------------------
  545. // Purpose: Handles key release events.
  546. // Input : Per CWnd::OnKeyup
  547. //-----------------------------------------------------------------------------
  548. void CMapView3D::OnKeyUp(UINT nChar, UINT nRepCnt, UINT nFlags)
  549. {
  550. // Got to check for m_pToolManager here because otherwise it can crash on startup if they have keys pressed.
  551. if ( m_pToolManager )
  552. {
  553. // Pass the message to the active tool.
  554. CBaseTool *pTool = m_pToolManager->GetActiveTool();
  555. if (pTool)
  556. {
  557. if (pTool->OnKeyUp3D(this, nChar, nRepCnt, nFlags))
  558. {
  559. return;
  560. }
  561. }
  562. m_Keyboard.OnKeyUp(nChar, nRepCnt, nFlags);
  563. UpdateCameraVariables();
  564. }
  565. CView::OnKeyUp(nChar, nRepCnt, nFlags);
  566. }
  567. //-----------------------------------------------------------------------------
  568. // Purpose: Called when the view is resized.
  569. // Input : nType -
  570. // cx -
  571. // cy -
  572. //-----------------------------------------------------------------------------
  573. void CMapView3D::OnSize(UINT nType, int cx, int cy)
  574. {
  575. if ( m_pCamera )
  576. {
  577. m_pCamera->SetViewPort( cx, cy );
  578. }
  579. CView::OnSize(nType, cx, cy);
  580. }
  581. //-----------------------------------------------------------------------------
  582. // Purpose: Finds the axis that is most closely aligned with the given vector.
  583. // Input : Vector - Vector to find closest axis to.
  584. // Output : Returns an axis index as follows:
  585. // 0 - Positive X axis.
  586. // 1 - Positive Y axis.
  587. // 2 - Positive Z axis.
  588. // 3 - Negative X axis.
  589. // 4 - Negative Y axis.
  590. // 5 - Negative Z axis.
  591. //-----------------------------------------------------------------------------
  592. const Vector&ClosestAxis(const Vector& v)
  593. {
  594. static Vector vBestAxis;
  595. float fBestDot = -1;
  596. Vector vNormal = v;
  597. VectorNormalize( vNormal );
  598. vBestAxis.Init();
  599. for (int i = 0; i < 6; i++)
  600. {
  601. Vector vTestAxis(0,0,0);
  602. vTestAxis[i%3] = (i>=3)?-1:1;
  603. float fTestDot = DotProduct(v, vTestAxis);
  604. if (fTestDot > fBestDot)
  605. {
  606. fBestDot = fTestDot;
  607. vBestAxis = vTestAxis;
  608. }
  609. }
  610. return vBestAxis;
  611. }
  612. void CMapView3D::GetBestTransformPlane( Vector &horzAxis, Vector &vertAxis, Vector &thirdAxis)
  613. {
  614. Vector vAxis;
  615. m_pCamera->GetViewRight( vAxis );
  616. horzAxis = ClosestAxis( vAxis );
  617. m_pCamera->GetViewUp( vAxis );
  618. vertAxis = ClosestAxis( vAxis );
  619. m_pCamera->GetViewForward( vAxis );
  620. thirdAxis = ClosestAxis( vAxis );
  621. }
  622. //-----------------------------------------------------------------------------
  623. // Purpose: Synchronizes the 2D camera information with the 3D view.
  624. //-----------------------------------------------------------------------------
  625. void CMapView3D::UpdateCameraVariables(void)
  626. {
  627. Camera3D *pCamTool = dynamic_cast<Camera3D*>(m_pToolManager->GetToolForID( TOOL_CAMERA ));
  628. if (!m_pCamera || !pCamTool )
  629. return;
  630. Vector viewPoint,viewForward;
  631. m_pCamera->GetViewPoint(viewPoint);
  632. m_pCamera->GetViewForward(viewForward);
  633. // tell camera tool to update active camera
  634. pCamTool->UpdateActiveCamera( viewPoint, viewForward );
  635. }
  636. //-----------------------------------------------------------------------------
  637. // Purpose: Handles the left mouse button double click event.
  638. //-----------------------------------------------------------------------------
  639. void CMapView3D::OnLButtonDblClk(UINT nFlags, CPoint point)
  640. {
  641. //
  642. // Don't forward message if we are controlling the camera.
  643. //
  644. if ((GetAsyncKeyState(VK_SPACE) & 0x8000) != 0)
  645. {
  646. return;
  647. }
  648. //
  649. // Pass the message to the active tool.
  650. //
  651. CBaseTool *pTool = m_pToolManager->GetActiveTool();
  652. if (pTool != NULL)
  653. {
  654. Vector2D vPoint( point.x,point.y);
  655. if (pTool->OnLMouseDblClk3D( this, nFlags, vPoint ))
  656. {
  657. return;
  658. }
  659. }
  660. }
  661. //-----------------------------------------------------------------------------
  662. // Purpose: Handles the left mouse button down event.
  663. //-----------------------------------------------------------------------------
  664. void CMapView3D::OnLButtonDown(UINT nFlags, CPoint point)
  665. {
  666. if ((GetAsyncKeyState(VK_SPACE) & 0x8000) != 0)
  667. {
  668. EnableRotating(true);
  669. return;
  670. }
  671. //
  672. // Pass the message to the active tool.
  673. //
  674. CBaseTool *pTool = m_pToolManager->GetActiveTool();
  675. if (pTool != NULL)
  676. {
  677. Vector2D vPoint( point.x,point.y);
  678. if (pTool->OnLMouseDown3D(this, nFlags, vPoint))
  679. {
  680. return;
  681. }
  682. }
  683. CView::OnLButtonDown(nFlags, point);
  684. }
  685. //-----------------------------------------------------------------------------
  686. // Purpose: Called by the selection tool to begin timed selection by depth.
  687. //-----------------------------------------------------------------------------
  688. void CMapView3D::BeginPick(void)
  689. {
  690. SetTimer(MVTIMER_PICKNEXT, 500, NULL);
  691. }
  692. //-----------------------------------------------------------------------------
  693. // Purpose: Called by the selection tool to end timed selection by depth.
  694. //-----------------------------------------------------------------------------
  695. void CMapView3D::EndPick(void)
  696. {
  697. //
  698. // Kill pick timer.
  699. //
  700. KillTimer(MVTIMER_PICKNEXT);
  701. }
  702. //-----------------------------------------------------------------------------
  703. // Purpose:
  704. // Input : nFlags -
  705. // point -
  706. //-----------------------------------------------------------------------------
  707. void CMapView3D::OnLButtonUp(UINT nFlags, CPoint point)
  708. {
  709. if (m_bRotating)
  710. {
  711. EnableRotating(false);
  712. UpdateCameraVariables();
  713. return;
  714. }
  715. //
  716. // Pass the message to the active tool.
  717. //
  718. CBaseTool *pTool = m_pToolManager->GetActiveTool();
  719. if (pTool != NULL)
  720. {
  721. Vector2D vPoint( point.x,point.y);
  722. if (pTool->OnLMouseUp3D(this, nFlags, vPoint))
  723. {
  724. return;
  725. }
  726. }
  727. CView::OnLButtonUp(nFlags, point);
  728. }
  729. //-----------------------------------------------------------------------------
  730. // Purpose: Creates the renderer and the camera and initializes them.
  731. //-----------------------------------------------------------------------------
  732. void CMapView3D::OnInitialUpdate(void)
  733. {
  734. InitializeKeyMap();
  735. //
  736. // Create a title window.
  737. //
  738. m_pwndTitle = CTitleWnd::CreateTitleWnd(this, ID_2DTITLEWND);
  739. Assert(m_pwndTitle != NULL);
  740. if (m_pwndTitle != NULL)
  741. {
  742. m_pwndTitle->SetTitle("camera");
  743. }
  744. //
  745. // CMainFrame::LoadWindowStates calls InitialUpdateFrame which causes us to get two
  746. // OnInitialUpdate messages! Check for a NULL renderer to avoid processing twice.
  747. //
  748. if (m_pRender != NULL)
  749. {
  750. return;
  751. }
  752. //
  753. // Create and initialize the renderer.
  754. //
  755. m_pRender = new CRender3D();
  756. CMapDoc *pDoc = GetMapDoc();
  757. if (pDoc == NULL)
  758. {
  759. Assert(pDoc != NULL);
  760. return;
  761. }
  762. m_pRender->SetView( this );
  763. m_pToolManager = pDoc->GetTools();
  764. SetDrawType(m_eDrawType);
  765. //
  766. // Create and initialize the camera.
  767. //
  768. m_pCamera = new CCamera();
  769. Assert(m_pCamera != NULL);
  770. if (m_pCamera == NULL)
  771. {
  772. return;
  773. }
  774. CRect rect;
  775. GetClientRect( rect );
  776. m_pCamera->SetViewPort( rect.Width(), rect.Height() );
  777. m_fForwardSpeedMax = Options.view3d.nForwardSpeedMax;
  778. m_fStrafeSpeedMax = Options.view3d.nForwardSpeedMax * 0.75f;
  779. m_fVerticalSpeedMax = Options.view3d.nForwardSpeedMax * 0.5f;
  780. //
  781. // Calculate the acceleration based on max speed and the time to max speed.
  782. //
  783. if (Options.view3d.nTimeToMaxSpeed != 0)
  784. {
  785. m_fForwardAcceleration = m_fForwardSpeedMax / (Options.view3d.nTimeToMaxSpeed / 1000.0f);
  786. m_fStrafeAcceleration = m_fStrafeSpeedMax / (Options.view3d.nTimeToMaxSpeed / 1000.0f);
  787. m_fVerticalAcceleration = m_fVerticalSpeedMax / (Options.view3d.nTimeToMaxSpeed / 1000.0f);
  788. }
  789. else
  790. {
  791. m_fForwardAcceleration = 0;
  792. m_fStrafeAcceleration = 0;
  793. m_fVerticalAcceleration = 0;
  794. }
  795. //
  796. // Set up the frustum. We set the vertical FOV to zero because the renderer
  797. // only uses the horizontal FOV.
  798. //
  799. if ( Options.general.bRadiusCulling )
  800. {
  801. // Hack! Don't use frustum culling when doing radial distance culling (slam the distance to 10K)
  802. m_pCamera->SetPerspective( Options.view3d.fFOV, CAMERA_FRONT_PLANE_DISTANCE, 10000);
  803. }
  804. else
  805. {
  806. m_pCamera->SetPerspective( Options.view3d.fFOV, CAMERA_FRONT_PLANE_DISTANCE, Options.view3d.iBackPlane);
  807. }
  808. //
  809. // Set the distance at which studio models become bounding boxes.
  810. //
  811. CMapStudioModel::SetRenderDistance(Options.view3d.nModelDistance);
  812. CMapStudioModel::EnableAnimation(Options.view3d.bAnimateModels);
  813. //
  814. // Enable or disable reverse selection.
  815. //
  816. m_pRender->RenderEnable(RENDER_REVERSE_SELECTION, (Options.view3d.bReverseSelection == TRUE));
  817. //
  818. // Enable or disable the 3D grid.
  819. //
  820. m_pRender->RenderEnable(RENDER_GRID, pDoc->Is3DGridEnabled());
  821. //
  822. // Enable or disable texture filtering.
  823. //
  824. m_pRender->RenderEnable(RENDER_FILTER_TEXTURES, (Options.view3d.bFilterTextures == TRUE));
  825. // Get the initial viewpoint and view direction from the default camera in the document.
  826. Camera3D *pCamTool = dynamic_cast<Camera3D*>(m_pToolManager->GetToolForID( TOOL_CAMERA ));
  827. if ( pCamTool )
  828. {
  829. Vector vecPos,vecLookAt;
  830. pCamTool->GetCameraPos( vecPos,vecLookAt );
  831. SetCamera(vecPos, vecLookAt);
  832. }
  833. CView::OnInitialUpdate();
  834. }
  835. //-----------------------------------------------------------------------------
  836. // Purpose: Turns on wireframe mode from the floating "Camera" menu.
  837. //-----------------------------------------------------------------------------
  838. void CMapView3D::OnView3dWireframe(void)
  839. {
  840. SetDrawType(VIEW3D_WIREFRAME);
  841. }
  842. //-----------------------------------------------------------------------------
  843. // Purpose: Turns on flat shaded mode from the floating "Camera" menu.
  844. //-----------------------------------------------------------------------------
  845. void CMapView3D::OnView3dPolygon(void)
  846. {
  847. SetDrawType(VIEW3D_POLYGON);
  848. }
  849. //-----------------------------------------------------------------------------
  850. // Purpose: Turns on textured mode from the floating "Camera" menu.
  851. //-----------------------------------------------------------------------------
  852. void CMapView3D::OnView3dTextured(void)
  853. {
  854. SetDrawType(VIEW3D_TEXTURED);
  855. }
  856. //-----------------------------------------------------------------------------
  857. // Purpose: Turns on lightmap grid mode from the floating "Camera" menu.
  858. //-----------------------------------------------------------------------------
  859. void CMapView3D::OnView3dLightmapGrid(void)
  860. {
  861. SetDrawType(VIEW3D_LIGHTMAP_GRID);
  862. }
  863. //-----------------------------------------------------------------------------
  864. // Purpose: Turns on lighting preview mode from the floating "Camera" menu.
  865. //-----------------------------------------------------------------------------
  866. void CMapView3D::OnView3dLightingPreview(void)
  867. {
  868. SetDrawType(VIEW3D_LIGHTING_PREVIEW2);
  869. }
  870. void CMapView3D::OnView3dLightingPreviewRayTraced(void)
  871. {
  872. SetDrawType(VIEW3D_LIGHTING_PREVIEW_RAYTRACED);
  873. }
  874. //-----------------------------------------------------------------------------
  875. // Purpose: Turns on engine mode from the floating "Camera" menu.
  876. //-----------------------------------------------------------------------------
  877. //void CMapView3D::OnView3dEngine(void)
  878. //{
  879. // SetDrawType(VIEW3D_ENGINE);
  880. //}
  881. //-----------------------------------------------------------------------------
  882. // Purpose:
  883. // Input : bActivate -
  884. // pActivateView -
  885. // pDeactiveView -
  886. //-----------------------------------------------------------------------------
  887. void CMapView3D::ActivateView(bool bActivate)
  888. {
  889. CMapView::ActivateView(bActivate);
  890. if (bActivate)
  891. {
  892. CMapDoc *pDoc = GetMapDoc();
  893. CMapDoc::SetActiveMapDoc(pDoc);
  894. UpdateStatusBar();
  895. // tell doc to update title
  896. pDoc->UpdateTitle(this);
  897. m_Keyboard.ClearKeyStates();
  898. //
  899. // Reset the last input sample time.
  900. //
  901. m_dwTimeLastInputSample = 0;
  902. }
  903. }
  904. void CMapView3D::OnDraw(CDC *pDC)
  905. {
  906. CWnd *focusWnd = GetForegroundWindow();
  907. if ( focusWnd && focusWnd->ContinueModal() )
  908. {
  909. // render the view now since were not running the main loop
  910. RenderView();
  911. }
  912. else
  913. {
  914. // just flag view to be update with next main loop
  915. m_bUpdateView = true;
  916. }
  917. }
  918. //-----------------------------------------------------------------------------
  919. //-----------------------------------------------------------------------------
  920. void CMapView3D::RenderView()
  921. {
  922. Render();
  923. m_bUpdateView = false;
  924. }
  925. //-----------------------------------------------------------------------------
  926. //-----------------------------------------------------------------------------
  927. bool CMapView3D::ShouldRender()
  928. {
  929. if ( m_eDrawType == VIEW3D_LIGHTING_PREVIEW_RAYTRACED )
  930. {
  931. // check if we have new results from lpreview thread
  932. // if ( m_nLastRaytracedBitmapRenderTimeStamp !=
  933. // GetUpdateCounter( EVTYPE_BITMAP_RECEIVED_FROM_LPREVIEW ) )
  934. // return true;
  935. }
  936. else
  937. {
  938. // don't animate ray traced displays
  939. if ( Options.view3d.bAnimateModels )
  940. {
  941. DWORD dwTimeElapsed = timeGetTime() - m_dwTimeLastRender;
  942. if ( (dwTimeElapsed/1000.0f) > 1.0f/20.0f)
  943. {
  944. m_bUpdateView = true;
  945. }
  946. }
  947. }
  948. return CMapView::ShouldRender();
  949. }
  950. //-----------------------------------------------------------------------------
  951. // Purpose:
  952. // Input : pDC -
  953. //-----------------------------------------------------------------------------
  954. void CMapView3D::OnSetFocus(CWnd *pOldWnd)
  955. {
  956. // Make sure the whole window region is marked as invalid
  957. m_bUpdateView = true;
  958. }
  959. //-----------------------------------------------------------------------------
  960. // Purpose: Called to paint the non client area of the window.
  961. //-----------------------------------------------------------------------------
  962. void CMapView3D::OnNcPaint(void)
  963. {
  964. // Make sure the whole window region is marked as invalid
  965. m_bUpdateView = true;
  966. }
  967. //-----------------------------------------------------------------------------
  968. // Purpose:
  969. // Input : pSender -
  970. // lHint -
  971. // pHint -
  972. //-----------------------------------------------------------------------------
  973. void CMapView3D::UpdateView(int nFlags)
  974. {
  975. if ( !m_pRender )
  976. return;
  977. if (nFlags & ( MAPVIEW_UPDATE_ONLY_2D | MAPVIEW_UPDATE_ONLY_LOGICAL ) )
  978. return;
  979. //
  980. // One of the options in the 3D options page is changing.
  981. //
  982. if (nFlags & MAPVIEW_OPTIONS_CHANGED)
  983. {
  984. InitializeKeyMap();
  985. CMapStudioModel::SetRenderDistance(Options.view3d.nModelDistance);
  986. CMapStudioModel::EnableAnimation(Options.view3d.bAnimateModels);
  987. m_pRender->RenderEnable(RENDER_REVERSE_SELECTION, (Options.view3d.bReverseSelection == TRUE));
  988. m_fForwardSpeedMax = Options.view3d.nForwardSpeedMax;
  989. m_fStrafeSpeedMax = Options.view3d.nForwardSpeedMax * 0.75f;
  990. m_fVerticalSpeedMax = Options.view3d.nForwardSpeedMax * 0.5f;
  991. //
  992. // Calculate the acceleration based on max speed and the time to max speed.
  993. //
  994. if (Options.view3d.nTimeToMaxSpeed != 0)
  995. {
  996. m_fForwardAcceleration = m_fForwardSpeedMax / (Options.view3d.nTimeToMaxSpeed / 1000.0f);
  997. m_fStrafeAcceleration = m_fStrafeSpeedMax / (Options.view3d.nTimeToMaxSpeed / 1000.0f);
  998. m_fVerticalAcceleration = m_fVerticalSpeedMax / (Options.view3d.nTimeToMaxSpeed / 1000.0f);
  999. }
  1000. else
  1001. {
  1002. m_fForwardAcceleration = 0;
  1003. m_fStrafeAcceleration = 0;
  1004. m_fVerticalAcceleration = 0;
  1005. }
  1006. m_pCamera->SetPerspective( Options.view3d.fFOV, CAMERA_FRONT_PLANE_DISTANCE, Options.view3d.iBackPlane);
  1007. CMapDoc *pDoc = GetMapDoc();
  1008. if ((pDoc != NULL) && (m_pRender != NULL))
  1009. {
  1010. m_pRender->RenderEnable(RENDER_GRID, pDoc->Is3DGridEnabled());
  1011. m_pRender->RenderEnable(RENDER_FILTER_TEXTURES, (Options.view3d.bFilterTextures == TRUE));
  1012. }
  1013. }
  1014. if (nFlags & MAPVIEW_UPDATE_OBJECTS)
  1015. {
  1016. // dvs: could use this hint to update the octree
  1017. }
  1018. CMapView::UpdateView( nFlags );
  1019. }
  1020. //-----------------------------------------------------------------------------
  1021. // Purpose: Determines the object at the point (point.x, point.y) in the 3D view.
  1022. // Input : point - Point to use for hit test.
  1023. // ulFace - Index of face in object that was hit.
  1024. // Output : Returns a pointer to the CMapClass object at the coordinates, NULL if none.
  1025. //-----------------------------------------------------------------------------
  1026. CMapClass *CMapView3D::NearestObjectAt( const Vector2D &vPoint, ULONG &ulFace, unsigned int nFlags, VMatrix *pLocalMatrix )
  1027. {
  1028. ulFace = 0;
  1029. if (m_pRender == NULL)
  1030. {
  1031. return(NULL);
  1032. }
  1033. HitInfo_t Hits;
  1034. if (m_pRender->ObjectsAt( vPoint.x, vPoint.y, 1, 1, &Hits, 1, nFlags ) != 0)
  1035. {
  1036. //
  1037. // If they clicked on a solid, the index of the face they clicked on is stored
  1038. // in array index [1].
  1039. //
  1040. CMapAtom *pObject = (CMapAtom *)Hits.pObject;
  1041. CMapSolid *pSolid = dynamic_cast<CMapSolid *>(pObject);
  1042. if ( pLocalMatrix != NULL )
  1043. {
  1044. *pLocalMatrix = Hits.m_LocalMatrix;
  1045. }
  1046. if (pSolid != NULL)
  1047. {
  1048. ulFace = Hits.uData;
  1049. return(pSolid);
  1050. }
  1051. return((CMapClass *)pObject);
  1052. }
  1053. return(NULL);
  1054. }
  1055. //-----------------------------------------------------------------------------
  1056. // Purpose: Casts a ray from the viewpoint through the given plane and determines
  1057. // the point of intersection of the ray on the plane.
  1058. // Input : point - Point in client screen coordinates.
  1059. // plane - Plane being 'clicked' on.
  1060. // pos - Returns the point on the plane that projects to the given point.
  1061. //-----------------------------------------------------------------------------
  1062. void CMapView3D::GetHitPos(const Vector2D &point, PLANE &plane, Vector &pos)
  1063. {
  1064. //
  1065. // Find the point they clicked on in world coordinates. It lies on the near
  1066. // clipping plane.
  1067. //
  1068. Vector ClickPoint;
  1069. ClientToWorld( ClickPoint, point );
  1070. //
  1071. // Build a ray from the viewpoint through the point on the near clipping plane.
  1072. //
  1073. Vector ViewPoint;
  1074. Vector Ray;
  1075. m_pCamera->GetViewPoint(ViewPoint);
  1076. VectorSubtract(ClickPoint, ViewPoint, Ray);
  1077. //
  1078. // Find the point of intersection of the ray with the given plane.
  1079. //
  1080. float t = DotProduct(plane.normal, ViewPoint) - plane.dist;
  1081. t = t / -DotProduct(plane.normal, Ray);
  1082. pos = ViewPoint + t * Ray;
  1083. }
  1084. bool CMapView3D::HitTest( const Vector2D &vPoint, const Vector& mins, const Vector& maxs)
  1085. {
  1086. Vector vStart, vEnd;
  1087. int nFace;
  1088. BuildRay( vPoint, vStart, vEnd );
  1089. return IntersectionLineAABBox( mins, maxs, vStart, vEnd, nFace ) >= 0.0f;
  1090. }
  1091. //-----------------------------------------------------------------------------
  1092. // Purpose: Finds all objects under the given rectangular region in the view.
  1093. // Input : x - Client x coordinate.
  1094. // y - Client y coordinate.
  1095. // fWidth - Width of region in client pixels.
  1096. // fHeight - Height of region in client pixels.
  1097. // pObjects - Receives objects in the given region.
  1098. // nMaxObjects - Size of the array pointed to by pObjects.
  1099. // Output : Returns the number of objects in the given region.
  1100. //-----------------------------------------------------------------------------
  1101. int CMapView3D::ObjectsAt( const Vector2D &vPoint, HitInfo_t *pObjects, int nMaxObjects, unsigned int nFlags )
  1102. {
  1103. if (m_pRender != NULL)
  1104. {
  1105. return m_pRender->ObjectsAt( vPoint.x, vPoint.y, 1, 1, pObjects, nMaxObjects, nFlags );
  1106. }
  1107. return 0;
  1108. }
  1109. //-----------------------------------------------------------------------------
  1110. // Purpose: Makes sure that this view has focus if the mouse moves over it.
  1111. //-----------------------------------------------------------------------------
  1112. void CMapView3D::OnMouseMove(UINT nFlags, CPoint point)
  1113. {
  1114. //
  1115. // Make sure we are the active view.
  1116. //
  1117. if (!IsActive())
  1118. {
  1119. CMapDoc *pDoc = GetMapDoc();
  1120. pDoc->SetActiveView(this);
  1121. }
  1122. //
  1123. // If we are the active application, make sure this view has the input focus.
  1124. //
  1125. if (APP()->IsActiveApp())
  1126. {
  1127. if (GetFocus() != this)
  1128. {
  1129. SetFocus();
  1130. }
  1131. }
  1132. CView::OnMouseMove(nFlags, point);
  1133. }
  1134. //-----------------------------------------------------------------------------
  1135. // Purpose:
  1136. //-----------------------------------------------------------------------------
  1137. void CMapView3D::ProcessInput(void)
  1138. {
  1139. if (m_dwTimeLastInputSample == 0)
  1140. {
  1141. m_dwTimeLastInputSample = timeGetTime();
  1142. }
  1143. DWORD dwTimeNow = timeGetTime();
  1144. float fElapsedTime = (float)(dwTimeNow - m_dwTimeLastInputSample) / 1000.0f;
  1145. m_dwTimeLastInputSample = dwTimeNow;
  1146. // Clamp (can get really big when we cache textures in )
  1147. if (fElapsedTime > 0.3f)
  1148. {
  1149. fElapsedTime = 0.3f;
  1150. }
  1151. else if ( fElapsedTime <=0 )
  1152. {
  1153. return; // dont process input
  1154. }
  1155. ProcessKeys( fElapsedTime );
  1156. ProcessMouse();
  1157. if ( Options.general.bRadiusCulling )
  1158. {
  1159. ProcessCulling();
  1160. }
  1161. }
  1162. //-----------------------------------------------------------------------------
  1163. // Purpose: Applies an acceleration to a velocity, allowing instantaneous direction
  1164. // change and zeroing the velocity in the absence of acceleration.
  1165. // Input : fVelocity - Current velocity.
  1166. // fAccel - Amount of acceleration to apply.
  1167. // fTimeScale - The time for which the acceleration should be applied.
  1168. // fMaxVelocity - The maximum velocity to allow.
  1169. // Output : Returns the new velocity.
  1170. //-----------------------------------------------------------------------------
  1171. static float Accelerate(float fVelocity, float fAccel, float fAccelScale, float fTimeScale, float fVelocityMax)
  1172. {
  1173. //
  1174. // If we have a finite acceleration in this direction, apply it to the velocity.
  1175. //
  1176. if ((fAccel != 0) && (fAccelScale != 0))
  1177. {
  1178. //
  1179. // Check for direction reversal - zero velocity when reversing.
  1180. //
  1181. if (fAccelScale > 0)
  1182. {
  1183. if (fVelocity < 0)
  1184. {
  1185. fVelocity = 0;
  1186. }
  1187. }
  1188. else if (fAccelScale < 0)
  1189. {
  1190. if (fVelocity > 0)
  1191. {
  1192. fVelocity = 0;
  1193. }
  1194. }
  1195. //
  1196. // Apply the acceleration.
  1197. //
  1198. fVelocity += fAccel * fAccelScale * fTimeScale;
  1199. if (fVelocity > fVelocityMax)
  1200. {
  1201. fVelocity = fVelocityMax;
  1202. }
  1203. else if (fVelocity < -fVelocityMax)
  1204. {
  1205. fVelocity = -fVelocityMax;
  1206. }
  1207. }
  1208. //
  1209. // If we have infinite acceleration, go straight to maximum velocity.
  1210. //
  1211. else if (fAccelScale != 0)
  1212. {
  1213. fVelocity = fVelocityMax * fAccelScale;
  1214. }
  1215. //
  1216. // Else no velocity in this direction at all.
  1217. //
  1218. else
  1219. {
  1220. fVelocity = 0;
  1221. }
  1222. return(fVelocity);
  1223. }
  1224. //-----------------------------------------------------------------------------
  1225. // Purpose: Moves the camera based on the keyboard state.
  1226. //-----------------------------------------------------------------------------
  1227. void CMapView3D::ProcessMovementKeys(float fElapsedTime)
  1228. {
  1229. //
  1230. // Read the state of the camera movement keys.
  1231. //
  1232. float fBack = m_Keyboard.GetKeyScale(LOGICAL_KEY_BACK);
  1233. float fMoveForward = m_Keyboard.GetKeyScale(LOGICAL_KEY_FORWARD) - fBack;
  1234. float fLeft = m_Keyboard.GetKeyScale(LOGICAL_KEY_LEFT);
  1235. float fMoveRight = m_Keyboard.GetKeyScale(LOGICAL_KEY_RIGHT) - fLeft;
  1236. float fDown = m_Keyboard.GetKeyScale(LOGICAL_KEY_DOWN);
  1237. float fMoveUp = m_Keyboard.GetKeyScale(LOGICAL_KEY_UP) - fDown;
  1238. float fPitchUp = m_Keyboard.GetKeyScale(LOGICAL_KEY_PITCH_UP);
  1239. float fPitchDown = m_Keyboard.GetKeyScale(LOGICAL_KEY_PITCH_DOWN);
  1240. float fYawLeft = m_Keyboard.GetKeyScale(LOGICAL_KEY_YAW_LEFT);
  1241. float fYawRight = m_Keyboard.GetKeyScale(LOGICAL_KEY_YAW_RIGHT);
  1242. //
  1243. // Apply pitch and yaw if they are nonzero.
  1244. //
  1245. if ((fPitchDown - fPitchUp) != 0)
  1246. {
  1247. m_pCamera->Pitch((fPitchDown - fPitchUp) * fElapsedTime * PITCH_SPEED);
  1248. m_bUpdateView = true;
  1249. }
  1250. if ((fYawRight - fYawLeft) != 0)
  1251. {
  1252. m_pCamera->Yaw((fYawRight - fYawLeft) * fElapsedTime * YAW_SPEED);
  1253. m_bUpdateView = true;
  1254. }
  1255. //
  1256. // Apply the accelerations to the forward, strafe, and vertical speeds. They are actually
  1257. // velocities because they are signed values.
  1258. //
  1259. m_fForwardSpeed = Accelerate(m_fForwardSpeed, m_fForwardAcceleration, fMoveForward, fElapsedTime, m_fForwardSpeedMax);
  1260. m_fStrafeSpeed = Accelerate(m_fStrafeSpeed, m_fStrafeAcceleration, fMoveRight, fElapsedTime, m_fStrafeSpeedMax);
  1261. m_fVerticalSpeed = Accelerate(m_fVerticalSpeed, m_fVerticalAcceleration, fMoveUp, fElapsedTime, m_fVerticalSpeedMax);
  1262. //
  1263. // Move the camera if any of the speeds are nonzero.
  1264. //
  1265. if (m_fForwardSpeed != 0)
  1266. {
  1267. m_pCamera->MoveForward(m_fForwardSpeed * fElapsedTime);
  1268. m_bUpdateView = true;
  1269. m_bCameraPosChanged = true;
  1270. }
  1271. if (m_fStrafeSpeed != 0)
  1272. {
  1273. m_pCamera->MoveRight(m_fStrafeSpeed * fElapsedTime);
  1274. m_bUpdateView = true;
  1275. m_bCameraPosChanged = true;
  1276. }
  1277. if (m_fVerticalSpeed != 0)
  1278. {
  1279. m_pCamera->MoveUp(m_fVerticalSpeed * fElapsedTime);
  1280. m_bUpdateView = true;
  1281. m_bCameraPosChanged = true;
  1282. }
  1283. }
  1284. //-----------------------------------------------------------------------------
  1285. // Purpose:
  1286. //-----------------------------------------------------------------------------
  1287. void CMapView3D::ProcessKeys(float fElapsedTime)
  1288. {
  1289. ProcessMovementKeys(fElapsedTime);
  1290. m_Keyboard.ClearImpulseFlags();
  1291. }
  1292. //-----------------------------------------------------------------------------
  1293. // Purpose:
  1294. //-----------------------------------------------------------------------------
  1295. void CMapView3D::ProcessCulling( void )
  1296. {
  1297. if ( m_bCameraPosChanged || m_bClippingChanged )
  1298. {
  1299. CMapDoc *pDoc = GetMapDoc();
  1300. pDoc->UpdateVisibilityAll();
  1301. m_bClippingChanged = false;
  1302. m_bCameraPosChanged = false;
  1303. }
  1304. }
  1305. //-----------------------------------------------------------------------------
  1306. // Purpose:
  1307. //-----------------------------------------------------------------------------
  1308. bool CMapView3D::ControlCamera(const CPoint &point)
  1309. {
  1310. if (!m_bStrafing && !m_bRotating && !m_bMouseLook)
  1311. {
  1312. return false;
  1313. }
  1314. bool bShift = ((GetAsyncKeyState(VK_SHIFT) & 0x8000) != 0);
  1315. CRect rect;
  1316. GetClientRect(&rect);
  1317. // get mouse distance to client window center
  1318. CPoint WindowCenter = rect.CenterPoint();
  1319. CSize MouseLookDelta = point - WindowCenter;
  1320. // camera look is on, but no mouse changes
  1321. if ( MouseLookDelta.cx == 0 && MouseLookDelta.cy == 0 )
  1322. true;
  1323. //
  1324. // If strafing, left-right movement moves the camera from side to side.
  1325. // Up-down movement either moves the camera forward and back if the SHIFT
  1326. // key is held down, or up and down if the SHIFT key is not held down.
  1327. // If rotating and strafing simultaneously, the behavior is as if SHIFT is
  1328. // held down.
  1329. //
  1330. if (m_bStrafing)
  1331. {
  1332. if (bShift || m_bRotating)
  1333. {
  1334. MoveForward(-MouseLookDelta.cy * 2);
  1335. }
  1336. else
  1337. {
  1338. MoveUp(-MouseLookDelta.cy * 2);
  1339. }
  1340. MoveRight(MouseLookDelta.cx * 2);
  1341. m_bCameraPosChanged = true;
  1342. }
  1343. //
  1344. // If mouse looking, left-right movement controls yaw, and up-down
  1345. // movement controls pitch.
  1346. //
  1347. else
  1348. {
  1349. //
  1350. // Up-down mouse movement changes the camera pitch.
  1351. //
  1352. if (MouseLookDelta.cy)
  1353. {
  1354. float fTheta = MouseLookDelta.cy * 0.4;
  1355. if (Options.view3d.bReverseY)
  1356. {
  1357. fTheta = -fTheta;
  1358. }
  1359. Pitch(fTheta);
  1360. }
  1361. //
  1362. // Left-right mouse movement changes the camera yaw.
  1363. //
  1364. if (MouseLookDelta.cx)
  1365. {
  1366. float fTheta = MouseLookDelta.cx * 0.4;
  1367. Yaw(fTheta);
  1368. }
  1369. }
  1370. // move mouse back to center
  1371. CWnd::ClientToScreen(&WindowCenter);
  1372. SetCursorPos(WindowCenter.x, WindowCenter.y);
  1373. m_bUpdateView = true;
  1374. return true;
  1375. }
  1376. //-----------------------------------------------------------------------------
  1377. // Purpose: Called by RunFrame to tell this view to process mouse input. This
  1378. // function samples the cursor position and takes the appropriate
  1379. // action based on the current mode (camera, morphing).
  1380. //-----------------------------------------------------------------------------
  1381. void CMapView3D::ProcessMouse(void)
  1382. {
  1383. //
  1384. // Get the cursor position in client coordinates.
  1385. //
  1386. CPoint point;
  1387. GetCursorPos(&point);
  1388. ScreenToClient(&point);
  1389. if ( point == m_ptLastMouseMovement )
  1390. return;
  1391. m_ptLastMouseMovement = point;
  1392. if ( ControlCamera( point ) )
  1393. {
  1394. return;
  1395. }
  1396. // If not in mouselook mode, only process mouse messages if there
  1397. // is an active tool.
  1398. //
  1399. CBaseTool *pTool = m_pToolManager->GetActiveTool();
  1400. if (pTool != NULL)
  1401. {
  1402. //
  1403. // Pass the message to the tool.
  1404. //
  1405. int nFlags = 0;
  1406. if ((GetAsyncKeyState(VK_CONTROL) & 0x8000) != 0)
  1407. {
  1408. nFlags |= MK_CONTROL;
  1409. }
  1410. if ((GetAsyncKeyState(VK_SHIFT) & 0x8000) != 0)
  1411. {
  1412. nFlags |= MK_SHIFT;
  1413. }
  1414. Vector2D vPoint( point.x,point.y);
  1415. pTool->OnMouseMove3D(this, nFlags, vPoint);
  1416. }
  1417. }
  1418. //-----------------------------------------------------------------------------
  1419. // Purpose: Handles mouse wheel events. The mouse wheel is used in camera mode
  1420. // to dolly the camera forward and back.
  1421. // Input : Per CWnd::OnMouseWheel.
  1422. //-----------------------------------------------------------------------------
  1423. BOOL CMapView3D::OnMouseWheel(UINT nFlags, short zDelta, CPoint point)
  1424. {
  1425. //
  1426. // Pass the message to the active tool.
  1427. //
  1428. CBaseTool *pTool = m_pToolManager->GetActiveTool();
  1429. if (pTool != NULL)
  1430. {
  1431. Vector2D vPoint( point.x,point.y);
  1432. if (pTool->OnMouseWheel3D(this, nFlags, zDelta, vPoint))
  1433. {
  1434. return(TRUE);
  1435. }
  1436. }
  1437. m_pCamera->MoveForward(zDelta / 2);
  1438. //
  1439. // Render now to avoid an ugly lag between the 2D views and the 3D view
  1440. // when "center 2D views on camera" is enabled.
  1441. //
  1442. m_bUpdateView = true;
  1443. m_bCameraPosChanged = true;
  1444. UpdateCameraVariables();
  1445. return CView::OnMouseWheel(nFlags, zDelta, point);
  1446. }
  1447. //-----------------------------------------------------------------------------
  1448. // Purpose: Handles right mouse button down events.
  1449. // Input : Per CWnd::OnRButtonDown.
  1450. //-----------------------------------------------------------------------------
  1451. void CMapView3D::OnRButtonDown(UINT nFlags, CPoint point)
  1452. {
  1453. if ((GetAsyncKeyState(VK_SPACE) & 0x8000) != 0)
  1454. {
  1455. EnableStrafing(true);
  1456. return;
  1457. }
  1458. //
  1459. // Pass the message to the active tool.
  1460. //
  1461. CBaseTool *pTool = m_pToolManager->GetActiveTool();
  1462. if (pTool != NULL)
  1463. {
  1464. Vector2D vPoint( point.x,point.y);
  1465. if (pTool->OnRMouseDown3D( this, nFlags, vPoint ))
  1466. {
  1467. return;
  1468. }
  1469. }
  1470. CView::OnRButtonDown(nFlags, point);
  1471. }
  1472. //-----------------------------------------------------------------------------
  1473. // Purpose: Handles right mouse button up events.
  1474. // Input : Per CWnd::OnRButtonUp.
  1475. //-----------------------------------------------------------------------------
  1476. void CMapView3D::OnRButtonUp(UINT nFlags, CPoint point)
  1477. {
  1478. if (m_bStrafing)
  1479. {
  1480. //
  1481. // Turn off strafing and update the 2D views.
  1482. //
  1483. EnableStrafing(false);
  1484. UpdateCameraVariables();
  1485. return;
  1486. }
  1487. //
  1488. // Pass the message to the active tool.
  1489. //
  1490. CBaseTool *pTool = m_pToolManager->GetActiveTool();
  1491. if (pTool != NULL)
  1492. {
  1493. Vector2D vPoint( point.x,point.y);
  1494. if (pTool->OnRMouseUp3D( this, nFlags, vPoint ))
  1495. {
  1496. return;
  1497. }
  1498. }
  1499. CView::OnRButtonUp(nFlags, point);
  1500. }
  1501. //-----------------------------------------------------------------------------
  1502. // Purpose: Handles character events.
  1503. // Input : Per CWnd::OnChar.
  1504. //-----------------------------------------------------------------------------
  1505. void CMapView3D::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags)
  1506. {
  1507. // Got to check for m_pToolManager here because otherwise it can crash on startup if they have keys pressed.
  1508. if ( m_pToolManager )
  1509. {
  1510. //
  1511. // Pass the message to the active tool.
  1512. //
  1513. CBaseTool *pTool = m_pToolManager->GetActiveTool();
  1514. if (pTool != NULL)
  1515. {
  1516. if (pTool->OnChar3D(this, nChar, nRepCnt, nFlags))
  1517. {
  1518. return;
  1519. }
  1520. }
  1521. }
  1522. CView::OnChar(nChar, nRepCnt, nFlags);
  1523. }
  1524. //-----------------------------------------------------------------------------
  1525. // Purpose: Called when mouselook is enabled. The cursor is moved to the center
  1526. // of the screen and hidden.
  1527. // Input : bEnable - true to lock and hide the cursor, false to unlock and show it.
  1528. //-----------------------------------------------------------------------------
  1529. void CMapView3D::EnableCrosshair(bool bEnable)
  1530. {
  1531. CRect Rect;
  1532. CPoint Point;
  1533. GetClientRect(&Rect);
  1534. CWnd::ClientToScreen(&Rect);
  1535. Point = Rect.CenterPoint();
  1536. SetCursorPos(Point.x, Point.y);
  1537. if (bEnable)
  1538. {
  1539. ClipCursor(&Rect);
  1540. }
  1541. else
  1542. {
  1543. ClipCursor(NULL);
  1544. }
  1545. ShowCursor(bEnable ? FALSE : TRUE);
  1546. m_pRender->RenderEnable(RENDER_CENTER_CROSSHAIR, bEnable);
  1547. }
  1548. //-----------------------------------------------------------------------------
  1549. // Purpose: Enables or disables mouselook. When mouselooking, the cursor is hidden
  1550. // and a crosshair is rendered in the center of the view.
  1551. // Input : bEnable - TRUE to enable, FALSE to disable mouselook.
  1552. //-----------------------------------------------------------------------------
  1553. //void CMapView3D::EnableMouseLook(bool bEnable)
  1554. //{
  1555. // if (m_bMouseLook != bEnable)
  1556. // {
  1557. // CMapDoc *pDoc = GetDocument();
  1558. // if (pDoc != NULL)
  1559. // {
  1560. // EnableCrosshair(bEnable);
  1561. // m_bMouseLook = bEnable;
  1562. // }
  1563. // }
  1564. //}
  1565. //-----------------------------------------------------------------------------
  1566. // Purpose: Enables or disables mouselook. When mouselooking, the cursor is hidden
  1567. // and a crosshair is rendered in the center of the view.
  1568. //-----------------------------------------------------------------------------
  1569. void CMapView3D::EnableMouseLook(bool bEnable)
  1570. {
  1571. if (m_bMouseLook != bEnable)
  1572. {
  1573. if (!(m_bStrafing || m_bRotating))
  1574. {
  1575. EnableCrosshair(bEnable);
  1576. }
  1577. m_bMouseLook = bEnable;
  1578. }
  1579. }
  1580. //-----------------------------------------------------------------------------
  1581. // Purpose: Enables or disables camera rotating. When rotating, the cursor is hidden
  1582. // and a crosshair is rendered in the center of the view.
  1583. //-----------------------------------------------------------------------------
  1584. void CMapView3D::EnableRotating(bool bEnable)
  1585. {
  1586. if (m_bRotating != bEnable)
  1587. {
  1588. if (!(m_bStrafing || m_bMouseLook))
  1589. {
  1590. EnableCrosshair(bEnable);
  1591. }
  1592. m_bRotating = bEnable;
  1593. }
  1594. }
  1595. //-----------------------------------------------------------------------------
  1596. // Purpose: Enables or disables camera strafing. When strafing, the cursor is hidden
  1597. // and a crosshair is rendered in the center of the view.
  1598. //-----------------------------------------------------------------------------
  1599. void CMapView3D::EnableStrafing(bool bEnable)
  1600. {
  1601. if (m_bStrafing != bEnable)
  1602. {
  1603. if (!(m_bMouseLook || m_bRotating))
  1604. {
  1605. EnableCrosshair(bEnable);
  1606. }
  1607. m_bStrafing = bEnable;
  1608. }
  1609. }
  1610. //-----------------------------------------------------------------------------
  1611. // Purpose: Actually renders the 3D view. Called from the frame loop and from
  1612. // some mouse messages when timely updating is important.
  1613. //-----------------------------------------------------------------------------
  1614. void CMapView3D::Render(void)
  1615. {
  1616. if ( m_pRender != NULL )
  1617. {
  1618. m_pRender->Render();
  1619. }
  1620. if (m_pwndTitle != NULL)
  1621. {
  1622. m_pwndTitle->BringWindowToTop();
  1623. m_pwndTitle->Invalidate();
  1624. m_pwndTitle->UpdateWindow();
  1625. }
  1626. }
  1627. //-----------------------------------------------------------------------------
  1628. // Purpose:
  1629. // Input : *pObject -
  1630. //-----------------------------------------------------------------------------
  1631. void CMapView3D::RenderPreloadObject(CMapAtom *pObject)
  1632. {
  1633. if ((pObject != NULL) && (m_pRender != NULL))
  1634. {
  1635. pObject->RenderPreload(m_pRender, false);
  1636. }
  1637. }
  1638. //-----------------------------------------------------------------------------
  1639. // Release all video memory.
  1640. //-----------------------------------------------------------------------------
  1641. void CMapView3D::ReleaseVideoMemory(void)
  1642. {
  1643. m_pRender->UncacheAllTextures();
  1644. }
  1645. //-----------------------------------------------------------------------------
  1646. // Purpose: Moves the camera forward by flDistance units. Negative units move back.
  1647. //-----------------------------------------------------------------------------
  1648. void CMapView3D::MoveForward(float flDistance)
  1649. {
  1650. if (m_pCamera != NULL)
  1651. {
  1652. m_pCamera->MoveForward(flDistance);
  1653. }
  1654. }
  1655. //-----------------------------------------------------------------------------
  1656. // Purpose: Moves the camera up by flDistance units. Negative units move down.
  1657. //-----------------------------------------------------------------------------
  1658. void CMapView3D::MoveUp(float flDistance)
  1659. {
  1660. if (m_pCamera != NULL)
  1661. {
  1662. m_pCamera->MoveUp(flDistance);
  1663. }
  1664. }
  1665. //-----------------------------------------------------------------------------
  1666. // Purpose: Moves the camera right by flDistance units. Negative units move left.
  1667. //-----------------------------------------------------------------------------
  1668. void CMapView3D::MoveRight(float flDistance)
  1669. {
  1670. if (m_pCamera != NULL)
  1671. {
  1672. m_pCamera->MoveRight(flDistance);
  1673. }
  1674. }
  1675. //-----------------------------------------------------------------------------
  1676. // Purpose: Pitches the camera forward by flDegrees degrees. Negative units pitch back.
  1677. //-----------------------------------------------------------------------------
  1678. void CMapView3D::Pitch(float flDegrees)
  1679. {
  1680. if (m_pCamera != NULL)
  1681. {
  1682. m_pCamera->Pitch(flDegrees);
  1683. }
  1684. }
  1685. //-----------------------------------------------------------------------------
  1686. // Purpose: Yaws the camera left by flDegrees degrees. Negative units yaw right.
  1687. //-----------------------------------------------------------------------------
  1688. void CMapView3D::Yaw(float flDegrees)
  1689. {
  1690. if (m_pCamera != NULL)
  1691. {
  1692. m_pCamera->Yaw(flDegrees);
  1693. }
  1694. }
  1695. void CMapView3D::WorldToClient(Vector2D &vClient, const Vector &vWorld)
  1696. {
  1697. m_pCamera->WorldToView( vWorld, vClient );
  1698. }
  1699. void CMapView3D::ClientToWorld(Vector &vWorld, const Vector2D &vClient)
  1700. {
  1701. m_pCamera->ViewToWorld( vClient, vWorld );
  1702. }
  1703. void CMapView3D::SetCursor( vgui::HCursor hCursor )
  1704. {
  1705. // translate VGUI -> GDI cursors
  1706. switch( hCursor )
  1707. {
  1708. case vgui::dc_arrow : ::SetCursor(AfxGetApp()->LoadStandardCursor(IDC_ARROW)); break;
  1709. case vgui::dc_sizenwse : ::SetCursor(AfxGetApp()->LoadStandardCursor(IDC_SIZENWSE)); break;
  1710. case vgui::dc_sizenesw : ::SetCursor(AfxGetApp()->LoadStandardCursor(IDC_SIZENESW)); break;
  1711. case vgui::dc_sizewe : ::SetCursor(AfxGetApp()->LoadStandardCursor(IDC_SIZEWE)); break;
  1712. case vgui::dc_sizens : ::SetCursor(AfxGetApp()->LoadStandardCursor(IDC_SIZENS)); break;
  1713. case vgui::dc_sizeall : ::SetCursor(AfxGetApp()->LoadStandardCursor(IDC_SIZEALL)); break;
  1714. case vgui::dc_crosshair : ::SetCursor(AfxGetApp()->LoadStandardCursor(IDC_CROSS)); break;
  1715. default : ::SetCursor(AfxGetApp()->LoadStandardCursor(IDC_ARROW)); break;
  1716. }
  1717. }
  1718. LRESULT CMapView3D::WindowProc( UINT message, WPARAM wParam, LPARAM lParam )
  1719. {
  1720. switch ( message )
  1721. {
  1722. case WM_KILLFOCUS:
  1723. m_Keyboard.ClearKeyStates();
  1724. // Msg( mwStatus, "debug: lost focus, clearing key states\n");
  1725. break;
  1726. }
  1727. return CView::WindowProc( message, wParam, lParam ) ;
  1728. }