Viewport.cpp 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991
  1. /*
  2. * Copyright (c) Contributors to the Open 3D Engine Project.
  3. * For complete copyright and license terms please see the LICENSE at the root of this distribution.
  4. *
  5. * SPDX-License-Identifier: Apache-2.0 OR MIT
  6. *
  7. */
  8. #include "EditorDefs.h"
  9. #include "Viewport.h"
  10. // Qt
  11. #include <QPainter>
  12. // AzQtComponents
  13. #include <AzQtComponents/DragAndDrop/ViewportDragAndDrop.h>
  14. #include <AzCore/Math/IntersectSegment.h>
  15. // AzToolsFramework
  16. #include <AzToolsFramework/API/ComponentEntitySelectionBus.h>
  17. #include <AzToolsFramework/Viewport/ViewportMessages.h>
  18. #include <AzToolsFramework/ViewportSelection/EditorSelectionUtil.h>
  19. // Editor
  20. #include "Editor/Plugins/ComponentEntityEditorPlugin/SandboxIntegration.h"
  21. #include "ViewManager.h"
  22. #include "Include/HitContext.h"
  23. #include "Util/3DConnexionDriver.h"
  24. #include "PluginManager.h"
  25. #include "GameEngine.h"
  26. #include "Settings.h"
  27. #include <Editor/EditorViewportSettings.h>
  28. #ifdef LoadCursor
  29. #undef LoadCursor
  30. #endif
  31. //////////////////////////////////////////////////////////////////////
  32. // Viewport drag and drop support
  33. //////////////////////////////////////////////////////////////////////
  34. void QtViewport::BuildDragDropContext(
  35. AzQtComponents::ViewportDragContext& context, const AzFramework::ViewportId viewportId, const QPoint& point)
  36. {
  37. context.m_hitLocation = AzToolsFramework::FindClosestPickIntersection(
  38. viewportId,
  39. AzToolsFramework::ViewportInteraction::ScreenPointFromQPoint(point * devicePixelRatioF()),
  40. AzToolsFramework::EditorPickRayLength,
  41. AzToolsFramework::GetDefaultEntityPlacementDistance());
  42. }
  43. void QtViewport::dragEnterEvent(QDragEnterEvent* event)
  44. {
  45. if (!GetIEditor()->GetGameEngine()->IsLevelLoaded())
  46. {
  47. return;
  48. }
  49. // first use the legacy pathway, which assumes its always okay as long as any callback is installed
  50. if (m_dropCallback)
  51. {
  52. event->setDropAction(Qt::CopyAction);
  53. event->setAccepted(true);
  54. }
  55. else
  56. {
  57. // new bus-based way of doing it (install a listener!)
  58. using namespace AzQtComponents;
  59. ViewportDragContext context;
  60. BuildDragDropContext(context, GetViewportId(), event->pos());
  61. DragAndDropEventsBus::Event(DragAndDropContexts::EditorViewport, &DragAndDropEvents::DragEnter, event, context);
  62. }
  63. }
  64. void QtViewport::dragMoveEvent(QDragMoveEvent* event)
  65. {
  66. if (!GetIEditor()->GetGameEngine()->IsLevelLoaded())
  67. {
  68. return;
  69. }
  70. // first use the legacy pathway, which assumes its always okay as long as any callback is installed
  71. if (m_dropCallback)
  72. {
  73. event->setDropAction(Qt::CopyAction);
  74. event->setAccepted(true);
  75. }
  76. else
  77. {
  78. // new bus-based way of doing it (install a listener!)
  79. using namespace AzQtComponents;
  80. ViewportDragContext context;
  81. BuildDragDropContext(context, GetViewportId(), event->pos());
  82. DragAndDropEventsBus::Event(DragAndDropContexts::EditorViewport, &DragAndDropEvents::DragMove, event, context);
  83. }
  84. }
  85. void QtViewport::dropEvent(QDropEvent* event)
  86. {
  87. using namespace AzQtComponents;
  88. if (!GetIEditor()->GetGameEngine()->IsLevelLoaded())
  89. {
  90. return;
  91. }
  92. // first use the legacy pathway, which assumes its always okay as long as any callback is installed
  93. if (m_dropCallback)
  94. {
  95. m_dropCallback(this, event->pos().x(), event->pos().y(), m_dropCallbackCustom);
  96. event->setAccepted(true);
  97. }
  98. else
  99. {
  100. // new bus-based way of doing it (install a listener!)
  101. ViewportDragContext context;
  102. BuildDragDropContext(context, GetViewportId(), event->pos());
  103. DragAndDropEventsBus::Event(DragAndDropContexts::EditorViewport, &DragAndDropEvents::Drop, event, context);
  104. if (event->isAccepted())
  105. {
  106. // send focus to whatever window accepted it. Its not necessarily this window, as it might be a child embedded in it.
  107. QWidget* widget = qApp->widgetAt(event->pos());
  108. if (widget)
  109. {
  110. widget->setFocus(Qt::MouseFocusReason);
  111. }
  112. }
  113. }
  114. }
  115. void QtViewport::dragLeaveEvent(QDragLeaveEvent* event)
  116. {
  117. using namespace AzQtComponents;
  118. DragAndDropEventsBus::Event(DragAndDropContexts::EditorViewport, &DragAndDropEvents::DragLeave, event);
  119. }
  120. //////////////////////////////////////////////////////////////////////////
  121. float CViewport::GetFOV() const
  122. {
  123. return SandboxEditor::CameraDefaultFovRadians();
  124. }
  125. //////////////////////////////////////////////////////////////////////
  126. // Construction/Destruction
  127. //////////////////////////////////////////////////////////////////////
  128. bool QtViewport::m_bDegradateQuality = false;
  129. QtViewport::QtViewport(QWidget* parent)
  130. : QWidget(parent)
  131. , m_renderOverlay(this)
  132. {
  133. m_cViewMenu.addMenu(tr("&View Options"))->addAction(tr("&Fullscreen"));
  134. //connect(action, &QAction::triggered, );
  135. m_selectionTolerance = 0;
  136. m_fGridZoom = 1.0f;
  137. m_nLastUpdateFrame = 0;
  138. m_nLastMouseMoveFrame = 0;
  139. //////////////////////////////////////////////////////////////////////////
  140. // Init standard cursors.
  141. //////////////////////////////////////////////////////////////////////////
  142. m_hCurrCursor = QCursor();
  143. m_hCursor[STD_CURSOR_DEFAULT] = QCursor(Qt::ArrowCursor);
  144. m_hCursor[STD_CURSOR_HIT] = CMFCUtils::LoadCursor(IDC_POINTER_OBJHIT);
  145. m_hCursor[STD_CURSOR_MOVE] = CMFCUtils::LoadCursor(IDC_POINTER_OBJECT_MOVE);
  146. m_hCursor[STD_CURSOR_ROTATE] = CMFCUtils::LoadCursor(IDC_POINTER_OBJECT_ROTATE);
  147. m_hCursor[STD_CURSOR_SCALE] = CMFCUtils::LoadCursor(IDC_POINTER_OBJECT_SCALE);
  148. m_hCursor[STD_CURSOR_SEL_PLUS] = CMFCUtils::LoadCursor(IDC_POINTER_PLUS);
  149. m_hCursor[STD_CURSOR_SEL_MINUS] = CMFCUtils::LoadCursor(IDC_POINTER_MINUS);
  150. m_hCursor[STD_CURSOR_SUBOBJ_SEL] = CMFCUtils::LoadCursor(IDC_POINTER_SO_SELECT);
  151. m_hCursor[STD_CURSOR_SUBOBJ_SEL_PLUS] = CMFCUtils::LoadCursor(IDC_POINTER_SO_SELECT_PLUS);
  152. m_hCursor[STD_CURSOR_SUBOBJ_SEL_MINUS] = CMFCUtils::LoadCursor(IDC_POINTER_SO_SELECT_MINUS);
  153. m_activeAxis = AXIS_TERRAIN;
  154. m_screenTM.SetIdentity();
  155. m_bAdvancedSelectMode = false;
  156. GetIEditor()->GetViewManager()->RegisterViewport(this);
  157. m_nCurViewportID = MAX_NUM_VIEWPORTS - 1;
  158. m_dropCallback = nullptr; // Leroy@Conffx
  159. setMouseTracking(true);
  160. setFocusPolicy(Qt::StrongFocus);
  161. // Create drop target to handle Qt drop events.
  162. setAcceptDrops(true);
  163. m_renderOverlay.setVisible(true);
  164. m_renderOverlay.setUpdatesEnabled(false);
  165. m_renderOverlay.setMouseTracking(true);
  166. m_renderOverlay.setObjectName("renderOverlay");
  167. m_renderOverlay.winId(); // Force the render overlay to create a backing native window
  168. m_viewportUi.InitializeViewportUi(this, &m_renderOverlay);
  169. setAcceptDrops(true);
  170. }
  171. //////////////////////////////////////////////////////////////////////////
  172. QtViewport::~QtViewport()
  173. {
  174. GetIEditor()->GetViewManager()->UnregisterViewport(this);
  175. }
  176. //////////////////////////////////////////////////////////////////////////
  177. void QtViewport::ScreenToClient(QPoint& pPoint) const
  178. {
  179. pPoint = mapFromGlobal(pPoint);
  180. }
  181. //////////////////////////////////////////////////////////////////////////
  182. void QtViewport::GetDimensions(int* pWidth, int* pHeight) const
  183. {
  184. if (pWidth)
  185. {
  186. *pWidth = width();
  187. }
  188. if (pHeight)
  189. {
  190. *pHeight = height();
  191. }
  192. }
  193. //////////////////////////////////////////////////////////////////////////
  194. void QtViewport::AddPostRenderer(IPostRenderer* pPostRenderer)
  195. {
  196. stl::push_back_unique(m_postRenderers, pPostRenderer);
  197. }
  198. //////////////////////////////////////////////////////////////////////////
  199. bool QtViewport::RemovePostRenderer(IPostRenderer* pPostRenderer)
  200. {
  201. PostRenderers::iterator itr = m_postRenderers.begin();
  202. PostRenderers::iterator end = m_postRenderers.end();
  203. for (; itr != end; ++itr)
  204. {
  205. if (*itr == pPostRenderer)
  206. {
  207. break;
  208. }
  209. }
  210. if (itr != end)
  211. {
  212. m_postRenderers.erase(itr);
  213. return true;
  214. }
  215. return false;
  216. }
  217. //////////////////////////////////////////////////////////////////////////
  218. void QtViewport::OnMouseWheel([[maybe_unused]] Qt::KeyboardModifiers modifiers, short zDelta, [[maybe_unused]] const QPoint& pt)
  219. {
  220. if (zDelta != 0)
  221. {
  222. float z = GetZoomFactor() + (zDelta / 120.0f) * 0.5f;
  223. SetZoomFactor(z);
  224. GetIEditor()->GetViewManager()->SetZoomFactor(z);
  225. }
  226. }
  227. //////////////////////////////////////////////////////////////////////////
  228. QString QtViewport::GetName() const
  229. {
  230. return windowTitle();
  231. }
  232. //////////////////////////////////////////////////////////////////////////
  233. void QtViewport::SetName(const QString& name)
  234. {
  235. setWindowTitle(name);
  236. }
  237. //////////////////////////////////////////////////////////////////////////
  238. void QtViewport::resizeEvent(QResizeEvent* event)
  239. {
  240. QWidget::resizeEvent(event);
  241. m_renderOverlay.setGeometry(rect());
  242. Update();
  243. }
  244. //////////////////////////////////////////////////////////////////////////
  245. void QtViewport::paintEvent([[maybe_unused]] QPaintEvent* event)
  246. {
  247. QPainter painter(this);
  248. // Fill the entire client area
  249. painter.fillRect(rect(), QColor(0xf0, 0xf0, 0xf0));
  250. }
  251. //////////////////////////////////////////////////////////////////////////
  252. void QtViewport::OnActivate()
  253. {
  254. ////////////////////////////////////////////////////////////////////////
  255. // Make this edit window the current one
  256. ////////////////////////////////////////////////////////////////////////
  257. }
  258. //////////////////////////////////////////////////////////////////////////
  259. void QtViewport::OnDeactivate()
  260. {
  261. }
  262. //////////////////////////////////////////////////////////////////////////
  263. void QtViewport::ResetContent()
  264. {
  265. }
  266. //////////////////////////////////////////////////////////////////////////
  267. void QtViewport::UpdateContent(int flags)
  268. {
  269. if (flags & eRedrawViewports)
  270. {
  271. update();
  272. }
  273. }
  274. //////////////////////////////////////////////////////////////////////////
  275. void QtViewport::Update()
  276. {
  277. m_viewportUi.Update();
  278. m_bAdvancedSelectMode = false;
  279. if (CheckVirtualKey(Qt::Key_Space) && !CheckVirtualKey(Qt::Key_Shift) && hasFocus())
  280. {
  281. m_bAdvancedSelectMode = true;
  282. }
  283. m_nLastUpdateFrame++;
  284. }
  285. //////////////////////////////////////////////////////////////////////////
  286. QPoint QtViewport::WorldToView(const Vec3& wp) const
  287. {
  288. return QPoint(static_cast<int>(wp.x), static_cast<int>(wp.y));
  289. }
  290. //////////////////////////////////////////////////////////////////////////
  291. Vec3 QtViewport::WorldToView3D(const Vec3& wp, [[maybe_unused]] int nFlags) const
  292. {
  293. QPoint p = WorldToView(wp);
  294. Vec3 out;
  295. out.x = static_cast<f32>(p.x());
  296. out.y = static_cast<f32>(p.y());
  297. out.z = wp.z;
  298. return out;
  299. }
  300. //////////////////////////////////////////////////////////////////////////
  301. Vec3 QtViewport::ViewToWorld(const QPoint& vp, bool* pCollideWithTerrain, [[maybe_unused]] bool onlyTerrain, [[maybe_unused]] bool bSkipVegetation, [[maybe_unused]] bool bTestRenderMesh, [[maybe_unused]] bool* collideWithObject) const
  302. {
  303. Vec3 wp;
  304. wp.x = static_cast<f32>(vp.x());
  305. wp.y = static_cast<f32>(vp.y());
  306. wp.z = 0;
  307. if (pCollideWithTerrain)
  308. {
  309. *pCollideWithTerrain = true;
  310. }
  311. return wp;
  312. }
  313. //////////////////////////////////////////////////////////////////////////
  314. Vec3 QtViewport::ViewToWorldNormal([[maybe_unused]] const QPoint& vp, [[maybe_unused]] bool onlyTerrain, [[maybe_unused]] bool bTestRenderMesh)
  315. {
  316. return Vec3(0, 0, 0);
  317. }
  318. //////////////////////////////////////////////////////////////////////////
  319. void QtViewport::ViewToWorldRay([[maybe_unused]] const QPoint& vp, Vec3& raySrc, Vec3& rayDir) const
  320. {
  321. raySrc(0, 0, 0);
  322. rayDir(0, 0, -1);
  323. }
  324. void QtViewport::mousePressEvent(QMouseEvent* event)
  325. {
  326. switch (event->button())
  327. {
  328. case Qt::LeftButton:
  329. OnLButtonDown(event->modifiers(), event->pos());
  330. break;
  331. case Qt::MiddleButton:
  332. OnMButtonDown(event->modifiers(), event->pos());
  333. break;
  334. case Qt::RightButton:
  335. OnRButtonDown(event->modifiers(), event->pos());
  336. break;
  337. }
  338. }
  339. void QtViewport::mouseReleaseEvent(QMouseEvent* event)
  340. {
  341. switch (event->button())
  342. {
  343. case Qt::LeftButton:
  344. OnLButtonUp(event->modifiers(), event->pos());
  345. break;
  346. case Qt::MiddleButton:
  347. OnMButtonUp(event->modifiers(), event->pos());
  348. break;
  349. case Qt::RightButton:
  350. OnRButtonUp(event->modifiers(), event->pos());
  351. break;
  352. }
  353. // For MFC compatibility, send a spurious move event after a button release.
  354. // CryDesigner depends on this behaviour
  355. mouseMoveEvent(event);
  356. }
  357. void QtViewport::mouseDoubleClickEvent(QMouseEvent* event)
  358. {
  359. switch (event->button())
  360. {
  361. case Qt::LeftButton:
  362. OnLButtonDblClk(event->modifiers(), event->pos());
  363. break;
  364. case Qt::MiddleButton:
  365. OnMButtonDblClk(event->modifiers(), event->pos());
  366. break;
  367. case Qt::RightButton:
  368. OnRButtonDblClk(event->modifiers(), event->pos());
  369. break;
  370. }
  371. }
  372. void QtViewport::mouseMoveEvent(QMouseEvent* event)
  373. {
  374. OnMouseMove(event->modifiers(), event->buttons(), event->pos());
  375. OnSetCursor();
  376. }
  377. void QtViewport::wheelEvent(QWheelEvent* event)
  378. {
  379. OnMouseWheel(event->modifiers(), static_cast<short>(event->angleDelta().y()), event->position().toPoint());
  380. event->accept();
  381. }
  382. void QtViewport::keyPressEvent(QKeyEvent* event)
  383. {
  384. int nativeKey = event->nativeVirtualKey();
  385. #if AZ_TRAIT_OS_PLATFORM_APPLE
  386. // nativeVirtualKey is always zero on macOS, therefore we
  387. // need to manually set the nativeKey based on the Qt key
  388. switch (event->key())
  389. {
  390. case Qt::Key_Control:
  391. nativeKey = VK_CONTROL;
  392. break;
  393. case Qt::Key_Alt:
  394. nativeKey = VK_MENU;
  395. break;
  396. case Qt::Key_QuoteLeft:
  397. nativeKey = VK_OEM_3;
  398. break;
  399. case Qt::Key_BracketLeft:
  400. nativeKey = VK_OEM_4;
  401. break;
  402. case Qt::Key_BracketRight:
  403. nativeKey = VK_OEM_6;
  404. break;
  405. case Qt::Key_Comma:
  406. nativeKey = VK_OEM_COMMA;
  407. break;
  408. case Qt::Key_Period:
  409. nativeKey = VK_OEM_PERIOD;
  410. break;
  411. case Qt::Key_Escape:
  412. nativeKey = VK_ESCAPE;
  413. break;
  414. }
  415. #endif
  416. OnKeyDown(nativeKey, 1, event->nativeModifiers());
  417. }
  418. void QtViewport::keyReleaseEvent(QKeyEvent* event)
  419. {
  420. int nativeKey = event->nativeVirtualKey();
  421. #if AZ_TRAIT_OS_PLATFORM_APPLE
  422. // nativeVirtualKey is always zero on macOS, therefore we
  423. // need to manually set the nativeKey based on the Qt key
  424. switch (event->key())
  425. {
  426. case Qt::Key_Control:
  427. nativeKey = VK_CONTROL;
  428. break;
  429. case Qt::Key_Alt:
  430. nativeKey = VK_MENU;
  431. break;
  432. case Qt::Key_QuoteLeft:
  433. nativeKey = VK_OEM_3;
  434. break;
  435. case Qt::Key_BracketLeft:
  436. nativeKey = VK_OEM_4;
  437. break;
  438. case Qt::Key_BracketRight:
  439. nativeKey = VK_OEM_6;
  440. break;
  441. case Qt::Key_Comma:
  442. nativeKey = VK_OEM_COMMA;
  443. break;
  444. case Qt::Key_Period:
  445. nativeKey = VK_OEM_PERIOD;
  446. break;
  447. case Qt::Key_Escape:
  448. nativeKey = VK_ESCAPE;
  449. break;
  450. }
  451. #endif
  452. OnKeyUp(nativeKey, 1, event->nativeModifiers());
  453. }
  454. //////////////////////////////////////////////////////////////////////////
  455. void QtViewport::OnSetCursor()
  456. {
  457. }
  458. //////////////////////////////////////////////////////////////////////////
  459. void QtViewport::ResetSelectionRegion()
  460. {
  461. AABB box(Vec3(0, 0, 0), Vec3(0, 0, 0));
  462. m_selectedRect = QRect();
  463. }
  464. void QtViewport::SetSelectionRectangle(const QRect& rect)
  465. {
  466. m_selectedRect = rect.normalized();
  467. }
  468. //////////////////////////////////////////////////////////////////////////
  469. void QtViewport::OnDragSelectRectangle(const QRect& rect, bool bNormalizeRect)
  470. {
  471. Vec3 org;
  472. AABB box;
  473. box.Reset();
  474. //adjust QRect bottom and right corner once before extracting bottom/right coordinates
  475. const QRect correctedRect = rect.adjusted(0, 0, 1, 1);
  476. Vec3 p1 = ViewToWorld(correctedRect.topLeft());
  477. Vec3 p2 = ViewToWorld(correctedRect.bottomRight());
  478. org = p1;
  479. // Calculate selection volume.
  480. if (!bNormalizeRect)
  481. {
  482. box.Add(p1);
  483. box.Add(p2);
  484. }
  485. else
  486. {
  487. const QRect rc = correctedRect.normalized();
  488. box.Add(ViewToWorld(rc.topLeft()));
  489. box.Add(ViewToWorld(rc.topRight()));
  490. box.Add(ViewToWorld(rc.bottomLeft()));
  491. box.Add(ViewToWorld(rc.bottomRight()));
  492. }
  493. box.min.z = -10000;
  494. box.max.z = 10000;
  495. // Show marker position in the status bar
  496. float w = box.max.x - box.min.x;
  497. float h = box.max.y - box.min.y;
  498. char szNewStatusText[512];
  499. sprintf_s(szNewStatusText, "X:%g Y:%g Z:%g W:%g H:%g", org.x, org.y, org.z, w, h);
  500. GetIEditor()->SetStatusText(szNewStatusText);
  501. }
  502. //////////////////////////////////////////////////////////////////////////
  503. void QtViewport::SetCurrentCursor(const QCursor& hCursor, const QString& cursorString)
  504. {
  505. setCursor(hCursor);
  506. m_cursorStr = cursorString;
  507. }
  508. //////////////////////////////////////////////////////////////////////////
  509. void QtViewport::SetCurrentCursor(EStdCursor stdCursor, const QString& cursorString)
  510. {
  511. QCursor hCursor = m_hCursor[stdCursor];
  512. setCursor(hCursor);
  513. m_cursorStr = cursorString;
  514. }
  515. void QtViewport::SetSupplementaryCursorStr(const QString& str)
  516. {
  517. m_cursorSupplementaryStr = str;
  518. }
  519. //////////////////////////////////////////////////////////////////////////
  520. void QtViewport::SetCurrentCursor(EStdCursor stdCursor)
  521. {
  522. QCursor hCursor = m_hCursor[stdCursor];
  523. setCursor(hCursor);
  524. }
  525. //////////////////////////////////////////////////////////////////////////
  526. void QtViewport::SetCursorString(const QString& cursorString)
  527. {
  528. m_cursorStr = cursorString;
  529. }
  530. //////////////////////////////////////////////////////////////////////////
  531. void QtViewport::ResetCursor()
  532. {
  533. SetCurrentCursor(STD_CURSOR_DEFAULT, QString());
  534. }
  535. //////////////////////////////////////////////////////////////////////////
  536. HWND QtViewport::renderOverlayHWND() const
  537. {
  538. return reinterpret_cast<HWND>(m_renderOverlay.winId());
  539. }
  540. //////////////////////////////////////////////////////////////////////////
  541. void QtViewport::setRenderOverlayVisible(bool visible)
  542. {
  543. m_renderOverlay.setVisible(visible);
  544. }
  545. bool QtViewport::isRenderOverlayVisible() const
  546. {
  547. return m_renderOverlay.isVisible();
  548. }
  549. //////////////////////////////////////////////////////////////////////////
  550. void QtViewport::SetAxisConstrain(int axis)
  551. {
  552. m_activeAxis = axis;
  553. };
  554. AzToolsFramework::ViewportInteraction::MouseInteraction QtViewport::BuildMouseInteraction(
  555. [[maybe_unused]] Qt::MouseButtons buttons, [[maybe_unused]] Qt::KeyboardModifiers modifiers, [[maybe_unused]] const QPoint& point)
  556. {
  557. // Implemented by sub-class
  558. return AzToolsFramework::ViewportInteraction::MouseInteraction();
  559. }
  560. //////////////////////////////////////////////////////////////////////////
  561. bool QtViewport::HitTest(const QPoint& point, HitContext& hitInfo)
  562. {
  563. Vec3 raySrc(0, 0, 0), rayDir(1, 0, 0);
  564. ViewToWorldRay(point, hitInfo.raySrc, hitInfo.rayDir);
  565. hitInfo.view = this;
  566. hitInfo.point2d = point;
  567. if (m_bAdvancedSelectMode)
  568. {
  569. hitInfo.bUseSelectionHelpers = true;
  570. }
  571. const int viewportId = GetViewportId();
  572. AzToolsFramework::EntityIdList visibleEntityIds;
  573. AzToolsFramework::ViewportInteraction::EditorEntityViewportInteractionRequestBus::Event(
  574. viewportId, &AzToolsFramework::ViewportInteraction::EditorEntityViewportInteractionRequestBus::Events::FindVisibleEntities,
  575. visibleEntityIds);
  576. // Look through all visible entities to find the closest one to the specified mouse point
  577. using namespace AzToolsFramework::ViewportInteraction;
  578. AZ::EntityId entityIdUnderCursor;
  579. float closestDistance = std::numeric_limits<float>::max();
  580. MouseInteraction mouseInteraction = BuildMouseInteraction(QGuiApplication::mouseButtons(),
  581. QGuiApplication::queryKeyboardModifiers(),
  582. point);
  583. for (auto entityId : visibleEntityIds)
  584. {
  585. using AzFramework::ViewportInfo;
  586. // Check if components provide an aabb
  587. if (const AZ::Aabb aabb = AzToolsFramework::CalculateEditorEntitySelectionBounds(entityId, ViewportInfo{ viewportId });
  588. aabb.IsValid())
  589. {
  590. // Coarse grain check
  591. if (AzToolsFramework::AabbIntersectMouseRay(mouseInteraction, aabb))
  592. {
  593. // If success, pick against specific component
  594. if (AzToolsFramework::PickEntity(
  595. entityId, mouseInteraction,
  596. closestDistance, viewportId))
  597. {
  598. entityIdUnderCursor = entityId;
  599. }
  600. }
  601. }
  602. }
  603. // If we hit a valid Entity, then store the distance in the HitContext
  604. // so that the caller can use this for calculations
  605. if (entityIdUnderCursor.IsValid())
  606. {
  607. hitInfo.dist = closestDistance;
  608. return true;
  609. }
  610. return false;
  611. }
  612. //////////////////////////////////////////////////////////////////////////
  613. void QtViewport::SetZoomFactor(float fZoomFactor)
  614. {
  615. m_fZoomFactor = fZoomFactor;
  616. if (gSettings.viewports.bSync2DViews && GetType() != ET_ViewportCamera && GetType() != ET_ViewportModel)
  617. {
  618. GetViewManager()->SetZoom2D(fZoomFactor);
  619. }
  620. };
  621. //////////////////////////////////////////////////////////////////////////
  622. float QtViewport::GetZoomFactor() const
  623. {
  624. if (gSettings.viewports.bSync2DViews && GetType() != ET_ViewportCamera && GetType() != ET_ViewportModel)
  625. {
  626. m_fZoomFactor = GetViewManager()->GetZoom2D();
  627. }
  628. return m_fZoomFactor;
  629. };
  630. //////////////////////////////////////////////////////////////////////////
  631. Vec3 QtViewport::SnapToGrid(const Vec3& vec)
  632. {
  633. return vec;
  634. }
  635. //////////////////////////////////////////////////////////////////////////
  636. void QtViewport::BeginUndo()
  637. {
  638. DegradateQuality(true);
  639. GetIEditor()->BeginUndo();
  640. }
  641. //////////////////////////////////////////////////////////////////////////
  642. void QtViewport::AcceptUndo(const QString& undoDescription)
  643. {
  644. DegradateQuality(false);
  645. GetIEditor()->AcceptUndo(undoDescription);
  646. GetIEditor()->UpdateViews(eUpdateObjects);
  647. }
  648. //////////////////////////////////////////////////////////////////////////
  649. void QtViewport::CancelUndo()
  650. {
  651. DegradateQuality(false);
  652. GetIEditor()->CancelUndo();
  653. GetIEditor()->UpdateViews(eUpdateObjects);
  654. }
  655. //////////////////////////////////////////////////////////////////////////
  656. void QtViewport::RestoreUndo()
  657. {
  658. GetIEditor()->RestoreUndo();
  659. }
  660. //////////////////////////////////////////////////////////////////////////
  661. bool QtViewport::IsUndoRecording() const
  662. {
  663. return GetIEditor()->IsUndoRecording();
  664. }
  665. //////////////////////////////////////////////////////////////////////////
  666. void QtViewport::DegradateQuality(bool bEnable)
  667. {
  668. m_bDegradateQuality = bEnable;
  669. }
  670. //////////////////////////////////////////////////////////////////////////
  671. QSize QtViewport::GetIdealSize() const
  672. {
  673. return QSize(0, 0);
  674. }
  675. //////////////////////////////////////////////////////////////////////////
  676. bool QtViewport::IsBoundsVisible([[maybe_unused]] const AABB& box) const
  677. {
  678. // Always visible in standard implementation.
  679. return true;
  680. }
  681. //////////////////////////////////////////////////////////////////////////
  682. float QtViewport::GetDistanceToLine(const Vec3& lineP1, const Vec3& lineP2, const QPoint& point) const
  683. {
  684. QPoint p1 = WorldToView(lineP1);
  685. QPoint p2 = WorldToView(lineP2);
  686. return AZ::Intersect::PointSegmentDistanceSq(
  687. AZ::Vector3(static_cast<f32>(point.x()), static_cast<f32>(point.y()), 0.0f),
  688. AZ::Vector3(static_cast<f32>(p1.x()), static_cast<f32>(p1.y()), 0.0f),
  689. AZ::Vector3(static_cast<f32>(p2.x()), static_cast<f32>(p2.y()), 0.0f)
  690. );
  691. }
  692. //////////////////////////////////////////////////////////////////////////
  693. void QtViewport::GetPerpendicularAxis(EAxis* pAxis, bool* pIs2D) const
  694. {
  695. EViewportType vpType = GetType();
  696. switch (vpType)
  697. {
  698. case ET_ViewportXY:
  699. if (pIs2D)
  700. {
  701. *pIs2D = true;
  702. }
  703. if (pAxis)
  704. {
  705. *pAxis = AXIS_Z;
  706. }
  707. break;
  708. case ET_ViewportXZ:
  709. if (pIs2D)
  710. {
  711. *pIs2D = true;
  712. }
  713. if (pAxis)
  714. {
  715. *pAxis = AXIS_Y;
  716. }
  717. break;
  718. case ET_ViewportYZ:
  719. if (pIs2D)
  720. {
  721. *pIs2D = true;
  722. }
  723. if (pAxis)
  724. {
  725. *pAxis = AXIS_X;
  726. }
  727. break;
  728. case ET_ViewportMap:
  729. case ET_ViewportZ:
  730. if (pIs2D)
  731. {
  732. *pIs2D = true;
  733. }
  734. break;
  735. }
  736. }
  737. //////////////////////////////////////////////////////////////////////////
  738. bool QtViewport::GetAdvancedSelectModeFlag()
  739. {
  740. return m_bAdvancedSelectMode;
  741. }
  742. //////////////////////////////////////////////////////////////////////////
  743. #if defined(AZ_PLATFORM_WINDOWS)
  744. // Note: Both CreateAnglesYPR and CreateOrientationYPR were copied verbatim from Cry_Camera.h which has been removed.
  745. //
  746. // Description
  747. // <PRE>
  748. // x-YAW
  749. // y-PITCH (negative=looking down / positive=looking up)
  750. // z-ROLL
  751. // </PRE>
  752. // Note: If we are looking along the z-axis, its not possible to specify the x and z-angle
  753. inline Ang3 CreateAnglesYPR(const Matrix33& m)
  754. {
  755. assert(m.IsOrthonormal());
  756. float l = Vec3(m.m01, m.m11, 0.0f).GetLength();
  757. if (l > 0.0001)
  758. {
  759. return Ang3(atan2f(-m.m01 / l, m.m11 / l), atan2f(m.m21, l), atan2f(-m.m20 / l, m.m22 / l));
  760. }
  761. else
  762. {
  763. return Ang3(0, atan2f(m.m21, l), 0);
  764. }
  765. }
  766. // Description
  767. // This function builds a 3x3 orientation matrix using YPR-angles
  768. // Rotation order for the orientation-matrix is Z-X-Y. (Zaxis=YAW / Xaxis=PITCH / Yaxis=ROLL)
  769. //
  770. // <PRE>
  771. // COORDINATE-SYSTEM
  772. //
  773. // z-axis
  774. // ^
  775. // |
  776. // | y-axis
  777. // | /
  778. // | /
  779. // |/
  780. // +---------------> x-axis
  781. // </PRE>
  782. //
  783. // Example:
  784. // Matrix33 orientation=CreateOrientationYPR( Ang3(1,2,3) );
  785. inline Matrix33 CreateOrientationYPR(const Ang3& ypr)
  786. {
  787. f32 sz, cz;
  788. sincos_tpl(ypr.x, &sz, &cz); //Zaxis = YAW
  789. f32 sx, cx;
  790. sincos_tpl(ypr.y, &sx, &cx); //Xaxis = PITCH
  791. f32 sy, cy;
  792. sincos_tpl(ypr.z, &sy, &cy); //Yaxis = ROLL
  793. Matrix33 c;
  794. c.m00 = cy * cz - sy * sz * sx;
  795. c.m01 = -sz * cx;
  796. c.m02 = sy * cz + cy * sz * sx;
  797. c.m10 = cy * sz + sy * sx * cz;
  798. c.m11 = cz * cx;
  799. c.m12 = sy * sz - cy * sx * cz;
  800. c.m20 = -sy * cx;
  801. c.m21 = sx;
  802. c.m22 = cy * cx;
  803. return c;
  804. }
  805. void QtViewport::OnRawInput([[maybe_unused]] UINT wParam, HRAWINPUT lParam)
  806. {
  807. static C3DConnexionDriver* p3DConnexionDriver = 0;
  808. if (GetType() == ET_ViewportCamera)
  809. {
  810. if (!p3DConnexionDriver)
  811. {
  812. p3DConnexionDriver = (C3DConnexionDriver*)GetIEditor()->GetPluginManager()->GetPluginByGUID("{AD109901-9128-4ffd-8E67-137CB2B1C41B}");
  813. }
  814. if (p3DConnexionDriver)
  815. {
  816. S3DConnexionMessage msg;
  817. if (p3DConnexionDriver->GetInputMessageData((LPARAM)lParam, msg))
  818. {
  819. if (msg.bGotTranslation || msg.bGotRotation)
  820. {
  821. static int all6DOFs[6] = { 0 };
  822. if (msg.bGotTranslation)
  823. {
  824. all6DOFs[0] = msg.raw_translation[0];
  825. all6DOFs[1] = msg.raw_translation[1];
  826. all6DOFs[2] = msg.raw_translation[2];
  827. }
  828. if (msg.bGotRotation)
  829. {
  830. all6DOFs[3] = msg.raw_rotation[0];
  831. all6DOFs[4] = msg.raw_rotation[1];
  832. all6DOFs[5] = msg.raw_rotation[2];
  833. }
  834. Matrix34 viewTM = GetViewTM();
  835. // Scale axis according to CVars
  836. ICVar* sys_scale3DMouseTranslation = gEnv->pConsole->GetCVar("sys_scale3DMouseTranslation");
  837. ICVar* sys_Scale3DMouseYPR = gEnv->pConsole->GetCVar("sys_Scale3DMouseYPR");
  838. float fScaleYPR = sys_Scale3DMouseYPR->GetFVal();
  839. float s = 0.01f * gSettings.cameraMoveSpeed;
  840. Vec3 t = Vec3(s * all6DOFs[0], -s * all6DOFs[1], -s * all6DOFs[2] * 0.5f);
  841. t *= sys_scale3DMouseTranslation->GetFVal();
  842. float as = 0.001f * gSettings.cameraMoveSpeed;
  843. Ang3 ypr = CreateAnglesYPR(Matrix33(viewTM));
  844. ypr.x += -all6DOFs[5] * as * fScaleYPR;
  845. ypr.y = AZStd::clamp(ypr.y + all6DOFs[3] * as * fScaleYPR, -1.5f, 1.5f); // to keep rotation in reasonable range
  846. ypr.z = 0; // to have camera always upward
  847. viewTM = Matrix34(CreateOrientationYPR(ypr), viewTM.GetTranslation());
  848. viewTM = viewTM * Matrix34::CreateTranslationMat(t);
  849. SetViewTM(viewTM);
  850. }
  851. }
  852. }
  853. }
  854. }
  855. #endif
  856. //////////////////////////////////////////////////////////////////////////
  857. float QtViewport::GetFOV() const
  858. {
  859. return SandboxEditor::CameraDefaultFovRadians();
  860. }
  861. //////////////////////////////////////////////////////////////////////////
  862. void QtViewport::setRay(QPoint& vp, Vec3& raySrc, Vec3& rayDir)
  863. {
  864. m_vp = vp;
  865. m_raySrc = raySrc;
  866. m_rayDir = rayDir;
  867. }
  868. #include <moc_Viewport.cpp>