diff --git a/AutomatedTesting/Gem/PythonTests/editor/EditorScripts/Menus_EditMenuOptions.py b/AutomatedTesting/Gem/PythonTests/editor/EditorScripts/Menus_EditMenuOptions.py index c7088a54c5..bd213be293 100644 --- a/AutomatedTesting/Gem/PythonTests/editor/EditorScripts/Menus_EditMenuOptions.py +++ b/AutomatedTesting/Gem/PythonTests/editor/EditorScripts/Menus_EditMenuOptions.py @@ -40,11 +40,12 @@ def Menus_EditMenuOptions_Work(): ("Toggle Pivot Location",), ("Reset Entity Transform",), ("Reset Manipulator",), - ("Reset Transform (Local)",), - ("Reset Transform (World)",), ("Hide Selection",), ("Show All",), - ("Modify", "Snap", "Snap angle"), + ("Lock Selection",), + ("Unlock All Entities",), + ("Modify", "Snap", "Angle snapping"), + ("Modify", "Snap", "Grid snapping"), ("Modify", "Transform Mode", "Move"), ("Modify", "Transform Mode", "Rotate"), ("Modify", "Transform Mode", "Scale"), diff --git a/AutomatedTesting/Gem/PythonTests/editor/EditorScripts/Menus_ViewMenuOptions.py b/AutomatedTesting/Gem/PythonTests/editor/EditorScripts/Menus_ViewMenuOptions.py index f1b9e5d4d8..deff2855a0 100644 --- a/AutomatedTesting/Gem/PythonTests/editor/EditorScripts/Menus_ViewMenuOptions.py +++ b/AutomatedTesting/Gem/PythonTests/editor/EditorScripts/Menus_ViewMenuOptions.py @@ -39,7 +39,8 @@ def Menus_ViewMenuOptions_Work(): ("Viewport", "Go to Location"), ("Viewport", "Remember Location"), ("Viewport", "Switch Camera"), - ("Viewport", "Show/Hide Helpers"), + ("Viewport", "Show Helpers"), + ("Viewport", "Show Icons"), ("Refresh Style",), ] diff --git a/Code/Editor/Core/LevelEditorMenuHandler.cpp b/Code/Editor/Core/LevelEditorMenuHandler.cpp index 70aff10f87..a90b0a597a 100644 --- a/Code/Editor/Core/LevelEditorMenuHandler.cpp +++ b/Code/Editor/Core/LevelEditorMenuHandler.cpp @@ -538,6 +538,7 @@ void LevelEditorMenuHandler::PopulateEditMenu(ActionManager::MenuWrapper& editMe auto snapMenu = modifyMenu.AddMenu(tr("Snap")); snapMenu.AddAction(AzToolsFramework::SnapAngle); + snapMenu.AddAction(AzToolsFramework::SnapToGrid); auto transformModeMenu = modifyMenu.AddMenu(tr("Transform Mode")); transformModeMenu.AddAction(AzToolsFramework::EditModeMove); @@ -723,7 +724,8 @@ QMenu* LevelEditorMenuHandler::CreateViewMenu() // MISSING AVIRECORDER viewportViewsMenuWrapper.AddSeparator(); - viewportViewsMenuWrapper.AddAction(ID_DISPLAY_SHOWHELPERS); + viewportViewsMenuWrapper.AddAction(AzToolsFramework::Helpers); + viewportViewsMenuWrapper.AddAction(AzToolsFramework::Icons); // Refresh Style viewMenu.AddAction(ID_SKINS_REFRESH); diff --git a/Code/Editor/CryEdit.cpp b/Code/Editor/CryEdit.cpp index 3890a9e59a..4415308730 100644 --- a/Code/Editor/CryEdit.cpp +++ b/Code/Editor/CryEdit.cpp @@ -445,7 +445,6 @@ void CCryEditApp::RegisterActionHandlers() ON_COMMAND(ID_OPEN_ASSET_BROWSER, OnOpenAssetBrowserView) ON_COMMAND(ID_OPEN_AUDIO_CONTROLS_BROWSER, OnOpenAudioControlsEditor) - ON_COMMAND(ID_DISPLAY_SHOWHELPERS, OnShowHelpers) ON_COMMAND(ID_OPEN_TRACKVIEW, OnOpenTrackView) ON_COMMAND(ID_OPEN_UICANVASEDITOR, OnOpenUICanvasEditor) @@ -2617,12 +2616,6 @@ void CCryEditApp::OnUpdateSelected(QAction* action) action->setEnabled(!GetIEditor()->GetSelection()->IsEmpty()); } -void CCryEditApp::OnShowHelpers() -{ - GetIEditor()->GetDisplaySettings()->DisplayHelpers(!GetIEditor()->GetDisplaySettings()->IsDisplayHelpers()); - GetIEditor()->Notify(eNotify_OnDisplayRenderUpdate); -} - ////////////////////////////////////////////////////////////////////////// void CCryEditApp::OnEditLevelData() { diff --git a/Code/Editor/CryEdit.h b/Code/Editor/CryEdit.h index 8c514170ae..97fcde8f34 100644 --- a/Code/Editor/CryEdit.h +++ b/Code/Editor/CryEdit.h @@ -237,7 +237,6 @@ public: void OnSyncPlayerUpdate(QAction* action); void OnResourcesReduceworkingset(); void OnDummyCommand() {}; - void OnShowHelpers(); void OnFileSave(); void OnUpdateDocumentReady(QAction* action); void OnUpdateFileOpen(QAction* action); diff --git a/Code/Editor/DisplaySettings.cpp b/Code/Editor/DisplaySettings.cpp index ed4ca180b4..bfeac3e37f 100644 --- a/Code/Editor/DisplaySettings.cpp +++ b/Code/Editor/DisplaySettings.cpp @@ -68,8 +68,6 @@ void CDisplaySettings::SetObjectHideMask(int hideMask) m_objectHideMask = hideMask; gSettings.objectHideMask = m_objectHideMask; - - GetIEditor()->Notify(eNotify_OnDisplayRenderUpdate); }; ////////////////////////////////////////////////////////////////////////// diff --git a/Code/Editor/EditorViewportWidget.cpp b/Code/Editor/EditorViewportWidget.cpp index 3f9ff03203..754ea84544 100644 --- a/Code/Editor/EditorViewportWidget.cpp +++ b/Code/Editor/EditorViewportWidget.cpp @@ -46,6 +46,7 @@ #include #include #include +#include #include #include @@ -1621,14 +1622,14 @@ Vec3 EditorViewportWidget::ViewToWorld( auto ray = m_renderViewport->ViewportScreenToWorldRay(AzToolsFramework::ViewportInteraction::ScreenPointFromQPoint(vp)); const float maxDistance = 10000.f; - Vec3 v = AZVec3ToLYVec3(ray.direction) * maxDistance; + Vec3 v = AZVec3ToLYVec3(ray.m_direction) * maxDistance; if (!_finite(v.x) || !_finite(v.y) || !_finite(v.z)) { return Vec3(0, 0, 0); } - Vec3 colp = AZVec3ToLYVec3(ray.origin) + 0.002f * v; + Vec3 colp = AZVec3ToLYVec3(ray.m_origin) + 0.002f * v; return colp; } @@ -2420,6 +2421,16 @@ AZ::Vector3 EditorViewportSettings::DefaultEditorCameraPosition() const return SandboxEditor::CameraDefaultEditorPosition(); } +bool EditorViewportSettings::IconsVisible() const +{ + return AzToolsFramework::IconsVisible(); +} + +bool EditorViewportSettings::HelpersVisible() const +{ + return AzToolsFramework::HelpersVisible(); +} + AZ_CVAR_EXTERNED(bool, ed_previewGameInFullscreen_once); bool EditorViewportWidget::ShouldPreviewFullscreen() const diff --git a/Code/Editor/EditorViewportWidget.h b/Code/Editor/EditorViewportWidget.h index 3d52b2416d..83ca655326 100644 --- a/Code/Editor/EditorViewportWidget.h +++ b/Code/Editor/EditorViewportWidget.h @@ -79,6 +79,8 @@ struct EditorViewportSettings : public AzToolsFramework::ViewportInteraction::Vi float ManipulatorCircleBoundWidth() const override; bool StickySelectEnabled() const override; AZ::Vector3 DefaultEditorCameraPosition() const override; + bool IconsVisible() const override; + bool HelpersVisible() const override; }; // EditorViewportWidget window diff --git a/Code/Editor/IEditor.h b/Code/Editor/IEditor.h index 48c8392f32..c6f72a7dbc 100644 --- a/Code/Editor/IEditor.h +++ b/Code/Editor/IEditor.h @@ -168,8 +168,6 @@ enum EEditorNotifyEvent eNotify_OnVegetationObjectSelection, // When vegetation objects selection change. eNotify_OnVegetationPanelUpdate, // When vegetation objects selection change. - eNotify_OnDisplayRenderUpdate, // Sent when editor finish terrain texture generation. - eNotify_OnDataBaseUpdate, // DataBase Library was modified. eNotify_OnLayerImportBegin, //layer import was started diff --git a/Code/Editor/MainWindow.cpp b/Code/Editor/MainWindow.cpp index 38e433c3a3..f92e39f285 100644 --- a/Code/Editor/MainWindow.cpp +++ b/Code/Editor/MainWindow.cpp @@ -47,6 +47,7 @@ AZ_POP_DISABLE_WARNING #include #include #include +#include #include // AzQtComponents @@ -445,11 +446,11 @@ void MainWindow::Initialize() { m_viewPaneManager->SetMainWindow(m_viewPaneHost, &m_settings, /*unused*/ QByteArray()); + InitActions(); + RegisterStdViewClasses(); InitCentralWidget(); - InitActions(); - // load toolbars ("shelves") and macros GetIEditor()->GetToolBoxManager()->Load(m_actionManager); @@ -798,27 +799,40 @@ void MainWindow::InitActions() EditorTransformComponentSelectionRequests::Mode::Scale); }); - am->AddAction(AzToolsFramework::SnapToGrid, tr("Snap to grid")) + am->AddAction(AzToolsFramework::SnapToGrid, tr("Grid snapping")) .SetIcon(Style::icon("Grid")) + .SetStatusTip(tr("Toggle grid snapping")) .SetShortcut(tr("G")) - .SetToolTip(tr("Snap to grid (G)")) - .SetStatusTip(tr("Toggles snap to grid")) .SetCheckable(true) - .RegisterUpdateCallback([](QAction* action) { - Q_ASSERT(action->isCheckable()); - action->setChecked(SandboxEditor::GridSnappingEnabled()); - }) - .Connect(&QAction::triggered, []() { SandboxEditor::SetGridSnapping(!SandboxEditor::GridSnappingEnabled()); }); + .RegisterUpdateCallback( + [](QAction* action) + { + Q_ASSERT(action->isCheckable()); + action->setChecked(SandboxEditor::GridSnappingEnabled()); + }) + .Connect( + &QAction::triggered, + [] + { + SandboxEditor::SetGridSnapping(!SandboxEditor::GridSnappingEnabled()); + }); - am->AddAction(AzToolsFramework::SnapAngle, tr("Snap angle")) + am->AddAction(AzToolsFramework::SnapAngle, tr("Angle snapping")) .SetIcon(Style::icon("Angle")) - .SetStatusTip(tr("Snap angle")) + .SetStatusTip(tr("Toggle angle snapping")) .SetCheckable(true) - .RegisterUpdateCallback([](QAction* action) { - Q_ASSERT(action->isCheckable()); - action->setChecked(SandboxEditor::AngleSnappingEnabled()); - }) - .Connect(&QAction::triggered, []() { SandboxEditor::SetAngleSnapping(!SandboxEditor::AngleSnappingEnabled()); }); + .RegisterUpdateCallback( + [](QAction* action) + { + Q_ASSERT(action->isCheckable()); + action->setChecked(SandboxEditor::AngleSnappingEnabled()); + }) + .Connect( + &QAction::triggered, + [] + { + SandboxEditor::SetAngleSnapping(!SandboxEditor::AngleSnappingEnabled()); + }); // Display actions am->AddAction(ID_SWITCHCAMERA_DEFAULTCAMERA, tr("Default Camera")).SetCheckable(true) @@ -918,9 +932,41 @@ void MainWindow::InitActions() .SetStatusTip(tr("Cycle 2D Viewport")) .RegisterUpdateCallback(cryEdit, &CCryEditApp::OnUpdateNonGameMode); #endif - am->AddAction(ID_DISPLAY_SHOWHELPERS, tr("Show/Hide Helpers")) + am->AddAction(AzToolsFramework::Helpers, tr("Show Helpers")) .SetShortcut(tr("Shift+Space")) - .SetToolTip(tr("Show/Hide Helpers (Shift+Space)")); + .SetToolTip(tr("Show/Hide Helpers (Shift+Space)")) + .SetCheckable(true) + .RegisterUpdateCallback( + [](QAction* action) + { + Q_ASSERT(action->isCheckable()); + action->setChecked(AzToolsFramework::HelpersVisible()); + }) + .Connect( + &QAction::triggered, + []() + { + AzToolsFramework::SetHelpersVisible(!AzToolsFramework::HelpersVisible()); + AzToolsFramework::ViewportInteraction::ViewportSettingsNotificationBus::Broadcast( + &AzToolsFramework::ViewportInteraction::ViewportSettingNotifications::OnDrawHelpersChanged, + AzToolsFramework::HelpersVisible()); + }); + am->AddAction(AzToolsFramework::Icons, tr("Show Icons")) + .SetShortcut(tr("Ctrl+Space")) + .SetToolTip(tr("Show/Hide Icons (Ctrl+Space)")) + .SetCheckable(true) + .RegisterUpdateCallback( + [](QAction* action) + { + Q_ASSERT(action->isCheckable()); + action->setChecked(AzToolsFramework::IconsVisible()); + }) + .Connect( + &QAction::triggered, + []() + { + AzToolsFramework::SetIconsVisible(!AzToolsFramework::IconsVisible()); + }); // Audio actions am->AddAction(ID_SOUND_STOPALLSOUNDS, tr("Stop All Sounds")) diff --git a/Code/Editor/Plugins/ComponentEntityEditorPlugin/SandboxIntegration.cpp b/Code/Editor/Plugins/ComponentEntityEditorPlugin/SandboxIntegration.cpp index d5b903585e..69b195d243 100644 --- a/Code/Editor/Plugins/ComponentEntityEditorPlugin/SandboxIntegration.cpp +++ b/Code/Editor/Plugins/ComponentEntityEditorPlugin/SandboxIntegration.cpp @@ -1986,8 +1986,3 @@ void SandboxIntegrationManager::BrowseForAssets(AssetSelectionModel& selection) { AssetBrowserComponentRequestBus::Broadcast(&AssetBrowserComponentRequests::PickAssets, selection, GetMainWindow()); } - -bool SandboxIntegrationManager::DisplayHelpersVisible() -{ - return GetIEditor()->GetDisplaySettings()->IsDisplayHelpers(); -} diff --git a/Code/Editor/Plugins/ComponentEntityEditorPlugin/SandboxIntegration.h b/Code/Editor/Plugins/ComponentEntityEditorPlugin/SandboxIntegration.h index 79e7a4334d..c58f019c85 100644 --- a/Code/Editor/Plugins/ComponentEntityEditorPlugin/SandboxIntegration.h +++ b/Code/Editor/Plugins/ComponentEntityEditorPlugin/SandboxIntegration.h @@ -165,7 +165,6 @@ private: void InstantiateSliceFromAssetId(const AZ::Data::AssetId& assetId) override; void ClearRedoStack() override; int GetIconTextureIdFromEntityIconPath(const AZStd::string& entityIconPath) override; - bool DisplayHelpersVisible() override; ////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////// diff --git a/Code/Editor/Resource.h b/Code/Editor/Resource.h index ba3cd39fe7..432f07a531 100644 --- a/Code/Editor/Resource.h +++ b/Code/Editor/Resource.h @@ -191,7 +191,6 @@ #define ID_BRUSH_CSGSUBSTRUCT 33837 #define ID_MATERIAL_PICKTOOL 33842 #define ID_MODIFY_AIPOINT_PICKIMPASSLINK 33865 -#define ID_DISPLAY_SHOWHELPERS 33871 #define ID_FILE_EXPORTSELECTION 33875 #define ID_EDIT_PASTE_WITH_LINKS 33893 #define ID_FILE_EXPORT_TERRAINAREA 33904 diff --git a/Code/Editor/ViewportManipulatorController.cpp b/Code/Editor/ViewportManipulatorController.cpp index e46328eb65..9879a84b62 100644 --- a/Code/Editor/ViewportManipulatorController.cpp +++ b/Code/Editor/ViewportManipulatorController.cpp @@ -129,8 +129,8 @@ namespace SandboxEditor ViewportInteractionRequestBus::EventResult( ray, GetViewportId(), &ViewportInteractionRequestBus::Events::ViewportScreenToWorldRay, screenPoint); - m_mouseInteraction.m_mousePick.m_rayOrigin = ray.origin; - m_mouseInteraction.m_mousePick.m_rayDirection = ray.direction; + m_mouseInteraction.m_mousePick.m_rayOrigin = ray.m_origin; + m_mouseInteraction.m_mousePick.m_rayDirection = ray.m_direction; m_mouseInteraction.m_mousePick.m_screenCoordinates = screenPoint; } diff --git a/Code/Editor/ViewportTitleDlg.cpp b/Code/Editor/ViewportTitleDlg.cpp index 49459fad0f..888089fd72 100644 --- a/Code/Editor/ViewportTitleDlg.cpp +++ b/Code/Editor/ViewportTitleDlg.cpp @@ -6,7 +6,6 @@ * */ - // Description : CViewportTitleDlg implementation file #if !defined(Q_MOC_RUN) @@ -42,38 +41,18 @@ #include #include #include +#include +#include #include AZ_PUSH_DISABLE_DLL_EXPORT_MEMBER_WARNING #include "ui_ViewportTitleDlg.h" AZ_POP_DISABLE_DLL_EXPORT_MEMBER_WARNING -#endif //!defined(Q_MOC_RUN) +#endif //! defined(Q_MOC_RUN) // CViewportTitleDlg dialog -inline namespace Helpers -{ - void ToggleHelpers() - { - const bool newValue = !GetIEditor()->GetDisplaySettings()->IsDisplayHelpers(); - GetIEditor()->GetDisplaySettings()->DisplayHelpers(newValue); - GetIEditor()->Notify(eNotify_OnDisplayRenderUpdate); - - if (newValue == false) - { - GetIEditor()->GetObjectManager()->SendEvent(EVENT_HIDE_HELPER); - } - AzToolsFramework::ViewportInteraction::ViewportSettingsNotificationBus::Broadcast( - &AzToolsFramework::ViewportInteraction::ViewportSettingNotifications::OnDrawHelpersChanged, newValue); - } - - bool IsHelpersShown() - { - return GetIEditor()->GetDisplaySettings()->IsDisplayHelpers(); - } -} - namespace { class CViewportTitleDlgDisplayInfoHelper @@ -98,7 +77,7 @@ namespace emit ViewportInfoStatusUpdated(static_cast(state)); } }; -} //end anonymous namespace +} // end anonymous namespace CViewportTitleDlg::CViewportTitleDlg(QWidget* pParent) : QWidget(pParent) @@ -215,13 +194,65 @@ void CViewportTitleDlg::SetupViewportInformationMenu() m_ui->m_debugInformationMenu->setMenu(GetViewportInformationMenu()); connect(m_ui->m_debugInformationMenu, &QToolButton::clicked, this, &CViewportTitleDlg::OnToggleDisplayInfo); m_ui->m_debugInformationMenu->setPopupMode(QToolButton::MenuButtonPopup); - } void CViewportTitleDlg::SetupHelpersButton() { - connect(m_ui->m_helpers, &QToolButton::clicked, this, &CViewportTitleDlg::OnToggleHelpers); - m_ui->m_helpers->setChecked(Helpers::IsHelpersShown()); + if (m_helpersMenu == nullptr) + { + m_helpersMenu = new QMenu("Helpers State", this); + + auto helperAction = MainWindow::instance()->GetActionManager()->GetAction(AzToolsFramework::Helpers); + connect( + helperAction, &QAction::triggered, this, + [this] + { + m_ui->m_helpers->setChecked(AzToolsFramework::HelpersVisible() || AzToolsFramework::IconsVisible()); + }); + + auto iconAction = MainWindow::instance()->GetActionManager()->GetAction(AzToolsFramework::Icons); + connect( + iconAction, &QAction::triggered, this, + [this] + { + m_ui->m_helpers->setChecked(AzToolsFramework::HelpersVisible() || AzToolsFramework::IconsVisible()); + }); + + m_helpersAction = new QAction(tr("Helpers"), m_helpersMenu); + m_helpersAction->setCheckable(true); + connect( + m_helpersAction, &QAction::triggered, this, + [helperAction] + { + helperAction->trigger(); + }); + + m_iconsAction = new QAction(tr("Icons"), m_helpersMenu); + m_iconsAction->setCheckable(true); + connect( + m_iconsAction, &QAction::triggered, this, + [iconAction] + { + iconAction->trigger(); + }); + + m_helpersMenu->addAction(m_helpersAction); + m_helpersMenu->addAction(m_iconsAction); + + connect( + m_helpersMenu, &QMenu::aboutToShow, this, + [this] + { + m_helpersAction->setChecked(AzToolsFramework::HelpersVisible()); + m_iconsAction->setChecked(AzToolsFramework::IconsVisible()); + }); + + m_ui->m_helpers->setCheckable(true); + m_ui->m_helpers->setMenu(m_helpersMenu); + m_ui->m_helpers->setPopupMode(QToolButton::InstantPopup); + } + + m_ui->m_helpers->setChecked(AzToolsFramework::HelpersVisible() || AzToolsFramework::IconsVisible()); } void CViewportTitleDlg::SetupOverflowMenu() @@ -279,15 +310,20 @@ void CViewportTitleDlg::SetupOverflowMenu() UpdateMuteActionText(); } - ////////////////////////////////////////////////////////////////////////// void CViewportTitleDlg::SetViewPane(CLayoutViewPane* pViewPane) { if (m_pViewPane) + { m_pViewPane->disconnect(this); + } + m_pViewPane = pViewPane; + if (m_pViewPane) + { connect(this, &QWidget::customContextMenuRequested, m_pViewPane, &CLayoutViewPane::ShowTitleMenu); + } } ////////////////////////////////////////////////////////////////////////// @@ -318,7 +354,6 @@ void CViewportTitleDlg::OnInitDialog() m_ui->m_prefabFocusPath->hide(); m_ui->m_prefabFocusBackButton->hide(); } - } ////////////////////////////////////////////////////////////////////////// @@ -336,13 +371,6 @@ void CViewportTitleDlg::OnMaximize() } } -////////////////////////////////////////////////////////////////////////// -void CViewportTitleDlg::OnToggleHelpers() -{ - Helpers::ToggleHelpers(); - m_ui->m_helpers->setChecked(Helpers::IsHelpersShown()); -} - void CViewportTitleDlg::SetNoViewportInfo() { AZ::AtomBridge::AtomViewportInfoDisplayRequestBus::Broadcast( @@ -367,7 +395,6 @@ void CViewportTitleDlg::SetCompactViewportInfo() &AZ::AtomBridge::AtomViewportInfoDisplayRequestBus::Events::SetDisplayState, AZ::AtomBridge::ViewportInfoDisplayState::CompactInfo); } - ////////////////////////////////////////////////////////////////////////// void CViewportTitleDlg::UpdateDisplayInfo() { @@ -783,9 +810,6 @@ void CViewportTitleDlg::OnEditorNotifyEvent(EEditorNotifyEvent event) { switch (event) { - case eNotify_OnDisplayRenderUpdate: - m_ui->m_helpers->setChecked(Helpers::IsHelpersShown()); - break; case eNotify_OnBeginGameMode: case eNotify_OnEndGameMode: UpdateMuteActionText(); @@ -997,24 +1021,18 @@ void CViewportTitleDlg::UpdateOverFlowMenuState() m_angleSizeActionWidget->setEnabled(angleSnappingActive); } -namespace + namespace { void PyToggleHelpers() { - GetIEditor()->GetDisplaySettings()->DisplayHelpers(!GetIEditor()->GetDisplaySettings()->IsDisplayHelpers()); - GetIEditor()->Notify(eNotify_OnDisplayRenderUpdate); - - if (GetIEditor()->GetDisplaySettings()->IsDisplayHelpers() == false) - { - GetIEditor()->GetObjectManager()->SendEvent(EVENT_HIDE_HELPER); - } + AzToolsFramework::SetHelpersVisible(!AzToolsFramework::HelpersVisible()); } bool PyIsHelpersShown() { - return GetIEditor()->GetDisplaySettings()->IsDisplayHelpers(); + return AzToolsFramework::HelpersVisible(); } -} +} // namespace namespace AzToolsFramework { @@ -1029,11 +1047,12 @@ namespace AzToolsFramework ->Attribute(AZ::Script::Attributes::Category, "Legacy/Editor") ->Attribute(AZ::Script::Attributes::Module, "legacy.general"); }; + addLegacyGeneral(behaviorContext->Method("toggle_helpers", PyToggleHelpers, nullptr, "Toggles the display of helpers.")); addLegacyGeneral(behaviorContext->Method("is_helpers_shown", PyIsHelpersShown, nullptr, "Gets the display state of helpers.")); } } -} +} // namespace AzToolsFramework #include "ViewportTitleDlg.moc" #include diff --git a/Code/Editor/ViewportTitleDlg.h b/Code/Editor/ViewportTitleDlg.h index a3e19837b4..ba3dba858a 100644 --- a/Code/Editor/ViewportTitleDlg.h +++ b/Code/Editor/ViewportTitleDlg.h @@ -80,7 +80,6 @@ protected: void OnSystemEvent(ESystemEvent event, UINT_PTR wparam, UINT_PTR lparam) override; void OnMaximize(); - void OnToggleHelpers(); void UpdateDisplayInfo(); void SetupCameraDropdownMenu(); @@ -153,6 +152,9 @@ protected: QMenu* m_aspectMenu = nullptr; QMenu* m_resolutionMenu = nullptr; QMenu* m_viewportInformationMenu = nullptr; + QMenu* m_helpersMenu = nullptr; + QAction* m_helpersAction = nullptr; + QAction* m_iconsAction = nullptr; QAction* m_noInformationAction = nullptr; QAction* m_normalInformationAction = nullptr; QAction* m_fullInformationAction = nullptr; diff --git a/Code/Framework/AzFramework/AzFramework/Viewport/CameraInput.cpp b/Code/Framework/AzFramework/AzFramework/Viewport/CameraInput.cpp index 856d40e57d..cd33f60b91 100644 --- a/Code/Framework/AzFramework/AzFramework/Viewport/CameraInput.cpp +++ b/Code/Framework/AzFramework/AzFramework/Viewport/CameraInput.cpp @@ -213,27 +213,33 @@ namespace AzFramework Camera Cameras::StepCamera(const Camera& targetCamera, const ScreenVector& cursorDelta, const float scrollDelta, const float deltaTime) { - for (int i = 0; i < m_idleCameraInputs.size();) + for (int idleIndex = 0; idleIndex < m_idleCameraInputs.size();) { - auto& cameraInput = m_idleCameraInputs[i]; + auto& cameraInput = m_idleCameraInputs[idleIndex]; const bool canBegin = cameraInput->Beginning() && AZStd::all_of(m_activeCameraInputs.cbegin(), m_activeCameraInputs.cend(), [](const auto& input) { return !input->Exclusive(); }) && - (!cameraInput->Exclusive() || (cameraInput->Exclusive() && m_activeCameraInputs.empty())); + (!cameraInput->Exclusive() || m_activeCameraInputs.empty()); if (canBegin) { m_activeCameraInputs.push_back(cameraInput); using AZStd::swap; - swap(m_idleCameraInputs[i], m_idleCameraInputs[m_idleCameraInputs.size() - 1]); + swap(m_idleCameraInputs[idleIndex], m_idleCameraInputs[m_idleCameraInputs.size() - 1]); m_idleCameraInputs.pop_back(); } else { - i++; + // if a camera attempted to start but was not allowed to, ensure activation is cancelled + if (!cameraInput->Idle()) + { + cameraInput->CancelActivation(); + } + + idleIndex++; } } @@ -245,21 +251,21 @@ namespace AzFramework return acc; }); - for (int i = 0; i < m_activeCameraInputs.size();) + for (int activeIndex = 0; activeIndex < m_activeCameraInputs.size();) { - auto& cameraInput = m_activeCameraInputs[i]; + auto& cameraInput = m_activeCameraInputs[activeIndex]; if (cameraInput->Ending()) { cameraInput->ClearActivation(); m_idleCameraInputs.push_back(cameraInput); using AZStd::swap; - swap(m_activeCameraInputs[i], m_activeCameraInputs[m_activeCameraInputs.size() - 1]); + swap(m_activeCameraInputs[activeIndex], m_activeCameraInputs[m_activeCameraInputs.size() - 1]); m_activeCameraInputs.pop_back(); } else { cameraInput->ContinueActivation(); - i++; + activeIndex++; } } @@ -470,9 +476,10 @@ namespace AzFramework { if (input->m_state == InputChannel::State::Began) { - m_translation |= TranslationFromKey(input->m_channelId, m_translateCameraInputChannelIds); - if (m_translation != TranslationType::Nil) + if (auto translation = TranslationFromKey(input->m_channelId, m_translateCameraInputChannelIds); + translation != TranslationType::Nil) { + m_translation |= translation; BeginActivation(); } @@ -484,11 +491,16 @@ namespace AzFramework // ensure we don't process end events in the idle state else if (input->m_state == InputChannel::State::Ended && !Idle()) { - m_translation &= ~(TranslationFromKey(input->m_channelId, m_translateCameraInputChannelIds)); - if (m_translation == TranslationType::Nil) + if (auto translation = TranslationFromKey(input->m_channelId, m_translateCameraInputChannelIds); + translation != TranslationType::Nil) { - EndActivation(); + m_translation &= ~translation; + if (m_translation == TranslationType::Nil) + { + EndActivation(); + } } + if (input->m_channelId == m_translateCameraInputChannelIds.m_boostChannelId) { m_boost = false; diff --git a/Code/Framework/AzFramework/AzFramework/Viewport/CameraInput.h b/Code/Framework/AzFramework/AzFramework/Viewport/CameraInput.h index 96a9b54dc8..b652d616b2 100644 --- a/Code/Framework/AzFramework/AzFramework/Viewport/CameraInput.h +++ b/Code/Framework/AzFramework/AzFramework/Viewport/CameraInput.h @@ -185,6 +185,11 @@ namespace AzFramework m_activation = Activation::Ending; } + void CancelActivation() + { + m_activation = Activation::Idle; + } + void ContinueActivation() { // continue activation is called after the first step of the camera input, diff --git a/Code/Framework/AzFramework/AzFramework/Viewport/ScreenGeometry.h b/Code/Framework/AzFramework/AzFramework/Viewport/ScreenGeometry.h index 7a5d7fdc62..27031c6ab3 100644 --- a/Code/Framework/AzFramework/AzFramework/Viewport/ScreenGeometry.h +++ b/Code/Framework/AzFramework/AzFramework/Viewport/ScreenGeometry.h @@ -10,6 +10,7 @@ #include #include +#include #include #include @@ -203,6 +204,12 @@ namespace AzFramework return AZ::Vector2(aznumeric_cast(screenPoint.m_x), aznumeric_cast(screenPoint.m_y)); } + //! Return an AZ::Vector3 from a ScreenPoint (including z/depth value, defaulting to 0.0f). + inline AZ::Vector3 Vector3FromScreenPoint(const ScreenPoint& screenPoint, const float z = 0.0f) + { + return AZ::Vector3(aznumeric_cast(screenPoint.m_x), aznumeric_cast(screenPoint.m_y), z); + } + //! Return an AZ::Vector2 from a ScreenVector. inline AZ::Vector2 Vector2FromScreenVector(const ScreenVector& screenVector) { diff --git a/Code/Framework/AzFramework/Tests/CameraInputTests.cpp b/Code/Framework/AzFramework/Tests/CameraInputTests.cpp index 5f327fb2fd..0ddf9e89b9 100644 --- a/Code/Framework/AzFramework/Tests/CameraInputTests.cpp +++ b/Code/Framework/AzFramework/Tests/CameraInputTests.cpp @@ -416,4 +416,78 @@ namespace UnitTest using ::testing::FloatNear; EXPECT_THAT(m_camera.m_pitch, FloatNear(expectedPitch, 0.001f)); } + + TEST_F(CameraInputFixture, InvalidTranslationInputKeyCannotBeginTranslateCameraInputAgain) + { + HandleEventAndUpdate(AzFramework::DiscreteInputEvent{ m_translateCameraInputChannelIds.m_forwardChannelId, + AzFramework::InputChannel::State::Began }); + + const bool consumed = + m_cameraSystem->HandleEvents(AzFramework::DiscreteInputEvent{ m_orbitChannelId, AzFramework::InputChannel::State::Began }); + + using ::testing::IsFalse; + using ::testing::IsTrue; + EXPECT_THAT(consumed, IsTrue()); + EXPECT_THAT(m_firstPersonTranslateCamera->Beginning(), IsFalse()); + EXPECT_THAT(m_firstPersonTranslateCamera->Active(), IsTrue()); + } + + TEST_F(CameraInputFixture, InvalidTranslationInputKeyDownCannotBeginTranslateCameraInputAgain) + { + HandleEventAndUpdate(AzFramework::DiscreteInputEvent{ m_translateCameraInputChannelIds.m_forwardChannelId, + AzFramework::InputChannel::State::Began }); + + const bool consumed = + m_cameraSystem->HandleEvents(AzFramework::DiscreteInputEvent{ m_orbitChannelId, AzFramework::InputChannel::State::Began }); + + using ::testing::IsFalse; + using ::testing::IsTrue; + EXPECT_THAT(consumed, IsTrue()); + EXPECT_THAT(m_firstPersonTranslateCamera->Beginning(), IsFalse()); + EXPECT_THAT(m_firstPersonTranslateCamera->Active(), IsTrue()); + } + + TEST_F(CameraInputFixture, InvalidTranslationInputKeyUpDoesNotAffectTranslateCameraInputEnd) + { + HandleEventAndUpdate(AzFramework::DiscreteInputEvent{ m_translateCameraInputChannelIds.m_forwardChannelId, + AzFramework::InputChannel::State::Began }); + + const bool consumed = + m_cameraSystem->HandleEvents(AzFramework::DiscreteInputEvent{ m_orbitChannelId, AzFramework::InputChannel::State::Began }); + + HandleEventAndUpdate(AzFramework::DiscreteInputEvent{ m_translateCameraInputChannelIds.m_forwardChannelId, + AzFramework::InputChannel::State::Ended }); + + using ::testing::IsFalse; + using ::testing::IsTrue; + EXPECT_THAT(consumed, IsTrue()); + EXPECT_THAT(m_firstPersonTranslateCamera->Idle(), IsTrue()); + } + + TEST_F(CameraInputFixture, OrbitCameraInputCannotBeLeftInInvalidStateIfItCannotFullyBeginAfterInputChannelBegin) + { + HandleEventAndUpdate(AzFramework::DiscreteInputEvent{ m_translateCameraInputChannelIds.m_forwardChannelId, + AzFramework::InputChannel::State::Began }); + + HandleEventAndUpdate(AzFramework::DiscreteInputEvent{ m_orbitChannelId, AzFramework::InputChannel::State::Began }); + + using ::testing::IsFalse; + using ::testing::IsTrue; + EXPECT_THAT(m_orbitCamera->Beginning(), IsFalse()); + EXPECT_THAT(m_orbitCamera->Idle(), IsTrue()); + } + + TEST_F(CameraInputFixture, OrbitCameraInputCannotBeLeftInInvalidStateIfItCannotFullyBeginAfterInputChannelBeginAndEnd) + { + HandleEventAndUpdate(AzFramework::DiscreteInputEvent{ m_translateCameraInputChannelIds.m_forwardChannelId, + AzFramework::InputChannel::State::Began }); + + HandleEventAndUpdate(AzFramework::DiscreteInputEvent{ m_orbitChannelId, AzFramework::InputChannel::State::Began }); + HandleEventAndUpdate(AzFramework::DiscreteInputEvent{ m_orbitChannelId, AzFramework::InputChannel::State::Ended }); + + using ::testing::IsFalse; + using ::testing::IsTrue; + EXPECT_THAT(m_orbitCamera->Ending(), IsFalse()); + EXPECT_THAT(m_orbitCamera->Idle(), IsTrue()); + } } // namespace UnitTest diff --git a/Code/Framework/AzManipulatorTestFramework/Include/AzManipulatorTestFramework/AzManipulatorTestFramework.h b/Code/Framework/AzManipulatorTestFramework/Include/AzManipulatorTestFramework/AzManipulatorTestFramework.h index 66227c692b..865a571d3b 100644 --- a/Code/Framework/AzManipulatorTestFramework/Include/AzManipulatorTestFramework/AzManipulatorTestFramework.h +++ b/Code/Framework/AzManipulatorTestFramework/Include/AzManipulatorTestFramework/AzManipulatorTestFramework.h @@ -26,29 +26,33 @@ namespace AzManipulatorTestFramework { public: virtual ~ViewportInteractionInterface() = default; - //! Return the camera state. + //! Returns the camera state. virtual AzFramework::CameraState GetCameraState() = 0; - //! Set the camera state. + //! Sets the camera state. virtual void SetCameraState(const AzFramework::CameraState& cameraState) = 0; - //! Retrieve the debug display. + //! Retrieves the debug display. virtual AzFramework::DebugDisplayRequests& GetDebugDisplay() = 0; - //! Set if grid snapping is enabled or not. + //! Sets if grid snapping is enabled or not. virtual void SetGridSnapping(bool enabled) = 0; - //! Set if angular snapping is enabled or not. + //! Sets if angular snapping is enabled or not. virtual void SetAngularSnapping(bool enabled) = 0; - //! Set the grid size. + //! Sets the grid size. virtual void SetGridSize(float size) = 0; - //! Set the angular step. + //! Sets the angular step. virtual void SetAngularStep(float step) = 0; - //! Get the viewport id. + //! Gets the viewport id. virtual AzFramework::ViewportId GetViewportId() const = 0; //! Updates the visibility state. //! Updates which entities are currently visible given the current camera state. virtual void UpdateVisibility() = 0; - //! Set if sticky select is enabled or not. + //! Sets if sticky select is enabled or not. virtual void SetStickySelect(bool enabled) = 0; - //! Get default Editor Camera Position. + //! Gets default Editor Camera Position. virtual AZ::Vector3 DefaultEditorCameraPosition() const = 0; + //! Sets if icons are visible in the viewport. + virtual void SetIconsVisible(bool visible) = 0; + //! Sets if helpers are visible in the viewport. + virtual void SetHelpersVisible(bool visible) = 0; }; //! This interface is used to simulate the manipulator manager while the manipulators are under test. diff --git a/Code/Framework/AzManipulatorTestFramework/Include/AzManipulatorTestFramework/AzManipulatorTestFrameworkTestHelpers.h b/Code/Framework/AzManipulatorTestFramework/Include/AzManipulatorTestFramework/AzManipulatorTestFrameworkTestHelpers.h index 63392eb82f..8528795206 100644 --- a/Code/Framework/AzManipulatorTestFramework/Include/AzManipulatorTestFramework/AzManipulatorTestFrameworkTestHelpers.h +++ b/Code/Framework/AzManipulatorTestFramework/Include/AzManipulatorTestFramework/AzManipulatorTestFrameworkTestHelpers.h @@ -26,6 +26,7 @@ namespace UnitTest using IndirectCallManipulatorViewportInteraction = AzManipulatorTestFramework::IndirectCallManipulatorViewportInteraction; using ImmediateModeActionDispatcher = AzManipulatorTestFramework::ImmediateModeActionDispatcher; + public: void SetUpEditorFixtureImpl() override { ToolsApplicationFixtureT::SetUpEditorFixtureImpl(); @@ -43,7 +44,6 @@ namespace UnitTest ToolsApplicationFixtureT::TearDownEditorFixtureImpl(); } - public: AzFramework::CameraState m_cameraState; AZStd::unique_ptr m_actionDispatcher; AZStd::unique_ptr m_viewportManipulatorInteraction; diff --git a/Code/Framework/AzManipulatorTestFramework/Include/AzManipulatorTestFramework/AzManipulatorTestFrameworkUtils.h b/Code/Framework/AzManipulatorTestFramework/Include/AzManipulatorTestFramework/AzManipulatorTestFrameworkUtils.h index 1dcbea2125..653644aefe 100644 --- a/Code/Framework/AzManipulatorTestFramework/Include/AzManipulatorTestFramework/AzManipulatorTestFrameworkUtils.h +++ b/Code/Framework/AzManipulatorTestFramework/Include/AzManipulatorTestFramework/AzManipulatorTestFrameworkUtils.h @@ -27,29 +27,6 @@ namespace AzManipulatorTestFramework const AZ::Vector3& position = AZ::Vector3::CreateZero(), float radius = 1.0f); - //! Create a mouse pick from the specified ray and screen point. - AzToolsFramework::ViewportInteraction::MousePick CreateMousePick( - const AZ::Vector3& origin, const AZ::Vector3& direction, const AzFramework::ScreenPoint& screenPoint); - - //! Build a mouse pick from the specified mouse position and camera state. - AzToolsFramework::ViewportInteraction::MousePick BuildMousePick( - const AzFramework::ScreenPoint& screenPoint, const AzFramework::CameraState& cameraState); - - //! Create a mouse interaction from the specified pick, buttons, interaction id and keyboard modifiers. - AzToolsFramework::ViewportInteraction::MouseInteraction CreateMouseInteraction( - const AzToolsFramework::ViewportInteraction::MousePick& mousePick, - AzToolsFramework::ViewportInteraction::MouseButtons buttons, - AzToolsFramework::ViewportInteraction::InteractionId interactionId, - AzToolsFramework::ViewportInteraction::KeyboardModifiers modifiers); - - //! Create a mouse buttons from the specified mouse button. - AzToolsFramework::ViewportInteraction::MouseButtons CreateMouseButtons(AzToolsFramework::ViewportInteraction::MouseButton button); - - //! Create a mouse interaction event from the specified interaction and event. - AzToolsFramework::ViewportInteraction::MouseInteractionEvent CreateMouseInteractionEvent( - const AzToolsFramework::ViewportInteraction::MouseInteraction& mouseInteraction, - AzToolsFramework::ViewportInteraction::MouseEvent event); - //! Dispatch a mouse event to the main manipulator manager via a bus call. void DispatchMouseInteractionEvent(const AzToolsFramework::ViewportInteraction::MouseInteractionEvent& event); diff --git a/Code/Framework/AzManipulatorTestFramework/Include/AzManipulatorTestFramework/IndirectManipulatorViewportInteraction.h b/Code/Framework/AzManipulatorTestFramework/Include/AzManipulatorTestFramework/IndirectManipulatorViewportInteraction.h index da2804dfd5..2d5a41c2c2 100644 --- a/Code/Framework/AzManipulatorTestFramework/Include/AzManipulatorTestFramework/IndirectManipulatorViewportInteraction.h +++ b/Code/Framework/AzManipulatorTestFramework/Include/AzManipulatorTestFramework/IndirectManipulatorViewportInteraction.h @@ -24,9 +24,12 @@ namespace AzManipulatorTestFramework explicit IndirectCallManipulatorViewportInteraction(AZStd::shared_ptr debugDisplayRequests); ~IndirectCallManipulatorViewportInteraction(); - // ManipulatorViewportInteractionInterface ... + // ManipulatorViewportInteraction overrides ... const ViewportInteractionInterface& GetViewportInteraction() const override; const ManipulatorManagerInterface& GetManipulatorManager() const override; + // make non-const overloads visible + using ManipulatorViewportInteraction::GetViewportInteraction; + using ManipulatorViewportInteraction::GetManipulatorManager; private: AZStd::unique_ptr m_viewportInteraction; diff --git a/Code/Framework/AzManipulatorTestFramework/Include/AzManipulatorTestFramework/ViewportInteraction.h b/Code/Framework/AzManipulatorTestFramework/Include/AzManipulatorTestFramework/ViewportInteraction.h index 1568c1a931..f29245bb34 100644 --- a/Code/Framework/AzManipulatorTestFramework/Include/AzManipulatorTestFramework/ViewportInteraction.h +++ b/Code/Framework/AzManipulatorTestFramework/Include/AzManipulatorTestFramework/ViewportInteraction.h @@ -39,7 +39,8 @@ namespace AzManipulatorTestFramework AzFramework::ViewportId GetViewportId() const override; void UpdateVisibility() override; void SetStickySelect(bool enabled) override; - AZ::Vector3 DefaultEditorCameraPosition() const override; + void SetIconsVisible(bool visible) override; + void SetHelpersVisible(bool visible) override; // ViewportInteractionRequestBus overrides ... AzFramework::CameraState GetCameraState() override; @@ -58,6 +59,9 @@ namespace AzManipulatorTestFramework float ManipulatorLineBoundWidth() const override; float ManipulatorCircleBoundWidth() const override; bool StickySelectEnabled() const override; + AZ::Vector3 DefaultEditorCameraPosition() const override; + bool IconsVisible() const override; + bool HelpersVisible() const override; // EditorEntityViewportInteractionRequestBus overrides ... void FindVisibleEntities(AZStd::vector& visibleEntities) override; @@ -68,10 +72,12 @@ namespace AzManipulatorTestFramework AzFramework::EntityVisibilityQuery m_entityVisibilityQuery; AZStd::shared_ptr m_debugDisplayRequests; AzFramework::CameraState m_cameraState; + float m_gridSize = 1.0f; + float m_angularStep = 0.0f; bool m_gridSnapping = false; bool m_angularSnapping = false; bool m_stickySelect = true; - float m_gridSize = 1.0f; - float m_angularStep = 0.0f; + bool m_iconsVisible = true; + bool m_helpersVisible = true; }; } // namespace AzManipulatorTestFramework diff --git a/Code/Framework/AzManipulatorTestFramework/Source/AzManipulatorTestFrameworkUtils.cpp b/Code/Framework/AzManipulatorTestFramework/Source/AzManipulatorTestFrameworkUtils.cpp index 6fbf2cb219..4c7d7f6901 100644 --- a/Code/Framework/AzManipulatorTestFramework/Source/AzManipulatorTestFrameworkUtils.cpp +++ b/Code/Framework/AzManipulatorTestFramework/Source/AzManipulatorTestFrameworkUtils.cpp @@ -82,49 +82,6 @@ namespace AzManipulatorTestFramework return manipulator; } - AzToolsFramework::ViewportInteraction::MousePick CreateMousePick( - const AZ::Vector3& origin, const AZ::Vector3& direction, const AzFramework::ScreenPoint& screenPoint) - { - return { origin, direction, screenPoint }; - } - - AzToolsFramework::ViewportInteraction::MousePick BuildMousePick( - const AzFramework::ScreenPoint& screenPoint, const AzFramework::CameraState& cameraState) - { - const auto nearPlaneWorldPosition = AzFramework::ScreenToWorld(screenPoint, cameraState); - - AzToolsFramework::ViewportInteraction::MousePick mousePick; - mousePick.m_screenCoordinates = screenPoint; - mousePick.m_rayOrigin = nearPlaneWorldPosition; - mousePick.m_rayDirection = (nearPlaneWorldPosition - cameraState.m_position).GetNormalized(); - - return mousePick; - } - - MouseInteraction CreateMouseInteraction( - const MousePick& mousePick, MouseButtons buttons, InteractionId interactionId, KeyboardModifiers modifiers) - { - AzToolsFramework::ViewportInteraction::MouseInteraction interaction; - interaction.m_mousePick = mousePick; - interaction.m_mouseButtons = buttons; - interaction.m_interactionId = interactionId; - interaction.m_keyboardModifiers = modifiers; - - return interaction; - } - - MouseButtons CreateMouseButtons(MouseButton button) - { - MouseButtons buttons; - buttons.m_mouseButtons = static_cast(button); - return buttons; - } - - MouseInteractionEvent CreateMouseInteractionEvent(const MouseInteraction& mouseInteraction, MouseEvent event) - { - return MouseInteractionEvent(mouseInteraction, event, /*captured=*/false); - } - void DispatchMouseInteractionEvent(const MouseInteractionEvent& event) { AzToolsFramework::EditorInteractionSystemViewportSelectionRequestBus::Event( diff --git a/Code/Framework/AzManipulatorTestFramework/Source/ImmediateModeActionDispatcher.cpp b/Code/Framework/AzManipulatorTestFramework/Source/ImmediateModeActionDispatcher.cpp index aea93ca342..715c2b1083 100644 --- a/Code/Framework/AzManipulatorTestFramework/Source/ImmediateModeActionDispatcher.cpp +++ b/Code/Framework/AzManipulatorTestFramework/Source/ImmediateModeActionDispatcher.cpp @@ -120,7 +120,8 @@ namespace AzManipulatorTestFramework void ImmediateModeActionDispatcher::MousePositionImpl(const AzFramework::ScreenPoint& position) { const auto cameraState = m_manipulatorViewportInteraction.GetViewportInteraction().GetCameraState(); - GetMouseInteractionEvent()->m_mouseInteraction.m_mousePick = BuildMousePick(position, cameraState); + GetMouseInteractionEvent()->m_mouseInteraction.m_mousePick = + AzToolsFramework::ViewportInteraction::BuildMousePick(cameraState, position); GetMouseInteractionEvent()->m_mouseEvent = AzToolsFramework::ViewportInteraction::MouseEvent::Move; m_manipulatorViewportInteraction.GetManipulatorManager().ConsumeMouseInteractionEvent(*m_event); } diff --git a/Code/Framework/AzManipulatorTestFramework/Source/ViewportInteraction.cpp b/Code/Framework/AzManipulatorTestFramework/Source/ViewportInteraction.cpp index 1a28c8cad1..b7fd5e2b73 100644 --- a/Code/Framework/AzManipulatorTestFramework/Source/ViewportInteraction.cpp +++ b/Code/Framework/AzManipulatorTestFramework/Source/ViewportInteraction.cpp @@ -10,6 +10,7 @@ #include #include #include +#include namespace AzManipulatorTestFramework { @@ -19,6 +20,9 @@ namespace AzManipulatorTestFramework AzToolsFramework::ViewportInteraction::ViewportInteractionRequestBus::Handler::BusConnect(m_viewportId); AzToolsFramework::ViewportInteraction::ViewportSettingsRequestBus::Handler::BusConnect(m_viewportId); AzToolsFramework::ViewportInteraction::EditorEntityViewportInteractionRequestBus::Handler::BusConnect(m_viewportId); + + m_cameraState = + AzFramework::CreateIdentityDefaultCamera(AZ::Vector3::CreateZero(), AzManipulatorTestFramework::DefaultViewportSize); } ViewportInteraction::~ViewportInteraction() @@ -113,6 +117,16 @@ namespace AzManipulatorTestFramework m_stickySelect = enabled; } + void ViewportInteraction::SetIconsVisible(const bool visible) + { + m_iconsVisible = visible; + } + + void ViewportInteraction::SetHelpersVisible(const bool visible) + { + m_helpersVisible = visible; + } + AZ::Vector3 ViewportInteraction::DefaultEditorCameraPosition() const { return {}; @@ -148,4 +162,14 @@ namespace AzManipulatorTestFramework { return 1.0f; } + + bool ViewportInteraction::IconsVisible() const + { + return m_iconsVisible; + } + + bool ViewportInteraction::HelpersVisible() const + { + return m_helpersVisible; + } } // namespace AzManipulatorTestFramework diff --git a/Code/Framework/AzManipulatorTestFramework/Tests/AzManipulatorTestFrameworkTestFixtures.h b/Code/Framework/AzManipulatorTestFramework/Tests/AzManipulatorTestFrameworkTestFixtures.h index 4679ac142c..24ede71904 100644 --- a/Code/Framework/AzManipulatorTestFramework/Tests/AzManipulatorTestFrameworkTestFixtures.h +++ b/Code/Framework/AzManipulatorTestFramework/Tests/AzManipulatorTestFrameworkTestFixtures.h @@ -8,21 +8,22 @@ #pragma once +#include #include #include -#include namespace UnitTest { - class LinearManipulatorTestFixture - : public ToolsApplicationFixture + class LinearManipulatorTestFixture : public ToolsApplicationFixture { protected: LinearManipulatorTestFixture(const AzToolsFramework::ManipulatorManagerId& manipulatorManagerId) - : m_manipulatorManagerId(manipulatorManagerId) {} + : m_manipulatorManagerId(manipulatorManagerId) + { + } void SetUpEditorFixtureImpl() override - { + { m_linearManipulator = AzManipulatorTestFramework::CreateLinearManipulator( m_manipulatorManagerId, /*position=*/AZ::Vector3::CreateZero(), @@ -31,21 +32,21 @@ namespace UnitTest // default sanity check call backs m_linearManipulator->InstallLeftMouseDownCallback( [this](const AzToolsFramework::LinearManipulator::Action& /*action*/) - { - m_receivedLeftMouseDown = true; - }); + { + m_receivedLeftMouseDown = true; + }); m_linearManipulator->InstallMouseMoveCallback( [this](const AzToolsFramework::LinearManipulator::Action& /*action*/) - { - m_receivedMouseMove = true; - }); + { + m_receivedMouseMove = true; + }); m_linearManipulator->InstallLeftMouseUpCallback( [this](const AzToolsFramework::LinearManipulator::Action& /*action*/) - { - m_receivedLeftMouseUp = true; - }); + { + m_receivedLeftMouseUp = true; + }); } void TearDownEditorFixtureImpl() override @@ -63,16 +64,16 @@ namespace UnitTest bool m_receivedLeftMouseUp = false; // initial world space starting position for mouse interaction - const AzToolsFramework::ViewportInteraction::MousePick m_mouseStartingPositionRay = - AzManipulatorTestFramework::CreateMousePick( - AZ::Vector3(0.0f, -2.0f, 0.0f), AZ::Vector3(0.0f, 1.0f, 0.0f), AzFramework::ScreenPoint( 0,0 )); + const AzToolsFramework::ViewportInteraction::MousePick m_mouseStartingPositionRay{ AZ::Vector3(0.0f, -2.0f, 0.0f), + AZ::Vector3(0.0f, 1.0f, 0.0f), + AzFramework::ScreenPoint(0, 0) }; // left mouse down ray in world space 2 units back from origin looking down +y axis with a null interaction // id and no keyboard modifiers AzToolsFramework::ViewportInteraction::MouseInteraction m_interaction = - AzManipulatorTestFramework::CreateMouseInteraction( + AzToolsFramework::ViewportInteraction::BuildMouseInteraction( m_mouseStartingPositionRay, - AzManipulatorTestFramework::CreateMouseButtons(AzToolsFramework::ViewportInteraction::MouseButton::Left), + AzToolsFramework::ViewportInteraction::BuildMouseButtons(AzToolsFramework::ViewportInteraction::MouseButton::Left), AzToolsFramework::ViewportInteraction::InteractionId(AZ::EntityId(0), 0), AzToolsFramework::ViewportInteraction::KeyboardModifiers(0)); }; diff --git a/Code/Framework/AzManipulatorTestFramework/Tests/BusCallTest.cpp b/Code/Framework/AzManipulatorTestFramework/Tests/BusCallTest.cpp index 11f35d8fdc..8d86a96ffa 100644 --- a/Code/Framework/AzManipulatorTestFramework/Tests/BusCallTest.cpp +++ b/Code/Framework/AzManipulatorTestFramework/Tests/BusCallTest.cpp @@ -7,6 +7,8 @@ */ #include "AzManipulatorTestFrameworkTestFixtures.h" + +#include #include #include @@ -34,8 +36,8 @@ namespace UnitTest TEST_F(AzManipulatorTestFrameworkBusCallTestFixture, ConsumeViewportLeftMouseClick) { // given a left mouse down ray in world space - auto event = - AzManipulatorTestFramework::CreateMouseInteractionEvent(m_interaction, AzToolsFramework::ViewportInteraction::MouseEvent::Down); + auto event = AzToolsFramework::ViewportInteraction::BuildMouseInteractionEvent( + m_interaction, AzToolsFramework::ViewportInteraction::MouseEvent::Down); // consume the mouse down and up events AzManipulatorTestFramework::DispatchMouseInteractionEvent(event); @@ -53,8 +55,8 @@ namespace UnitTest TEST_F(AzManipulatorTestFrameworkBusCallTestFixture, ConsumeViewportMouseMoveHover) { // given a left mouse down ray in world space - const auto event = - AzManipulatorTestFramework::CreateMouseInteractionEvent(m_interaction, AzToolsFramework::ViewportInteraction::MouseEvent::Move); + const auto event = AzToolsFramework::ViewportInteraction::BuildMouseInteractionEvent( + m_interaction, AzToolsFramework::ViewportInteraction::MouseEvent::Move); // consume the mouse move event AzManipulatorTestFramework::DispatchMouseInteractionEvent(event); @@ -72,8 +74,8 @@ namespace UnitTest TEST_F(AzManipulatorTestFrameworkBusCallTestFixture, ConsumeViewportMouseMoveActive) { // given a left mouse down ray in world space - auto event = - AzManipulatorTestFramework::CreateMouseInteractionEvent(m_interaction, AzToolsFramework::ViewportInteraction::MouseEvent::Down); + auto event = AzToolsFramework::ViewportInteraction::BuildMouseInteractionEvent( + m_interaction, AzToolsFramework::ViewportInteraction::MouseEvent::Down); // consume the mouse down event AzManipulatorTestFramework::DispatchMouseInteractionEvent(event); @@ -113,8 +115,8 @@ namespace UnitTest }); // given a left mouse down ray in world space - auto event = - AzManipulatorTestFramework::CreateMouseInteractionEvent(m_interaction, AzToolsFramework::ViewportInteraction::MouseEvent::Down); + auto event = AzToolsFramework::ViewportInteraction::BuildMouseInteractionEvent( + m_interaction, AzToolsFramework::ViewportInteraction::MouseEvent::Down); // consume the mouse down event AzManipulatorTestFramework::DispatchMouseInteractionEvent(event); diff --git a/Code/Framework/AzTest/AzTest/Printers.cpp b/Code/Framework/AzTest/AzTest/Printers.cpp index dc639d87d1..978fda3b32 100644 --- a/Code/Framework/AzTest/AzTest/Printers.cpp +++ b/Code/Framework/AzTest/AzTest/Printers.cpp @@ -5,9 +5,12 @@ * SPDX-License-Identifier: Apache-2.0 OR MIT * */ -#include + +#include #include +#include + namespace AZ::IO { void PrintTo(const AZ::IO::PathView& path, ::std::ostream* os) @@ -24,4 +27,12 @@ namespace AZ::IO { *os << "path: " << AZ::IO::FixedMaxPath(path.Native(), AZ::IO::PosixPathSeparator).MakePreferred().c_str(); } -} +} // namespace AZ::IO + +namespace AZ +{ + void PrintTo(const AZ::EntityId entityId, ::std::ostream* os) + { + *os << entityId.ToString().c_str(); + } +} // namespace AZ diff --git a/Code/Framework/AzTest/AzTest/Printers.h b/Code/Framework/AzTest/AzTest/Printers.h index 3615f7b576..82af0e07d7 100644 --- a/Code/Framework/AzTest/AzTest/Printers.h +++ b/Code/Framework/AzTest/AzTest/Printers.h @@ -5,6 +5,7 @@ * SPDX-License-Identifier: Apache-2.0 OR MIT * */ + #pragma once #include @@ -37,4 +38,11 @@ namespace AZ::IO void PrintTo(const AZ::IO::FixedMaxPath& path, ::std::ostream* os); } +namespace AZ +{ + class EntityId; + + void PrintTo(AZ::EntityId entityId, ::std::ostream* os); +} + #include diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/API/ToolsApplicationAPI.h b/Code/Framework/AzToolsFramework/AzToolsFramework/API/ToolsApplicationAPI.h index 282898c37d..bca68a6c0a 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/API/ToolsApplicationAPI.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/API/ToolsApplicationAPI.h @@ -878,9 +878,6 @@ namespace AzToolsFramework /// Return the icon texture id (from internal IconManager) for a given entity icon path. /// This can be passed to DrawTextureLabel to draw an entity icon. virtual int GetIconTextureIdFromEntityIconPath(const AZStd::string& entityIconPath) = 0; - - /// Returns if the Display Helpers option is toggled on in the Editor. - virtual bool DisplayHelpersVisible() = 0; }; using EditorRequestBus = AZ::EBus; diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/ProceduralPrefabSystemComponent.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/ProceduralPrefabSystemComponent.cpp index 8eeee4b28f..4a8e140e73 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/ProceduralPrefabSystemComponent.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/ProceduralPrefabSystemComponent.cpp @@ -24,7 +24,7 @@ namespace AzToolsFramework { if (auto serializationContext = azrtti_cast(context)) { - serializationContext->Class(); + serializationContext->Class(); } } diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Viewport/ViewportMessages.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Viewport/ViewportMessages.cpp index df96836bde..24b3c95310 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Viewport/ViewportMessages.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Viewport/ViewportMessages.cpp @@ -89,8 +89,8 @@ namespace AzToolsFramework const float rayLength) { AZ_Assert(rayLength > 0.0f, "Invalid ray length passed to RefreshRayRequest"); - rayRequest.m_startWorldPosition = viewportRay.origin; - rayRequest.m_endWorldPosition = viewportRay.origin + viewportRay.direction * rayLength; + rayRequest.m_startWorldPosition = viewportRay.m_origin; + rayRequest.m_endWorldPosition = viewportRay.m_origin + viewportRay.m_direction * rayLength; } AZ::Vector3 FindClosestPickIntersection( diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Viewport/ViewportMessages.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Viewport/ViewportMessages.h index aec2d3fbca..4dbcc9d926 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Viewport/ViewportMessages.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Viewport/ViewportMessages.h @@ -15,7 +15,6 @@ #include #include #include -#include #include #include @@ -151,13 +150,6 @@ namespace AzToolsFramework static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single; }; - //! A ray projection, originating from a point and extending in a direction specified as a normal. - struct ProjectedViewportRay - { - AZ::Vector3 origin; - AZ::Vector3 direction; - }; - //! Requests that can be made to the viewport to query and modify its state. class ViewportInteractionRequests { @@ -183,15 +175,6 @@ namespace AzToolsFramework //! Type to inherit to implement ViewportInteractionRequests. using ViewportInteractionRequestBus = AZ::EBus; - //! Utility function to return a viewport ray. - inline ProjectedViewportRay ViewportScreenToWorldRay( - const AzFramework::CameraState& cameraState, const AzFramework::ScreenPoint& screenPoint) - { - const AZ::Vector3 rayOrigin = AzFramework::ScreenToWorld(screenPoint, cameraState); - const AZ::Vector3 rayDirection = (rayOrigin - cameraState.m_position).GetNormalized(); - return AzToolsFramework::ViewportInteraction::ProjectedViewportRay{ rayOrigin, rayDirection }; - } - //! Utility function to return a viewport ray using the ViewportInteractionRequestBus. inline ProjectedViewportRay ViewportScreenToWorldRay( const AzFramework::ViewportId viewportId, const AzFramework::ScreenPoint& screenPoint) @@ -225,6 +208,10 @@ namespace AzToolsFramework virtual bool StickySelectEnabled() const = 0; //! Returns the default viewport camera position. virtual AZ::Vector3 DefaultEditorCameraPosition() const = 0; + //! Returns if icons are visible in the viewport. + virtual bool IconsVisible() const = 0; + //! Returns if viewport helpers (additional debug drawing) are visible in the viewport. + virtual bool HelpersVisible() const = 0; protected: ~ViewportSettingsRequests() = default; diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Viewport/ViewportSettings.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Viewport/ViewportSettings.cpp index f8550b1a29..3bf25d4231 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Viewport/ViewportSettings.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Viewport/ViewportSettings.cpp @@ -20,6 +20,8 @@ namespace AzToolsFramework constexpr AZStd::string_view ScaleManipulatorBoxHalfExtentSetting = "/Amazon/Preferences/Editor/Manipulator/ScaleManipulatorBoxHalfExtent"; constexpr AZStd::string_view RotationManipulatorRadiusSetting = "/Amazon/Preferences/Editor/Manipulator/RotationManipulatorRadius"; constexpr AZStd::string_view ManipulatorViewBaseScaleSetting = "/Amazon/Preferences/Editor/Manipulator/ViewBaseScale"; + constexpr AZStd::string_view IconsVisibleSetting = "/Amazon/Preferences/Editor/IconsVisible"; + constexpr AZStd::string_view HelpersVisibleSetting = "/Amazon/Preferences/Editor/HelpersVisible"; bool FlipManipulatorAxesTowardsView() { @@ -120,4 +122,24 @@ namespace AzToolsFramework { SetRegistry(ManipulatorViewBaseScaleSetting, scale); } + + bool IconsVisible() + { + return GetRegistry(IconsVisibleSetting, true); + } + + void SetIconsVisible(const bool visible) + { + SetRegistry(IconsVisibleSetting, visible); + } + + bool HelpersVisible() + { + return GetRegistry(HelpersVisibleSetting, true); + } + + void SetHelpersVisible(const bool visible) + { + SetRegistry(HelpersVisibleSetting, visible); + } } // namespace AzToolsFramework diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Viewport/ViewportSettings.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Viewport/ViewportSettings.h index f5371b6035..80880e0bae 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Viewport/ViewportSettings.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Viewport/ViewportSettings.h @@ -66,4 +66,10 @@ namespace AzToolsFramework float ManipulatorViewBaseScale(); void SetManipulatorViewBaseScale(float scale); + + bool IconsVisible(); + void SetIconsVisible(bool visible); + + bool HelpersVisible(); + void SetHelpersVisible(bool visible); } // namespace AzToolsFramework diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Viewport/ViewportTypes.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Viewport/ViewportTypes.cpp index 546320d1e9..f884ab245e 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Viewport/ViewportTypes.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Viewport/ViewportTypes.cpp @@ -49,5 +49,22 @@ namespace AzToolsFramework ->Field("MouseEvent", &MouseInteractionEvent::m_mouseEvent) ->Field("WheelDelta", &MouseInteractionEvent::m_wheelDelta); } + + MouseInteraction BuildMouseInteraction( + const MousePick& mousePick, const MouseButtons buttons, const InteractionId interactionId, const KeyboardModifiers modifiers) + { + MouseInteraction interaction; + interaction.m_mousePick = mousePick; + interaction.m_mouseButtons = buttons; + interaction.m_interactionId = interactionId; + interaction.m_keyboardModifiers = modifiers; + return interaction; + } + + MouseInteractionEvent BuildMouseInteractionEvent( + const MouseInteraction& mouseInteraction, const MouseEvent event, const bool cursorCaptured /*= false*/) + { + return MouseInteractionEvent(mouseInteraction, event, cursorCaptured); + } } // namespace ViewportInteraction } // namespace AzToolsFramework diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Viewport/ViewportTypes.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Viewport/ViewportTypes.h index bc1d277609..903c91fb0a 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Viewport/ViewportTypes.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Viewport/ViewportTypes.h @@ -8,11 +8,11 @@ #pragma once -#include "AzFramework/Viewport/ScreenGeometry.h" - #include #include #include +#include +#include #include @@ -20,7 +20,7 @@ namespace AZ { class ReflectContext; class SerializeContext; -} +} // namespace AZ namespace AzToolsFramework { @@ -178,6 +178,12 @@ namespace AzToolsFramework //! @cond AZ_TYPE_INFO(MousePick, "{A69B9562-FC8C-4DE7-9137-0FF867B1513D}"); MousePick() = default; + MousePick(const AZ::Vector3& rayOrigin, const AZ::Vector3& rayDirection, const AzFramework::ScreenPoint& screenPoint) + : m_rayOrigin(rayOrigin) + , m_rayDirection(rayDirection) + , m_screenCoordinates(screenPoint) + { + } //! @endcond AZ::Vector3 m_rayOrigin = AZ::Vector3::CreateZero(); //!< World space. @@ -249,6 +255,22 @@ namespace AzToolsFramework return mouseInteractionEvent.m_wheelDelta; } + //! A ray projection, originating from a point and extending in a direction specified as a normal. + struct ProjectedViewportRay + { + AZ::Vector3 m_origin; + AZ::Vector3 m_direction; + }; + + //! Utility function to return a viewport ray. + inline ProjectedViewportRay ViewportScreenToWorldRay( + const AzFramework::CameraState& cameraState, const AzFramework::ScreenPoint& screenPoint) + { + const AZ::Vector3 rayOrigin = AzFramework::ScreenToWorld(screenPoint, cameraState); + const AZ::Vector3 rayDirection = (rayOrigin - cameraState.m_position).GetNormalized(); + return ProjectedViewportRay{ rayOrigin, rayDirection }; + } + //! Return QPoint from AzFramework::ScreenPoint. inline QPoint QPointFromScreenPoint(const AzFramework::ScreenPoint& screenPoint) { @@ -301,6 +323,27 @@ namespace AzToolsFramework return mouseButtons; } + //! Build a mouse pick from the specified mouse position and camera state. + inline MousePick BuildMousePick(const AzFramework::CameraState& cameraState, const AzFramework::ScreenPoint& screenPoint) + { + const auto ray = ViewportScreenToWorldRay(cameraState, screenPoint); + return MousePick(ray.m_origin, ray.m_direction, screenPoint); + } + + //! Create a mouse interaction from the specified pick, buttons, interaction id and keyboard modifiers. + MouseInteraction BuildMouseInteraction( + const MousePick& mousePick, MouseButtons buttons, InteractionId interactionId, KeyboardModifiers modifiers); + + //! Create a mouse buttons from the specified mouse button. + inline MouseButtons BuildMouseButtons(const MouseButton button) + { + return MouseButtons(aznumeric_cast(button)); + } + + //! Create a mouse interaction event from the specified interaction and event. + MouseInteractionEvent BuildMouseInteractionEvent( + const MouseInteraction& mouseInteraction, MouseEvent event, bool cursorCaptured = false); + //! Reflect all viewport related types. void ViewportInteractionReflect(AZ::ReflectContext* context); } // namespace ViewportInteraction diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorHelpers.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorHelpers.cpp index ee30b9e29d..ace2156d85 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorHelpers.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorHelpers.cpp @@ -52,34 +52,45 @@ AZ_CVAR( AZ::ConsoleFunctorFlags::Null, "Use a lock icon when the cursor is over entities that cannot be interacted with"); +AZ_CVAR(float, ed_iconMinScale, 0.1f, nullptr, AZ::ConsoleFunctorFlags::Null, "Minimum scale for icons in the distance"); +AZ_CVAR(float, ed_iconMaxScale, 1.0f, nullptr, AZ::ConsoleFunctorFlags::Null, "Maximum scale for icons near the camera"); +AZ_CVAR(float, ed_iconCloseDist, 3.0f, nullptr, AZ::ConsoleFunctorFlags::Null, "Distance at which icons are at maximum scale"); +AZ_CVAR(float, ed_iconFarDist, 40.f, nullptr, AZ::ConsoleFunctorFlags::Null, "Distance at which icons are at minimum scale"); + namespace AzToolsFramework { AZ_CLASS_ALLOCATOR_IMPL(EditorHelpers, AZ::SystemAllocator, 0) - static const int s_iconSize = 36; // icon display size (in pixels) - static const float s_iconMinScale = 0.1f; // minimum scale for icons in the distance - static const float s_iconMaxScale = 1.0f; // maximum scale for icons near the camera - static const float s_iconCloseDist = 3.f; // distance at which icons are at maximum scale - static const float s_iconFarDist = 40.f; // distance at which icons are at minimum scale + static const int IconSize = 36; // icon display size (in pixels) // helper function to wrap EBus call to check if helpers are being displayed - // note: the ['?'] icon in the top right of the editor - static bool HelpersVisible() + static bool HelpersVisible(const AzFramework::ViewportId viewportId) { bool helpersVisible = false; - EditorRequestBus::BroadcastResult(helpersVisible, &EditorRequests::DisplayHelpersVisible); + ViewportInteraction::ViewportSettingsRequestBus::EventResult( + helpersVisible, viewportId, &ViewportInteraction::ViewportSettingsRequestBus::Events::HelpersVisible); return helpersVisible; } - // calculate the icon scale based on how far away it is (distanceSq) from a given point - // note: this is mostly likely distance from the camera - static float GetIconScale(const float distSq) + // helper function to wrap EBus call to check if icons are being displayed + static bool IconsVisible(const AzFramework::ViewportId viewportId) { - AZ_PROFILE_FUNCTION(AzToolsFramework); + bool iconsVisible = false; + ViewportInteraction::ViewportSettingsRequestBus::EventResult( + iconsVisible, viewportId, &ViewportInteraction::ViewportSettingsRequestBus::Events::IconsVisible); + return iconsVisible; + } - return s_iconMinScale + - (s_iconMaxScale - s_iconMinScale) * - (1.0f - AZ::GetClamp(AZ::GetMax(0.0f, sqrtf(distSq) - s_iconCloseDist) / s_iconFarDist, 0.0f, 1.0f)); + float GetIconScale(const float distance) + { + return ed_iconMinScale + + (ed_iconMaxScale - ed_iconMinScale) * + (1.0f - AZ::GetClamp(AZ::GetMax(0.0f, distance - ed_iconCloseDist) / (ed_iconFarDist - ed_iconCloseDist), 0.0f, 1.0f)); + } + + float GetIconSize(const float distance) + { + return GetIconScale(distance) * IconSize; } static void DisplayComponents( @@ -171,11 +182,14 @@ namespace AzToolsFramework const int viewportId = mouseInteraction.m_mouseInteraction.m_interactionId.m_viewportId; - const bool helpersVisible = HelpersVisible(); + const bool iconsVisible = IconsVisible(viewportId); + + const AZ::Matrix3x4 cameraView = AzFramework::CameraView(cameraState); + const AZ::Matrix4x4 cameraProjection = AzFramework::CameraProjection(cameraState); // selecting new entities AZ::EntityId entityIdUnderCursor; - float closestDistance = std::numeric_limits::max(); + float closestDistance = AZStd::numeric_limits::max(); for (size_t entityCacheIndex = 0; entityCacheIndex < m_entityDataCache->VisibleEntityDataCount(); ++entityCacheIndex) { const AZ::EntityId entityId = m_entityDataCache->GetVisibleEntityId(entityCacheIndex); @@ -185,8 +199,7 @@ namespace AzToolsFramework continue; } - // 2d screen space selection - did we click an icon - if (helpersVisible) + if (iconsVisible) { // some components choose to hide their icons (e.g. meshes) // we also do not want to test against icons that may not be showing as they're inside a 'closed' entity container @@ -197,17 +210,23 @@ namespace AzToolsFramework const AZ::Vector3& entityPosition = m_entityDataCache->GetVisibleEntityPosition(entityCacheIndex); // selecting based on 2d icon - should only do it when visible and not selected - const AzFramework::ScreenPoint screenPosition = AzFramework::WorldToScreen(entityPosition, cameraState); + const AZ::Vector3 ndcPoint = AzFramework::WorldToScreenNdc(entityPosition, cameraView, cameraProjection); + const AzFramework::ScreenPoint screenPosition = + AzFramework::ScreenPointFromNdc(AZ::Vector3ToVector2(ndcPoint), cameraState.m_viewportSize); - const float distSqFromCamera = cameraState.m_position.GetDistanceSq(entityPosition); - const auto iconRange = static_cast(GetIconScale(distSqFromCamera) * s_iconSize * 0.5f); + const float distanceFromCamera = cameraState.m_position.GetDistance(entityPosition); + const auto iconRange = GetIconSize(distanceFromCamera) * 0.5f; const auto screenCoords = mouseInteraction.m_mouseInteraction.m_mousePick.m_screenCoordinates; + // 2d screen space selection - did we click an icon if (screenCoords.m_x >= screenPosition.m_x - iconRange && screenCoords.m_x <= screenPosition.m_x + iconRange && - screenCoords.m_y >= screenPosition.m_y - iconRange && screenCoords.m_y <= screenPosition.m_y + iconRange) + screenCoords.m_y >= screenPosition.m_y - iconRange && screenCoords.m_y <= screenPosition.m_y + iconRange && + ndcPoint.GetZ() < closestDistance) { + // use ndc z value for distance here which is in 0-1 range so will most likely 'win' when it comes to the + // distance check (this is what we want as the cursor should always favor icons if they are hovered) + closestDistance = ndcPoint.GetZ(); entityIdUnderCursor = entityId; - break; } } } @@ -220,9 +239,14 @@ namespace AzToolsFramework if (AabbIntersectMouseRay(mouseInteraction.m_mouseInteraction, aabb)) { // if success, pick against specific component - if (PickEntity(entityId, mouseInteraction.m_mouseInteraction, closestDistance, viewportId)) + float closestBoundDifference = AZStd::numeric_limits::max(); + if (PickEntity(entityId, mouseInteraction.m_mouseInteraction, closestBoundDifference, viewportId)) { - entityIdUnderCursor = entityId; + if (closestBoundDifference < closestDistance) + { + closestDistance = closestBoundDifference; + entityIdUnderCursor = entityId; + } } } } @@ -276,55 +300,78 @@ namespace AzToolsFramework { AZ_PROFILE_FUNCTION(AzToolsFramework); - if (HelpersVisible()) + const bool iconsVisible = IconsVisible(viewportInfo.m_viewportId); + const bool helpersVisible = HelpersVisible(viewportInfo.m_viewportId); + + auto displayCheck = [this](const size_t entityCacheIndex, const AZ::EntityId entityId) + { + if (!m_entityDataCache->IsVisibleEntityVisible(entityCacheIndex) || !IsSelectableInViewport(entityId)) + { + return false; + } + return true; + }; + + if (helpersVisible) { for (size_t entityCacheIndex = 0; entityCacheIndex < m_entityDataCache->VisibleEntityDataCount(); ++entityCacheIndex) { - const AZ::EntityId entityId = m_entityDataCache->GetVisibleEntityId(entityCacheIndex); - - if (!m_entityDataCache->IsVisibleEntityVisible(entityCacheIndex) || !IsSelectableInViewport(entityId)) + if (const AZ::EntityId entityId = m_entityDataCache->GetVisibleEntityId(entityCacheIndex); + displayCheck(entityCacheIndex, entityId)) { - continue; + // notify components to display + DisplayComponents(entityId, viewportInfo, debugDisplay); } + } + } - // notify components to display - DisplayComponents(entityId, viewportInfo, debugDisplay); + if (iconsVisible) + { + auto editorViewportIconDisplay = EditorViewportIconDisplay::Get(); + if (!editorViewportIconDisplay) + { + return; + } - if (m_entityDataCache->IsVisibleEntityIconHidden(entityCacheIndex) || - (m_entityDataCache->IsVisibleEntitySelected(entityCacheIndex) && !showIconCheck(entityId))) + for (size_t entityCacheIndex = 0; entityCacheIndex < m_entityDataCache->VisibleEntityDataCount(); ++entityCacheIndex) + { + if (const AZ::EntityId entityId = m_entityDataCache->GetVisibleEntityId(entityCacheIndex); + displayCheck(entityCacheIndex, entityId)) { - continue; - } - - int iconTextureId = 0; - EditorEntityIconComponentRequestBus::EventResult( - iconTextureId, entityId, &EditorEntityIconComponentRequests::GetEntityIconTextureId); - - const AZ::Vector3& entityPosition = m_entityDataCache->GetVisibleEntityPosition(entityCacheIndex); - const float distSqFromCamera = cameraState.m_position.GetDistanceSq(entityPosition); - - const float iconScale = GetIconScale(distSqFromCamera); - const float iconSize = s_iconSize * iconScale; - - using ComponentEntityAccentType = Components::EditorSelectionAccentSystemComponent::ComponentEntityAccentType; - const AZ::Color iconHighlight = [this, entityCacheIndex]() - { - if (m_entityDataCache->IsVisibleEntityLocked(entityCacheIndex)) + if (m_entityDataCache->IsVisibleEntityIconHidden(entityCacheIndex) || + (m_entityDataCache->IsVisibleEntitySelected(entityCacheIndex) && !showIconCheck(entityId))) { - return AZ::Color(AZ::u8(100), AZ::u8(100), AZ::u8(100), AZ::u8(255)); + continue; } - if (m_entityDataCache->GetVisibleEntityAccent(entityCacheIndex) == ComponentEntityAccentType::Hover) + int iconTextureId = 0; + EditorEntityIconComponentRequestBus::EventResult( + iconTextureId, entityId, &EditorEntityIconComponentRequests::GetEntityIconTextureId); + + using ComponentEntityAccentType = Components::EditorSelectionAccentSystemComponent::ComponentEntityAccentType; + const AZ::Color iconHighlight = [this, entityCacheIndex]() { - return AZ::Color(AZ::u8(255), AZ::u8(120), AZ::u8(0), AZ::u8(204)); - } + if (m_entityDataCache->IsVisibleEntityLocked(entityCacheIndex)) + { + return AZ::Color(AZ::u8(100), AZ::u8(100), AZ::u8(100), AZ::u8(255)); + } - return AZ::Color(1.0f, 1.0f, 1.0f, 1.0f); - }(); + if (m_entityDataCache->GetVisibleEntityAccent(entityCacheIndex) == ComponentEntityAccentType::Hover) + { + return AZ::Color(AZ::u8(255), AZ::u8(120), AZ::u8(0), AZ::u8(204)); + } - EditorViewportIconDisplay::Get()->DrawIcon({ viewportInfo.m_viewportId, iconTextureId, iconHighlight, entityPosition, - EditorViewportIconDisplayInterface::CoordinateSpace::WorldSpace, - AZ::Vector2{ iconSize, iconSize } }); + return AZ::Color(1.0f, 1.0f, 1.0f, 1.0f); + }(); + + const AZ::Vector3& entityPosition = m_entityDataCache->GetVisibleEntityPosition(entityCacheIndex); + const float distanceFromCamera = cameraState.m_position.GetDistance(entityPosition); + const float iconSize = GetIconSize(distanceFromCamera); + + editorViewportIconDisplay->DrawIcon({ viewportInfo.m_viewportId, iconTextureId, iconHighlight, entityPosition, + EditorViewportIconDisplayInterface::CoordinateSpace::WorldSpace, + AZ::Vector2{ iconSize, iconSize } }); + } } } } diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorHelpers.h b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorHelpers.h index 458f15c1f2..358e6d9117 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorHelpers.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorHelpers.h @@ -106,4 +106,12 @@ namespace AzToolsFramework const EditorVisibleEntityDataCache* m_entityDataCache = nullptr; //!< Entity Data queried by the EditorHelpers. const FocusModeInterface* m_focusModeInterface = nullptr; //!< API to interact with focus mode functionality. }; + + //! Calculate the icon scale based on how far away it is from a given point. + //! @note This is mostly likely distance from the camera. + float GetIconScale(float distance); + + //! Calculate the icon size based on how far away it is from a given point. + //! @note This is the base icon size multiplied by the icon scale to give a final viewport size. + float GetIconSize(float distance); } // namespace AzToolsFramework diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorTransformComponentSelection.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorTransformComponentSelection.cpp index bd9292db32..b14f58fafa 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorTransformComponentSelection.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorTransformComponentSelection.cpp @@ -2521,10 +2521,9 @@ namespace AzToolsFramework AZStd::erase_if( m_selectedEntityIds, [readOnlyEntityPublicInterface](auto entityId) - { - return readOnlyEntityPublicInterface->IsReadOnly(entityId); - } - ); + { + return readOnlyEntityPublicInterface->IsReadOnly(entityId); + }); } // note: create/destroy pattern to be addressed @@ -3285,9 +3284,9 @@ namespace AzToolsFramework QObject::connect( action, &QAction::triggered, action, [this] - { - ToggleCenterPivotSelection(); - }); + { + ToggleCenterPivotSelection(); + }); } } diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorTransformComponentSelectionRequestBus.h b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorTransformComponentSelectionRequestBus.h index 35f5b0ba99..7ae1db1073 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorTransformComponentSelectionRequestBus.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorTransformComponentSelectionRequestBus.h @@ -32,6 +32,8 @@ namespace AzToolsFramework constexpr inline AZ::Crc32 EditReset = AZ_CRC_CE("com.o3de.action.editortransform.editreset"); constexpr inline AZ::Crc32 EditResetManipulator = AZ_CRC_CE("com.o3de.action.editortransform.editresetmanipulator"); constexpr inline AZ::Crc32 ViewportUiVisible = AZ_CRC_CE("com.o3de.action.editortransform.viewportuivisible"); + constexpr inline AZ::Crc32 Helpers = AZ_CRC_CE("com.o3de.action.editor.helpers"); + constexpr inline AZ::Crc32 Icons = AZ_CRC_CE("com.o3de.action.editor.icons"); //@} //! Provide interface for EditorTransformComponentSelection requests. diff --git a/Code/Framework/AzToolsFramework/Tests/EditorTransformComponentSelectionTests.cpp b/Code/Framework/AzToolsFramework/Tests/EditorTransformComponentSelectionTests.cpp index 859cc67c41..dc9e1180b7 100644 --- a/Code/Framework/AzToolsFramework/Tests/EditorTransformComponentSelectionTests.cpp +++ b/Code/Framework/AzToolsFramework/Tests/EditorTransformComponentSelectionTests.cpp @@ -40,16 +40,12 @@ #include -namespace AZ -{ - std::ostream& operator<<(std::ostream& os, const EntityId entityId) - { - return os << entityId.ToString().c_str(); - } -} // namespace AZ - namespace UnitTest { + using AzToolsFramework::ViewportInteraction::BuildMouseButtons; + using AzToolsFramework::ViewportInteraction::BuildMouseInteraction; + using AzToolsFramework::ViewportInteraction::BuildMousePick; + AzToolsFramework::EntityIdList SelectedEntities() { AzToolsFramework::EntityIdList selectedEntitiesBefore; @@ -137,6 +133,18 @@ namespace UnitTest AzToolsFramework::EntityIdList m_entityIds; }; + AZ::EntityId CreateEntityWithBounds(const char* entityName) + { + AZ::Entity* entity = nullptr; + AZ::EntityId entityId = CreateDefaultEditorEntity(entityName, &entity); + + entity->Deactivate(); + entity->CreateComponent(); + entity->Activate(); + + return entityId; + } + class EditorTransformComponentSelectionViewportPickingFixture : public ToolsApplicationFixture { public: @@ -146,21 +154,9 @@ namespace UnitTest // register a simple component implementing BoundsRequestBus and EditorComponentSelectionRequestsBus app->RegisterComponentDescriptor(BoundsTestComponent::CreateDescriptor()); - auto createEntityWithBoundsFn = [](const char* entityName) - { - AZ::Entity* entity = nullptr; - AZ::EntityId entityId = CreateDefaultEditorEntity(entityName, &entity); - - entity->Deactivate(); - entity->CreateComponent(); - entity->Activate(); - - return entityId; - }; - - m_entityId1 = createEntityWithBoundsFn("Entity1"); - m_entityId2 = createEntityWithBoundsFn("Entity2"); - m_entityId3 = createEntityWithBoundsFn("Entity3"); + m_entityId1 = CreateEntityWithBounds("Entity1"); + m_entityId2 = CreateEntityWithBounds("Entity2"); + m_entityId3 = CreateEntityWithBounds("Entity3"); } void PositionEntities() @@ -959,6 +955,9 @@ namespace UnitTest const auto entity2ScreenPosition = AzFramework::WorldToScreen(AzToolsFramework::GetWorldTranslation(m_entityId2), m_cameraState); + // ensure icons are not enabled to avoid them interfering with bound detection + m_viewportManipulatorInteraction->GetViewportInteraction().SetIconsVisible(false); + // click the entity in the viewport m_actionDispatcher->SetStickySelect(true) ->CameraState(m_cameraState) @@ -974,6 +973,137 @@ namespace UnitTest EXPECT_THAT(selectedEntities, UnorderedElementsAreArray(expectedSelectedEntities)); } + // entity can be selected using icon + TEST_F(EditorTransformComponentSelectionViewportPickingManipulatorTestFixture, CursorOverEntityIconReturnsThatEntityId) + { + const AZ::EntityId boundlessEntityId = CreateDefaultEditorEntity("BoundlessEntity"); + + // camera (go to position format) -5.00, -8.00, 5.00, 0.00, 0.00 + AzFramework::SetCameraTransform(m_cameraState, AZ::Transform::CreateTranslation(AZ::Vector3(-5.0f, -8.0f, 5.0f))); + // position entity in the world + AZ::TransformBus::Event(boundlessEntityId, &AZ::TransformBus::Events::SetWorldTranslation, AZ::Vector3(-5.0f, -1.0f, 5.0f)); + + const float distanceFromCamera = m_cameraState.m_position.GetDistance(AzToolsFramework::GetWorldTranslation(boundlessEntityId)); + + const auto quaterIconSize = AzToolsFramework::GetIconSize(distanceFromCamera) * 0.25f; + const auto entity1ScreenPosition = + AzFramework::WorldToScreen(AzToolsFramework::GetWorldTranslation(boundlessEntityId), m_cameraState) + + AzFramework::ScreenVectorFromVector2(AZ::Vector2(quaterIconSize)); + + AzToolsFramework::EditorVisibleEntityDataCache editorVisibleEntityDataCache; + AzToolsFramework::EditorHelpers editorHelpers(&editorVisibleEntityDataCache); + + const auto viewportId = m_viewportManipulatorInteraction->GetViewportInteraction().GetViewportId(); + const auto mousePick = BuildMousePick(m_cameraState, entity1ScreenPosition); + const auto mouseInteraction = BuildMouseInteraction( + mousePick, BuildMouseButtons(AzToolsFramework::ViewportInteraction::MouseButton::None), + AzToolsFramework::ViewportInteraction::InteractionId(AZ::EntityId(), viewportId), + AzToolsFramework::ViewportInteraction::KeyboardModifiers()); + const auto mouseInteractionEvent = AzToolsFramework::ViewportInteraction::BuildMouseInteractionEvent( + mouseInteraction, AzToolsFramework::ViewportInteraction::MouseEvent::Move, false); + + // mimic mouse move + m_actionDispatcher->CameraState(m_cameraState)->MousePosition(entity1ScreenPosition); + + // simulate hovering over an icon in the viewport + editorVisibleEntityDataCache.CalculateVisibleEntityDatas(AzFramework::ViewportInfo{ viewportId }); + auto entityIdUnderCursor = editorHelpers.FindEntityIdUnderCursor(m_cameraState, mouseInteractionEvent); + + using ::testing::Eq; + EXPECT_THAT(entityIdUnderCursor.EntityIdUnderCursor(), Eq(boundlessEntityId)); + } + + // overlapping icons, nearest is detected + TEST_F(EditorTransformComponentSelectionViewportPickingManipulatorTestFixture, CursorOverOverlappingEntityIconsReturnsClosestEntityId) + { + const AZ::EntityId boundlessEntityId1 = CreateDefaultEditorEntity("BoundlessEntity1"); + const AZ::EntityId boundlessEntityId2 = CreateDefaultEditorEntity("BoundlessEntity2"); + + // camera (go to position format) -5.00, -8.00, 5.00, 0.00, 0.00 + AzFramework::SetCameraTransform(m_cameraState, AZ::Transform::CreateTranslation(AZ::Vector3(-5.0f, -8.0f, 5.0f))); + // position entities in the world + AZ::TransformBus::Event(boundlessEntityId1, &AZ::TransformBus::Events::SetWorldTranslation, AZ::Vector3(-5.0f, -1.0f, 5.0f)); + // note: boundlessEntityId2 is closer to the camera + AZ::TransformBus::Event(boundlessEntityId2, &AZ::TransformBus::Events::SetWorldTranslation, AZ::Vector3(-5.0f, -3.0f, 5.0f)); + + const float distanceFromCamera = m_cameraState.m_position.GetDistance(AzToolsFramework::GetWorldTranslation(boundlessEntityId2)); + + const auto quaterIconSize = AzToolsFramework::GetIconSize(distanceFromCamera) * 0.25f; + const auto entity2ScreenPosition = + AzFramework::WorldToScreen(AzToolsFramework::GetWorldTranslation(boundlessEntityId2), m_cameraState) + + AzFramework::ScreenVectorFromVector2(AZ::Vector2(quaterIconSize)); + + AzToolsFramework::EditorVisibleEntityDataCache editorVisibleEntityDataCache; + AzToolsFramework::EditorHelpers editorHelpers(&editorVisibleEntityDataCache); + + const auto viewportId = m_viewportManipulatorInteraction->GetViewportInteraction().GetViewportId(); + const auto mousePick = BuildMousePick(m_cameraState, entity2ScreenPosition); + const auto mouseInteraction = BuildMouseInteraction( + mousePick, BuildMouseButtons(AzToolsFramework::ViewportInteraction::MouseButton::None), + AzToolsFramework::ViewportInteraction::InteractionId(AZ::EntityId(), viewportId), + AzToolsFramework::ViewportInteraction::KeyboardModifiers()); + const auto mouseInteractionEvent = AzToolsFramework::ViewportInteraction::BuildMouseInteractionEvent( + mouseInteraction, AzToolsFramework::ViewportInteraction::MouseEvent::Move, false); + + // mimic mouse move + m_actionDispatcher->CameraState(m_cameraState)->MousePosition(entity2ScreenPosition); + + // simulate hovering over an icon in the viewport + editorVisibleEntityDataCache.CalculateVisibleEntityDatas(AzFramework::ViewportInfo{ viewportId }); + auto entityIdUnderCursor = editorHelpers.FindEntityIdUnderCursor(m_cameraState, mouseInteractionEvent); + + using ::testing::Eq; + EXPECT_THAT(entityIdUnderCursor.EntityIdUnderCursor(), Eq(boundlessEntityId2)); + } + + // if an entity with an icon is behind an entity with a bound, the entity with the icon will be selected + // even if the bound is closer (this is because icons are treated as if they are on the near clip plane) + TEST_F( + EditorTransformComponentSelectionViewportPickingManipulatorTestFixture, FurtherAwayEntityWithIconReturnedWhenBoundEntityIsInFront) + { + const AZ::EntityId boundEntityId = CreateEntityWithBounds("BoundEntity"); + const AZ::EntityId boundlessEntityId = CreateDefaultEditorEntity("BoundlessEntity"); + + auto* boundTestComponent = AzToolsFramework::GetEntityById(boundEntityId)->FindComponent(); + boundTestComponent->m_localBounds = AZ::Aabb::CreateFromMinMax(AZ::Vector3(-1.5f, -0.5f, -0.5f), AZ::Vector3(1.5f, 0.5, 0.5f)); + + // camera (go to position format) -5.00, -8.00, 5.00, 0.00, 0.00 + AzFramework::SetCameraTransform(m_cameraState, AZ::Transform::CreateTranslation(AZ::Vector3(-5.0f, -8.0f, 5.0f))); + // position entities in the world + AZ::TransformBus::Event(boundEntityId, &AZ::TransformBus::Events::SetWorldTranslation, AZ::Vector3(-4.0f, -3.0f, 5.0f)); + // note: boundlessEntityId2 is closer to the camera + AZ::TransformBus::Event(boundlessEntityId, &AZ::TransformBus::Events::SetWorldTranslation, AZ::Vector3(-5.0f, -1.0f, 5.0f)); + + const float distanceFromCamera = m_cameraState.m_position.GetDistance(AzToolsFramework::GetWorldTranslation(boundlessEntityId)); + + const auto quaterIconSize = AzToolsFramework::GetIconSize(distanceFromCamera) * 0.25f; + const auto entity2ScreenPosition = + AzFramework::WorldToScreen(AzToolsFramework::GetWorldTranslation(boundlessEntityId), m_cameraState) + + AzFramework::ScreenVectorFromVector2(AZ::Vector2(quaterIconSize)); + + AzToolsFramework::EditorVisibleEntityDataCache editorVisibleEntityDataCache; + AzToolsFramework::EditorHelpers editorHelpers(&editorVisibleEntityDataCache); + + const auto viewportId = m_viewportManipulatorInteraction->GetViewportInteraction().GetViewportId(); + const auto mousePick = BuildMousePick(m_cameraState, entity2ScreenPosition); + const auto mouseInteraction = BuildMouseInteraction( + mousePick, BuildMouseButtons(AzToolsFramework::ViewportInteraction::MouseButton::None), + AzToolsFramework::ViewportInteraction::InteractionId(AZ::EntityId(), viewportId), + AzToolsFramework::ViewportInteraction::KeyboardModifiers()); + const auto mouseInteractionEvent = AzToolsFramework::ViewportInteraction::BuildMouseInteractionEvent( + mouseInteraction, AzToolsFramework::ViewportInteraction::MouseEvent::Move, false); + + // mimic mouse move + m_actionDispatcher->CameraState(m_cameraState)->MousePosition(entity2ScreenPosition); + + // simulate hovering over an icon in the viewport + editorVisibleEntityDataCache.CalculateVisibleEntityDatas(AzFramework::ViewportInfo{ viewportId }); + auto entityIdUnderCursor = editorHelpers.FindEntityIdUnderCursor(m_cameraState, mouseInteractionEvent); + + using ::testing::Eq; + EXPECT_THAT(entityIdUnderCursor.EntityIdUnderCursor(), Eq(boundlessEntityId)); + } + class EditorTransformComponentSelectionViewportPickingManipulatorTestFixtureParam : public EditorTransformComponentSelectionViewportPickingManipulatorTestFixture , public ::testing::WithParamInterface @@ -1709,8 +1839,9 @@ namespace UnitTest using MouseInteractionResult = AzToolsFramework::ViewportInteraction::MouseInteractionResult; public: - WheelEventWidget(QWidget* parent = nullptr) + WheelEventWidget(const AzFramework::ViewportId viewportId, QWidget* parent = nullptr) : QWidget(parent) + , m_viewportId(viewportId) { } @@ -1719,7 +1850,7 @@ namespace UnitTest namespace vi = AzToolsFramework::ViewportInteraction; vi::MouseInteraction mouseInteraction; mouseInteraction.m_interactionId.m_cameraId = AZ::EntityId(); - mouseInteraction.m_interactionId.m_viewportId = 0; + mouseInteraction.m_interactionId.m_viewportId = m_viewportId; mouseInteraction.m_mouseButtons = vi::BuildMouseButtons(ev->buttons()); mouseInteraction.m_mousePick = vi::MousePick(); mouseInteraction.m_keyboardModifiers = vi::BuildKeyboardModifiers(ev->modifiers()); @@ -1731,15 +1862,15 @@ namespace UnitTest } MouseInteractionResult m_mouseInteractionResult; + AzFramework::ViewportId m_viewportId; }; - TEST_F(EditorTransformComponentSelectionFixture, MouseScrollWheelSwitchesTransformMode) + TEST_F(EditorTransformComponentSelectionManipulatorTestFixture, MouseScrollWheelSwitchesTransformMode) { - using ::testing::Eq; namespace vi = AzToolsFramework::ViewportInteraction; using AzToolsFramework::EditorTransformComponentSelectionRequestBus; - const auto transformMode = []() + const auto transformMode = [] { EditorTransformComponentSelectionRequestBus::Events::Mode transformMode; EditorTransformComponentSelectionRequestBus::EventResult( @@ -1752,7 +1883,7 @@ namespace UnitTest // preconditions EXPECT_THAT(transformMode(), EditorTransformComponentSelectionRequestBus::Events::Mode::Translation); - auto wheelEventWidget = WheelEventWidget(); + auto wheelEventWidget = WheelEventWidget(m_viewportManipulatorInteraction->GetViewportInteraction().GetViewportId()); // attach the global event filter to the placeholder widget AzQtComponents::GlobalEventFilter globalEventFilter(QApplication::instance()); wheelEventWidget.installEventFilter(&globalEventFilter); @@ -1768,6 +1899,7 @@ namespace UnitTest // then // transform mode has changed and mouse event was handled + using ::testing::Eq; EXPECT_THAT(transformMode(), Eq(EditorTransformComponentSelectionRequestBus::Events::Mode::Rotation)); EXPECT_THAT(wheelEventWidget.m_mouseInteractionResult, Eq(vi::MouseInteractionResult::Viewport)); } @@ -3100,7 +3232,7 @@ namespace UnitTest const AZ::Transform finalEntityTransform = AzToolsFramework::GetWorldTransform(m_entityIdBox); const auto viewportRay = AzToolsFramework::ViewportInteraction::ViewportScreenToWorldRay(m_cameraState, initialPositionScreen); - const auto distanceAway = (finalEntityTransform.GetTranslation() - viewportRay.origin).GetLength(); + const auto distanceAway = (finalEntityTransform.GetTranslation() - viewportRay.m_origin).GetLength(); // ensure final world positions match EXPECT_THAT(finalEntityTransform, IsCloseTolerance(finalTransformWorld, 0.01f)); diff --git a/Code/Framework/AzToolsFramework/Tests/EntityIdQLabelTests.cpp b/Code/Framework/AzToolsFramework/Tests/EntityIdQLabelTests.cpp index 486224c011..c2b4ff3cc4 100644 --- a/Code/Framework/AzToolsFramework/Tests/EntityIdQLabelTests.cpp +++ b/Code/Framework/AzToolsFramework/Tests/EntityIdQLabelTests.cpp @@ -62,7 +62,6 @@ namespace UnitTest void BrowseForAssets(AssetBrowser::AssetSelectionModel& /*selection*/) override {} int GetIconTextureIdFromEntityIconPath(const AZStd::string& entityIconPath) override { AZ_UNUSED(entityIconPath); return 0; } - bool DisplayHelpersVisible() override { return false; } void GoToSelectedEntitiesInViewports() override { diff --git a/Code/Framework/AzToolsFramework/Tests/FocusMode/ContainerEntitySelectionTests.cpp b/Code/Framework/AzToolsFramework/Tests/FocusMode/ContainerEntitySelectionTests.cpp index a47e41da42..0ad61b924b 100644 --- a/Code/Framework/AzToolsFramework/Tests/FocusMode/ContainerEntitySelectionTests.cpp +++ b/Code/Framework/AzToolsFramework/Tests/FocusMode/ContainerEntitySelectionTests.cpp @@ -8,12 +8,12 @@ #include -namespace AzToolsFramework +namespace UnitTest { - TEST_F(EditorFocusModeSelectionFixture, ContainerEntitySelectionTests_FindHighestSelectableEntityWithNoContainers) + TEST_F(EditorFocusModeSelectionFixture, ContainerEntitySelectionFindHighestSelectableEntityWithNoContainers) { // When no containers are in the way, the function will just return the entityId of the entity that was clicked. - + // Click on Car Entity ClickAtWorldPositionOnViewport(WorldCarEntityPosition); @@ -23,7 +23,7 @@ namespace AzToolsFramework EXPECT_EQ(selectedEntitiesAfter.front(), m_entityMap[CarEntityName]); } - TEST_F(EditorFocusModeSelectionFixture, ContainerEntitySelectionTests_FindHighestSelectableEntityWithClosedContainer) + TEST_F(EditorFocusModeSelectionFixture, ContainerEntitySelectionFindHighestSelectableEntityWithClosedContainer) { // If a closed container is an ancestor of the queried entity, the closed container is selected. m_containerEntityInterface->RegisterEntityAsContainer(m_entityMap[StreetEntityName]); // Containers are closed by default @@ -40,7 +40,7 @@ namespace AzToolsFramework m_containerEntityInterface->UnregisterEntityAsContainer(m_entityMap[StreetEntityName]); } - TEST_F(EditorFocusModeSelectionFixture, ContainerEntitySelectionTests_FindHighestSelectableEntityWithOpenContainer) + TEST_F(EditorFocusModeSelectionFixture, ContainerEntitySelectionFindHighestSelectableEntityWithOpenContainer) { // If a closed container is an ancestor of the queried entity, the closed container is selected. m_containerEntityInterface->RegisterEntityAsContainer(m_entityMap[StreetEntityName]); @@ -58,7 +58,7 @@ namespace AzToolsFramework m_containerEntityInterface->UnregisterEntityAsContainer(m_entityMap[StreetEntityName]); } - TEST_F(EditorFocusModeSelectionFixture, ContainerEntitySelectionTests_FindHighestSelectableEntityWithMultipleClosedContainers) + TEST_F(EditorFocusModeSelectionFixture, ContainerEntitySelectionFindHighestSelectableEntityWithMultipleClosedContainers) { // If multiple closed containers are ancestors of the queried entity, the highest closed container is selected. m_containerEntityInterface->RegisterEntityAsContainer(m_entityMap[StreetEntityName]); @@ -77,7 +77,7 @@ namespace AzToolsFramework m_containerEntityInterface->UnregisterEntityAsContainer(m_entityMap[CityEntityName]); } - TEST_F(EditorFocusModeSelectionFixture, ContainerEntitySelectionTests_FindHighestSelectableEntityWithMultipleContainers) + TEST_F(EditorFocusModeSelectionFixture, ContainerEntitySelectionFindHighestSelectableEntityWithMultipleContainers) { // If multiple containers are ancestors of the queried entity, the highest closed container is selected. m_containerEntityInterface->RegisterEntityAsContainer(m_entityMap[StreetEntityName]); @@ -96,4 +96,4 @@ namespace AzToolsFramework m_containerEntityInterface->UnregisterEntityAsContainer(m_entityMap[StreetEntityName]); m_containerEntityInterface->UnregisterEntityAsContainer(m_entityMap[CityEntityName]); } -} +} // namespace UnitTest diff --git a/Code/Framework/AzToolsFramework/Tests/FocusMode/ContainerEntityTests.cpp b/Code/Framework/AzToolsFramework/Tests/FocusMode/ContainerEntityTests.cpp index 031062f027..db81f7bb0b 100644 --- a/Code/Framework/AzToolsFramework/Tests/FocusMode/ContainerEntityTests.cpp +++ b/Code/Framework/AzToolsFramework/Tests/FocusMode/ContainerEntityTests.cpp @@ -8,9 +8,9 @@ #include -namespace AzToolsFramework +namespace UnitTest { - TEST_F(EditorFocusModeFixture, ContainerEntityTests_Register) + TEST_F(EditorFocusModeFixture, ContainerEntityRegister) { // Registering an entity is successful. auto outcome = m_containerEntityInterface->RegisterEntityAsContainer(m_entityMap[CarEntityName]); @@ -20,7 +20,7 @@ namespace AzToolsFramework m_containerEntityInterface->UnregisterEntityAsContainer(m_entityMap[CarEntityName]); } - TEST_F(EditorFocusModeFixture, ContainerEntityTests_RegisterTwice) + TEST_F(EditorFocusModeFixture, ContainerEntityRegisterTwice) { // Registering an entity twice fails. m_containerEntityInterface->RegisterEntityAsContainer(m_entityMap[CarEntityName]); @@ -31,7 +31,7 @@ namespace AzToolsFramework m_containerEntityInterface->UnregisterEntityAsContainer(m_entityMap[CarEntityName]); } - TEST_F(EditorFocusModeFixture, ContainerEntityTests_Unregister) + TEST_F(EditorFocusModeFixture, ContainerEntityUnregister) { // Unregistering a container entity is successful. m_containerEntityInterface->RegisterEntityAsContainer(m_entityMap[CarEntityName]); @@ -39,21 +39,21 @@ namespace AzToolsFramework EXPECT_TRUE(outcome.IsSuccess()); } - TEST_F(EditorFocusModeFixture, ContainerEntityTests_UnregisterRegularEntity) + TEST_F(EditorFocusModeFixture, ContainerEntityUnregisterRegularEntity) { // Unregistering an entity that was not previously registered fails. auto outcome = m_containerEntityInterface->UnregisterEntityAsContainer(m_entityMap[CarEntityName]); EXPECT_FALSE(outcome.IsSuccess()); } - TEST_F(EditorFocusModeFixture, ContainerEntityTests_UnregisterTwice) + TEST_F(EditorFocusModeFixture, ContainerEntityUnregisterTwice) { // Unregistering a container entity twice fails. auto outcome = m_containerEntityInterface->UnregisterEntityAsContainer(m_entityMap[CarEntityName]); EXPECT_FALSE(outcome.IsSuccess()); } - TEST_F(EditorFocusModeFixture, ContainerEntityTests_IsContainerOnRegularEntity) + TEST_F(EditorFocusModeFixture, ContainerEntityIsContainerOnRegularEntity) { // If a regular entity is passed, IsContainer returns false. // Note that we use a different entity than the tests above to validate a completely new EntityId. @@ -61,7 +61,7 @@ namespace AzToolsFramework EXPECT_FALSE(isContainer); } - TEST_F(EditorFocusModeFixture, ContainerEntityTests_IsContainerOnRegisteredContainer) + TEST_F(EditorFocusModeFixture, ContainerEntityIsContainerOnRegisteredContainer) { // If a container entity is passed, IsContainer returns true. m_containerEntityInterface->RegisterEntityAsContainer(m_entityMap[SportsCarEntityName]); @@ -72,7 +72,7 @@ namespace AzToolsFramework m_containerEntityInterface->UnregisterEntityAsContainer(m_entityMap[SportsCarEntityName]); } - TEST_F(EditorFocusModeFixture, ContainerEntityTests_IsContainerOnUnRegisteredContainer) + TEST_F(EditorFocusModeFixture, ContainerEntityIsContainerOnUnRegisteredContainer) { // If an entity that was previously a container but was then unregistered is passed, IsContainer returns false. m_containerEntityInterface->RegisterEntityAsContainer(m_entityMap[SportsCarEntityName]); @@ -82,14 +82,14 @@ namespace AzToolsFramework EXPECT_FALSE(isContainer); } - TEST_F(EditorFocusModeFixture, ContainerEntityTests_SetContainerOpenOnRegularEntity) + TEST_F(EditorFocusModeFixture, ContainerEntitySetContainerOpenOnRegularEntity) { // Setting a regular entity to open should return a failure. auto outcome = m_containerEntityInterface->SetContainerOpen(m_entityMap[StreetEntityName], true); EXPECT_FALSE(outcome.IsSuccess()); } - TEST_F(EditorFocusModeFixture, ContainerEntityTests_SetContainerOpen) + TEST_F(EditorFocusModeFixture, ContainerEntitySetContainerOpen) { // Set a container entity to open, and verify the operation was successful. m_containerEntityInterface->RegisterEntityAsContainer(m_entityMap[StreetEntityName]); @@ -100,7 +100,7 @@ namespace AzToolsFramework m_containerEntityInterface->UnregisterEntityAsContainer(m_entityMap[StreetEntityName]); } - TEST_F(EditorFocusModeFixture, ContainerEntityTests_SetContainerOpenTwice) + TEST_F(EditorFocusModeFixture, ContainerEntitySetContainerOpenTwice) { // Set a container entity to open twice, and verify that does not cause a failure (as intended). m_containerEntityInterface->RegisterEntityAsContainer(m_entityMap[StreetEntityName]); @@ -112,7 +112,7 @@ namespace AzToolsFramework m_containerEntityInterface->UnregisterEntityAsContainer(m_entityMap[StreetEntityName]); } - TEST_F(EditorFocusModeFixture, ContainerEntityTests_SetContainerClosed) + TEST_F(EditorFocusModeFixture, ContainerEntitySetContainerClosed) { // Set a container entity to closed, and verify the operation was successful. m_containerEntityInterface->RegisterEntityAsContainer(m_entityMap[StreetEntityName]); @@ -122,16 +122,16 @@ namespace AzToolsFramework // Restore default state for other tests. m_containerEntityInterface->UnregisterEntityAsContainer(m_entityMap[StreetEntityName]); } - - TEST_F(EditorFocusModeFixture, ContainerEntityTests_IsContainerOpenOnRegularEntity) + + TEST_F(EditorFocusModeFixture, ContainerEntityIsContainerOpenOnRegularEntity) { // Query open state on a regular entity, and verify it returns true. // Open containers behave exactly as regular entities, so this is the expected return value. bool isOpen = m_containerEntityInterface->IsContainerOpen(m_entityMap[CityEntityName]); EXPECT_TRUE(isOpen); } - - TEST_F(EditorFocusModeFixture, ContainerEntityTests_IsContainerOpenOnDefaultContainerEntity) + + TEST_F(EditorFocusModeFixture, ContainerEntityIsContainerOpenOnDefaultContainerEntity) { // Query open state on a newly registered container entity, and verify it returns false. // Containers are registered closed by default. @@ -142,8 +142,8 @@ namespace AzToolsFramework // Restore default state for other tests. m_containerEntityInterface->UnregisterEntityAsContainer(m_entityMap[CityEntityName]); } - - TEST_F(EditorFocusModeFixture, ContainerEntityTests_IsContainerOpenOnOpenContainerEntity) + + TEST_F(EditorFocusModeFixture, ContainerEntityIsContainerOpenOnOpenContainerEntity) { // Query open state on a container entity that was opened, and verify it returns true. m_containerEntityInterface->RegisterEntityAsContainer(m_entityMap[CityEntityName]); @@ -154,8 +154,8 @@ namespace AzToolsFramework // Restore default state for other tests. m_containerEntityInterface->UnregisterEntityAsContainer(m_entityMap[CityEntityName]); } - - TEST_F(EditorFocusModeFixture, ContainerEntityTests_IsContainerOpenOnClosedContainerEntity) + + TEST_F(EditorFocusModeFixture, ContainerEntityIsContainerOpenOnClosedContainerEntity) { // Query open state on a container entity that was opened and then closed, and verify it returns false. m_containerEntityInterface->RegisterEntityAsContainer(m_entityMap[CityEntityName]); @@ -167,8 +167,8 @@ namespace AzToolsFramework // Restore default state for other tests. m_containerEntityInterface->UnregisterEntityAsContainer(m_entityMap[CityEntityName]); } - - TEST_F(EditorFocusModeFixture, ContainerEntityTests_ContainerOpenStateIsPreserved) + + TEST_F(EditorFocusModeFixture, ContainerEntityContainerOpenStateIsPreserved) { // Register an entity as container, open it, then unregister it. // When the entity is registered again, the open state should be preserved. @@ -184,15 +184,15 @@ namespace AzToolsFramework // Restore default state for other tests. m_containerEntityInterface->UnregisterEntityAsContainer(m_entityMap[CityEntityName]); } - - TEST_F(EditorFocusModeFixture, ContainerEntityTests_ClearSucceeds) + + TEST_F(EditorFocusModeFixture, ContainerEntityClearSucceeds) { // The Clear function works if no container is registered. auto outcome = m_containerEntityInterface->Clear(m_editorEntityContextId); EXPECT_TRUE(outcome.IsSuccess()); } - - TEST_F(EditorFocusModeFixture, ContainerEntityTests_ClearFailsIfContainersAreStillRegistered) + + TEST_F(EditorFocusModeFixture, ContainerEntityClearFailsIfContainersAreStillRegistered) { // The Clear function fails if a container is registered. m_containerEntityInterface->RegisterEntityAsContainer(m_entityMap[Passenger1EntityName]); @@ -202,8 +202,8 @@ namespace AzToolsFramework // Restore default state for other tests. m_containerEntityInterface->UnregisterEntityAsContainer(m_entityMap[Passenger1EntityName]); } - - TEST_F(EditorFocusModeFixture, ContainerEntityTests_ClearSucceedsIfContainersAreUnregistered) + + TEST_F(EditorFocusModeFixture, ContainerEntityClearSucceedsIfContainersAreUnregistered) { // The Clear function fails if a container is registered. m_containerEntityInterface->RegisterEntityAsContainer(m_entityMap[Passenger1EntityName]); @@ -212,7 +212,7 @@ namespace AzToolsFramework EXPECT_TRUE(outcome.IsSuccess()); } - TEST_F(EditorFocusModeFixture, ContainerEntityTests_ClearDeletesPreservedOpenStates) + TEST_F(EditorFocusModeFixture, ContainerEntityClearDeletesPreservedOpenStates) { // Register an entity as container, open it, unregister it, then call clear. // When the entity is registered again, the open state should not be preserved. @@ -230,14 +230,14 @@ namespace AzToolsFramework m_containerEntityInterface->UnregisterEntityAsContainer(m_entityMap[Passenger1EntityName]); } - TEST_F(EditorFocusModeFixture, ContainerEntityTests_FindHighestSelectableEntityWithNoContainers) + TEST_F(EditorFocusModeFixture, ContainerEntityFindHighestSelectableEntityWithNoContainers) { // When no containers are in the way, the function will just return the entityId that was passed to it. AZ::EntityId selectedEntityId = m_containerEntityInterface->FindHighestSelectableEntity(m_entityMap[Passenger2EntityName]); EXPECT_EQ(selectedEntityId, m_entityMap[Passenger2EntityName]); } - TEST_F(EditorFocusModeFixture, ContainerEntityTests_FindHighestSelectableEntityWithClosedContainer) + TEST_F(EditorFocusModeFixture, ContainerEntityFindHighestSelectableEntityWithClosedContainer) { // If a closed container is an ancestor of the queried entity, the closed container is selected. m_containerEntityInterface->RegisterEntityAsContainer(m_entityMap[SportsCarEntityName]); // Containers are closed by default @@ -248,7 +248,7 @@ namespace AzToolsFramework m_containerEntityInterface->UnregisterEntityAsContainer(m_entityMap[SportsCarEntityName]); } - TEST_F(EditorFocusModeFixture, ContainerEntityTests_FindHighestSelectableEntityWithOpenContainer) + TEST_F(EditorFocusModeFixture, ContainerEntityFindHighestSelectableEntityWithOpenContainer) { // If an open container is an ancestor of the queried entity, it is ignored. m_containerEntityInterface->RegisterEntityAsContainer(m_entityMap[SportsCarEntityName]); @@ -261,7 +261,7 @@ namespace AzToolsFramework m_containerEntityInterface->UnregisterEntityAsContainer(m_entityMap[SportsCarEntityName]); } - TEST_F(EditorFocusModeFixture, ContainerEntityTests_FindHighestSelectableEntityWithMultipleClosedContainers) + TEST_F(EditorFocusModeFixture, ContainerEntityFindHighestSelectableEntityWithMultipleClosedContainers) { // If multiple closed containers are ancestors of the queried entity, the highest closed container is selected. m_containerEntityInterface->RegisterEntityAsContainer(m_entityMap[StreetEntityName]); @@ -275,7 +275,7 @@ namespace AzToolsFramework m_containerEntityInterface->UnregisterEntityAsContainer(m_entityMap[SportsCarEntityName]); } - TEST_F(EditorFocusModeFixture, ContainerEntityTests_FindHighestSelectableEntityWithMultipleContainers) + TEST_F(EditorFocusModeFixture, ContainerEntityFindHighestSelectableEntityWithMultipleContainers) { // If multiple containers are ancestors of the queried entity, the highest closed container is selected. m_containerEntityInterface->RegisterEntityAsContainer(m_entityMap[StreetEntityName]); @@ -289,5 +289,4 @@ namespace AzToolsFramework m_containerEntityInterface->UnregisterEntityAsContainer(m_entityMap[StreetEntityName]); m_containerEntityInterface->UnregisterEntityAsContainer(m_entityMap[SportsCarEntityName]); } - -} +} // namespace UnitTest diff --git a/Code/Framework/AzToolsFramework/Tests/FocusMode/EditorFocusModeFixture.cpp b/Code/Framework/AzToolsFramework/Tests/FocusMode/EditorFocusModeFixture.cpp index 49bf7cee15..90becfa46f 100644 --- a/Code/Framework/AzToolsFramework/Tests/FocusMode/EditorFocusModeFixture.cpp +++ b/Code/Framework/AzToolsFramework/Tests/FocusMode/EditorFocusModeFixture.cpp @@ -12,7 +12,7 @@ #include -namespace AzToolsFramework +namespace UnitTest { void ClearSelectedEntities() { @@ -31,14 +31,14 @@ namespace AzToolsFramework void EditorFocusModeFixture::SetUpEditorFixtureImpl() { // Without this, the user settings component would attempt to save on finalize/shutdown. Since the file is - // shared across the whole engine, if multiple tests are run in parallel, the saving could cause a crash + // shared across the whole engine, if multiple tests are run in parallel, the saving could cause a crash // in the unit tests. AZ::UserSettingsComponentRequestBus::Broadcast(&AZ::UserSettingsComponentRequests::DisableSaveOnFinalize); - m_containerEntityInterface = AZ::Interface::Get(); + m_containerEntityInterface = AZ::Interface::Get(); ASSERT_TRUE(m_containerEntityInterface != nullptr); - m_focusModeInterface = AZ::Interface::Get(); + m_focusModeInterface = AZ::Interface::Get(); ASSERT_TRUE(m_focusModeInterface != nullptr); // register a simple component implementing BoundsRequestBus and EditorComponentSelectionRequestsBus @@ -68,26 +68,26 @@ namespace AzToolsFramework ClearSelectedEntities(); } - void EditorFocusModeFixture::GenerateTestHierarchy() + void EditorFocusModeFixture::GenerateTestHierarchy() { /* - * City - * |_ Street - * |_ Car - * | |_ Passenger - * |_ SportsCar - * |_ Passenger - */ + * City + * |_ Street + * |_ Car + * | |_ Passenger + * |_ SportsCar + * |_ Passenger + */ - m_entityMap[CityEntityName] = CreateEditorEntity(CityEntityName, AZ::EntityId()); - m_entityMap[StreetEntityName] = CreateEditorEntity(StreetEntityName, m_entityMap[CityEntityName]); - m_entityMap[CarEntityName] = CreateEditorEntity(CarEntityName, m_entityMap[StreetEntityName]); - m_entityMap[Passenger1EntityName] = CreateEditorEntity(Passenger1EntityName, m_entityMap[CarEntityName]); - m_entityMap[SportsCarEntityName] = CreateEditorEntity(SportsCarEntityName, m_entityMap[StreetEntityName]); - m_entityMap[Passenger2EntityName] = CreateEditorEntity(Passenger2EntityName, m_entityMap[SportsCarEntityName]); + m_entityMap[CityEntityName] = CreateEditorEntity(CityEntityName, AZ::EntityId()); + m_entityMap[StreetEntityName] = CreateEditorEntity(StreetEntityName, m_entityMap[CityEntityName]); + m_entityMap[CarEntityName] = CreateEditorEntity(CarEntityName, m_entityMap[StreetEntityName]); + m_entityMap[Passenger1EntityName] = CreateEditorEntity(Passenger1EntityName, m_entityMap[CarEntityName]); + m_entityMap[SportsCarEntityName] = CreateEditorEntity(SportsCarEntityName, m_entityMap[StreetEntityName]); + m_entityMap[Passenger2EntityName] = CreateEditorEntity(Passenger2EntityName, m_entityMap[SportsCarEntityName]); // Add a BoundsTestComponent to the Car entity. - AZ::Entity* entity = GetEntityById(m_entityMap[CarEntityName]); + AZ::Entity* entity = AzToolsFramework::GetEntityById(m_entityMap[CarEntityName]); entity->Deactivate(); entity->CreateComponent(); @@ -113,4 +113,4 @@ namespace AzToolsFramework return entity->GetId(); } -} +} // namespace UnitTest diff --git a/Code/Framework/AzToolsFramework/Tests/FocusMode/EditorFocusModeFixture.h b/Code/Framework/AzToolsFramework/Tests/FocusMode/EditorFocusModeFixture.h index c48795a3a4..0cf1be6ffd 100644 --- a/Code/Framework/AzToolsFramework/Tests/FocusMode/EditorFocusModeFixture.h +++ b/Code/Framework/AzToolsFramework/Tests/FocusMode/EditorFocusModeFixture.h @@ -18,10 +18,9 @@ #include #include -namespace AzToolsFramework +namespace UnitTest { - class EditorFocusModeFixture - : public UnitTest::ToolsApplicationFixture + class EditorFocusModeFixture : public ToolsApplicationFixture { protected: void SetUpEditorFixtureImpl() override; @@ -32,8 +31,8 @@ namespace AzToolsFramework AZStd::unordered_map m_entityMap; - ContainerEntityInterface* m_containerEntityInterface = nullptr; - FocusModeInterface* m_focusModeInterface = nullptr; + AzToolsFramework::ContainerEntityInterface* m_containerEntityInterface = nullptr; + AzToolsFramework::FocusModeInterface* m_focusModeInterface = nullptr; public: AzToolsFramework::EntityIdList GetSelectedEntities(); @@ -53,4 +52,4 @@ namespace AzToolsFramework inline static AZ::Vector3 WorldCarEntityPosition = AZ::Vector3(5.0f, 15.0f, 0.0f); }; -} +} // namespace UnitTest diff --git a/Code/Framework/AzToolsFramework/Tests/FocusMode/EditorFocusModeSelectionFixture.h b/Code/Framework/AzToolsFramework/Tests/FocusMode/EditorFocusModeSelectionFixture.h index 4c9369bc46..fe1de9b122 100644 --- a/Code/Framework/AzToolsFramework/Tests/FocusMode/EditorFocusModeSelectionFixture.h +++ b/Code/Framework/AzToolsFramework/Tests/FocusMode/EditorFocusModeSelectionFixture.h @@ -26,11 +26,17 @@ #include #include -namespace AzToolsFramework +namespace UnitTest { - class EditorFocusModeSelectionFixture : public UnitTest::IndirectCallManipulatorViewportInteractionFixtureMixin + class EditorFocusModeSelectionFixture : public IndirectCallManipulatorViewportInteractionFixtureMixin { public: + void SetUpEditorFixtureImpl() override + { + IndirectCallManipulatorViewportInteractionFixtureMixin::SetUpEditorFixtureImpl(); + m_viewportManipulatorInteraction->GetViewportInteraction().SetIconsVisible(false); + } + void ClickAtWorldPositionOnViewport(const AZ::Vector3& worldPosition) { // Calculate the world position in screen space @@ -40,4 +46,4 @@ namespace AzToolsFramework m_actionDispatcher->CameraState(m_cameraState)->MousePosition(carScreenPosition)->MouseLButtonDown()->MouseLButtonUp(); } }; -} // namespace AzToolsFramework +} // namespace UnitTest diff --git a/Code/Framework/AzToolsFramework/Tests/FocusMode/EditorFocusModeSelectionTests.cpp b/Code/Framework/AzToolsFramework/Tests/FocusMode/EditorFocusModeSelectionTests.cpp index 2f746c9d63..1efcb15b30 100644 --- a/Code/Framework/AzToolsFramework/Tests/FocusMode/EditorFocusModeSelectionTests.cpp +++ b/Code/Framework/AzToolsFramework/Tests/FocusMode/EditorFocusModeSelectionTests.cpp @@ -8,9 +8,9 @@ #include -namespace AzToolsFramework +namespace UnitTest { - TEST_F(EditorFocusModeSelectionFixture, EditorFocusModeSelectionTests_SelectEntityWithFocusOnLevel) + TEST_F(EditorFocusModeSelectionFixture, EditorFocusModeSelectionSelectEntityWithFocusOnLevel) { // Click on Car Entity ClickAtWorldPositionOnViewport(WorldCarEntityPosition); @@ -21,7 +21,7 @@ namespace AzToolsFramework EXPECT_EQ(selectedEntitiesAfter.front(), m_entityMap[CarEntityName]); } - TEST_F(EditorFocusModeSelectionFixture, EditorFocusModeSelectionTests_SelectEntityWithFocusOnAncestor) + TEST_F(EditorFocusModeSelectionFixture, EditorFocusModeSelectionSelectEntityWithFocusOnAncestor) { // Set the focus on the Street Entity (parent of the test entity) m_focusModeInterface->SetFocusRoot(m_entityMap[StreetEntityName]); @@ -35,7 +35,7 @@ namespace AzToolsFramework EXPECT_EQ(selectedEntitiesAfter.front(), m_entityMap[CarEntityName]); } - TEST_F(EditorFocusModeSelectionFixture, EditorFocusModeSelectionTests_SelectEntityWithFocusOnItself) + TEST_F(EditorFocusModeSelectionFixture, EditorFocusModeSelectionSelectEntityWithFocusOnItself) { // Set the focus on the Car Entity (test entity) m_focusModeInterface->SetFocusRoot(m_entityMap[CarEntityName]); @@ -49,7 +49,7 @@ namespace AzToolsFramework EXPECT_EQ(selectedEntitiesAfter.front(), m_entityMap[CarEntityName]); } - TEST_F(EditorFocusModeSelectionFixture, EditorFocusModeSelectionTests_SelectEntityWithFocusOnSibling) + TEST_F(EditorFocusModeSelectionFixture, EditorFocusModeSelectionSelectEntityWithFocusOnSibling) { // Set the focus on the SportsCar Entity (sibling of the test entity) m_focusModeInterface->SetFocusRoot(m_entityMap[SportsCarEntityName]); @@ -62,7 +62,7 @@ namespace AzToolsFramework EXPECT_EQ(selectedEntitiesAfter.size(), 0); } - TEST_F(EditorFocusModeSelectionFixture, EditorFocusModeSelectionTests_SelectEntityWithFocusOnDescendant) + TEST_F(EditorFocusModeSelectionFixture, EditorFocusModeSelectionSelectEntityWithFocusOnDescendant) { // Set the focus on the Passenger1 Entity (child of the entity) m_focusModeInterface->SetFocusRoot(m_entityMap[Passenger1EntityName]); @@ -74,4 +74,4 @@ namespace AzToolsFramework auto selectedEntitiesAfter = GetSelectedEntities(); EXPECT_EQ(selectedEntitiesAfter.size(), 0); } -} +} // namespace UnitTest diff --git a/Code/Framework/AzToolsFramework/Tests/FocusMode/EditorFocusModeTests.cpp b/Code/Framework/AzToolsFramework/Tests/FocusMode/EditorFocusModeTests.cpp index eec3902f99..bac60230d6 100644 --- a/Code/Framework/AzToolsFramework/Tests/FocusMode/EditorFocusModeTests.cpp +++ b/Code/Framework/AzToolsFramework/Tests/FocusMode/EditorFocusModeTests.cpp @@ -8,9 +8,9 @@ #include -namespace AzToolsFramework +namespace UnitTest { - TEST_F(EditorFocusModeFixture, EditorFocusModeTests_SetFocus) + TEST_F(EditorFocusModeFixture, SetFocus) { // When an entity is set as the focus root, GetFocusRoot should return its EntityId. m_focusModeInterface->SetFocusRoot(m_entityMap[CarEntityName]); @@ -20,7 +20,7 @@ namespace AzToolsFramework m_focusModeInterface->ClearFocusRoot(m_editorEntityContextId); } - TEST_F(EditorFocusModeFixture, EditorFocusModeTests_ClearFocus) + TEST_F(EditorFocusModeFixture, ClearFocus) { // Change the value from the default. m_focusModeInterface->SetFocusRoot(m_entityMap[CarEntityName]); @@ -30,7 +30,7 @@ namespace AzToolsFramework EXPECT_EQ(m_focusModeInterface->GetFocusRoot(m_editorEntityContextId), AZ::EntityId()); } - TEST_F(EditorFocusModeFixture, EditorFocusModeTests_IsInFocusSubTree_AncestorsDescendants) + TEST_F(EditorFocusModeFixture, IsInFocusSubTreeAncestorsDescendants) { // When the focus is set to an entity, all its descendants are in the focus subtree while the ancestors aren't. m_focusModeInterface->SetFocusRoot(m_entityMap[StreetEntityName]); @@ -43,7 +43,7 @@ namespace AzToolsFramework EXPECT_EQ(m_focusModeInterface->IsInFocusSubTree(m_entityMap[Passenger2EntityName]), true); } - TEST_F(EditorFocusModeFixture, EditorFocusModeTests_IsInFocusSubTree_Siblings) + TEST_F(EditorFocusModeFixture, IsInFocusSubTreeSiblings) { // If the root entity has siblings, they are also outside of the focus subtree. m_focusModeInterface->SetFocusRoot(m_entityMap[CarEntityName]); @@ -56,7 +56,7 @@ namespace AzToolsFramework EXPECT_EQ(m_focusModeInterface->IsInFocusSubTree(m_entityMap[Passenger2EntityName]), false); } - TEST_F(EditorFocusModeFixture, EditorFocusModeTests_IsInFocusSubTree_Leaf) + TEST_F(EditorFocusModeFixture, IsInFocusSubTreeLeaf) { // If the root is a leaf, then the focus subtree will consists of just that entity. m_focusModeInterface->SetFocusRoot(m_entityMap[Passenger2EntityName]); @@ -69,7 +69,7 @@ namespace AzToolsFramework EXPECT_EQ(m_focusModeInterface->IsInFocusSubTree(m_entityMap[Passenger2EntityName]), true); } - TEST_F(EditorFocusModeFixture, EditorFocusModeTests_IsInFocusSubTree_Clear) + TEST_F(EditorFocusModeFixture, IsInFocusSubTreeClear) { // Change the value from the default. m_focusModeInterface->SetFocusRoot(m_entityMap[StreetEntityName]); @@ -84,4 +84,4 @@ namespace AzToolsFramework EXPECT_EQ(m_focusModeInterface->IsInFocusSubTree(m_entityMap[SportsCarEntityName]), true); EXPECT_EQ(m_focusModeInterface->IsInFocusSubTree(m_entityMap[Passenger2EntityName]), true); } -} +} // namespace UnitTest diff --git a/Code/Framework/AzToolsFramework/Tests/SliceStabilityTests/SliceStabilityTestFramework.h b/Code/Framework/AzToolsFramework/Tests/SliceStabilityTests/SliceStabilityTestFramework.h index 01b40fbb16..56f4bb5243 100644 --- a/Code/Framework/AzToolsFramework/Tests/SliceStabilityTests/SliceStabilityTestFramework.h +++ b/Code/Framework/AzToolsFramework/Tests/SliceStabilityTests/SliceStabilityTestFramework.h @@ -137,7 +137,6 @@ namespace UnitTest void CreateEditorRepresentation(AZ::Entity* entity) override; void BrowseForAssets(AzToolsFramework::AssetBrowser::AssetSelectionModel& selection) override { AZ_UNUSED(selection); } int GetIconTextureIdFromEntityIconPath(const AZStd::string& entityIconPath) override { AZ_UNUSED(entityIconPath); return 0; } - bool DisplayHelpersVisible() override { return false; } /* * AssetSystemRequestBus diff --git a/Code/Framework/AzToolsFramework/Tests/UI/EntityPropertyEditorTests.cpp b/Code/Framework/AzToolsFramework/Tests/UI/EntityPropertyEditorTests.cpp index bf3e6e9787..9a96c716fb 100644 --- a/Code/Framework/AzToolsFramework/Tests/UI/EntityPropertyEditorTests.cpp +++ b/Code/Framework/AzToolsFramework/Tests/UI/EntityPropertyEditorTests.cpp @@ -243,7 +243,6 @@ namespace UnitTest // These are required by implementing the EditorRequestBus void BrowseForAssets(AssetBrowser::AssetSelectionModel& /*selection*/) override {} int GetIconTextureIdFromEntityIconPath([[maybe_unused]] const AZStd::string& entityIconPath) override { return 0; } - bool DisplayHelpersVisible() override { return false; } public: EntityPropertyEditor* m_levelEditor; diff --git a/Code/Tools/LuaIDE/Source/LUA/LUAEditorFindDialog.cpp b/Code/Tools/LuaIDE/Source/LUA/LUAEditorFindDialog.cpp index c775ddc0ba..c426566c5f 100644 --- a/Code/Tools/LuaIDE/Source/LUA/LUAEditorFindDialog.cpp +++ b/Code/Tools/LuaIDE/Source/LUA/LUAEditorFindDialog.cpp @@ -610,7 +610,7 @@ namespace LUAEditor { m_resultList[qAssetName].m_assetId = docInfo.m_assetId; } - entry.m_lineNumber = line; + entry.m_lineNumber = line + 1; entry.m_lineText = entry.m_lineText.trimmed(); while (index > -1) diff --git a/Gems/Atom/Feature/Common/Assets/Passes/PassTemplates.azasset b/Gems/Atom/Feature/Common/Assets/Passes/PassTemplates.azasset index eba745fb3c..96cf769690 100644 --- a/Gems/Atom/Feature/Common/Assets/Passes/PassTemplates.azasset +++ b/Gems/Atom/Feature/Common/Assets/Passes/PassTemplates.azasset @@ -64,6 +64,10 @@ "Name": "CascadedShadowmapsTemplate", "Path": "Passes/CascadedShadowmaps.pass" }, + { + "Name": "SlowClearPassTemplate", + "Path": "Passes/SlowClear.pass" + }, { "Name": "FullscreenCopyTemplate", "Path": "Passes/FullscreenCopy.pass" diff --git a/Gems/Atom/Feature/Common/Assets/Passes/SMAA1xApplyLinearHDRColor.pass b/Gems/Atom/Feature/Common/Assets/Passes/SMAA1xApplyLinearHDRColor.pass index 70604fba25..9ae0f62bc7 100644 --- a/Gems/Atom/Feature/Common/Assets/Passes/SMAA1xApplyLinearHDRColor.pass +++ b/Gems/Atom/Feature/Common/Assets/Passes/SMAA1xApplyLinearHDRColor.pass @@ -25,10 +25,7 @@ { "Name": "OutputColor", "SlotType": "Output", - "ScopeAttachmentUsage": "RenderTarget", - "LoadStoreAction": { - "LoadAction": "DontCare" - } + "ScopeAttachmentUsage": "RenderTarget" } ], "Connections": [ diff --git a/Gems/Atom/Feature/Common/Assets/Passes/SMAA1xApplyPerceptualColor.pass b/Gems/Atom/Feature/Common/Assets/Passes/SMAA1xApplyPerceptualColor.pass index 27fcff21cf..04484e1f17 100644 --- a/Gems/Atom/Feature/Common/Assets/Passes/SMAA1xApplyPerceptualColor.pass +++ b/Gems/Atom/Feature/Common/Assets/Passes/SMAA1xApplyPerceptualColor.pass @@ -25,10 +25,7 @@ { "Name": "OutputColor", "SlotType": "Output", - "ScopeAttachmentUsage": "RenderTarget", - "LoadStoreAction": { - "LoadAction": "DontCare" - } + "ScopeAttachmentUsage": "RenderTarget" } ], "Connections": [ diff --git a/Gems/Atom/Feature/Common/Assets/Passes/SlowClear.pass b/Gems/Atom/Feature/Common/Assets/Passes/SlowClear.pass new file mode 100644 index 0000000000..97b486191a --- /dev/null +++ b/Gems/Atom/Feature/Common/Assets/Passes/SlowClear.pass @@ -0,0 +1,34 @@ +{ + "Type": "JsonSerialization", + "Version": 1, + "ClassName": "PassAsset", + "ClassData": { + "PassTemplate": { + + // This is for debug purposes and edge cases only + // If you want to clear an attachment you should + // use the LoadStoreAction on your pass slot. + "Name": "SlowClearPassTemplate", + "PassClass": "SlowClearPass", + "Slots": [ + { + "Name": "ClearInputOutput", + "SlotType": "InputOutput", + "ScopeAttachmentUsage": "RenderTarget", + "LoadStoreAction": { + "ClearValue": { + "Value": [ + 0.0, + 0.0, + 0.0, + 0.0 + ] + }, + "LoadAction": "Clear", + "LoadActionStencil": "Clear" + } + } + ] + } + } +} diff --git a/Gems/Atom/Feature/Common/Assets/Passes/UIParent.pass b/Gems/Atom/Feature/Common/Assets/Passes/UIParent.pass index 4ae67b9b09..54491216dd 100644 --- a/Gems/Atom/Feature/Common/Assets/Passes/UIParent.pass +++ b/Gems/Atom/Feature/Common/Assets/Passes/UIParent.pass @@ -41,7 +41,8 @@ "PassData": { "$type": "RasterPassData", "DrawListTag": "2dpass", - "PipelineViewTag": "MainCamera" + "PipelineViewTag": "MainCamera", + "DrawListSortType": "KeyThenReverseDepth" } }, { diff --git a/Gems/Atom/Feature/Common/Assets/atom_feature_common_asset_files.cmake b/Gems/Atom/Feature/Common/Assets/atom_feature_common_asset_files.cmake index c4d198fef9..a03058e2bf 100644 --- a/Gems/Atom/Feature/Common/Assets/atom_feature_common_asset_files.cmake +++ b/Gems/Atom/Feature/Common/Assets/atom_feature_common_asset_files.cmake @@ -53,6 +53,7 @@ set(FILES Materials/Types/StandardPBR_LowEndForward.azsl Materials/Types/StandardPBR_LowEndForward.shader Materials/Types/StandardPBR_LowEndForward_EDS.shader + Materials/Types/StandardPBR_Metallic.lua Materials/Types/StandardPBR_ParallaxState.lua Materials/Types/StandardPBR_Roughness.lua Materials/Types/StandardPBR_ShaderEnable.lua @@ -129,6 +130,7 @@ set(FILES Passes/DownsampleMipChain.pass Passes/EnvironmentCubeMapDepthMSAA.pass Passes/EnvironmentCubeMapForwardMSAA.pass + Passes/EnvironmentCubeMapForwardSubsurfaceMSAA.pass Passes/EnvironmentCubeMapPipeline.pass Passes/EnvironmentCubeMapSkyBox.pass Passes/EsmShadowmaps.pass @@ -198,6 +200,7 @@ set(FILES Passes/Skinning.pass Passes/SkyBox.pass Passes/SkyBox_TwoOutputs.pass + Passes/SlowClear.pass Passes/SMAA1xApplyLinearHDRColor.pass Passes/SMAA1xApplyPerceptualColor.pass Passes/SMAABlendingWeightCalculation.pass @@ -303,6 +306,7 @@ set(FILES ShaderLib/Atom/Features/ScreenSpace/ScreenSpaceUtil.azsli ShaderLib/Atom/Features/Shadow/BicubicPcfFilters.azsli ShaderLib/Atom/Features/Shadow/DirectionalLightShadow.azsli + ShaderLib/Atom/Features/Shadow/ESM.azsli ShaderLib/Atom/Features/Shadow/NormalOffsetShadows.azsli ShaderLib/Atom/Features/Shadow/ProjectedShadow.azsli ShaderLib/Atom/Features/Shadow/ReceiverPlaneDepthBias.azsli diff --git a/Gems/Atom/Feature/Common/Code/Source/PostProcessing/EyeAdaptationPass.cpp b/Gems/Atom/Feature/Common/Code/Source/PostProcessing/EyeAdaptationPass.cpp index 5683241693..20254690f9 100644 --- a/Gems/Atom/Feature/Common/Code/Source/PostProcessing/EyeAdaptationPass.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/PostProcessing/EyeAdaptationPass.cpp @@ -73,8 +73,6 @@ namespace AZ return false; } - AZ_Assert(m_pipeline->GetScene(), "EyeAdaptationPass's Pipeline does not have a valid scene pointer"); - AZ::RPI::Scene* scene = GetScene(); bool enabled = false; diff --git a/Gems/Atom/Feature/Common/Code/Source/RayTracing/RayTracingAccelerationStructurePass.cpp b/Gems/Atom/Feature/Common/Code/Source/RayTracing/RayTracingAccelerationStructurePass.cpp index abdf59a915..2073c0b8c0 100644 --- a/Gems/Atom/Feature/Common/Code/Source/RayTracing/RayTracingAccelerationStructurePass.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/RayTracing/RayTracingAccelerationStructurePass.cpp @@ -150,18 +150,17 @@ namespace AZ } // build newly added BLAS objects - // [GFX TODO][ATOM-14159] Add changelist for meshes in the RayTracingFeatureProcessor - RayTracingFeatureProcessor::MeshMap& rayTracingMeshes = rayTracingFeatureProcessor->GetMeshes(); - for (auto& rayTracingMesh : rayTracingMeshes) + RayTracingFeatureProcessor::BlasInstanceMap& blasInstances = rayTracingFeatureProcessor->GetBlasInstances(); + for (auto& blasInstance : blasInstances) { - if (rayTracingMesh.second.m_blasBuilt == false) + if (blasInstance.second.m_blasBuilt == false) { - for (auto& rayTracingSubMesh : rayTracingMesh.second.m_subMeshes) + for (auto& blasInstanceSubMesh : blasInstance.second.m_subMeshes) { - context.GetCommandList()->BuildBottomLevelAccelerationStructure(*rayTracingSubMesh.m_blas); + context.GetCommandList()->BuildBottomLevelAccelerationStructure(*blasInstanceSubMesh.m_blas); } - rayTracingMesh.second.m_blasBuilt = true; + blasInstance.second.m_blasBuilt = true; } } diff --git a/Gems/Atom/Feature/Common/Code/Source/RayTracing/RayTracingFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/RayTracing/RayTracingFeatureProcessor.cpp index bef95ced17..0a9782980f 100644 --- a/Gems/Atom/Feature/Common/Code/Source/RayTracing/RayTracingFeatureProcessor.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/RayTracing/RayTracingFeatureProcessor.cpp @@ -149,23 +149,18 @@ namespace AZ { AZ_Assert(blasInstanceFound == false, "Partial set of RayTracingBlas objects found for mesh"); - // create the BLAS object - subMesh.m_blas = AZ::RHI::RayTracingBlas::CreateRHIRayTracingBlas(); + // create the BLAS object and store it in the BLAS list + RHI::Ptr rayTracingBlas = AZ::RHI::RayTracingBlas::CreateRHIRayTracingBlas(); + itMeshBlasInstance->second.m_subMeshes.push_back({ rayTracingBlas }); - // create the buffers from the descriptor - subMesh.m_blas->CreateBuffers(*device, &blasDescriptor, *m_bufferPools); + // create the buffers from the BLAS descriptor + rayTracingBlas->CreateBuffers(*device, &blasDescriptor, *m_bufferPools); - // store the BLAS in the side list - itMeshBlasInstance->second.m_subMeshes.push_back({ subMesh.m_blas }); + // store the BLAS in the mesh + subMesh.m_blas = rayTracingBlas; } } - if (blasInstanceFound) - { - // set the mesh BLAS flag so we don't try to rebuild it in the RayTracingAccelerationStructurePass - mesh.m_blasBuilt = true; - } - // set initial transform mesh.m_transform = m_transformServiceFeatureProcessor->GetTransformForId(objectId); mesh.m_nonUniformScale = m_transformServiceFeatureProcessor->GetNonUniformScaleForId(objectId); diff --git a/Gems/Atom/Feature/Common/Code/Source/RayTracing/RayTracingFeatureProcessor.h b/Gems/Atom/Feature/Common/Code/Source/RayTracing/RayTracingFeatureProcessor.h index fbed3b80cf..d098fca35a 100644 --- a/Gems/Atom/Feature/Common/Code/Source/RayTracing/RayTracingFeatureProcessor.h +++ b/Gems/Atom/Feature/Common/Code/Source/RayTracing/RayTracingFeatureProcessor.h @@ -127,9 +127,6 @@ namespace AZ // mesh non-uniform scale AZ::Vector3 m_nonUniformScale = AZ::Vector3::CreateOne(); - - // flag indicating if the Blas objects in the sub-meshes are built - bool m_blasBuilt = false; }; using MeshMap = AZStd::map; @@ -184,6 +181,23 @@ namespace AZ //! Updates the RayTracingSceneSrg and RayTracingMaterialSrg, called after the TLAS is allocated in the RayTracingAccelerationStructurePass void UpdateRayTracingSrgs(); + struct SubMeshBlasInstance + { + RHI::Ptr m_blas; + }; + + struct MeshBlasInstance + { + uint32_t m_count = 0; + AZStd::vector m_subMeshes; + + // flag indicating if the Blas objects in the sub-mesh list are built + bool m_blasBuilt = false; + }; + + using BlasInstanceMap = AZStd::unordered_map; + BlasInstanceMap& GetBlasInstances() { return m_blasInstanceMap; } + private: AZ_DISABLE_COPY_MOVE(RayTracingFeatureProcessor); @@ -266,18 +280,6 @@ namespace AZ bool m_materialInfoBufferNeedsUpdate = false; // side list for looking up existing BLAS objects so they can be re-used when the same mesh is added multiple times - struct SubMeshBlasInstance - { - RHI::Ptr m_blas; - }; - - struct MeshBlasInstance - { - uint32_t m_count = 0; - AZStd::vector m_subMeshes; - }; - - using BlasInstanceMap = AZStd::unordered_map; BlasInstanceMap m_blasInstanceMap; // Cache view pointers so we dont need to update them if none changed from frame to frame. diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/ParentPass.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/ParentPass.h index 6523f0a6d8..00b7a76f77 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/ParentPass.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/ParentPass.h @@ -131,6 +131,19 @@ namespace AZ // Generates child passes from source PassTemplate void CreatePassesFromTemplate(); + + // Generates child clear passes to clear input and input/output attachments + // TODO: These two functions are a workaround for a complicated edge case: + // Let Parent Pass P1 have two children, C1 and C2. C1 writes to an attachment that C2 reads, + // but C1 can be disabled, in which case we just want C2 to read the cleared texture. + // Because of this, the attachment is owned by the parent pass, that way it is always available for C2 + // to read even when C1 is disabled. However we still want to clear the attachment before C2 reads it. + // We tried overriding the LoadStoreAction to clear on C2's slot when C1 is disabled, but the RHI + // doesn't allow for clears on Input only slots. Changing the slot to InputOutput was in conflict with + // the texture definition in the SRG, and it couldn't be changed to RW because it was an MSAA texture. + // So now we detect clear actions on parent slots and generate a clear pass for them. + void CreateClearPassFromBinding(PassAttachmentBinding& binding, PassRequest& clearRequest); + void CreateClearPassesFromBindings(); }; template diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/SlowClearPass.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/SlowClearPass.h new file mode 100644 index 0000000000..6fcb7abd17 --- /dev/null +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/SlowClearPass.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ +#pragma once + +#include +#include + +namespace AZ +{ + namespace RPI + { + //! Only use this for debug purposes and edge cases + //! The correct and efficient way to clear a pass is through the LoadStoreAction on the pass slot + //! This will clear a given image attachment to the specified clear value. + class SlowClearPass + : public RenderPass + { + AZ_RPI_PASS(SlowClearPass); + + public: + AZ_RTTI(SlowClearPass, "{31CBAD6C-108F-4F3F-B498-ED968DFCFCE2}", RenderPass); + AZ_CLASS_ALLOCATOR(SlowClearPass, SystemAllocator, 0); + virtual ~SlowClearPass() = default; + + //! Creates a SlowClearPass + static Ptr Create(const PassDescriptor& descriptor); + + protected: + SlowClearPass(const PassDescriptor& descriptor); + void InitializeInternal() override; + + private: + RHI::ClearValue m_clearValue; + }; + + } // namespace RPI +} // namespace AZ diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/Pass/SlowClearPassData.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/Pass/SlowClearPassData.h new file mode 100644 index 0000000000..7607bca285 --- /dev/null +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/Pass/SlowClearPassData.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ +#pragma once + +#include +#include + +namespace AZ +{ + namespace RPI + { + //! Custom data for the SlowClearPass. Should be specified in the PassRequest. + struct SlowClearPassData + : public RenderPassData + { + AZ_RTTI(SlowClearPassData, "{5F2C24A4-62D0-4E60-91EC-C207C10D15C6}", RenderPassData); + AZ_CLASS_ALLOCATOR(SlowClearPassData, SystemAllocator, 0); + + SlowClearPassData() = default; + virtual ~SlowClearPassData() = default; + + static void Reflect(ReflectContext* context) + { + if (auto* serializeContext = azrtti_cast(context)) + { + serializeContext->Class() + ->Version(0) + ->Field("ClearValue", &SlowClearPassData::m_clearValue) + ; + } + } + + RHI::ClearValue m_clearValue; + }; + + } // namespace RPI +} // namespace AZ + diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/ParentPass.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/ParentPass.cpp index dccf5dbc2e..55f3e44173 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/ParentPass.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/ParentPass.cpp @@ -9,11 +9,15 @@ #include #include +#include #include +#include #include #include #include +#include +#include #include namespace AZ @@ -196,7 +200,7 @@ namespace AZ } } - // --- PassTemplate related functions --- + // --- Child creation --- void ParentPass::CreatePassesFromTemplate() { @@ -217,6 +221,49 @@ namespace AZ } } + void ParentPass::CreateClearPassFromBinding(PassAttachmentBinding& binding, PassRequest& clearRequest) + { + if (binding.m_unifiedScopeDesc.m_loadStoreAction.m_loadAction == RHI::AttachmentLoadAction::Clear || + binding.m_unifiedScopeDesc.m_loadStoreAction.m_loadActionStencil == RHI::AttachmentLoadAction::Clear) + { + // Set the name of the child clear pass as well as the binding it's connected to + clearRequest.m_passName = ConcatPassName(Name("Clear"), binding.m_name); + clearRequest.m_connections[0].m_attachmentRef.m_attachment = binding.m_name; + + // Set the pass clear value to the clear value of the attachment binding + SlowClearPassData* clearData = static_cast(clearRequest.m_passData.get()); + clearData->m_clearValue = binding.m_unifiedScopeDesc.m_loadStoreAction.m_clearValue; + + // Create and add the pass + Ptr clearPass = PassSystemInterface::Get()->CreatePassFromRequest(&clearRequest); + if (clearPass) + { + AddChild(clearPass); + } + } + + } + + void ParentPass::CreateClearPassesFromBindings() + { + PassRequest clearRequest; + clearRequest.m_templateName = Name("SlowClearPassTemplate"); + clearRequest.m_passData = AZStd::make_shared(); + clearRequest.m_connections.push_back(); + clearRequest.m_connections[0].m_localSlot = Name("ClearInputOutput"); + clearRequest.m_connections[0].m_attachmentRef.m_pass = Name("Parent"); + + for (uint32_t idx = 0; idx < GetInputCount(); ++idx) + { + CreateClearPassFromBinding(GetInputBinding(idx), clearRequest); + } + + for (uint32_t idx = 0; idx < GetInputOutputCount(); ++idx) + { + CreateClearPassFromBinding(GetInputOutputBinding(idx), clearRequest); + } + } + // --- Pass behavior functions --- void ParentPass::CreateChildPasses() @@ -229,6 +276,7 @@ namespace AZ m_flags.m_alreadyCreatedChildren = true; RemoveChildren(); + CreateClearPassesFromBindings(); CreatePassesFromTemplate(); CreateChildPassesInternal(); diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/PassFactory.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/PassFactory.cpp index ef8d7a3fae..cc79df144d 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/PassFactory.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/PassFactory.cpp @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -60,6 +61,7 @@ namespace AZ { AddPassCreator(Name("ParentPass"), &ParentPass::Create); AddPassCreator(Name("RasterPass"), &RasterPass::Create); + AddPassCreator(Name("SlowClearPass"), &SlowClearPass::Create); AddPassCreator(Name("CopyPass"), &CopyPass::Create); AddPassCreator(Name("FullScreenTriangle"), &FullscreenTrianglePass::Create); AddPassCreator(Name("ComputePass"), &ComputePass::Create); diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/PassSystem.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/PassSystem.cpp index cd64010680..9e1333b7ab 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/PassSystem.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/PassSystem.cpp @@ -39,6 +39,7 @@ #include #include #include +#include namespace AZ { @@ -67,6 +68,7 @@ namespace AZ PassSlot::Reflect(context); PassData::Reflect(context); + SlowClearPassData::Reflect(context); CopyPassData::Reflect(context); RenderPassData::Reflect(context); ComputePassData::Reflect(context); diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/SlowClearPass.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/SlowClearPass.cpp new file mode 100644 index 0000000000..62a8241242 --- /dev/null +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/SlowClearPass.cpp @@ -0,0 +1,45 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#include +#include + +#include + +namespace AZ +{ + namespace RPI + { + Ptr SlowClearPass::Create(const PassDescriptor& descriptor) + { + Ptr pass = aznew SlowClearPass(descriptor); + return pass; + } + + SlowClearPass::SlowClearPass(const PassDescriptor& descriptor) + : RenderPass(descriptor) + { + const SlowClearPassData* passData = PassUtils::GetPassData(descriptor); + if (passData != nullptr) + { + m_clearValue = passData->m_clearValue; + } + } + + void SlowClearPass::InitializeInternal() + { + RenderPass::InitializeInternal(); + + // Set clear value + AZ_Assert(GetInputOutputCount() > 0, "SlowClearPass: Missing InputOutput binding!"); + RPI::PassAttachmentBinding& binding = GetInputOutputBinding(0); + binding.m_unifiedScopeDesc.m_loadStoreAction.m_clearValue = m_clearValue; + } + + } // namespace RPI +} // namespace AZ diff --git a/Gems/Atom/RPI/Code/atom_rpi_public_files.cmake b/Gems/Atom/RPI/Code/atom_rpi_public_files.cmake index 93b85375f0..36df56cdab 100644 --- a/Gems/Atom/RPI/Code/atom_rpi_public_files.cmake +++ b/Gems/Atom/RPI/Code/atom_rpi_public_files.cmake @@ -73,6 +73,7 @@ set(FILES Include/Atom/RPI.Public/Pass/RasterPass.h Include/Atom/RPI.Public/Pass/RenderPass.h Include/Atom/RPI.Public/Pass/MSAAResolvePass.h + Include/Atom/RPI.Public/Pass/SlowClearPass.h Include/Atom/RPI.Public/Pass/Specific/DownsampleMipChainPass.h Include/Atom/RPI.Public/Pass/Specific/ImageAttachmentPreviewPass.h Include/Atom/RPI.Public/Pass/Specific/EnvironmentCubeMapPass.h @@ -149,6 +150,7 @@ set(FILES Source/RPI.Public/Pass/RasterPass.cpp Source/RPI.Public/Pass/RenderPass.cpp Source/RPI.Public/Pass/MSAAResolvePass.cpp + Source/RPI.Public/Pass/SlowClearPass.cpp Source/RPI.Public/Pass/Specific/DownsampleMipChainPass.cpp Source/RPI.Public/Pass/Specific/ImageAttachmentPreviewPass.cpp Source/RPI.Public/Pass/Specific/EnvironmentCubeMapPass.cpp diff --git a/Gems/Atom/RPI/Code/atom_rpi_reflect_files.cmake b/Gems/Atom/RPI/Code/atom_rpi_reflect_files.cmake index 4f0e432511..df8f389c37 100644 --- a/Gems/Atom/RPI/Code/atom_rpi_reflect_files.cmake +++ b/Gems/Atom/RPI/Code/atom_rpi_reflect_files.cmake @@ -75,6 +75,7 @@ set(FILES Include/Atom/RPI.Reflect/Pass/PassTemplate.h Include/Atom/RPI.Reflect/Pass/RasterPassData.h Include/Atom/RPI.Reflect/Pass/RenderPassData.h + Include/Atom/RPI.Reflect/Pass/SlowClearPassData.h Include/Atom/RPI.Reflect/Shader/ShaderCommonTypes.h Include/Atom/RPI.Reflect/Shader/ShaderAsset.h Include/Atom/RPI.Reflect/Shader/ShaderAssetCreator.h diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Tests/ViewportInteractionImplTests.cpp b/Gems/Atom/Tools/AtomToolsFramework/Code/Tests/ViewportInteractionImplTests.cpp index 19c55d7473..3a96d3c07b 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Tests/ViewportInteractionImplTests.cpp +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Tests/ViewportInteractionImplTests.cpp @@ -167,7 +167,8 @@ namespace UnitTest const auto ray = m_viewportInteractionImpl->ViewportScreenToWorldRay(ScreenPoint(832, 226)); float unused; - auto intersection = AZ::Intersect::IntersectRaySphere(ray.origin, ray.direction, AZ::Vector3(-14.0f, 5.7f, 0.75f), 0.5f, unused); + auto intersection = + AZ::Intersect::IntersectRaySphere(ray.m_origin, ray.m_direction, AZ::Vector3(-14.0f, 5.7f, 0.75f), 0.5f, unused); EXPECT_EQ(intersection, AZ::Intersect::SphereIsectTypes::ISECT_RAY_SPHERE_ISECT); } diff --git a/Gems/AtomLyIntegration/AtomViewportDisplayIcons/Code/Source/AtomViewportDisplayIconsSystemComponent.cpp b/Gems/AtomLyIntegration/AtomViewportDisplayIcons/Code/Source/AtomViewportDisplayIconsSystemComponent.cpp index fa7a0cf2bf..b96fdc9f1d 100644 --- a/Gems/AtomLyIntegration/AtomViewportDisplayIcons/Code/Source/AtomViewportDisplayIconsSystemComponent.cpp +++ b/Gems/AtomLyIntegration/AtomViewportDisplayIcons/Code/Source/AtomViewportDisplayIconsSystemComponent.cpp @@ -8,6 +8,7 @@ #include "AtomViewportDisplayIconsSystemComponent.h" +#include #include #include #include @@ -117,8 +118,7 @@ namespace AZ::Render return; } - auto perViewportDynamicDrawInterface = - AtomBridge::PerViewportDynamicDraw::Get(); + auto perViewportDynamicDrawInterface = AtomBridge::PerViewportDynamicDraw::Get(); if (!perViewportDynamicDrawInterface) { return; @@ -131,7 +131,7 @@ namespace AZ::Render return; } - // Find our icon, falling back on a grey placeholder if its image is unavailable + // Find our icon, falling back on a gray placeholder if its image is unavailable AZ::Data::Instance image = AZ::RPI::ImageSystemInterface::Get()->GetSystemImage(AZ::RPI::SystemImage::Grey); if (auto iconIt = m_iconData.find(drawParameters.m_icon); iconIt != m_iconData.end()) { @@ -172,13 +172,16 @@ namespace AZ::Render } else if (drawParameters.m_positionSpace == CoordinateSpace::WorldSpace) { + // Calculate the ndc point (0.0-1.0 range) including depth + const AZ::Vector3 ndcPoint = AzFramework::WorldToScreenNdc( + drawParameters.m_position, viewportContext->GetCameraViewMatrixAsMatrix3x4(), + viewportContext->GetCameraProjectionMatrix()); + // Calculate our screen space position using the viewport size // We want this instead of RenderViewportWidget::WorldToScreen which works in QWidget virtual coordinate space - const AzFramework::ScreenPoint position = AzFramework::WorldToScreen( - drawParameters.m_position, viewportContext->GetCameraViewMatrixAsMatrix3x4(), - viewportContext->GetCameraProjectionMatrix(), viewportSize); - screenPosition.SetX(aznumeric_cast(position.m_x)); - screenPosition.SetY(aznumeric_cast(position.m_y)); + const AzFramework::ScreenPoint screenPoint = AzFramework::ScreenPointFromNdc(AZ::Vector3ToVector2(ndcPoint), viewportSize); + + screenPosition = AzFramework::Vector3FromScreenPoint(screenPoint, ndcPoint.GetZ()); } struct Vertex @@ -210,7 +213,12 @@ namespace AZ::Render createVertex(-0.5f, 0.5f, 0.f, 1.f) }; AZStd::array indices = {0, 1, 2, 0, 2, 3}; - dynamicDraw->DrawIndexed(&vertices, static_cast(vertices.size()), &indices, static_cast(indices.size()), RHI::IndexFormat::Uint16, drawSrg); + + dynamicDraw->SetSortKey( + aznumeric_cast(screenPosition.GetZ() * aznumeric_cast(AZStd::numeric_limits::max()))); + dynamicDraw->DrawIndexed( + &vertices, static_cast(vertices.size()), &indices, static_cast(indices.size()), RHI::IndexFormat::Uint16, + drawSrg); } QString AtomViewportDisplayIconsSystemComponent::FindAssetPath(const QString& path) const @@ -354,7 +362,7 @@ namespace AZ::Render { // Once the shader is loaded, register it with the dynamic draw context Data::Asset shaderAsset = asset; - AtomBridge::PerViewportDynamicDraw::Get()->RegisterDynamicDrawContext(m_drawContextName, [shaderAsset](RPI::Ptr drawContext) + AtomBridge::PerViewportDynamicDraw::Get()->RegisterDynamicDrawContext(m_drawContextName, [shaderAsset](RPI::Ptr dynamicDraw) { AZ_Assert(shaderAsset->IsReady(), "Attempting to register the AtomViewportDisplayIconsSystemComponent" " dynamic draw context before the shader asset is loaded. The shader should be loaded first" @@ -362,12 +370,11 @@ namespace AZ::Render " will be executed during scene processing and there may be multiple scenes executing in parallel."); Data::Instance shader = RPI::Shader::FindOrCreate(shaderAsset); - drawContext->InitShader(shader); - drawContext->InitVertexFormat( - { {"POSITION", RHI::Format::R32G32B32_FLOAT}, - {"COLOR", RHI::Format::R8G8B8A8_UNORM}, - {"TEXCOORD", RHI::Format::R32G32_FLOAT} }); - drawContext->EndInit(); + dynamicDraw->InitShader(shader); + dynamicDraw->InitVertexFormat({ { "POSITION", RHI::Format::R32G32B32_FLOAT }, + { "COLOR", RHI::Format::R8G8B8A8_UNORM }, + { "TEXCOORD", RHI::Format::R32G32_FLOAT } }); + dynamicDraw->EndInit(); }); m_drawContextRegistered = true; diff --git a/Gems/PhysX/Code/Editor/DebugDraw.cpp b/Gems/PhysX/Code/Editor/DebugDraw.cpp index a54230ec38..0af5822edf 100644 --- a/Gems/PhysX/Code/Editor/DebugDraw.cpp +++ b/Gems/PhysX/Code/Editor/DebugDraw.cpp @@ -56,9 +56,9 @@ namespace PhysX bool IsDrawColliderReadOnly() { bool helpersVisible = false; - AzToolsFramework::EditorRequestBus::BroadcastResult(helpersVisible, - &AzToolsFramework::EditorRequests::DisplayHelpersVisible); - // if helpers are visible, draw colliders is NOT read only and can be changed. + AzToolsFramework::ViewportInteraction::ViewportSettingsRequestBus::BroadcastResult( + helpersVisible, &AzToolsFramework::ViewportInteraction::ViewportSettingsRequestBus::Events::HelpersVisible); + // if helpers are visible, draw colliders is not read only and can be changed return !helpersVisible; } diff --git a/Gems/WhiteBox/Code/Source/EditorWhiteBoxComponent.cpp b/Gems/WhiteBox/Code/Source/EditorWhiteBoxComponent.cpp index 5c6fa73bb2..c29305e1f4 100644 --- a/Gems/WhiteBox/Code/Source/EditorWhiteBoxComponent.cpp +++ b/Gems/WhiteBox/Code/Source/EditorWhiteBoxComponent.cpp @@ -720,7 +720,6 @@ namespace WhiteBox // must have at least one triangle if (m_faces->empty()) { - distance = std::numeric_limits::max(); return false; } @@ -735,7 +734,6 @@ namespace WhiteBox const AZ::Vector3 localRayEnd = localRayOrigin + localRayDirection * rayLength; bool intersection = false; - distance = std::numeric_limits::max(); for (const auto& face : m_faces.value()) { float t;