Counter Strike : Global Offensive Source Code
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.

2111 lines
53 KiB

  1. //========= Copyright � 1996-2005, 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. if ( !m_pToolManager )
  409. return;
  410. CBaseTool *pTool = m_pToolManager->GetActiveTool();
  411. if (pTool)
  412. {
  413. if ( pTool->OnContextMenu3D(this, 0, Vector2D(point.x, point.y) ) )
  414. {
  415. return;
  416. }
  417. }
  418. }
  419. //-----------------------------------------------------------------------------
  420. // Purpose: Handles the key down event.
  421. // Input : Per CWnd::OnKeyDown.
  422. //-----------------------------------------------------------------------------
  423. void CMapView3D::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
  424. {
  425. CMapDoc *pDoc = GetMapDoc();
  426. if (pDoc == NULL)
  427. {
  428. return;
  429. }
  430. //
  431. // 'z' toggles mouselook.
  432. //
  433. if (((char)tolower(nChar) == 'z') && !(nFlags & 0x4000) && (Options.view3d.bUseMouseLook))
  434. {
  435. CMapDoc *pDoc = GetMapDoc();
  436. if (pDoc != NULL)
  437. {
  438. EnableMouseLook(!m_bMouseLook);
  439. //
  440. // If we just stopped mouse looking, update the camera variables.
  441. //
  442. if (!m_bMouseLook)
  443. {
  444. UpdateCameraVariables();
  445. }
  446. }
  447. return;
  448. }
  449. // Got to check for m_pToolManager here because otherwise it can crash on startup if they have keys pressed.
  450. if ( m_pToolManager )
  451. {
  452. //
  453. // Pass the message to the active tool.
  454. //
  455. CBaseTool *pTool = m_pToolManager->GetActiveTool();
  456. if (pTool)
  457. {
  458. if (pTool->OnKeyDown3D(this, nChar, nRepCnt, nFlags))
  459. {
  460. return;
  461. }
  462. }
  463. }
  464. m_Keyboard.OnKeyDown(nChar, nRepCnt, nFlags);
  465. switch (nChar)
  466. {
  467. case VK_DELETE:
  468. {
  469. pDoc->OnCmdMsg(ID_EDIT_DELETE, CN_COMMAND, NULL, NULL);
  470. break;
  471. }
  472. case VK_NEXT:
  473. {
  474. pDoc->OnCmdMsg(ID_EDIT_SELNEXT, CN_COMMAND, NULL, NULL);
  475. break;
  476. }
  477. case VK_PRIOR:
  478. {
  479. pDoc->OnCmdMsg(ID_EDIT_SELPREV, CN_COMMAND, NULL, NULL);
  480. break;
  481. }
  482. //
  483. // Move the back clipping plane closer in.
  484. //
  485. case '1':
  486. {
  487. float fBack = m_pCamera->GetFarClip();
  488. if (fBack >= 2000)
  489. {
  490. m_pCamera->SetFarClip(fBack - 1000);
  491. Options.view3d.iBackPlane = fBack;
  492. }
  493. else if (fBack > 500)
  494. {
  495. m_pCamera->SetFarClip(fBack - 250);
  496. Options.view3d.iBackPlane = fBack;
  497. }
  498. m_bUpdateView = true;
  499. m_bClippingChanged = true;
  500. break;
  501. }
  502. //
  503. // Move the back clipping plane farther away.
  504. //
  505. case '2':
  506. {
  507. float fBack = m_pCamera->GetFarClip();
  508. if ((fBack <= 9000) && (fBack > 1000))
  509. {
  510. m_pCamera->SetFarClip(fBack + 1000);
  511. Options.view3d.iBackPlane = fBack;
  512. }
  513. else if (fBack < 10000)
  514. {
  515. m_pCamera->SetFarClip(fBack + 250);
  516. Options.view3d.iBackPlane = fBack;
  517. }
  518. m_bUpdateView = true;
  519. m_bClippingChanged = true;
  520. break;
  521. }
  522. case 'O':
  523. case 'o':
  524. {
  525. m_pRender->DebugHook1();
  526. break;
  527. }
  528. case 'I':
  529. case 'i':
  530. {
  531. m_pRender->DebugHook2();
  532. break;
  533. }
  534. case 'P':
  535. case 'p':
  536. {
  537. pDoc->OnToggle3DGrid();
  538. break;
  539. }
  540. default:
  541. {
  542. break;
  543. }
  544. }
  545. CView::OnKeyDown(nChar, nRepCnt, nFlags);
  546. }
  547. //-----------------------------------------------------------------------------
  548. // Purpose: Handles key release events.
  549. // Input : Per CWnd::OnKeyup
  550. //-----------------------------------------------------------------------------
  551. void CMapView3D::OnKeyUp(UINT nChar, UINT nRepCnt, UINT nFlags)
  552. {
  553. // Got to check for m_pToolManager here because otherwise it can crash on startup if they have keys pressed.
  554. if ( m_pToolManager )
  555. {
  556. // Pass the message to the active tool.
  557. CBaseTool *pTool = m_pToolManager->GetActiveTool();
  558. if (pTool)
  559. {
  560. if (pTool->OnKeyUp3D(this, nChar, nRepCnt, nFlags))
  561. {
  562. return;
  563. }
  564. }
  565. m_Keyboard.OnKeyUp(nChar, nRepCnt, nFlags);
  566. UpdateCameraVariables();
  567. }
  568. CView::OnKeyUp(nChar, nRepCnt, nFlags);
  569. }
  570. //-----------------------------------------------------------------------------
  571. // Purpose: Called when the view is resized.
  572. // Input : nType -
  573. // cx -
  574. // cy -
  575. //-----------------------------------------------------------------------------
  576. void CMapView3D::OnSize(UINT nType, int cx, int cy)
  577. {
  578. if ( m_pCamera )
  579. {
  580. m_pCamera->SetViewPort( cx, cy );
  581. }
  582. CView::OnSize(nType, cx, cy);
  583. }
  584. //-----------------------------------------------------------------------------
  585. // Purpose: Finds the axis that is most closely aligned with the given vector.
  586. // Input : Vector - Vector to find closest axis to.
  587. // Output : Returns an axis index as follows:
  588. // 0 - Positive X axis.
  589. // 1 - Positive Y axis.
  590. // 2 - Positive Z axis.
  591. // 3 - Negative X axis.
  592. // 4 - Negative Y axis.
  593. // 5 - Negative Z axis.
  594. //-----------------------------------------------------------------------------
  595. const Vector&ClosestAxis(const Vector& v)
  596. {
  597. static Vector vBestAxis;
  598. float fBestDot = -1;
  599. Vector vNormal = v;
  600. VectorNormalize( vNormal );
  601. vBestAxis.Init();
  602. for (int i = 0; i < 6; i++)
  603. {
  604. Vector vTestAxis(0,0,0);
  605. vTestAxis[i%3] = (i>=3)?-1:1;
  606. float fTestDot = DotProduct(v, vTestAxis);
  607. if (fTestDot > fBestDot)
  608. {
  609. fBestDot = fTestDot;
  610. vBestAxis = vTestAxis;
  611. }
  612. }
  613. return vBestAxis;
  614. }
  615. void CMapView3D::GetBestTransformPlane( Vector &horzAxis, Vector &vertAxis, Vector &thirdAxis)
  616. {
  617. Vector vAxis;
  618. m_pCamera->GetViewRight( vAxis );
  619. horzAxis = ClosestAxis( vAxis );
  620. m_pCamera->GetViewUp( vAxis );
  621. vertAxis = ClosestAxis( vAxis );
  622. m_pCamera->GetViewForward( vAxis );
  623. thirdAxis = ClosestAxis( vAxis );
  624. }
  625. //-----------------------------------------------------------------------------
  626. // Purpose: Synchronizes the 2D camera information with the 3D view.
  627. //-----------------------------------------------------------------------------
  628. void CMapView3D::UpdateCameraVariables(void)
  629. {
  630. Camera3D *pCamTool = dynamic_cast<Camera3D*>(m_pToolManager->GetToolForID( TOOL_CAMERA ));
  631. if (!m_pCamera || !pCamTool )
  632. return;
  633. Vector viewPoint,viewForward;
  634. m_pCamera->GetViewPoint(viewPoint);
  635. m_pCamera->GetViewForward(viewForward);
  636. // tell camera tool to update active camera
  637. pCamTool->UpdateActiveCamera( viewPoint, viewForward );
  638. }
  639. //-----------------------------------------------------------------------------
  640. // Purpose: Handles the left mouse button double click event.
  641. //-----------------------------------------------------------------------------
  642. void CMapView3D::OnLButtonDblClk(UINT nFlags, CPoint point)
  643. {
  644. //
  645. // Don't forward message if we are controlling the camera.
  646. //
  647. if ((GetAsyncKeyState(VK_SPACE) & 0x8000) != 0)
  648. {
  649. return;
  650. }
  651. //
  652. // Pass the message to the active tool.
  653. //
  654. if ( !m_pToolManager )
  655. return;
  656. CBaseTool *pTool = m_pToolManager->GetActiveTool();
  657. if (pTool != NULL)
  658. {
  659. Vector2D vPoint( point.x,point.y);
  660. if (pTool->OnLMouseDblClk3D( this, nFlags, vPoint ))
  661. {
  662. return;
  663. }
  664. }
  665. }
  666. //-----------------------------------------------------------------------------
  667. // Purpose: Handles the left mouse button down event.
  668. //-----------------------------------------------------------------------------
  669. void CMapView3D::OnLButtonDown(UINT nFlags, CPoint point)
  670. {
  671. if ((GetAsyncKeyState(VK_SPACE) & 0x8000) != 0)
  672. {
  673. EnableRotating(true);
  674. return;
  675. }
  676. //
  677. // Pass the message to the active tool.
  678. //
  679. if ( m_pToolManager != NULL )
  680. {
  681. CBaseTool *pTool = m_pToolManager->GetActiveTool();
  682. if (pTool != NULL)
  683. {
  684. Vector2D vPoint( point.x,point.y);
  685. if (pTool->OnLMouseDown3D(this, nFlags, vPoint))
  686. {
  687. return;
  688. }
  689. }
  690. }
  691. CView::OnLButtonDown(nFlags, point);
  692. }
  693. //-----------------------------------------------------------------------------
  694. // Purpose: Called by the selection tool to begin timed selection by depth.
  695. //-----------------------------------------------------------------------------
  696. void CMapView3D::BeginPick(void)
  697. {
  698. SetTimer(MVTIMER_PICKNEXT, 500, NULL);
  699. }
  700. //-----------------------------------------------------------------------------
  701. // Purpose: Called by the selection tool to end timed selection by depth.
  702. //-----------------------------------------------------------------------------
  703. void CMapView3D::EndPick(void)
  704. {
  705. //
  706. // Kill pick timer.
  707. //
  708. KillTimer(MVTIMER_PICKNEXT);
  709. }
  710. //-----------------------------------------------------------------------------
  711. // Purpose:
  712. // Input : nFlags -
  713. // point -
  714. //-----------------------------------------------------------------------------
  715. void CMapView3D::OnLButtonUp(UINT nFlags, CPoint point)
  716. {
  717. if (m_bRotating)
  718. {
  719. EnableRotating(false);
  720. UpdateCameraVariables();
  721. return;
  722. }
  723. //
  724. // Pass the message to the active tool.
  725. //
  726. if ( m_pToolManager != NULL )
  727. {
  728. CBaseTool *pTool = m_pToolManager->GetActiveTool();
  729. if (pTool != NULL)
  730. {
  731. Vector2D vPoint( point.x,point.y);
  732. if (pTool->OnLMouseUp3D(this, nFlags, vPoint))
  733. {
  734. return;
  735. }
  736. }
  737. }
  738. CView::OnLButtonUp(nFlags, point);
  739. }
  740. //-----------------------------------------------------------------------------
  741. // Purpose: Creates the renderer and the camera and initializes them.
  742. //-----------------------------------------------------------------------------
  743. void CMapView3D::OnInitialUpdate(void)
  744. {
  745. InitializeKeyMap();
  746. //
  747. // Create a title window.
  748. //
  749. m_pwndTitle = CTitleWnd::CreateTitleWnd(this, ID_2DTITLEWND);
  750. Assert(m_pwndTitle != NULL);
  751. if (m_pwndTitle != NULL)
  752. {
  753. m_pwndTitle->SetTitle("camera");
  754. }
  755. //
  756. // CMainFrame::LoadWindowStates calls InitialUpdateFrame which causes us to get two
  757. // OnInitialUpdate messages! Check for a NULL renderer to avoid processing twice.
  758. //
  759. if (m_pRender != NULL)
  760. {
  761. return;
  762. }
  763. //
  764. // Create and initialize the renderer.
  765. //
  766. m_pRender = new CRender3D();
  767. CMapDoc *pDoc = GetMapDoc();
  768. if (pDoc == NULL)
  769. {
  770. Assert(pDoc != NULL);
  771. return;
  772. }
  773. m_pRender->SetView( this );
  774. m_pToolManager = pDoc->GetTools();
  775. SetDrawType(m_eDrawType);
  776. //
  777. // Create and initialize the camera.
  778. //
  779. m_pCamera = new CCamera();
  780. Assert(m_pCamera != NULL);
  781. if (m_pCamera == NULL)
  782. {
  783. return;
  784. }
  785. CRect rect;
  786. GetClientRect( rect );
  787. m_pCamera->SetViewPort( rect.Width(), rect.Height() );
  788. m_fForwardSpeedMax = Options.view3d.nForwardSpeedMax;
  789. m_fStrafeSpeedMax = Options.view3d.nForwardSpeedMax * 0.75f;
  790. m_fVerticalSpeedMax = Options.view3d.nForwardSpeedMax * 0.5f;
  791. //
  792. // Calculate the acceleration based on max speed and the time to max speed.
  793. //
  794. if (Options.view3d.nTimeToMaxSpeed != 0)
  795. {
  796. m_fForwardAcceleration = m_fForwardSpeedMax / (Options.view3d.nTimeToMaxSpeed / 1000.0f);
  797. m_fStrafeAcceleration = m_fStrafeSpeedMax / (Options.view3d.nTimeToMaxSpeed / 1000.0f);
  798. m_fVerticalAcceleration = m_fVerticalSpeedMax / (Options.view3d.nTimeToMaxSpeed / 1000.0f);
  799. }
  800. else
  801. {
  802. m_fForwardAcceleration = 0;
  803. m_fStrafeAcceleration = 0;
  804. m_fVerticalAcceleration = 0;
  805. }
  806. //
  807. // Set up the frustum. We set the vertical FOV to zero because the renderer
  808. // only uses the horizontal FOV.
  809. //
  810. m_pCamera->SetPerspective( CMapEntity::GetShowDotACamera() ? 65.0f : Options.view3d.fFOV, CAMERA_FRONT_PLANE_DISTANCE, Options.view3d.iBackPlane);
  811. //
  812. // Set the distance at which studio models become bounding boxes.
  813. //
  814. CMapStudioModel::SetRenderDistance(Options.view3d.nModelDistance);
  815. CMapStudioModel::EnableAnimation(Options.view3d.bAnimateModels);
  816. //
  817. // Enable or disable reverse selection.
  818. //
  819. m_pRender->RenderEnable(RENDER_REVERSE_SELECTION, (Options.view3d.bReverseSelection == TRUE));
  820. //
  821. // Enable or disable the 3D grid.
  822. //
  823. m_pRender->RenderEnable(RENDER_GRID, pDoc->Is3DGridEnabled());
  824. //
  825. // Enable or disable texture filtering.
  826. //
  827. m_pRender->RenderEnable(RENDER_FILTER_TEXTURES, (Options.view3d.bFilterTextures == TRUE));
  828. // Get the initial viewpoint and view direction from the default camera in the document.
  829. Camera3D *pCamTool = dynamic_cast<Camera3D*>(m_pToolManager->GetToolForID( TOOL_CAMERA ));
  830. if ( pCamTool )
  831. {
  832. Vector vecPos,vecLookAt;
  833. pCamTool->GetCameraPos( vecPos,vecLookAt );
  834. SetCamera(vecPos, vecLookAt);
  835. }
  836. CView::OnInitialUpdate();
  837. }
  838. //-----------------------------------------------------------------------------
  839. // Purpose: Turns on wireframe mode from the floating "Camera" menu.
  840. //-----------------------------------------------------------------------------
  841. void CMapView3D::OnView3dWireframe(void)
  842. {
  843. SetDrawType(VIEW3D_WIREFRAME);
  844. }
  845. //-----------------------------------------------------------------------------
  846. // Purpose: Turns on flat shaded mode from the floating "Camera" menu.
  847. //-----------------------------------------------------------------------------
  848. void CMapView3D::OnView3dPolygon(void)
  849. {
  850. SetDrawType(VIEW3D_POLYGON);
  851. }
  852. //-----------------------------------------------------------------------------
  853. // Purpose: Turns on textured mode from the floating "Camera" menu.
  854. //-----------------------------------------------------------------------------
  855. void CMapView3D::OnView3dTextured(void)
  856. {
  857. SetDrawType(VIEW3D_TEXTURED);
  858. }
  859. //-----------------------------------------------------------------------------
  860. // Purpose: Turns on lightmap grid mode from the floating "Camera" menu.
  861. //-----------------------------------------------------------------------------
  862. void CMapView3D::OnView3dLightmapGrid(void)
  863. {
  864. SetDrawType(VIEW3D_LIGHTMAP_GRID);
  865. }
  866. //-----------------------------------------------------------------------------
  867. // Purpose: Turns on lighting preview mode from the floating "Camera" menu.
  868. //-----------------------------------------------------------------------------
  869. void CMapView3D::OnView3dLightingPreview(void)
  870. {
  871. SetDrawType(VIEW3D_LIGHTING_PREVIEW2);
  872. }
  873. void CMapView3D::OnView3dLightingPreviewRayTraced(void)
  874. {
  875. SetDrawType(VIEW3D_LIGHTING_PREVIEW_RAYTRACED);
  876. }
  877. //-----------------------------------------------------------------------------
  878. // Purpose: Turns on engine mode from the floating "Camera" menu.
  879. //-----------------------------------------------------------------------------
  880. //void CMapView3D::OnView3dEngine(void)
  881. //{
  882. // SetDrawType(VIEW3D_ENGINE);
  883. //}
  884. //-----------------------------------------------------------------------------
  885. // Purpose:
  886. // Input : bActivate -
  887. // pActivateView -
  888. // pDeactiveView -
  889. //-----------------------------------------------------------------------------
  890. void CMapView3D::ActivateView(bool bActivate)
  891. {
  892. CMapView::ActivateView(bActivate);
  893. if (bActivate)
  894. {
  895. CMapDoc *pDoc = GetMapDoc();
  896. CMapDoc::SetActiveMapDoc(pDoc);
  897. UpdateStatusBar();
  898. // tell doc to update title
  899. pDoc->UpdateTitle(this);
  900. m_Keyboard.ClearKeyStates();
  901. //
  902. // Reset the last input sample time.
  903. //
  904. m_dwTimeLastInputSample = 0;
  905. }
  906. }
  907. void CMapView3D::OnDraw(CDC *pDC)
  908. {
  909. CWnd *focusWnd = GetForegroundWindow();
  910. if ( focusWnd && focusWnd->ContinueModal() )
  911. {
  912. // render the view now since were not running the main loop
  913. RenderView();
  914. }
  915. else
  916. {
  917. // just flag view to be update with next main loop
  918. m_bUpdateView = true;
  919. }
  920. }
  921. //-----------------------------------------------------------------------------
  922. //-----------------------------------------------------------------------------
  923. void CMapView3D::RenderView()
  924. {
  925. RenderView2( false );
  926. }
  927. void CMapView3D::RenderView2( bool bRenderingOverEngine )
  928. {
  929. Render( bRenderingOverEngine );
  930. m_bUpdateView = false;
  931. }
  932. //-----------------------------------------------------------------------------
  933. //-----------------------------------------------------------------------------
  934. bool CMapView3D::ShouldRender()
  935. {
  936. if ( m_eDrawType == VIEW3D_LIGHTING_PREVIEW_RAYTRACED )
  937. {
  938. // check if we have new results from lpreview thread
  939. // if ( m_nLastRaytracedBitmapRenderTimeStamp !=
  940. // GetUpdateCounter( EVTYPE_BITMAP_RECEIVED_FROM_LPREVIEW ) )
  941. // return true;
  942. }
  943. else
  944. {
  945. // don't animate ray traced displays
  946. if ( Options.view3d.bAnimateModels )
  947. {
  948. DWORD dwTimeElapsed = timeGetTime() - m_dwTimeLastRender;
  949. if ( (dwTimeElapsed/1000.0f) > 1.0f/20.0f)
  950. {
  951. m_bUpdateView = true;
  952. }
  953. }
  954. }
  955. return CMapView::ShouldRender();
  956. }
  957. //-----------------------------------------------------------------------------
  958. // Purpose:
  959. // Input : pDC -
  960. //-----------------------------------------------------------------------------
  961. void CMapView3D::OnSetFocus(CWnd *pOldWnd)
  962. {
  963. // Make sure the whole window region is marked as invalid
  964. m_bUpdateView = true;
  965. }
  966. //-----------------------------------------------------------------------------
  967. // Purpose: Called to paint the non client area of the window.
  968. //-----------------------------------------------------------------------------
  969. void CMapView3D::OnNcPaint(void)
  970. {
  971. // Make sure the whole window region is marked as invalid
  972. m_bUpdateView = true;
  973. }
  974. //-----------------------------------------------------------------------------
  975. // Purpose:
  976. // Input : pSender -
  977. // lHint -
  978. // pHint -
  979. //-----------------------------------------------------------------------------
  980. void CMapView3D::UpdateView(int nFlags)
  981. {
  982. if ( !m_pRender )
  983. return;
  984. if (nFlags & ( MAPVIEW_UPDATE_ONLY_2D | MAPVIEW_UPDATE_ONLY_LOGICAL ) )
  985. return;
  986. //
  987. // One of the options in the 3D options page is changing.
  988. //
  989. if (nFlags & MAPVIEW_OPTIONS_CHANGED)
  990. {
  991. InitializeKeyMap();
  992. CMapStudioModel::SetRenderDistance(Options.view3d.nModelDistance);
  993. CMapStudioModel::EnableAnimation(Options.view3d.bAnimateModels);
  994. m_pRender->RenderEnable(RENDER_REVERSE_SELECTION, (Options.view3d.bReverseSelection == TRUE));
  995. m_fForwardSpeedMax = Options.view3d.nForwardSpeedMax;
  996. m_fStrafeSpeedMax = Options.view3d.nForwardSpeedMax * 0.75f;
  997. m_fVerticalSpeedMax = Options.view3d.nForwardSpeedMax * 0.5f;
  998. //
  999. // Calculate the acceleration based on max speed and the time to max speed.
  1000. //
  1001. if (Options.view3d.nTimeToMaxSpeed != 0)
  1002. {
  1003. m_fForwardAcceleration = m_fForwardSpeedMax / (Options.view3d.nTimeToMaxSpeed / 1000.0f);
  1004. m_fStrafeAcceleration = m_fStrafeSpeedMax / (Options.view3d.nTimeToMaxSpeed / 1000.0f);
  1005. m_fVerticalAcceleration = m_fVerticalSpeedMax / (Options.view3d.nTimeToMaxSpeed / 1000.0f);
  1006. }
  1007. else
  1008. {
  1009. m_fForwardAcceleration = 0;
  1010. m_fStrafeAcceleration = 0;
  1011. m_fVerticalAcceleration = 0;
  1012. }
  1013. m_pCamera->SetPerspective( CMapEntity::GetShowDotACamera() ? 65.0f : Options.view3d.fFOV, CAMERA_FRONT_PLANE_DISTANCE, Options.view3d.iBackPlane);
  1014. CMapDoc *pDoc = GetMapDoc();
  1015. if ((pDoc != NULL) && (m_pRender != NULL))
  1016. {
  1017. m_pRender->RenderEnable(RENDER_GRID, pDoc->Is3DGridEnabled());
  1018. m_pRender->RenderEnable(RENDER_FILTER_TEXTURES, (Options.view3d.bFilterTextures == TRUE));
  1019. }
  1020. }
  1021. if (nFlags & MAPVIEW_UPDATE_OBJECTS)
  1022. {
  1023. // dvs: could use this hint to update the octree
  1024. }
  1025. CMapView::UpdateView( nFlags );
  1026. }
  1027. //-----------------------------------------------------------------------------
  1028. // Purpose: Determines the object at the point (point.x, point.y) in the 3D view.
  1029. // Input : point - Point to use for hit test.
  1030. // ulFace - Index of face in object that was hit.
  1031. // Output : Returns a pointer to the CMapClass object at the coordinates, NULL if none.
  1032. //-----------------------------------------------------------------------------
  1033. CMapClass *CMapView3D::NearestObjectAt( const Vector2D &vPoint, ULONG &ulFace, unsigned int nFlags, VMatrix *pLocalMatrix )
  1034. {
  1035. ulFace = 0;
  1036. if (m_pRender == NULL)
  1037. {
  1038. return(NULL);
  1039. }
  1040. HitInfo_t Hits;
  1041. if (m_pRender->ObjectsAt( vPoint.x, vPoint.y, 1, 1, &Hits, 1, nFlags ) != 0)
  1042. {
  1043. //
  1044. // If they clicked on a solid, the index of the face they clicked on is stored
  1045. // in array index [1].
  1046. //
  1047. CMapAtom *pObject = (CMapAtom *)Hits.pObject;
  1048. CMapSolid *pSolid = dynamic_cast<CMapSolid *>(pObject);
  1049. if ( pLocalMatrix != NULL )
  1050. {
  1051. *pLocalMatrix = Hits.m_LocalMatrix;
  1052. }
  1053. if (pSolid != NULL)
  1054. {
  1055. ulFace = Hits.uData;
  1056. return(pSolid);
  1057. }
  1058. return((CMapClass *)pObject);
  1059. }
  1060. return(NULL);
  1061. }
  1062. //-----------------------------------------------------------------------------
  1063. // Purpose: Casts a ray from the viewpoint through the given plane and determines
  1064. // the point of intersection of the ray on the plane.
  1065. // Input : point - Point in client screen coordinates.
  1066. // plane - Plane being 'clicked' on.
  1067. // pos - Returns the point on the plane that projects to the given point.
  1068. //-----------------------------------------------------------------------------
  1069. void CMapView3D::GetHitPos(const Vector2D &point, PLANE &plane, Vector &pos)
  1070. {
  1071. //
  1072. // Find the point they clicked on in world coordinates. It lies on the near
  1073. // clipping plane.
  1074. //
  1075. Vector ClickPoint;
  1076. ClientToWorld( ClickPoint, point );
  1077. //
  1078. // Build a ray from the viewpoint through the point on the near clipping plane.
  1079. //
  1080. Vector ViewPoint;
  1081. Vector Ray;
  1082. m_pCamera->GetViewPoint(ViewPoint);
  1083. VectorSubtract(ClickPoint, ViewPoint, Ray);
  1084. //
  1085. // Find the point of intersection of the ray with the given plane.
  1086. //
  1087. float t = DotProduct(plane.normal, ViewPoint) - plane.dist;
  1088. t = t / -DotProduct(plane.normal, Ray);
  1089. pos = ViewPoint + t * Ray;
  1090. }
  1091. bool CMapView3D::HitTest( const Vector2D &vPoint, const Vector& mins, const Vector& maxs)
  1092. {
  1093. Vector vStart, vEnd;
  1094. int nFace;
  1095. BuildRay( vPoint, vStart, vEnd );
  1096. return IntersectionLineAABBox( mins, maxs, vStart, vEnd, nFace ) >= 0.0f;
  1097. }
  1098. //-----------------------------------------------------------------------------
  1099. // Purpose: Finds all objects under the given rectangular region in the view.
  1100. // Input : x - Client x coordinate.
  1101. // y - Client y coordinate.
  1102. // fWidth - Width of region in client pixels.
  1103. // fHeight - Height of region in client pixels.
  1104. // pObjects - Receives objects in the given region.
  1105. // nMaxObjects - Size of the array pointed to by pObjects.
  1106. // Output : Returns the number of objects in the given region.
  1107. //-----------------------------------------------------------------------------
  1108. int CMapView3D::ObjectsAt( const Vector2D &vPoint, HitInfo_t *pObjects, int nMaxObjects, unsigned int nFlags )
  1109. {
  1110. if (m_pRender != NULL)
  1111. {
  1112. return m_pRender->ObjectsAt( vPoint.x, vPoint.y, 1, 1, pObjects, nMaxObjects, nFlags );
  1113. }
  1114. return 0;
  1115. }
  1116. //-----------------------------------------------------------------------------
  1117. // Purpose: Makes sure that this view has focus if the mouse moves over it.
  1118. //-----------------------------------------------------------------------------
  1119. void CMapView3D::OnMouseMove(UINT nFlags, CPoint point)
  1120. {
  1121. //
  1122. // Make sure we are the active view.
  1123. //
  1124. if (!IsActive())
  1125. {
  1126. CMapDoc *pDoc = GetMapDoc();
  1127. pDoc->SetActiveView(this);
  1128. }
  1129. //
  1130. // If we are the active application, make sure this view has the input focus.
  1131. //
  1132. if (APP()->IsActiveApp())
  1133. {
  1134. if (GetFocus() != this)
  1135. {
  1136. SetFocus();
  1137. }
  1138. }
  1139. CView::OnMouseMove(nFlags, point);
  1140. }
  1141. //-----------------------------------------------------------------------------
  1142. // Purpose:
  1143. //-----------------------------------------------------------------------------
  1144. void CMapView3D::ProcessInput(void)
  1145. {
  1146. if (m_dwTimeLastInputSample == 0)
  1147. {
  1148. m_dwTimeLastInputSample = timeGetTime();
  1149. }
  1150. DWORD dwTimeNow = timeGetTime();
  1151. float fElapsedTime = (float)(dwTimeNow - m_dwTimeLastInputSample) / 1000.0f;
  1152. m_dwTimeLastInputSample = dwTimeNow;
  1153. // Clamp (can get really big when we cache textures in )
  1154. if (fElapsedTime > 0.3f)
  1155. {
  1156. fElapsedTime = 0.3f;
  1157. }
  1158. else if ( fElapsedTime <=0 )
  1159. {
  1160. return; // dont process input
  1161. }
  1162. ProcessKeys( fElapsedTime );
  1163. ProcessMouse();
  1164. if ( Options.general.bRadiusCulling )
  1165. {
  1166. ProcessCulling();
  1167. }
  1168. }
  1169. //-----------------------------------------------------------------------------
  1170. // Purpose: Applies an acceleration to a velocity, allowing instantaneous direction
  1171. // change and zeroing the velocity in the absence of acceleration.
  1172. // Input : fVelocity - Current velocity.
  1173. // fAccel - Amount of acceleration to apply.
  1174. // fTimeScale - The time for which the acceleration should be applied.
  1175. // fMaxVelocity - The maximum velocity to allow.
  1176. // Output : Returns the new velocity.
  1177. //-----------------------------------------------------------------------------
  1178. static float Accelerate(float fVelocity, float fAccel, float fAccelScale, float fTimeScale, float fVelocityMax)
  1179. {
  1180. //
  1181. // If we have a finite acceleration in this direction, apply it to the velocity.
  1182. //
  1183. if ((fAccel != 0) && (fAccelScale != 0))
  1184. {
  1185. //
  1186. // Check for direction reversal - zero velocity when reversing.
  1187. //
  1188. if (fAccelScale > 0)
  1189. {
  1190. if (fVelocity < 0)
  1191. {
  1192. fVelocity = 0;
  1193. }
  1194. }
  1195. else if (fAccelScale < 0)
  1196. {
  1197. if (fVelocity > 0)
  1198. {
  1199. fVelocity = 0;
  1200. }
  1201. }
  1202. //
  1203. // Apply the acceleration.
  1204. //
  1205. fVelocity += fAccel * fAccelScale * fTimeScale;
  1206. if (fVelocity > fVelocityMax)
  1207. {
  1208. fVelocity = fVelocityMax;
  1209. }
  1210. else if (fVelocity < -fVelocityMax)
  1211. {
  1212. fVelocity = -fVelocityMax;
  1213. }
  1214. }
  1215. //
  1216. // If we have infinite acceleration, go straight to maximum velocity.
  1217. //
  1218. else if (fAccelScale != 0)
  1219. {
  1220. fVelocity = fVelocityMax * fAccelScale;
  1221. }
  1222. //
  1223. // Else no velocity in this direction at all.
  1224. //
  1225. else
  1226. {
  1227. fVelocity = 0;
  1228. }
  1229. return(fVelocity);
  1230. }
  1231. //-----------------------------------------------------------------------------
  1232. // Purpose: Moves the camera based on the keyboard state.
  1233. //-----------------------------------------------------------------------------
  1234. void CMapView3D::ProcessMovementKeys(float fElapsedTime)
  1235. {
  1236. //
  1237. // Read the state of the camera movement keys.
  1238. //
  1239. float fBack = m_Keyboard.GetKeyScale(LOGICAL_KEY_BACK);
  1240. float fMoveForward = m_Keyboard.GetKeyScale(LOGICAL_KEY_FORWARD) - fBack;
  1241. float fLeft = m_Keyboard.GetKeyScale(LOGICAL_KEY_LEFT);
  1242. float fMoveRight = m_Keyboard.GetKeyScale(LOGICAL_KEY_RIGHT) - fLeft;
  1243. float fDown = m_Keyboard.GetKeyScale(LOGICAL_KEY_DOWN);
  1244. float fMoveUp = m_Keyboard.GetKeyScale(LOGICAL_KEY_UP) - fDown;
  1245. float fPitchUp = m_Keyboard.GetKeyScale(LOGICAL_KEY_PITCH_UP);
  1246. float fPitchDown = m_Keyboard.GetKeyScale(LOGICAL_KEY_PITCH_DOWN);
  1247. float fYawLeft = m_Keyboard.GetKeyScale(LOGICAL_KEY_YAW_LEFT);
  1248. float fYawRight = m_Keyboard.GetKeyScale(LOGICAL_KEY_YAW_RIGHT);
  1249. //
  1250. // Apply pitch and yaw if they are nonzero.
  1251. //
  1252. if ((fPitchDown - fPitchUp) != 0)
  1253. {
  1254. m_pCamera->Pitch((fPitchDown - fPitchUp) * fElapsedTime * PITCH_SPEED);
  1255. m_bUpdateView = true;
  1256. }
  1257. if ((fYawRight - fYawLeft) != 0)
  1258. {
  1259. m_pCamera->Yaw((fYawRight - fYawLeft) * fElapsedTime * YAW_SPEED);
  1260. m_bUpdateView = true;
  1261. }
  1262. //
  1263. // Apply the accelerations to the forward, strafe, and vertical speeds. They are actually
  1264. // velocities because they are signed values.
  1265. //
  1266. m_fForwardSpeed = Accelerate(m_fForwardSpeed, m_fForwardAcceleration, fMoveForward, fElapsedTime, m_fForwardSpeedMax);
  1267. m_fStrafeSpeed = Accelerate(m_fStrafeSpeed, m_fStrafeAcceleration, fMoveRight, fElapsedTime, m_fStrafeSpeedMax);
  1268. m_fVerticalSpeed = Accelerate(m_fVerticalSpeed, m_fVerticalAcceleration, fMoveUp, fElapsedTime, m_fVerticalSpeedMax);
  1269. if ( CMapEntity::GetShowDotACamera() )
  1270. {
  1271. CMapDoc *pDoc = (CMapDoc *)GetDocument();
  1272. Vector vForward;
  1273. m_pCamera->GetViewForward( vForward );
  1274. Vector vViewpoint;
  1275. m_pCamera->GetViewPoint( vViewpoint );
  1276. Vector vHitLoc;
  1277. bool bHit = pDoc->PickTrace( vViewpoint, vForward, &vHitLoc );
  1278. if ( !bHit )
  1279. {
  1280. vHitLoc = vViewpoint + ( vForward * 1500.0f );
  1281. }
  1282. Vector vDirection = vHitLoc - vViewpoint;
  1283. VectorNormalize( vDirection );
  1284. Vector vNewViewpoint = vHitLoc - vDirection * 1500.0f;
  1285. m_fForwardSpeed *= 2.0f;
  1286. m_fStrafeSpeed *= 2.0f;
  1287. m_pCamera->SetPitch( 65.0f );
  1288. m_pCamera->SetRoll( 0.0f );
  1289. m_pCamera->SetYaw( 0.0f );
  1290. m_pCamera->Move( Vector( m_fStrafeSpeed * fElapsedTime + ( vNewViewpoint.x - vViewpoint.x ), m_fForwardSpeed * fElapsedTime + ( vNewViewpoint.y - vViewpoint.y ), vNewViewpoint.z - vViewpoint.z ) );
  1291. m_bUpdateView = true;
  1292. m_bCameraPosChanged = true;
  1293. }
  1294. else
  1295. {
  1296. //
  1297. // Move the camera if any of the speeds are nonzero.
  1298. //
  1299. if (m_fForwardSpeed != 0)
  1300. {
  1301. m_pCamera->MoveForward(m_fForwardSpeed * fElapsedTime);
  1302. m_bUpdateView = true;
  1303. m_bCameraPosChanged = true;
  1304. }
  1305. if (m_fStrafeSpeed != 0)
  1306. {
  1307. m_pCamera->MoveRight(m_fStrafeSpeed * fElapsedTime);
  1308. m_bUpdateView = true;
  1309. m_bCameraPosChanged = true;
  1310. }
  1311. if (m_fVerticalSpeed != 0)
  1312. {
  1313. m_pCamera->MoveUp(m_fVerticalSpeed * fElapsedTime);
  1314. m_bUpdateView = true;
  1315. m_bCameraPosChanged = true;
  1316. }
  1317. }
  1318. }
  1319. //-----------------------------------------------------------------------------
  1320. // Purpose:
  1321. //-----------------------------------------------------------------------------
  1322. void CMapView3D::ProcessKeys(float fElapsedTime)
  1323. {
  1324. ProcessMovementKeys(fElapsedTime);
  1325. m_Keyboard.ClearImpulseFlags();
  1326. }
  1327. //-----------------------------------------------------------------------------
  1328. // Purpose:
  1329. //-----------------------------------------------------------------------------
  1330. void CMapView3D::ProcessCulling( void )
  1331. {
  1332. if ( m_bCameraPosChanged || m_bClippingChanged )
  1333. {
  1334. CMapDoc *pDoc = GetMapDoc();
  1335. pDoc->UpdateVisibilityAll();
  1336. m_bClippingChanged = false;
  1337. m_bCameraPosChanged = false;
  1338. }
  1339. }
  1340. //-----------------------------------------------------------------------------
  1341. // Purpose:
  1342. //-----------------------------------------------------------------------------
  1343. bool CMapView3D::ControlCamera(const CPoint &point)
  1344. {
  1345. if (!m_bStrafing && !m_bRotating && !m_bMouseLook)
  1346. {
  1347. return false;
  1348. }
  1349. bool bShift = ((GetAsyncKeyState(VK_SHIFT) & 0x8000) != 0);
  1350. CRect rect;
  1351. GetClientRect(&rect);
  1352. // get mouse distance to client window center
  1353. CPoint WindowCenter = rect.CenterPoint();
  1354. CSize MouseLookDelta = point - WindowCenter;
  1355. // camera look is on, but no mouse changes
  1356. if ( MouseLookDelta.cx == 0 && MouseLookDelta.cy == 0 )
  1357. true;
  1358. //
  1359. // If strafing, left-right movement moves the camera from side to side.
  1360. // Up-down movement either moves the camera forward and back if the SHIFT
  1361. // key is held down, or up and down if the SHIFT key is not held down.
  1362. // If rotating and strafing simultaneously, the behavior is as if SHIFT is
  1363. // held down.
  1364. //
  1365. if (m_bStrafing)
  1366. {
  1367. if (bShift || m_bRotating)
  1368. {
  1369. MoveForward(-MouseLookDelta.cy * 2);
  1370. }
  1371. else
  1372. {
  1373. MoveUp(-MouseLookDelta.cy * 2);
  1374. }
  1375. MoveRight(MouseLookDelta.cx * 2);
  1376. m_bCameraPosChanged = true;
  1377. }
  1378. //
  1379. // If mouse looking, left-right movement controls yaw, and up-down
  1380. // movement controls pitch.
  1381. //
  1382. else
  1383. {
  1384. //
  1385. // Up-down mouse movement changes the camera pitch.
  1386. //
  1387. if (MouseLookDelta.cy)
  1388. {
  1389. float fTheta = MouseLookDelta.cy * 0.4;
  1390. if (Options.view3d.bReverseY)
  1391. {
  1392. fTheta = -fTheta;
  1393. }
  1394. Pitch(fTheta);
  1395. }
  1396. //
  1397. // Left-right mouse movement changes the camera yaw.
  1398. //
  1399. if (MouseLookDelta.cx)
  1400. {
  1401. float fTheta = MouseLookDelta.cx * 0.4;
  1402. Yaw(fTheta);
  1403. }
  1404. }
  1405. // move mouse back to center
  1406. CWnd::ClientToScreen(&WindowCenter);
  1407. SetCursorPos(WindowCenter.x, WindowCenter.y);
  1408. m_bUpdateView = true;
  1409. return true;
  1410. }
  1411. //-----------------------------------------------------------------------------
  1412. // Purpose: Called by RunFrame to tell this view to process mouse input. This
  1413. // function samples the cursor position and takes the appropriate
  1414. // action based on the current mode (camera, morphing).
  1415. //-----------------------------------------------------------------------------
  1416. void CMapView3D::ProcessMouse(void)
  1417. {
  1418. //
  1419. // Get the cursor position in client coordinates.
  1420. //
  1421. CPoint point;
  1422. GetCursorPos(&point);
  1423. ScreenToClient(&point);
  1424. if ( point == m_ptLastMouseMovement )
  1425. return;
  1426. m_ptLastMouseMovement = point;
  1427. if ( ControlCamera( point ) )
  1428. {
  1429. return;
  1430. }
  1431. // If not in mouselook mode, only process mouse messages if there
  1432. // is an active tool.
  1433. //
  1434. CBaseTool *pTool = m_pToolManager->GetActiveTool();
  1435. if (pTool != NULL)
  1436. {
  1437. //
  1438. // Pass the message to the tool.
  1439. //
  1440. int nFlags = 0;
  1441. if ((GetAsyncKeyState(VK_CONTROL) & 0x8000) != 0)
  1442. {
  1443. nFlags |= MK_CONTROL;
  1444. }
  1445. if ((GetAsyncKeyState(VK_SHIFT) & 0x8000) != 0)
  1446. {
  1447. nFlags |= MK_SHIFT;
  1448. }
  1449. Vector2D vPoint( point.x,point.y);
  1450. pTool->OnMouseMove3D(this, nFlags, vPoint);
  1451. }
  1452. }
  1453. //-----------------------------------------------------------------------------
  1454. // Purpose: Handles mouse wheel events. The mouse wheel is used in camera mode
  1455. // to dolly the camera forward and back.
  1456. // Input : Per CWnd::OnMouseWheel.
  1457. //-----------------------------------------------------------------------------
  1458. BOOL CMapView3D::OnMouseWheel(UINT nFlags, short zDelta, CPoint point)
  1459. {
  1460. //
  1461. // Pass the message to the active tool.
  1462. //
  1463. if ( m_pToolManager != NULL )
  1464. {
  1465. CBaseTool *pTool = m_pToolManager->GetActiveTool();
  1466. if (pTool != NULL)
  1467. {
  1468. Vector2D vPoint( point.x,point.y);
  1469. if (pTool->OnMouseWheel3D(this, nFlags, zDelta, vPoint))
  1470. {
  1471. return(TRUE);
  1472. }
  1473. }
  1474. }
  1475. m_pCamera->MoveForward(zDelta / 2);
  1476. //
  1477. // Render now to avoid an ugly lag between the 2D views and the 3D view
  1478. // when "center 2D views on camera" is enabled.
  1479. //
  1480. m_bUpdateView = true;
  1481. m_bCameraPosChanged = true;
  1482. UpdateCameraVariables();
  1483. return CView::OnMouseWheel(nFlags, zDelta, point);
  1484. }
  1485. //-----------------------------------------------------------------------------
  1486. // Purpose: Handles right mouse button down events.
  1487. // Input : Per CWnd::OnRButtonDown.
  1488. //-----------------------------------------------------------------------------
  1489. void CMapView3D::OnRButtonDown(UINT nFlags, CPoint point)
  1490. {
  1491. if ((GetAsyncKeyState(VK_SPACE) & 0x8000) != 0)
  1492. {
  1493. EnableStrafing(true);
  1494. return;
  1495. }
  1496. //
  1497. // Pass the message to the active tool.
  1498. //
  1499. if ( m_pToolManager != NULL )
  1500. {
  1501. CBaseTool *pTool = m_pToolManager->GetActiveTool();
  1502. if (pTool != NULL)
  1503. {
  1504. Vector2D vPoint( point.x,point.y);
  1505. if (pTool->OnRMouseDown3D( this, nFlags, vPoint ))
  1506. {
  1507. return;
  1508. }
  1509. }
  1510. }
  1511. CView::OnRButtonDown(nFlags, point);
  1512. }
  1513. //-----------------------------------------------------------------------------
  1514. // Purpose: Handles right mouse button up events.
  1515. // Input : Per CWnd::OnRButtonUp.
  1516. //-----------------------------------------------------------------------------
  1517. void CMapView3D::OnRButtonUp(UINT nFlags, CPoint point)
  1518. {
  1519. if (m_bStrafing)
  1520. {
  1521. //
  1522. // Turn off strafing and update the 2D views.
  1523. //
  1524. EnableStrafing(false);
  1525. UpdateCameraVariables();
  1526. return;
  1527. }
  1528. //
  1529. // Pass the message to the active tool.
  1530. //
  1531. if ( m_pToolManager != NULL )
  1532. {
  1533. CBaseTool *pTool = m_pToolManager->GetActiveTool();
  1534. if (pTool != NULL)
  1535. {
  1536. Vector2D vPoint( point.x,point.y);
  1537. if (pTool->OnRMouseUp3D( this, nFlags, vPoint ))
  1538. {
  1539. return;
  1540. }
  1541. }
  1542. }
  1543. CView::OnRButtonUp(nFlags, point);
  1544. }
  1545. //-----------------------------------------------------------------------------
  1546. // Purpose: Handles character events.
  1547. // Input : Per CWnd::OnChar.
  1548. //-----------------------------------------------------------------------------
  1549. void CMapView3D::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags)
  1550. {
  1551. // Got to check for m_pToolManager here because otherwise it can crash on startup if they have keys pressed.
  1552. if ( m_pToolManager )
  1553. {
  1554. //
  1555. // Pass the message to the active tool.
  1556. //
  1557. CBaseTool *pTool = m_pToolManager->GetActiveTool();
  1558. if (pTool != NULL)
  1559. {
  1560. if (pTool->OnChar3D(this, nChar, nRepCnt, nFlags))
  1561. {
  1562. return;
  1563. }
  1564. }
  1565. }
  1566. CView::OnChar(nChar, nRepCnt, nFlags);
  1567. }
  1568. //-----------------------------------------------------------------------------
  1569. // Purpose: Called when mouselook is enabled. The cursor is moved to the center
  1570. // of the screen and hidden.
  1571. // Input : bEnable - true to lock and hide the cursor, false to unlock and show it.
  1572. //-----------------------------------------------------------------------------
  1573. void CMapView3D::EnableCrosshair(bool bEnable)
  1574. {
  1575. CRect Rect;
  1576. CPoint Point;
  1577. GetClientRect(&Rect);
  1578. CWnd::ClientToScreen(&Rect);
  1579. Point = Rect.CenterPoint();
  1580. SetCursorPos(Point.x, Point.y);
  1581. if (bEnable)
  1582. {
  1583. ClipCursor(&Rect);
  1584. }
  1585. else
  1586. {
  1587. ClipCursor(NULL);
  1588. }
  1589. ShowCursor(bEnable ? FALSE : TRUE);
  1590. m_pRender->RenderEnable(RENDER_CENTER_CROSSHAIR, bEnable);
  1591. }
  1592. //-----------------------------------------------------------------------------
  1593. // Purpose: Enables or disables mouselook. When mouselooking, the cursor is hidden
  1594. // and a crosshair is rendered in the center of the view.
  1595. // Input : bEnable - TRUE to enable, FALSE to disable mouselook.
  1596. //-----------------------------------------------------------------------------
  1597. //void CMapView3D::EnableMouseLook(bool bEnable)
  1598. //{
  1599. // if (m_bMouseLook != bEnable)
  1600. // {
  1601. // CMapDoc *pDoc = GetDocument();
  1602. // if (pDoc != NULL)
  1603. // {
  1604. // EnableCrosshair(bEnable);
  1605. // m_bMouseLook = bEnable;
  1606. // }
  1607. // }
  1608. //}
  1609. //-----------------------------------------------------------------------------
  1610. // Purpose: Enables or disables mouselook. When mouselooking, the cursor is hidden
  1611. // and a crosshair is rendered in the center of the view.
  1612. //-----------------------------------------------------------------------------
  1613. void CMapView3D::EnableMouseLook(bool bEnable)
  1614. {
  1615. if (m_bMouseLook != bEnable)
  1616. {
  1617. if (!(m_bStrafing || m_bRotating))
  1618. {
  1619. EnableCrosshair(bEnable);
  1620. }
  1621. m_bMouseLook = bEnable;
  1622. }
  1623. }
  1624. //-----------------------------------------------------------------------------
  1625. // Purpose: Enables or disables camera rotating. When rotating, the cursor is hidden
  1626. // and a crosshair is rendered in the center of the view.
  1627. //-----------------------------------------------------------------------------
  1628. void CMapView3D::EnableRotating(bool bEnable)
  1629. {
  1630. if (m_bRotating != bEnable)
  1631. {
  1632. if (!(m_bStrafing || m_bMouseLook))
  1633. {
  1634. EnableCrosshair(bEnable);
  1635. }
  1636. m_bRotating = bEnable;
  1637. }
  1638. }
  1639. //-----------------------------------------------------------------------------
  1640. // Purpose: Enables or disables camera strafing. When strafing, the cursor is hidden
  1641. // and a crosshair is rendered in the center of the view.
  1642. //-----------------------------------------------------------------------------
  1643. void CMapView3D::EnableStrafing(bool bEnable)
  1644. {
  1645. if (m_bStrafing != bEnable)
  1646. {
  1647. if (!(m_bMouseLook || m_bRotating))
  1648. {
  1649. EnableCrosshair(bEnable);
  1650. }
  1651. m_bStrafing = bEnable;
  1652. }
  1653. }
  1654. //-----------------------------------------------------------------------------
  1655. // Purpose: Actually renders the 3D view. Called from the frame loop and from
  1656. // some mouse messages when timely updating is important.
  1657. //-----------------------------------------------------------------------------
  1658. void CMapView3D::Render( bool bRenderingOverEngine )
  1659. {
  1660. if ( m_pRender != NULL )
  1661. {
  1662. m_pRender->Render( bRenderingOverEngine );
  1663. }
  1664. if (m_pwndTitle != NULL)
  1665. {
  1666. m_pwndTitle->BringWindowToTop();
  1667. m_pwndTitle->Invalidate();
  1668. m_pwndTitle->UpdateWindow();
  1669. }
  1670. }
  1671. //-----------------------------------------------------------------------------
  1672. // Purpose:
  1673. // Input : *pObject -
  1674. //-----------------------------------------------------------------------------
  1675. void CMapView3D::RenderPreloadObject(CMapAtom *pObject)
  1676. {
  1677. if ((pObject != NULL) && (m_pRender != NULL))
  1678. {
  1679. pObject->RenderPreload(m_pRender, false);
  1680. }
  1681. }
  1682. //-----------------------------------------------------------------------------
  1683. // Release all video memory.
  1684. //-----------------------------------------------------------------------------
  1685. void CMapView3D::ReleaseVideoMemory(void)
  1686. {
  1687. m_pRender->UncacheAllTextures();
  1688. }
  1689. void CMapView3D::Foundry_OnLButtonDown( int x, int y )
  1690. {
  1691. OnLButtonDown( 0, CPoint( x, y ) );
  1692. }
  1693. //-----------------------------------------------------------------------------
  1694. // Purpose: Moves the camera forward by flDistance units. Negative units move back.
  1695. //-----------------------------------------------------------------------------
  1696. void CMapView3D::MoveForward(float flDistance)
  1697. {
  1698. if (m_pCamera != NULL)
  1699. {
  1700. m_pCamera->MoveForward(flDistance);
  1701. }
  1702. }
  1703. //-----------------------------------------------------------------------------
  1704. // Purpose: Moves the camera up by flDistance units. Negative units move down.
  1705. //-----------------------------------------------------------------------------
  1706. void CMapView3D::MoveUp(float flDistance)
  1707. {
  1708. if (m_pCamera != NULL)
  1709. {
  1710. m_pCamera->MoveUp(flDistance);
  1711. }
  1712. }
  1713. //-----------------------------------------------------------------------------
  1714. // Purpose: Moves the camera right by flDistance units. Negative units move left.
  1715. //-----------------------------------------------------------------------------
  1716. void CMapView3D::MoveRight(float flDistance)
  1717. {
  1718. if (m_pCamera != NULL)
  1719. {
  1720. m_pCamera->MoveRight(flDistance);
  1721. }
  1722. }
  1723. //-----------------------------------------------------------------------------
  1724. // Purpose: Pitches the camera forward by flDegrees degrees. Negative units pitch back.
  1725. //-----------------------------------------------------------------------------
  1726. void CMapView3D::Pitch(float flDegrees)
  1727. {
  1728. if (m_pCamera != NULL)
  1729. {
  1730. m_pCamera->Pitch(flDegrees);
  1731. }
  1732. }
  1733. //-----------------------------------------------------------------------------
  1734. // Purpose: Yaws the camera left by flDegrees degrees. Negative units yaw right.
  1735. //-----------------------------------------------------------------------------
  1736. void CMapView3D::Yaw(float flDegrees)
  1737. {
  1738. if (m_pCamera != NULL)
  1739. {
  1740. m_pCamera->Yaw(flDegrees);
  1741. }
  1742. }
  1743. void CMapView3D::WorldToClient(Vector2D &vClient, const Vector &vWorld)
  1744. {
  1745. m_pCamera->WorldToView( vWorld, vClient );
  1746. }
  1747. void CMapView3D::ClientToWorld(Vector &vWorld, const Vector2D &vClient)
  1748. {
  1749. m_pCamera->ViewToWorld( vClient, vWorld );
  1750. }
  1751. void CMapView3D::SetCursor( vgui::HCursor hCursor )
  1752. {
  1753. // translate VGUI -> GDI cursors
  1754. switch( hCursor )
  1755. {
  1756. case vgui::dc_arrow : ::SetCursor(AfxGetApp()->LoadStandardCursor(IDC_ARROW)); break;
  1757. case vgui::dc_sizenwse : ::SetCursor(AfxGetApp()->LoadStandardCursor(IDC_SIZENWSE)); break;
  1758. case vgui::dc_sizenesw : ::SetCursor(AfxGetApp()->LoadStandardCursor(IDC_SIZENESW)); break;
  1759. case vgui::dc_sizewe : ::SetCursor(AfxGetApp()->LoadStandardCursor(IDC_SIZEWE)); break;
  1760. case vgui::dc_sizens : ::SetCursor(AfxGetApp()->LoadStandardCursor(IDC_SIZENS)); break;
  1761. case vgui::dc_sizeall : ::SetCursor(AfxGetApp()->LoadStandardCursor(IDC_SIZEALL)); break;
  1762. case vgui::dc_crosshair : ::SetCursor(AfxGetApp()->LoadStandardCursor(IDC_CROSS)); break;
  1763. default : ::SetCursor(AfxGetApp()->LoadStandardCursor(IDC_ARROW)); break;
  1764. }
  1765. }
  1766. LRESULT CMapView3D::WindowProc( UINT message, WPARAM wParam, LPARAM lParam )
  1767. {
  1768. switch ( message )
  1769. {
  1770. case WM_KILLFOCUS:
  1771. m_Keyboard.ClearKeyStates();
  1772. // Msg( mwStatus, "debug: lost focus, clearing key states\n");
  1773. break;
  1774. }
  1775. return CView::WindowProc( message, wParam, lParam ) ;
  1776. }