From 781eaabd943ffb7852e5d9481a373a7d28cdd862 Mon Sep 17 00:00:00 2001 From: Alex Peterson <26804013+AMZN-alexpete@users.noreply.github.com> Date: Fri, 29 Oct 2021 12:05:42 -0700 Subject: [PATCH 01/53] Access gem repos from catalog non-destructively Signed-off-by: Alex Peterson <26804013+AMZN-alexpete@users.noreply.github.com> --- .../Source/CreateProjectCtrl.cpp | 23 ++++++++++++-- .../ProjectManager/Source/CreateProjectCtrl.h | 2 ++ .../Source/GemCatalog/GemCatalogScreen.cpp | 16 ---------- .../Source/UpdateProjectCtrl.cpp | 30 ++++++++++++++++--- .../ProjectManager/Source/UpdateProjectCtrl.h | 6 +++- 5 files changed, 54 insertions(+), 23 deletions(-) diff --git a/Code/Tools/ProjectManager/Source/CreateProjectCtrl.cpp b/Code/Tools/ProjectManager/Source/CreateProjectCtrl.cpp index 65e01803aa..c5325bfb42 100644 --- a/Code/Tools/ProjectManager/Source/CreateProjectCtrl.cpp +++ b/Code/Tools/ProjectManager/Source/CreateProjectCtrl.cpp @@ -13,6 +13,7 @@ #include #include #include +#include #include #include @@ -47,8 +48,12 @@ namespace O3DE::ProjectManager m_gemCatalogScreen = new GemCatalogScreen(this); m_stack->addWidget(m_gemCatalogScreen); + + m_gemRepoScreen = new GemRepoScreen(this); + m_stack->addWidget(m_gemRepoScreen); vLayout->addWidget(m_stack); + connect(m_gemCatalogScreen, &ScreenWidget::ChangeScreenRequest, this, &CreateProjectCtrl::OnChangeScreenRequest); // When there are multiple project templates present, we re-gather the gems when changing the selected the project template. @@ -89,6 +94,9 @@ namespace O3DE::ProjectManager buttons->setObjectName("footer"); vLayout->addWidget(buttons); + m_primaryButton = buttons->addButton(tr("Create Project"), QDialogButtonBox::ApplyRole); + connect(m_primaryButton, &QPushButton::clicked, this, &CreateProjectCtrl::HandlePrimaryButton); + #ifdef TEMPLATE_GEM_CONFIGURATION_ENABLED connect(m_newProjectSettingsScreen, &ScreenWidget::ChangeScreenRequest, this, &CreateProjectCtrl::OnChangeScreenRequest); @@ -100,8 +108,6 @@ namespace O3DE::ProjectManager Update(); #endif // TEMPLATE_GEM_CONFIGURATION_ENABLED - m_primaryButton = buttons->addButton(tr("Create Project"), QDialogButtonBox::ApplyRole); - connect(m_primaryButton, &QPushButton::clicked, this, &CreateProjectCtrl::HandlePrimaryButton); setLayout(vLayout); } @@ -160,12 +166,21 @@ namespace O3DE::ProjectManager { m_header->setSubTitle(tr("Configure project with Gems")); m_secondaryButton->setVisible(false); + m_primaryButton->setVisible(true); + } + else if (m_stack->currentWidget() == m_gemRepoScreen) + { + m_header->setSubTitle(tr("Gem Repositories")); + m_secondaryButton->setVisible(true); + m_secondaryButton->setText(tr("Back")); + m_primaryButton->setVisible(false); } else { m_header->setSubTitle(tr("Enter Project Details")); m_secondaryButton->setVisible(true); m_secondaryButton->setText(tr("Configure Gems")); + m_primaryButton->setVisible(true); } } @@ -175,6 +190,10 @@ namespace O3DE::ProjectManager { HandleSecondaryButton(); } + else if (screen == ProjectManagerScreen::GemRepos) + { + NextScreen(); + } else { emit ChangeScreenRequest(screen); diff --git a/Code/Tools/ProjectManager/Source/CreateProjectCtrl.h b/Code/Tools/ProjectManager/Source/CreateProjectCtrl.h index 40ddb14b83..5352d58082 100644 --- a/Code/Tools/ProjectManager/Source/CreateProjectCtrl.h +++ b/Code/Tools/ProjectManager/Source/CreateProjectCtrl.h @@ -23,6 +23,7 @@ namespace O3DE::ProjectManager QT_FORWARD_DECLARE_CLASS(ScreenHeader) QT_FORWARD_DECLARE_CLASS(NewProjectSettingsScreen) QT_FORWARD_DECLARE_CLASS(GemCatalogScreen) + QT_FORWARD_DECLARE_CLASS(GemRepoScreen) class CreateProjectCtrl : public ScreenWidget @@ -67,6 +68,7 @@ namespace O3DE::ProjectManager NewProjectSettingsScreen* m_newProjectSettingsScreen = nullptr; GemCatalogScreen* m_gemCatalogScreen = nullptr; + GemRepoScreen* m_gemRepoScreen = nullptr; }; } // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp index 98121d7cd2..1d238cf275 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp @@ -348,22 +348,6 @@ namespace O3DE::ProjectManager void GemCatalogScreen::HandleOpenGemRepo() { - QVector gemsToBeAdded = m_gemModel->GatherGemsToBeAdded(true); - QVector gemsToBeRemoved = m_gemModel->GatherGemsToBeRemoved(true); - - if (!gemsToBeAdded.empty() || !gemsToBeRemoved.empty()) - { - QMessageBox::StandardButton warningResult = QMessageBox::warning( - nullptr, "Pending Changes", - "There are some unsaved changes to the gem selection,
they will be lost if you change screens.
Are you sure?", - QMessageBox::No | QMessageBox::Yes); - - if (warningResult != QMessageBox::Yes) - { - return; - } - } - emit ChangeScreenRequest(ProjectManagerScreen::GemRepos); } diff --git a/Code/Tools/ProjectManager/Source/UpdateProjectCtrl.cpp b/Code/Tools/ProjectManager/Source/UpdateProjectCtrl.cpp index 1c8f9a6931..5de3511f84 100644 --- a/Code/Tools/ProjectManager/Source/UpdateProjectCtrl.cpp +++ b/Code/Tools/ProjectManager/Source/UpdateProjectCtrl.cpp @@ -7,6 +7,7 @@ */ #include +#include #include #include #include @@ -39,10 +40,9 @@ namespace O3DE::ProjectManager m_updateSettingsScreen = new UpdateProjectSettingsScreen(); m_gemCatalogScreen = new GemCatalogScreen(); + m_gemRepoScreen = new GemRepoScreen(this); - connect(m_gemCatalogScreen, &ScreenWidget::ChangeScreenRequest, this, [this](ProjectManagerScreen screen){ - emit ChangeScreenRequest(screen); - }); + connect(m_gemCatalogScreen, &ScreenWidget::ChangeScreenRequest, this, &UpdateProjectCtrl::OnChangeScreenRequest); m_stack = new QStackedWidget(this); m_stack->setObjectName("body"); @@ -69,6 +69,7 @@ namespace O3DE::ProjectManager m_stack->addWidget(topBarFrameWidget); m_stack->addWidget(m_gemCatalogScreen); + m_stack->addWidget(m_gemRepoScreen); QDialogButtonBox* backNextButtons = new QDialogButtonBox(); backNextButtons->setObjectName("footer"); @@ -102,6 +103,19 @@ namespace O3DE::ProjectManager m_gemCatalogScreen->ReinitForProject(m_projectInfo.m_path); } + void UpdateProjectCtrl::OnChangeScreenRequest(ProjectManagerScreen screen) + { + if (screen == ProjectManagerScreen::GemRepos) + { + m_stack->setCurrentWidget(m_gemRepoScreen); + Update(); + } + else + { + emit ChangeScreenRequest(screen); + } + } + void UpdateProjectCtrl::HandleGemsButton() { if (UpdateProjectSettings(true)) @@ -181,18 +195,26 @@ namespace O3DE::ProjectManager void UpdateProjectCtrl::Update() { - if (m_stack->currentIndex() == ScreenOrder::Gems) + if (m_stack->currentIndex() == ScreenOrder::GemRepos) + { + m_header->setTitle(QString(tr("Edit Project Settings: \"%1\"")).arg(m_projectInfo.GetProjectDisplayName())); + m_header->setSubTitle(QString(tr("Gem Repositories"))); + m_nextButton->setVisible(false); + } + else if (m_stack->currentIndex() == ScreenOrder::Gems) { m_header->setTitle(QString(tr("Edit Project Settings: \"%1\"")).arg(m_projectInfo.GetProjectDisplayName())); m_header->setSubTitle(QString(tr("Configure Gems"))); m_nextButton->setText(tr("Save")); + m_nextButton->setVisible(true); } else { m_header->setTitle(""); m_header->setSubTitle(QString(tr("Edit Project Settings: \"%1\"")).arg(m_projectInfo.GetProjectDisplayName())); m_nextButton->setText(tr("Save")); + m_nextButton->setVisible(true); } } diff --git a/Code/Tools/ProjectManager/Source/UpdateProjectCtrl.h b/Code/Tools/ProjectManager/Source/UpdateProjectCtrl.h index 3321fad638..5fef296ee7 100644 --- a/Code/Tools/ProjectManager/Source/UpdateProjectCtrl.h +++ b/Code/Tools/ProjectManager/Source/UpdateProjectCtrl.h @@ -22,6 +22,7 @@ namespace O3DE::ProjectManager QT_FORWARD_DECLARE_CLASS(ScreenHeader) QT_FORWARD_DECLARE_CLASS(UpdateProjectSettingsScreen) QT_FORWARD_DECLARE_CLASS(GemCatalogScreen) + QT_FORWARD_DECLARE_CLASS(GemRepoScreen) class UpdateProjectCtrl : public ScreenWidget { @@ -37,6 +38,7 @@ namespace O3DE::ProjectManager void HandleBackButton(); void HandleNextButton(); void HandleGemsButton(); + void OnChangeScreenRequest(ProjectManagerScreen screen); void UpdateCurrentProject(const QString& projectPath); private: @@ -47,13 +49,15 @@ namespace O3DE::ProjectManager enum ScreenOrder { Settings, - Gems + Gems, + GemRepos }; ScreenHeader* m_header = nullptr; QStackedWidget* m_stack = nullptr; UpdateProjectSettingsScreen* m_updateSettingsScreen = nullptr; GemCatalogScreen* m_gemCatalogScreen = nullptr; + GemRepoScreen* m_gemRepoScreen = nullptr; QPushButton* m_backButton = nullptr; QPushButton* m_nextButton = nullptr; From 259ee654aec3c1793d5e78cc4fdbe443747fa3f6 Mon Sep 17 00:00:00 2001 From: Alex Peterson <26804013+AMZN-alexpete@users.noreply.github.com> Date: Mon, 1 Nov 2021 11:18:38 -0700 Subject: [PATCH 02/53] WIP refresh gem catalog in place Signed-off-by: Alex Peterson <26804013+AMZN-alexpete@users.noreply.github.com> --- .../Source/CreateProjectCtrl.cpp | 7 +++ .../Source/GemCatalog/GemCatalogScreen.cpp | 55 +++++++++++++++++++ .../Source/GemCatalog/GemCatalogScreen.h | 1 + .../Source/GemCatalog/GemModel.cpp | 11 ++++ .../Source/GemCatalog/GemModel.h | 3 + .../Source/GemRepo/GemRepoScreen.cpp | 4 ++ .../Source/GemRepo/GemRepoScreen.h | 4 ++ 7 files changed, 85 insertions(+) diff --git a/Code/Tools/ProjectManager/Source/CreateProjectCtrl.cpp b/Code/Tools/ProjectManager/Source/CreateProjectCtrl.cpp index c5325bfb42..e33e9449fe 100644 --- a/Code/Tools/ProjectManager/Source/CreateProjectCtrl.cpp +++ b/Code/Tools/ProjectManager/Source/CreateProjectCtrl.cpp @@ -55,6 +55,13 @@ namespace O3DE::ProjectManager connect(m_gemCatalogScreen, &ScreenWidget::ChangeScreenRequest, this, &CreateProjectCtrl::OnChangeScreenRequest); + connect( + m_gemRepoScreen, &GemRepoScreen::OnRefresh, + [this]() + { + const QString projectTemplatePath = m_newProjectSettingsScreen->GetProjectTemplatePath(); + m_gemCatalogScreen->Refresh(projectTemplatePath + "/Template"); + }); // When there are multiple project templates present, we re-gather the gems when changing the selected the project template. connect(m_newProjectSettingsScreen, &NewProjectSettingsScreen::OnTemplateSelectionChanged, this, [=](int oldIndex, [[maybe_unused]] int newIndex) diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp index 1d238cf275..fb78736a3c 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp @@ -23,6 +23,8 @@ #include #include #include +#include +#include namespace O3DE::ProjectManager { @@ -145,6 +147,59 @@ namespace O3DE::ProjectManager } } + void GemCatalogScreen::Refresh(const QString& projectPath) + { + QHash gemInfoHash; + + AZ::Outcome, AZStd::string> allGemInfosResult = PythonBindingsInterface::Get()->GetAllGemInfos(projectPath); + if (allGemInfosResult.IsSuccess()) + { + QVector gemInfos = allGemInfosResult.GetValue(); + for (const GemInfo& gemInfo : gemInfos) + { + gemInfoHash.insert(gemInfo.m_name, gemInfo); + } + } + + AZ::Outcome, AZStd::string> allRepoGemInfosResult = PythonBindingsInterface::Get()->GetAllGemRepoGemsInfos(); + if (allRepoGemInfosResult.IsSuccess()) + { + const QVector allRepoGemInfos = allRepoGemInfosResult.GetValue(); + for (const GemInfo& gemInfo : allRepoGemInfos) + { + if (!gemInfoHash.contains(gemInfo.m_name)) + { + gemInfoHash.insert(gemInfo.m_name, gemInfo); + } + } + } + + // remove rows for gems that were removed and not project dependencies + int i = 0; + while (i < m_gemModel->rowCount()) + { + QModelIndex index = m_gemModel->index(i,0); + QString gemName = m_gemModel->GetName(index); + if (!gemInfoHash.contains(gemName) && !m_gemModel->IsAdded(index) && !m_gemModel->IsAddedDependency(index)) + { + m_gemModel->removeRow(i); + } + else + { + gemInfoHash.remove(gemName); + i++; + } + } + + // add new rows + for(auto iter = gemInfoHash.begin(); iter != gemInfoHash.end(); ++iter) + { + m_gemModel->AddGem(iter.value()); + } + + m_gemModel->UpdateGemDependencies(); + } + void GemCatalogScreen::OnGemStatusChanged(const QString& gemName, uint32_t numChangedDependencies) { if (m_notificationsEnabled) diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.h b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.h index 1b34019d1a..b866b2d3af 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.h +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.h @@ -33,6 +33,7 @@ namespace O3DE::ProjectManager ProjectManagerScreen GetScreenEnum() override; void ReinitForProject(const QString& projectPath); + void Refresh(const QString& projectPath); enum class EnableDisableGemsResult { diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.cpp b/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.cpp index fb228c0b4a..a059df4cbf 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.cpp +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.cpp @@ -18,6 +18,7 @@ namespace O3DE::ProjectManager : QStandardItemModel(parent) { m_selectionModel = new QItemSelectionModel(this, parent); + connect(this, &QAbstractItemModel::rowsAboutToBeRemoved, this, &GemModel::OnRowsAboutToBeRemoved); } QItemSelectionModel* GemModel::GetSelectionModel() const @@ -359,6 +360,16 @@ namespace O3DE::ProjectManager gemModel->emit gemStatusChanged(gemName, numChangedDependencies); } + void GemModel::OnRowsAboutToBeRemoved(const QModelIndex& parent, int first, int last) + { + for (int i = first; i <= last; ++i) + { + QModelIndex modelIndex = index(i, 0, parent); + const QString& gemName = GetName(modelIndex); + m_nameToIndexMap.remove(gemName); + } + } + void GemModel::SetIsAddedDependency(QAbstractItemModel& model, const QModelIndex& modelIndex, bool isAdded) { model.setData(modelIndex, isAdded, RoleIsAddedDependency); diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.h b/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.h index 35231cc105..f4bc1ec502 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.h +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.h @@ -80,6 +80,9 @@ namespace O3DE::ProjectManager signals: void gemStatusChanged(const QString& gemName, uint32_t numChangedDependencies); + protected slots: + void OnRowsAboutToBeRemoved(const QModelIndex& parent, int first, int last); + private: void FindGemDisplayNamesByNameStrings(QStringList& inOutGemNames); void GetAllDependingGems(const QModelIndex& modelIndex, QSet& inOutGems); diff --git a/Code/Tools/ProjectManager/Source/GemRepo/GemRepoScreen.cpp b/Code/Tools/ProjectManager/Source/GemRepo/GemRepoScreen.cpp index 0ddfe41434..30a57417d2 100644 --- a/Code/Tools/ProjectManager/Source/GemRepo/GemRepoScreen.cpp +++ b/Code/Tools/ProjectManager/Source/GemRepo/GemRepoScreen.cpp @@ -91,6 +91,7 @@ namespace O3DE::ProjectManager if (addGemRepoResult) { Reinit(); + emit OnRefresh(); } else { @@ -116,6 +117,7 @@ namespace O3DE::ProjectManager if (removeGemRepoResult) { Reinit(); + emit OnRefresh(); } else { @@ -130,6 +132,7 @@ namespace O3DE::ProjectManager { bool refreshResult = PythonBindingsInterface::Get()->RefreshAllGemRepos(); Reinit(); + emit OnRefresh(); if (!refreshResult) { @@ -146,6 +149,7 @@ namespace O3DE::ProjectManager if (refreshResult.IsSuccess()) { Reinit(); + emit OnRefresh(); } else { diff --git a/Code/Tools/ProjectManager/Source/GemRepo/GemRepoScreen.h b/Code/Tools/ProjectManager/Source/GemRepo/GemRepoScreen.h index 46a733362a..0516005eef 100644 --- a/Code/Tools/ProjectManager/Source/GemRepo/GemRepoScreen.h +++ b/Code/Tools/ProjectManager/Source/GemRepo/GemRepoScreen.h @@ -28,6 +28,7 @@ namespace O3DE::ProjectManager class GemRepoScreen : public ScreenWidget { + Q_OBJECT public: explicit GemRepoScreen(QWidget* parent = nullptr); ~GemRepoScreen() = default; @@ -37,6 +38,9 @@ namespace O3DE::ProjectManager GemRepoModel* GetGemRepoModel() const { return m_gemRepoModel; } + signals: + void OnRefresh(); + public slots: void HandleAddRepoButton(); void HandleRemoveRepoButton(const QModelIndex& modelIndex); From 27c7e715168973e5b7fc175f427844500afbb4b1 Mon Sep 17 00:00:00 2001 From: Alex Peterson <26804013+AMZN-alexpete@users.noreply.github.com> Date: Wed, 3 Nov 2021 12:22:26 -0700 Subject: [PATCH 03/53] WIP default gem sorting Signed-off-by: Alex Peterson <26804013+AMZN-alexpete@users.noreply.github.com> --- .../Source/GemCatalog/GemCatalogScreen.cpp | 6 +++ .../Source/GemCatalog/GemModel.h | 50 +++++++++---------- 2 files changed, 31 insertions(+), 25 deletions(-) diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp index fb78736a3c..c76735d4f2 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp @@ -34,6 +34,9 @@ namespace O3DE::ProjectManager m_gemModel = new GemModel(this); m_proxModel = new GemSortFilterProxyModel(m_gemModel, this); + // default to sort by gem name + m_proxModel->setSortRole(GemModel::RoleName); + QVBoxLayout* vLayout = new QVBoxLayout(); vLayout->setMargin(0); vLayout->setSpacing(0); @@ -93,6 +96,8 @@ namespace O3DE::ProjectManager } m_proxModel->ResetFilters(); + m_proxModel->sort(/*column=*/0); + m_filterWidget = new GemFilterWidget(m_proxModel); m_filterWidgetLayout->addWidget(m_filterWidget); @@ -198,6 +203,7 @@ namespace O3DE::ProjectManager } m_gemModel->UpdateGemDependencies(); + m_proxModel->sort(/*column=*/0); } void GemCatalogScreen::OnGemStatusChanged(const QString& gemName, uint32_t numChangedDependencies) diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.h b/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.h index f4bc1ec502..9fac47d18e 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.h +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.h @@ -26,6 +26,31 @@ namespace O3DE::ProjectManager explicit GemModel(QObject* parent = nullptr); QItemSelectionModel* GetSelectionModel() const; + enum UserRole + { + RoleName = Qt::UserRole, + RoleDisplayName, + RoleCreator, + RoleGemOrigin, + RolePlatforms, + RoleSummary, + RoleWasPreviouslyAdded, + RoleWasPreviouslyAddedDependency, + RoleIsAdded, + RoleIsAddedDependency, + RoleDirectoryLink, + RoleDocLink, + RoleDependingGems, + RoleVersion, + RoleLastUpdated, + RoleBinarySize, + RoleFeatures, + RoleTypes, + RolePath, + RoleRequirement, + RoleDownloadStatus + }; + void AddGem(const GemInfo& gemInfo); void Clear(); void UpdateGemDependencies(); @@ -88,31 +113,6 @@ namespace O3DE::ProjectManager void GetAllDependingGems(const QModelIndex& modelIndex, QSet& inOutGems); QStringList GetDependingGems(const QModelIndex& modelIndex); - enum UserRole - { - RoleName = Qt::UserRole, - RoleDisplayName, - RoleCreator, - RoleGemOrigin, - RolePlatforms, - RoleSummary, - RoleWasPreviouslyAdded, - RoleWasPreviouslyAddedDependency, - RoleIsAdded, - RoleIsAddedDependency, - RoleDirectoryLink, - RoleDocLink, - RoleDependingGems, - RoleVersion, - RoleLastUpdated, - RoleBinarySize, - RoleFeatures, - RoleTypes, - RolePath, - RoleRequirement, - RoleDownloadStatus - }; - QHash m_nameToIndexMap; QItemSelectionModel* m_selectionModel = nullptr; QHash> m_gemDependencyMap; From d8c2088d1dd2e9f3c9e2a70e3d2b60a95427f15f Mon Sep 17 00:00:00 2001 From: Michael Pollind Date: Tue, 2 Nov 2021 08:59:19 -0700 Subject: [PATCH 04/53] bugifx: resolve crash with project manager (#5151) - system allocator not configured in environment for AZQtComponents - WA_DeleteOnClose will destroy the toast dialog causing a crashing when ToastNotificationsView tries to access the pointer issue: https://github.com/o3de/o3de/issues/5129 Signed-off-by: Michael Pollind --- .../AzQtComponents/Components/ToastNotification.cpp | 1 - .../AzQtComponents/Components/ToastNotification.h | 3 +-- .../AzQtComponents/Components/ToastNotificationConfiguration.h | 1 - .../UI/Notifications/ToastNotificationsView.cpp | 2 +- 4 files changed, 2 insertions(+), 5 deletions(-) diff --git a/Code/Framework/AzQtComponents/AzQtComponents/Components/ToastNotification.cpp b/Code/Framework/AzQtComponents/AzQtComponents/Components/ToastNotification.cpp index 8831bef89c..11fd1e60d8 100644 --- a/Code/Framework/AzQtComponents/AzQtComponents/Components/ToastNotification.cpp +++ b/Code/Framework/AzQtComponents/AzQtComponents/Components/ToastNotification.cpp @@ -27,7 +27,6 @@ namespace AzQtComponents setProperty("HasNoWindowDecorations", true); setAttribute(Qt::WA_ShowWithoutActivating); - setAttribute(Qt::WA_DeleteOnClose); m_borderRadius = toastConfiguration.m_borderRadius; if (m_borderRadius > 0) diff --git a/Code/Framework/AzQtComponents/AzQtComponents/Components/ToastNotification.h b/Code/Framework/AzQtComponents/AzQtComponents/Components/ToastNotification.h index 4343f37df4..81b1cb4055 100644 --- a/Code/Framework/AzQtComponents/AzQtComponents/Components/ToastNotification.h +++ b/Code/Framework/AzQtComponents/AzQtComponents/Components/ToastNotification.h @@ -31,7 +31,6 @@ namespace AzQtComponents { Q_OBJECT public: - AZ_CLASS_ALLOCATOR(ToastNotification, AZ::SystemAllocator, 0); ToastNotification(QWidget* parent, const ToastConfiguration& toastConfiguration); virtual ~ToastNotification(); @@ -73,7 +72,7 @@ namespace AzQtComponents AZ_PUSH_DISABLE_DLL_EXPORT_MEMBER_WARNING AZStd::chrono::milliseconds m_fadeDuration; - AZStd::unique_ptr m_ui; + QScopedPointer m_ui; AZ_POP_DISABLE_DLL_EXPORT_MEMBER_WARNING }; } // namespace AzQtComponents diff --git a/Code/Framework/AzQtComponents/AzQtComponents/Components/ToastNotificationConfiguration.h b/Code/Framework/AzQtComponents/AzQtComponents/Components/ToastNotificationConfiguration.h index 5ace9d1be2..2db374640e 100644 --- a/Code/Framework/AzQtComponents/AzQtComponents/Components/ToastNotificationConfiguration.h +++ b/Code/Framework/AzQtComponents/AzQtComponents/Components/ToastNotificationConfiguration.h @@ -27,7 +27,6 @@ namespace AzQtComponents class AZ_QT_COMPONENTS_API ToastConfiguration { public: - AZ_CLASS_ALLOCATOR(ToastConfiguration, AZ::SystemAllocator, 0); ToastConfiguration(ToastType toastType, const QString& title, const QString& description); bool m_closeOnClick = true; diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Notifications/ToastNotificationsView.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Notifications/ToastNotificationsView.cpp index a88711a9ed..277d3fa3c5 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Notifications/ToastNotificationsView.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Notifications/ToastNotificationsView.cpp @@ -129,7 +129,7 @@ namespace AzToolsFramework ToastId ToastNotificationsView::CreateToastNotification(const AzQtComponents::ToastConfiguration& toastConfiguration) { - AzQtComponents::ToastNotification* notification = aznew AzQtComponents::ToastNotification(parentWidget(), toastConfiguration); + AzQtComponents::ToastNotification* notification = new AzQtComponents::ToastNotification(this, toastConfiguration); ToastId toastId = AZ::Entity::MakeId(); m_notifications[toastId] = notification; From 861b29ffc7f6c829061e0c64f3cea975e57eef60 Mon Sep 17 00:00:00 2001 From: Alex Peterson <26804013+AMZN-alexpete@users.noreply.github.com> Date: Wed, 3 Nov 2021 13:45:40 -0700 Subject: [PATCH 05/53] Fix spelling change for member variable Signed-off-by: Alex Peterson <26804013+AMZN-alexpete@users.noreply.github.com> --- .../ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp index 08669d39a0..8234b80c8e 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp @@ -92,7 +92,7 @@ namespace O3DE::ProjectManager FillModel(projectPath); m_proxyModel->ResetFilters(); - m_proxModel->sort(/*column=*/0); + m_proxyModel->sort(/*column=*/0); if (m_filterWidget) { @@ -150,6 +150,7 @@ namespace O3DE::ProjectManager { m_gemModel->AddGem(gemInfoResult.GetValue()); m_gemModel->UpdateGemDependencies(); + m_proxyModel->sort(/*column=*/0); } } } @@ -206,7 +207,7 @@ namespace O3DE::ProjectManager } m_gemModel->UpdateGemDependencies(); - m_proxModel->sort(/*column=*/0); + m_proxyModel->sort(/*column=*/0); } void GemCatalogScreen::OnGemStatusChanged(const QString& gemName, uint32_t numChangedDependencies) From c9fb41d0e5abf036210563395a36f5cc48517aa6 Mon Sep 17 00:00:00 2001 From: nvsickle Date: Wed, 3 Nov 2021 19:57:51 -0700 Subject: [PATCH 06/53] Fix Entity Outliner sort order with Prefabs enabled The EditorEntitySortComponent was relying on serialization callbacks not exposed to the JSON serializer to marshal data between its serialized state and its runtime state, which led to the outliner sort order becoming disrupted every time a prefab propagation occurs (and the component is subsequently serialized and deserialized). This change: - Forces `PrepareSave` and `PostLoad` for `EditorEntitySortComponent` to be called at update (direct descendant added or removed) and activation time respectively while prefabs are enabled. While this could be optimized, and this logic stands to be refactored once slices are fully removed, I was unable to gather any samples in which `PrepareSave` are called in a sampling profiler in a scene with 1000 top-level entities, so I don't anticipate this introducing a meaningful performance regression in the short term. - Disables updates in `EditorEntitySortComponent` during prefab propagation, as any detected changes do not signal authored intent at this time - Made `GetEntityChildOrder` in `EditorEntityHelpers` work with prefabs enabled, which restores the existing "Sort: A -> Z" and "Sort: Z -> A" behaviors (which have some preexisting issues this does not fix) - Adds a Python regression test to the Editor suite to validate this behavior - the test is currently in TestSuite_Main and not TestSuite_Main_Optimized because it requires an Editor launch with prefabs enabled, this can be fixed once AutomatedTesting is further migrated away from slices @AMZN-daimini has a larger change that improves the JSON serialization format (https://github.com/o3de/o3de/pull/1292) which we should absolutely bring in in the future to improve the legibility of the Prefab format, but this change fixes the functionality (including saving & reloading a level and keeping a consistent order) without altering the Prefab format - this lower impact radius fix is my preference for our stabilization period. Signed-off-by: nvsickle --- .../EntityOutliner_EntityOrdering.py | 145 ++++++++++++++++++ .../Gem/PythonTests/editor/TestSuite_Main.py | 12 ++ .../Entity/EditorEntityHelpers.cpp | 12 ++ .../Entity/EditorEntitySortComponent.cpp | 43 ++++++ .../Entity/EditorEntitySortComponent.h | 6 + 5 files changed, 218 insertions(+) create mode 100644 AutomatedTesting/Gem/PythonTests/editor/EditorScripts/EntityOutliner_EntityOrdering.py diff --git a/AutomatedTesting/Gem/PythonTests/editor/EditorScripts/EntityOutliner_EntityOrdering.py b/AutomatedTesting/Gem/PythonTests/editor/EditorScripts/EntityOutliner_EntityOrdering.py new file mode 100644 index 0000000000..8b1e4763db --- /dev/null +++ b/AutomatedTesting/Gem/PythonTests/editor/EditorScripts/EntityOutliner_EntityOrdering.py @@ -0,0 +1,145 @@ +""" +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 +""" + + +class Tests: + entities_sorted = ( + "Entities sorted in the expected order", + "Entities sorted in an incorrect order", + ) + + +def EntityOutliner_EntityOrdering(): + """ + Summary: + Verify that manual entity ordering in the entity outliner works and is stable. + + Expected Behavior: + Several entities are created, some are manually ordered, and their order + is maintained, even when new entities are added. + + Test Steps: + 1) Open the empty Prefab Base level + 2) Add 5 entities to the outliner + 3) Move "Entity1" to the top of the order + 4) Move "Entity4" to the bottom of the order + 5) Add another new entity, ensure the rest of the order is unchanged + """ + + import editor_python_test_tools.pyside_utils as pyside_utils + import azlmbr.legacy.general as general + from editor_python_test_tools.utils import Report + from editor_python_test_tools.utils import TestHelper as helper + from PySide2 import QtCore, QtWidgets, QtGui, QtTest + + # Grab the Editor, Entity Outliner, and Outliner Model + editor_window = pyside_utils.get_editor_main_window() + entity_outliner = pyside_utils.find_child_by_hierarchy( + editor_window, ..., "EntityOutlinerWidgetUI", ..., "m_objectTree" + ) + entity_outliner_model = entity_outliner.model() + + # Get the outliner index for the root prefab container entity + def get_prefab_container_index(): + return entity_outliner_model.index(0, 0) + + # Get the outlienr index for the top level entity of a given name + def index_for_name(name): + root_index = get_prefab_container_index() + for row in range(entity_outliner_model.rowCount(root_index)): + row_index = entity_outliner_model.index(row, 0, root_index) + if row_index.data() == name: + return row_index + return None + + # Validate that the outliner top level entity order matches the expected order + def verify_entities_sorted(expected_order): + actual_order = [] + root_index = get_prefab_container_index() + for row in range(entity_outliner_model.rowCount(root_index)): + row_index = entity_outliner_model.index(row, 0, root_index) + actual_order.append(row_index.data()) + + sorted_correctly = actual_order == expected_order + Report.result(Tests.entities_sorted, sorted_correctly) + if not sorted_correctly: + print(f"Expected entity order: {expected_order}") + print(f"Actual entity order: {actual_order}") + + # Creates an entity from the outliner context menu + def create_entity(): + pyside_utils.trigger_context_menu_entry( + entity_outliner, "Create entity", index=get_prefab_container_index() + ) + general.idle_wait(0.0) + + # Moves an entity (wrapped by move_entity_before and move_entity_after) + def _move_entity(source_name, target_name, move_after=False): + source_index = index_for_name(source_name) + target_index = index_for_name(target_name) + + target_row = target_index.row() + if move_after: + target_row += 1 + + # Generate MIME data and directly inject it into the model instead of + # generating mouse click operations, as it's more reliable and we're + # testing the underlying drag & drop logic as opposed to Qt's mouse + # handling here + mime_data = entity_outliner_model.mimeData([source_index]) + entity_outliner_model.dropMimeData( + mime_data, QtCore.Qt.MoveAction, target_row, 0, target_index.parent() + ) + QtWidgets.QApplication.processEvents() + + # Move an entity before another entity in the order by dragging the source above the target + move_entity_before = lambda source_name, target_name: _move_entity( + source_name, target_name, move_after=False + ) + # Move an entity after another entity in the order by dragging the source beloew the target + move_entity_after = lambda source_name, target_name: _move_entity( + source_name, target_name, move_after=True + ) + + expected_order = [] + + # 1) Open the empty Prefab Base level + helper.init_idle() + helper.open_level("Prefab", "Base") + + # 2) Add 5 entities to the outliner + ENTITIES_TO_ADD = 5 + for i in range(ENTITIES_TO_ADD): + create_entity() + + # Our new entity should be given a name with a number automatically + new_entity = f"Entity{i+1}" + # The new entity should be added to the top of its parent entity + expected_order = [new_entity] + expected_order + + verify_entities_sorted(expected_order) + + # 3) Move "Entity1" to the top of the order + move_entity_before("Entity1", "Entity5") + expected_order = ["Entity1", "Entity5", "Entity4", "Entity3", "Entity2"] + verify_entities_sorted(expected_order) + + # 4) Move "Entity4" to the bottom of the order + move_entity_after("Entity4", "Entity2") + expected_order = ["Entity1", "Entity5", "Entity3", "Entity2", "Entity4"] + verify_entities_sorted(expected_order) + + # 5) Add another new entity, ensure the rest of the order is unchanged + create_entity() + expected_order = ["Entity6", "Entity1", "Entity5", "Entity3", "Entity2", "Entity4"] + verify_entities_sorted(expected_order) + + +if __name__ == "__main__": + from editor_python_test_tools.utils import Report + + Report.start_test(EntityOutliner_EntityOrdering) diff --git a/AutomatedTesting/Gem/PythonTests/editor/TestSuite_Main.py b/AutomatedTesting/Gem/PythonTests/editor/TestSuite_Main.py index 26b254ae71..49069569eb 100644 --- a/AutomatedTesting/Gem/PythonTests/editor/TestSuite_Main.py +++ b/AutomatedTesting/Gem/PythonTests/editor/TestSuite_Main.py @@ -41,3 +41,15 @@ class TestAutomation(TestAutomationBase): from .EditorScripts import BasicEditorWorkflows_LevelEntityComponentCRUD as test_module self._run_test(request, workspace, editor, test_module, batch_mode=False, autotest_mode=False, use_null_renderer=False) + + def test_EntityOutlienr_EntityOrdering(self, request, workspace, editor, launcher_platform): + from .EditorScripts import EntityOutliner_EntityOrdering as test_module + self._run_test( + request, + workspace, + editor, + test_module, + batch_mode=False, + autotest_mode=True, + extra_cmdline_args=["--regset=/Amazon/Preferences/EnablePrefabSystem=true"] + ) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/EditorEntityHelpers.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/EditorEntityHelpers.cpp index 28d6e2bc08..511f9dd580 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/EditorEntityHelpers.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/EditorEntityHelpers.cpp @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -468,6 +469,17 @@ namespace AzToolsFramework EntityIdList children; EditorEntityInfoRequestBus::EventResult(children, parentId, &EditorEntityInfoRequestBus::Events::GetChildren); + // If Prefabs are enabled, don't check the order for an invalid parent, just return its children (i.e. the root container entity) + if (!parentId.IsValid()) + { + bool isPrefabEnabled = false; + AzFramework::ApplicationRequests::Bus::BroadcastResult(isPrefabEnabled, &AzFramework::ApplicationRequests::IsPrefabSystemEnabled); + if (isPrefabEnabled) + { + return children; + } + } + EntityIdList entityChildOrder; AZ::EntityId sortEntityId = GetEntityIdForSortInfo(parentId); EditorEntitySortRequestBus::EventResult(entityChildOrder, sortEntityId, &EditorEntitySortRequestBus::Events::GetChildEntityOrderArray); diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/EditorEntitySortComponent.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/EditorEntitySortComponent.cpp index b747469f4d..6936397187 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/EditorEntitySortComponent.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/EditorEntitySortComponent.cpp @@ -11,6 +11,8 @@ #include #include #include +#include +#include static_assert(sizeof(AZ::u64) == sizeof(AZ::EntityId), "We use AZ::EntityId for Persistent ID, which is a u64 under the hood. These must be the same size otherwise the persistent id will have to be rewritten"); @@ -144,6 +146,12 @@ namespace AzToolsFramework bool EditorEntitySortComponent::AddChildEntityInternal(const AZ::EntityId& entityId, bool addToBack, EntityOrderArray::iterator insertPosition) { AZ_PROFILE_FUNCTION(AzToolsFramework); + + if (m_ignoreIncomingOrderChanges) + { + return true; + } + auto entityItr = m_childEntityOrderCache.find(entityId); if (entityItr == m_childEntityOrderCache.end()) { @@ -198,6 +206,12 @@ namespace AzToolsFramework bool EditorEntitySortComponent::RemoveChildEntity(const AZ::EntityId& entityId) { AZ_PROFILE_FUNCTION(AzToolsFramework); + + if (m_ignoreIncomingOrderChanges) + { + return true; + } + auto entityItr = m_childEntityOrderCache.find(entityId); if (entityItr != m_childEntityOrderCache.end()) { @@ -250,11 +264,30 @@ namespace AzToolsFramework } } + void EditorEntitySortComponent::OnPrefabInstancePropagationBegin() + { + m_ignoreIncomingOrderChanges = true; + } + + void EditorEntitySortComponent::OnPrefabInstancePropagationEnd() + { + m_ignoreIncomingOrderChanges = false; + } + void EditorEntitySortComponent::MarkDirtyAndSendChangedEvent() { // mark the order as dirty before sending the ChildEntityOrderArrayUpdated event in order for PrepareSave to be properly handled in the case // one of the event listeners needs to build the InstanceDataHierarchy m_entityOrderIsDirty = true; + + // Force an immediate update for prefabs, which won't receive PrepareSave + bool isPrefabEnabled = false; + AzFramework::ApplicationRequests::Bus::BroadcastResult( + isPrefabEnabled, &AzFramework::ApplicationRequests::IsPrefabSystemEnabled); + if (isPrefabEnabled) + { + PrepareSave(); + } EditorEntitySortNotificationBus::Event(GetEntityId(), &EditorEntitySortNotificationBus::Events::ChildEntityOrderArrayUpdated); } @@ -264,10 +297,20 @@ namespace AzToolsFramework // This is a special case for certain EditorComponents only! EditorEntitySortRequestBus::Handler::BusConnect(GetEntityId()); EditorEntityContextNotificationBus::Handler::BusConnect(); + AzToolsFramework::Prefab::PrefabPublicNotificationBus::Handler::BusConnect(); } void EditorEntitySortComponent::Activate() { + // Run the post-serialize handler if prefabs are enabled because PostLoad won't be called automatically + bool isPrefabEnabled = false; + AzFramework::ApplicationRequests::Bus::BroadcastResult( + isPrefabEnabled, &AzFramework::ApplicationRequests::IsPrefabSystemEnabled); + if (isPrefabEnabled) + { + PostLoad(); + } + // Send out that the order for our entity is now updated EditorEntitySortNotificationBus::Event(GetEntityId(), &EditorEntitySortNotificationBus::Events::ChildEntityOrderArrayUpdated); } diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/EditorEntitySortComponent.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/EditorEntitySortComponent.h index d728191c64..806e903c96 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/EditorEntitySortComponent.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/EditorEntitySortComponent.h @@ -10,6 +10,7 @@ #include "EditorEntitySortBus.h" #include #include +#include #include namespace AzToolsFramework @@ -20,6 +21,7 @@ namespace AzToolsFramework : public AzToolsFramework::Components::EditorComponentBase , public EditorEntitySortRequestBus::Handler , public EditorEntityContextNotificationBus::Handler + , public AzToolsFramework::Prefab::PrefabPublicNotificationBus::Handler { public: AZ_COMPONENT(EditorEntitySortComponent, "{6EA1E03D-68B2-466D-97F7-83998C8C27F0}", EditorComponentBase); @@ -45,6 +47,9 @@ namespace AzToolsFramework // EditorEntityContextNotificationBus::Handler void OnEntityStreamLoadSuccess() override; ////////////////////////////////////////////////////////////////////////// + + void OnPrefabInstancePropagationBegin() override; + void OnPrefabInstancePropagationEnd() override; private: void MarkDirtyAndSendChangedEvent(); bool AddChildEntityInternal(const AZ::EntityId& entityId, bool addToBack, EntityOrderArray::iterator insertPosition); @@ -106,6 +111,7 @@ namespace AzToolsFramework EntityOrderCache m_childEntityOrderCache; ///< The map of entity id to index for quick look up bool m_entityOrderIsDirty = true; ///< This flag indicates our stored serialization order data is out of date and must be rebuilt before serialization occurs + bool m_ignoreIncomingOrderChanges = false; ///< This is set when prefab propagation occurs so that non-authored order changes can be ignored }; } } // namespace AzToolsFramework From 2f8de3e797a40a4126d546c872f750ad55d76161 Mon Sep 17 00:00:00 2001 From: Alex Peterson <26804013+AMZN-alexpete@users.noreply.github.com> Date: Thu, 4 Nov 2021 09:37:26 -0700 Subject: [PATCH 07/53] Keep gem repos pages in sync Signed-off-by: Alex Peterson <26804013+AMZN-alexpete@users.noreply.github.com> --- .../Source/CreateProjectCtrl.cpp | 9 ++++---- .../Source/EngineScreenCtrl.cpp | 18 ++++++++++++++++ .../ProjectManager/Source/EngineScreenCtrl.h | 4 ++++ .../Source/GemCatalog/GemCatalogScreen.cpp | 21 +++++++++++++++---- .../Source/GemRepo/GemRepoScreen.cpp | 5 +++++ .../Source/GemRepo/GemRepoScreen.h | 3 +++ .../Source/UpdateProjectCtrl.cpp | 4 ++++ 7 files changed, 56 insertions(+), 8 deletions(-) diff --git a/Code/Tools/ProjectManager/Source/CreateProjectCtrl.cpp b/Code/Tools/ProjectManager/Source/CreateProjectCtrl.cpp index 6caa9b8a2b..1aad4a7206 100644 --- a/Code/Tools/ProjectManager/Source/CreateProjectCtrl.cpp +++ b/Code/Tools/ProjectManager/Source/CreateProjectCtrl.cpp @@ -51,13 +51,11 @@ namespace O3DE::ProjectManager m_gemRepoScreen = new GemRepoScreen(this); m_stack->addWidget(m_gemRepoScreen); + vLayout->addWidget(m_stack); - connect(m_gemCatalogScreen, &ScreenWidget::ChangeScreenRequest, this, &CreateProjectCtrl::OnChangeScreenRequest); - connect( - m_gemRepoScreen, &GemRepoScreen::OnRefresh, - [this]() + connect(m_gemRepoScreen, &GemRepoScreen::OnRefresh, [this]() { const QString projectTemplatePath = m_newProjectSettingsScreen->GetProjectTemplatePath(); m_gemCatalogScreen->Refresh(projectTemplatePath + "/Template"); @@ -135,6 +133,9 @@ namespace O3DE::ProjectManager // Gather the enabled gems from the default project template when starting the create new project workflow. ReinitGemCatalogForSelectedTemplate(); + + // make sure the gem repo has the latest details + m_gemRepoScreen->Reinit(); } void CreateProjectCtrl::HandleBackButton() diff --git a/Code/Tools/ProjectManager/Source/EngineScreenCtrl.cpp b/Code/Tools/ProjectManager/Source/EngineScreenCtrl.cpp index f30a8e0daa..9d9110922f 100644 --- a/Code/Tools/ProjectManager/Source/EngineScreenCtrl.cpp +++ b/Code/Tools/ProjectManager/Source/EngineScreenCtrl.cpp @@ -39,6 +39,10 @@ namespace O3DE::ProjectManager m_tabWidget->addTab(m_engineSettingsScreen, tr("General")); m_tabWidget->addTab(m_gemRepoScreen, tr("Gem Repositories")); + + // when tab changes, notify the current screen so it can refresh + connect(m_tabWidget, &QTabWidget::currentChanged, this, &EngineScreenCtrl::TabChanged); + topBarHLayout->addWidget(m_tabWidget); vLayout->addWidget(topBarFrameWidget); @@ -46,6 +50,11 @@ namespace O3DE::ProjectManager setLayout(vLayout); } + void EngineScreenCtrl::TabChanged([[maybe_unused]] int index) + { + NotifyCurrentScreen(); + } + ProjectManagerScreen EngineScreenCtrl::GetScreenEnum() { return ProjectManagerScreen::UpdateProject; @@ -71,6 +80,15 @@ namespace O3DE::ProjectManager return false; } + void EngineScreenCtrl::NotifyCurrentScreen() + { + ScreenWidget* screen = reinterpret_cast(m_tabWidget->currentWidget()); + if (screen) + { + screen->NotifyCurrentScreen(); + } + } + void EngineScreenCtrl::GoToScreen(ProjectManagerScreen screen) { if (screen == m_engineSettingsScreen->GetScreenEnum()) diff --git a/Code/Tools/ProjectManager/Source/EngineScreenCtrl.h b/Code/Tools/ProjectManager/Source/EngineScreenCtrl.h index b7142ba226..cf0d2a24d0 100644 --- a/Code/Tools/ProjectManager/Source/EngineScreenCtrl.h +++ b/Code/Tools/ProjectManager/Source/EngineScreenCtrl.h @@ -30,6 +30,10 @@ namespace O3DE::ProjectManager bool IsTab() override; bool ContainsScreen(ProjectManagerScreen screen) override; void GoToScreen(ProjectManagerScreen screen) override; + void NotifyCurrentScreen() override; + + public slots: + void TabChanged(int index); QTabWidget* m_tabWidget = nullptr; EngineSettingsScreen* m_engineSettingsScreen = nullptr; diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp index 8234b80c8e..915c837da4 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp @@ -23,7 +23,6 @@ #include #include #include -#include #include namespace O3DE::ProjectManager @@ -160,6 +159,7 @@ namespace O3DE::ProjectManager { QHash gemInfoHash; + // create a hash with the gem name as key AZ::Outcome, AZStd::string> allGemInfosResult = PythonBindingsInterface::Get()->GetAllGemInfos(projectPath); if (allGemInfosResult.IsSuccess()) { @@ -170,6 +170,7 @@ namespace O3DE::ProjectManager } } + // add all the gem repos into the hash AZ::Outcome, AZStd::string> allRepoGemInfosResult = PythonBindingsInterface::Get()->GetAllGemRepoGemsInfos(); if (allRepoGemInfosResult.IsSuccess()) { @@ -183,24 +184,32 @@ namespace O3DE::ProjectManager } } - // remove rows for gems that were removed and not project dependencies + // remove gems from the model that no longer exist in the hash and are not project dependencies int i = 0; while (i < m_gemModel->rowCount()) { QModelIndex index = m_gemModel->index(i,0); QString gemName = m_gemModel->GetName(index); - if (!gemInfoHash.contains(gemName) && !m_gemModel->IsAdded(index) && !m_gemModel->IsAddedDependency(index)) + const bool gemFound = gemInfoHash.contains(gemName); + if (!gemFound && !m_gemModel->IsAdded(index) && !m_gemModel->IsAddedDependency(index)) { m_gemModel->removeRow(i); } else { + if (!gemFound && (m_gemModel->IsAdded(index) || !m_gemModel->IsAddedDependency(index))) + { + const QString error = tr("Gem %1 was removed or unregistered, but is still used by the project.").arg(gemName); + AZ_Warning("Project Manager", false, error.toUtf8().constData()); + QMessageBox::warning(this, tr("Gem not found"), error.toUtf8().constData()); + } + gemInfoHash.remove(gemName); i++; } } - // add new rows + // add all gems remaining in the hash that were not removed for(auto iter = gemInfoHash.begin(); iter != gemInfoHash.end(); ++iter) { m_gemModel->AddGem(iter.value()); @@ -208,6 +217,10 @@ namespace O3DE::ProjectManager m_gemModel->UpdateGemDependencies(); m_proxyModel->sort(/*column=*/0); + + // temporary, until we can refresh filter counts + m_proxyModel->ResetFilters(); + m_filterWidget->ResetAllFilters(); } void GemCatalogScreen::OnGemStatusChanged(const QString& gemName, uint32_t numChangedDependencies) diff --git a/Code/Tools/ProjectManager/Source/GemRepo/GemRepoScreen.cpp b/Code/Tools/ProjectManager/Source/GemRepo/GemRepoScreen.cpp index 30a57417d2..794635a3e3 100644 --- a/Code/Tools/ProjectManager/Source/GemRepo/GemRepoScreen.cpp +++ b/Code/Tools/ProjectManager/Source/GemRepo/GemRepoScreen.cpp @@ -52,6 +52,11 @@ namespace O3DE::ProjectManager Reinit(); } + void GemRepoScreen::NotifyCurrentScreen() + { + Reinit(); + } + void GemRepoScreen::Reinit() { m_gemRepoModel->clear(); diff --git a/Code/Tools/ProjectManager/Source/GemRepo/GemRepoScreen.h b/Code/Tools/ProjectManager/Source/GemRepo/GemRepoScreen.h index 0516005eef..eed9a5ec4a 100644 --- a/Code/Tools/ProjectManager/Source/GemRepo/GemRepoScreen.h +++ b/Code/Tools/ProjectManager/Source/GemRepo/GemRepoScreen.h @@ -38,6 +38,8 @@ namespace O3DE::ProjectManager GemRepoModel* GetGemRepoModel() const { return m_gemRepoModel; } + void NotifyCurrentScreen() override; + signals: void OnRefresh(); @@ -47,6 +49,7 @@ namespace O3DE::ProjectManager void HandleRefreshAllButton(); void HandleRefreshRepoButton(const QModelIndex& modelIndex); + private: void FillModel(); QFrame* CreateNoReposContent(); diff --git a/Code/Tools/ProjectManager/Source/UpdateProjectCtrl.cpp b/Code/Tools/ProjectManager/Source/UpdateProjectCtrl.cpp index 5de3511f84..e76b4093a9 100644 --- a/Code/Tools/ProjectManager/Source/UpdateProjectCtrl.cpp +++ b/Code/Tools/ProjectManager/Source/UpdateProjectCtrl.cpp @@ -43,6 +43,7 @@ namespace O3DE::ProjectManager m_gemRepoScreen = new GemRepoScreen(this); connect(m_gemCatalogScreen, &ScreenWidget::ChangeScreenRequest, this, &UpdateProjectCtrl::OnChangeScreenRequest); + connect(m_gemRepoScreen, &GemRepoScreen::OnRefresh, [this](){ m_gemCatalogScreen->Refresh(m_projectInfo.m_path); }); m_stack = new QStackedWidget(this); m_stack->setObjectName("body"); @@ -101,6 +102,9 @@ namespace O3DE::ProjectManager // Gather the available gems that will be shown in the gem catalog. m_gemCatalogScreen->ReinitForProject(m_projectInfo.m_path); + + // make sure the gem repo has the latest repo details + m_gemRepoScreen->Reinit(); } void UpdateProjectCtrl::OnChangeScreenRequest(ProjectManagerScreen screen) From 774b7c2593ad7c9b03412b2915e9138a6da64278 Mon Sep 17 00:00:00 2001 From: Alex Peterson <26804013+AMZN-alexpete@users.noreply.github.com> Date: Thu, 4 Nov 2021 11:03:36 -0700 Subject: [PATCH 08/53] Fixed minor logic issue with gem removal warning Signed-off-by: Alex Peterson <26804013+AMZN-alexpete@users.noreply.github.com> --- .../Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp index 915c837da4..4574e8509b 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp @@ -197,7 +197,7 @@ namespace O3DE::ProjectManager } else { - if (!gemFound && (m_gemModel->IsAdded(index) || !m_gemModel->IsAddedDependency(index))) + if (!gemFound && (m_gemModel->IsAdded(index) || m_gemModel->IsAddedDependency(index))) { const QString error = tr("Gem %1 was removed or unregistered, but is still used by the project.").arg(gemName); AZ_Warning("Project Manager", false, error.toUtf8().constData()); From 9958e5f0128e17bd417022f949d19c1ae5054534 Mon Sep 17 00:00:00 2001 From: amzn-sj Date: Thu, 4 Nov 2021 11:04:01 -0700 Subject: [PATCH 09/53] [MacOS] Launching Editor from ProjectManager and other misc. fixes Signed-off-by: amzn-sj --- .../Asset/AssetSystemComponentHelper_Mac.cpp | 32 ++++++++++-------- .../BundleLauncher/O3DE_SDK_Launcher.cpp | 6 ++++ .../Platform/Linux/ProjectUtils_linux.cpp | 7 ++++ .../Platform/Mac/ProjectUtils_mac.cpp | 33 +++++++++++++++++++ .../Platform/Windows/ProjectUtils_windows.cpp | 7 ++++ .../ProjectManager/Source/ProjectUtils.h | 4 ++- .../ProjectManager/Source/ProjectsScreen.cpp | 4 +-- 7 files changed, 77 insertions(+), 16 deletions(-) diff --git a/Code/Framework/AzFramework/Platform/Mac/AzFramework/Asset/AssetSystemComponentHelper_Mac.cpp b/Code/Framework/AzFramework/Platform/Mac/AzFramework/Asset/AssetSystemComponentHelper_Mac.cpp index c6f481b65b..a3381dabb8 100644 --- a/Code/Framework/AzFramework/Platform/Mac/AzFramework/Asset/AssetSystemComponentHelper_Mac.cpp +++ b/Code/Framework/AzFramework/Platform/Mac/AzFramework/Asset/AssetSystemComponentHelper_Mac.cpp @@ -10,6 +10,8 @@ #include #include +#include + #include #include @@ -24,14 +26,20 @@ namespace AzFramework::AssetSystem::Platform AZ::IO::FixedMaxPath assetProcessorPath{ executableDirectory }; // In Mac the Editor and game is within a bundle, so the path to the sibling app // has to go up from the Contents/MacOS folder the binary is in - assetProcessorPath /= "../../../AssetProcessor.app"; + assetProcessorPath /= "../../../AssetProcessor.app/Contents/MacOS/AssetProcessor"; assetProcessorPath = assetProcessorPath.LexicallyNormal(); if (!AZ::IO::SystemFile::Exists(assetProcessorPath.c_str())) { - // Check for existence of one under a "bin" directory, i.e. engineRoot is an SDK structure. - assetProcessorPath = - AZ::IO::FixedMaxPath{engineRoot} / "bin" / AZ_TRAIT_OS_PLATFORM_NAME / AZ_BUILD_CONFIGURATION_TYPE / "AssetProcessor.app"; + if (auto settingsRegistry = AZ::SettingsRegistry::Get(); settingsRegistry != nullptr) + { + if (AZ::IO::FixedMaxPath installedBinariesPath; + settingsRegistry->Get(installedBinariesPath.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_InstalledBinaryFolder)) + { + // Check for existence of one under a "bin" directory, i.e. engineRoot is an SDK structure. + assetProcessorPath = AZ::IO::FixedMaxPath{ engineRoot } / installedBinariesPath / "AssetProcessor.app/Contents/MacOS/AssetProcessor"; + } + } if (!AZ::IO::SystemFile::Exists(assetProcessorPath.c_str())) { @@ -39,23 +47,21 @@ namespace AzFramework::AssetSystem::Platform } } - auto fullLaunchCommand = AZ::IO::FixedMaxPathString::format(R"(open -g "%s" --args --start-hidden)", assetProcessorPath.c_str()); + AZStd::string commandLineParams; // Add the engine path to the launch command if not empty if (!engineRoot.empty()) { - fullLaunchCommand += R"( --engine-path=")"; - fullLaunchCommand += engineRoot; - fullLaunchCommand += '"'; + commandLineParams += AZStd::string::format("\"--engine-path=\"%s\"\"", engineRoot.data()); } - // Add the active project path to the launch command if not empty if (!projectPath.empty()) { - fullLaunchCommand += R"( --project-path=")"; - fullLaunchCommand += projectPath; - fullLaunchCommand += '"'; + commandLineParams += AZStd::string::format(" \"--regset=/Amazon/AzCore/Bootstrap/project_path=\"%s\"\"", projectPath.data()); } - return system(fullLaunchCommand.c_str()) == 0; + AzFramework::ProcessLauncher::ProcessLaunchInfo processLaunchInfo; + processLaunchInfo.m_processExecutableString = AZStd::move(assetProcessorPath.Native()); + processLaunchInfo.m_commandlineParameters = commandLineParams; + return AzFramework::ProcessLauncher::LaunchUnwatchedProcess(processLaunchInfo); } } diff --git a/Code/Tools/BundleLauncher/O3DE_SDK_Launcher.cpp b/Code/Tools/BundleLauncher/O3DE_SDK_Launcher.cpp index 0c362ac829..4dd7e184e9 100644 --- a/Code/Tools/BundleLauncher/O3DE_SDK_Launcher.cpp +++ b/Code/Tools/BundleLauncher/O3DE_SDK_Launcher.cpp @@ -49,6 +49,12 @@ int main(int argc, char* argv[]) AZStd::unique_ptr shellProcess(AzFramework::ProcessWatcher::LaunchProcess(shellProcessLaunch, AzFramework::ProcessCommunicationType::COMMUNICATOR_TYPE_NONE)); shellProcess->WaitForProcessToExit(120); shellProcess.reset(); + + parameters = AZStd::string::format("-c \"%s/scripts/o3de.sh register --this-engine\"", enginePath.c_str()); + shellProcessLaunch.m_commandlineParameters = parameters; + shellProcess.reset(AzFramework::ProcessWatcher::LaunchProcess(shellProcessLaunch, AzFramework::ProcessCommunicationType::COMMUNICATOR_TYPE_NONE)); + shellProcess->WaitForProcessToExit(120); + shellProcess.reset(); AZ::IO::FixedMaxPath projectManagerPath = installedBinariesFolder/"o3de.app"/"Contents"/"MacOS"/"o3de"; AzFramework::ProcessLauncher::ProcessLaunchInfo processLaunchInfo; diff --git a/Code/Tools/ProjectManager/Platform/Linux/ProjectUtils_linux.cpp b/Code/Tools/ProjectManager/Platform/Linux/ProjectUtils_linux.cpp index 0d66009d90..e901d807b4 100644 --- a/Code/Tools/ProjectManager/Platform/Linux/ProjectUtils_linux.cpp +++ b/Code/Tools/ProjectManager/Platform/Linux/ProjectUtils_linux.cpp @@ -10,6 +10,8 @@ #include #include +#include + namespace O3DE::ProjectManager { namespace ProjectUtils @@ -94,5 +96,10 @@ namespace O3DE::ProjectManager QProcessEnvironment::systemEnvironment(), QObject::tr("Running get_python script...")); } + + AZ::IO::FixedMaxPath GetEditorDirectory() + { + return AZ::Utils::GetExecutableDirectory(); + } } // namespace ProjectUtils } // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/Platform/Mac/ProjectUtils_mac.cpp b/Code/Tools/ProjectManager/Platform/Mac/ProjectUtils_mac.cpp index e36f6cd0c8..b768200398 100644 --- a/Code/Tools/ProjectManager/Platform/Mac/ProjectUtils_mac.cpp +++ b/Code/Tools/ProjectManager/Platform/Mac/ProjectUtils_mac.cpp @@ -11,6 +11,9 @@ #include #include +#include +#include + namespace O3DE::ProjectManager { namespace ProjectUtils @@ -104,5 +107,35 @@ namespace O3DE::ProjectManager QProcessEnvironment::systemEnvironment(), QObject::tr("Running get_python script...")); } + + AZ::IO::FixedMaxPath GetEditorDirectory() + { + AZ::IO::FixedMaxPath executableDirectory = AZ::Utils::GetExecutableDirectory(); + AZ::IO::FixedMaxPath editorPath{ executableDirectory }; + editorPath /= "../../../Editor.app/Contents/MacOS"; + editorPath = editorPath.LexicallyNormal(); + if (!AZ::IO::SystemFile::IsDirectory(editorPath.c_str())) + { + if (auto settingsRegistry = AZ::SettingsRegistry::Get(); settingsRegistry != nullptr) + { + if (AZ::IO::FixedMaxPath installedBinariesPath; + settingsRegistry->Get(installedBinariesPath.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_InstalledBinaryFolder)) + { + if (AZ::IO::FixedMaxPath engineRootFolder; + settingsRegistry->Get(engineRootFolder.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_EngineRootFolder)) + { + editorPath = engineRootFolder / installedBinariesPath / "Editor.app/Contents/MacOS"; + } + } + } + + if (!AZ::IO::SystemFile::IsDirectory(editorPath.c_str())) + { + AZ_Error("ProjectManager", false, "Unable to find the Editor app bundle!"); + } + } + + return editorPath; + } } // namespace ProjectUtils } // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/Platform/Windows/ProjectUtils_windows.cpp b/Code/Tools/ProjectManager/Platform/Windows/ProjectUtils_windows.cpp index 831529d5e4..871f8e9567 100644 --- a/Code/Tools/ProjectManager/Platform/Windows/ProjectUtils_windows.cpp +++ b/Code/Tools/ProjectManager/Platform/Windows/ProjectUtils_windows.cpp @@ -14,6 +14,8 @@ #include #include +#include + namespace O3DE::ProjectManager { namespace ProjectUtils @@ -139,5 +141,10 @@ namespace O3DE::ProjectManager QProcessEnvironment::systemEnvironment(), QObject::tr("Running get_python script...")); } + + AZ::IO::FixedMaxPath GetEditorDirectory() + { + return AZ::Utils::GetExecutableDirectory(); + } } // namespace ProjectUtils } // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/Source/ProjectUtils.h b/Code/Tools/ProjectManager/Source/ProjectUtils.h index 1fdf76913e..890d50d2de 100644 --- a/Code/Tools/ProjectManager/Source/ProjectUtils.h +++ b/Code/Tools/ProjectManager/Source/ProjectUtils.h @@ -14,6 +14,7 @@ #include #include +#include #include namespace O3DE::ProjectManager @@ -67,7 +68,8 @@ namespace O3DE::ProjectManager AZ::Outcome GetProjectBuildPath(const QString& projectPath); AZ::Outcome OpenCMakeGUI(const QString& projectPath); AZ::Outcome RunGetPythonScript(const QString& enginePath); - + + AZ::IO::FixedMaxPath GetEditorDirectory(); } // namespace ProjectUtils } // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/Source/ProjectsScreen.cpp b/Code/Tools/ProjectManager/Source/ProjectsScreen.cpp index cf42da88fa..f86a689e59 100644 --- a/Code/Tools/ProjectManager/Source/ProjectsScreen.cpp +++ b/Code/Tools/ProjectManager/Source/ProjectsScreen.cpp @@ -392,11 +392,11 @@ namespace O3DE::ProjectManager { if (!WarnIfInBuildQueue(projectPath)) { - AZ::IO::FixedMaxPath executableDirectory = AZ::Utils::GetExecutableDirectory(); + AZ::IO::FixedMaxPath executableDirectory = ProjectUtils::GetEditorDirectory(); AZStd::string executableFilename = "Editor"; AZ::IO::FixedMaxPath editorExecutablePath = executableDirectory / (executableFilename + AZ_TRAIT_OS_EXECUTABLE_EXTENSION); auto cmdPath = AZ::IO::FixedMaxPathString::format( - "%s -regset=\"/Amazon/AzCore/Bootstrap/project_path=%s\"", editorExecutablePath.c_str(), + "%s --regset=\"/Amazon/AzCore/Bootstrap/project_path=%s\"", editorExecutablePath.c_str(), projectPath.toStdString().c_str()); AzFramework::ProcessLauncher::ProcessLaunchInfo processLaunchInfo; From 52604d79f6d2de34f9b94b30daf08e518bfa6429 Mon Sep 17 00:00:00 2001 From: nvsickle Date: Thu, 4 Nov 2021 12:05:46 -0700 Subject: [PATCH 10/53] Address some review feedback Signed-off-by: nvsickle --- .../EditorScripts/EntityOutliner_EntityOrdering.py | 11 ++++++----- .../AzToolsFramework/Entity/EditorEntityHelpers.cpp | 1 + 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/AutomatedTesting/Gem/PythonTests/editor/EditorScripts/EntityOutliner_EntityOrdering.py b/AutomatedTesting/Gem/PythonTests/editor/EditorScripts/EntityOutliner_EntityOrdering.py index 8b1e4763db..e4575d4d17 100644 --- a/AutomatedTesting/Gem/PythonTests/editor/EditorScripts/EntityOutliner_EntityOrdering.py +++ b/AutomatedTesting/Gem/PythonTests/editor/EditorScripts/EntityOutliner_EntityOrdering.py @@ -44,12 +44,12 @@ def EntityOutliner_EntityOrdering(): entity_outliner_model = entity_outliner.model() # Get the outliner index for the root prefab container entity - def get_prefab_container_index(): + def get_root_prefab_container_index(): return entity_outliner_model.index(0, 0) - # Get the outlienr index for the top level entity of a given name + # Get the outliner index for the top level entity of a given name def index_for_name(name): - root_index = get_prefab_container_index() + root_index = get_root_prefab_container_index() for row in range(entity_outliner_model.rowCount(root_index)): row_index = entity_outliner_model.index(row, 0, root_index) if row_index.data() == name: @@ -59,7 +59,7 @@ def EntityOutliner_EntityOrdering(): # Validate that the outliner top level entity order matches the expected order def verify_entities_sorted(expected_order): actual_order = [] - root_index = get_prefab_container_index() + root_index = get_root_prefab_container_index() for row in range(entity_outliner_model.rowCount(root_index)): row_index = entity_outliner_model.index(row, 0, root_index) actual_order.append(row_index.data()) @@ -73,8 +73,9 @@ def EntityOutliner_EntityOrdering(): # Creates an entity from the outliner context menu def create_entity(): pyside_utils.trigger_context_menu_entry( - entity_outliner, "Create entity", index=get_prefab_container_index() + entity_outliner, "Create entity", index=get_root_prefab_container_index() ) + # Wait a tick after entity creation to let events process general.idle_wait(0.0) # Moves an entity (wrapped by move_entity_before and move_entity_after) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/EditorEntityHelpers.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/EditorEntityHelpers.cpp index 511f9dd580..3e256430a2 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/EditorEntityHelpers.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/EditorEntityHelpers.cpp @@ -470,6 +470,7 @@ namespace AzToolsFramework EditorEntityInfoRequestBus::EventResult(children, parentId, &EditorEntityInfoRequestBus::Events::GetChildren); // If Prefabs are enabled, don't check the order for an invalid parent, just return its children (i.e. the root container entity) + // There will currently always be one root container entity, so there's no order to retrieve if (!parentId.IsValid()) { bool isPrefabEnabled = false; From 5b504086f9f630ac7841ef26cf2662096d1dc567 Mon Sep 17 00:00:00 2001 From: Mike Balfour <82224783+mbalfour-amzn@users.noreply.github.com> Date: Thu, 4 Nov 2021 15:27:00 -0500 Subject: [PATCH 11/53] Prevent infinite recursion with Altitude Gradient. Using the Altitude Gradient as an input to the Height Gradient List can cause infinite recursion since it is both setting and fetching the same height value. Added guards to warn if this occurs and gracefully handles the situation. Signed-off-by: Mike Balfour <82224783+mbalfour-amzn@users.noreply.github.com> --- .../TerrainHeightGradientListComponent.cpp | 37 +++++++++++-------- .../TerrainHeightGradientListComponent.h | 3 ++ 2 files changed, 24 insertions(+), 16 deletions(-) diff --git a/Gems/Terrain/Code/Source/Components/TerrainHeightGradientListComponent.cpp b/Gems/Terrain/Code/Source/Components/TerrainHeightGradientListComponent.cpp index 231d5abc28..06b7320a06 100644 --- a/Gems/Terrain/Code/Source/Components/TerrainHeightGradientListComponent.cpp +++ b/Gems/Terrain/Code/Source/Components/TerrainHeightGradientListComponent.cpp @@ -151,24 +151,29 @@ namespace Terrain { float maxSample = 0.0f; terrainExists = false; - - GradientSignal::GradientSampleParams params(AZ::Vector3(inPosition.GetX(), inPosition.GetY(), 0.0f)); - - // Right now, when the list contains multiple entries, we will use the highest point from each gradient. - // This is needed in part because gradients don't really have world bounds, so they exist everywhere but generally have a value - // of 0 outside their data bounds if they're using bounded data. We should examine the possibility of extending the gradient API - // to provide actual bounds so that it's possible to detect if the gradient even 'exists' in an area, at which point we could just - // make this list a prioritized list from top to bottom for any points that overlap. - for (auto& gradientId : m_configuration.m_gradientEntities) + AZ_WarningOnce("Terrain", !m_isRequestInProgress, "Detected cyclic dependences with terrain height entity references"); + if (!m_isRequestInProgress) { - // If gradients ever provide bounds, or if we add a value threshold in this component, it would be possible for terrain - // to *not* exist at a specific point. - terrainExists = true; + m_isRequestInProgress = true; + GradientSignal::GradientSampleParams params(AZ::Vector3(inPosition.GetX(), inPosition.GetY(), 0.0f)); - float sample = 0.0f; - GradientSignal::GradientRequestBus::EventResult( - sample, gradientId, &GradientSignal::GradientRequestBus::Events::GetValue, params); - maxSample = AZ::GetMax(maxSample, sample); + // Right now, when the list contains multiple entries, we will use the highest point from each gradient. + // This is needed in part because gradients don't really have world bounds, so they exist everywhere but generally have a value + // of 0 outside their data bounds if they're using bounded data. We should examine the possibility of extending the gradient + // API to provide actual bounds so that it's possible to detect if the gradient even 'exists' in an area, at which point we + // could just make this list a prioritized list from top to bottom for any points that overlap. + for (auto& gradientId : m_configuration.m_gradientEntities) + { + // If gradients ever provide bounds, or if we add a value threshold in this component, it would be possible for terrain + // to *not* exist at a specific point. + terrainExists = true; + + float sample = 0.0f; + GradientSignal::GradientRequestBus::EventResult( + sample, gradientId, &GradientSignal::GradientRequestBus::Events::GetValue, params); + maxSample = AZ::GetMax(maxSample, sample); + } + m_isRequestInProgress = false; } const float height = AZ::Lerp(m_cachedShapeBounds.GetMin().GetZ(), m_cachedShapeBounds.GetMax().GetZ(), maxSample); diff --git a/Gems/Terrain/Code/Source/Components/TerrainHeightGradientListComponent.h b/Gems/Terrain/Code/Source/Components/TerrainHeightGradientListComponent.h index 6c3fd7b820..b5b1a44192 100644 --- a/Gems/Terrain/Code/Source/Components/TerrainHeightGradientListComponent.h +++ b/Gems/Terrain/Code/Source/Components/TerrainHeightGradientListComponent.h @@ -91,6 +91,9 @@ namespace Terrain AZ::Vector2 m_cachedHeightQueryResolution{ 1.0f, 1.0f }; AZ::Aabb m_cachedShapeBounds; + // prevent recursion in case user attaches cyclic dependences + mutable bool m_isRequestInProgress{ false }; + LmbrCentral::DependencyMonitor m_dependencyMonitor; }; } From e32e1ce572a2e5fd5198da56b4d1b4ec64b1a2db Mon Sep 17 00:00:00 2001 From: Mike Balfour <82224783+mbalfour-amzn@users.noreply.github.com> Date: Thu, 4 Nov 2021 15:55:37 -0500 Subject: [PATCH 12/53] Fix terrain wireframe refresh. If a terrain layer spawner went outside the world bounds, the debug wireframe wouldn't update correctly because the heights were outside the wireframe sector AABBs. Adjusted the logic to account for this. Signed-off-by: Mike Balfour <82224783+mbalfour-amzn@users.noreply.github.com> --- .../Components/TerrainWorldDebuggerComponent.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/Gems/Terrain/Code/Source/Components/TerrainWorldDebuggerComponent.cpp b/Gems/Terrain/Code/Source/Components/TerrainWorldDebuggerComponent.cpp index e140129563..79fd5509f2 100644 --- a/Gems/Terrain/Code/Source/Components/TerrainWorldDebuggerComponent.cpp +++ b/Gems/Terrain/Code/Source/Components/TerrainWorldDebuggerComponent.cpp @@ -218,6 +218,12 @@ namespace Terrain AzFramework::Terrain::TerrainDataRequestBus::BroadcastResult( queryResolution, &AzFramework::Terrain::TerrainDataRequests::GetTerrainHeightQueryResolution); + // Take the dirty region and adjust the Z values to the world min/max so that even if the dirty region falls outside the current + // world bounds, we still update the wireframe accordingly. + AZ::Aabb dirtyRegion2D = AZ::Aabb::CreateFromMinMaxValues( + dirtyRegion.GetMin().GetX(), dirtyRegion.GetMin().GetY(), worldBounds.GetMin().GetZ(), + dirtyRegion.GetMax().GetX(), dirtyRegion.GetMax().GetY(), worldBounds.GetMax().GetZ()); + // Calculate the world size of each sector. Note that this size actually ends at the last point, not the last square. // So for example, the sector size for 3 points will go from (*--*--*) even though it will be used to draw (*--*--*--). const float xSectorSize = (queryResolution.GetX() * SectorSizeInGridPoints); @@ -230,7 +236,7 @@ namespace Terrain // If we haven't cached anything before, or if the world bounds has changed, clear our cache structure and repopulate it // with WireframeSector entries with the proper AABB sizes. - if (!m_wireframeBounds.IsValid() || !dirtyRegion.IsValid() || !m_wireframeBounds.IsClose(worldBounds)) + if (!m_wireframeBounds.IsValid() || !dirtyRegion2D.IsValid() || !m_wireframeBounds.IsClose(worldBounds)) { m_wireframeBounds = worldBounds; @@ -266,7 +272,7 @@ namespace Terrain // For each sector, if it overlaps with the dirty region, clear it out and recache the wireframe line data. for (auto& sector : m_wireframeSectors) { - if (dirtyRegion.IsValid() && !dirtyRegion.Overlaps(sector.m_aabb)) + if (dirtyRegion2D.IsValid() && !dirtyRegion2D.Overlaps(sector.m_aabb)) { continue; } From c37767f92a0ce4289275713e7d22ec5919934712 Mon Sep 17 00:00:00 2001 From: Chris Galvan Date: Thu, 4 Nov 2021 16:30:44 -0500 Subject: [PATCH 13/53] Set window flags so the processing overlay widget always appears on top. Signed-off-by: Chris Galvan --- .../SceneAPI/SceneUI/CommonWidgets/ProcessingOverlayWidget.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Code/Tools/SceneAPI/SceneUI/CommonWidgets/ProcessingOverlayWidget.cpp b/Code/Tools/SceneAPI/SceneUI/CommonWidgets/ProcessingOverlayWidget.cpp index bc9c4679df..a1326b0c82 100644 --- a/Code/Tools/SceneAPI/SceneUI/CommonWidgets/ProcessingOverlayWidget.cpp +++ b/Code/Tools/SceneAPI/SceneUI/CommonWidgets/ProcessingOverlayWidget.cpp @@ -63,7 +63,7 @@ namespace AZ } ProcessingOverlayWidget::ProcessingOverlayWidget(UI::OverlayWidget* overlay, Layout layout, Uuid traceTag) - : QWidget() + : QWidget(nullptr, Qt::Tool | Qt::WindowStaysOnTopHint) , m_traceTag(traceTag) , ui(new Ui::ProcessingOverlayWidget()) , m_overlay(overlay) From 047c5f2231dbba742363a2d9396170c23b572374 Mon Sep 17 00:00:00 2001 From: AMZN-Phil Date: Thu, 4 Nov 2021 15:09:11 -0700 Subject: [PATCH 14/53] Add ability to overwrite o3de object when downloading, and to check the last_updated field to check for updates. Signed-off-by: AMZN-Phil --- scripts/o3de/o3de/download.py | 103 ++++++++++++++++++++++++++++++---- scripts/o3de/o3de/utils.py | 9 ++- 2 files changed, 97 insertions(+), 15 deletions(-) diff --git a/scripts/o3de/o3de/download.py b/scripts/o3de/o3de/download.py index 98f5d051a4..5d15c4d0b3 100644 --- a/scripts/o3de/o3de/download.py +++ b/scripts/o3de/o3de/download.py @@ -20,6 +20,7 @@ import sys import urllib.parse import urllib.request import zipfile +from datetime import datetime from o3de import manifest, repo, utils, validation, register @@ -88,10 +89,9 @@ def get_downloadable(engine_name: str = None, search_func = lambda manifest_json_data: repo.search_repo(manifest_json_data, engine_name, project_name, gem_name, template_name) return repo.search_o3de_object(manifest_json, o3de_object_uris, search_func) - def download_o3de_object(object_name: str, default_folder_name: str, dest_path: str or pathlib.Path, object_type: str, downloadable_kwarg_key, skip_auto_register: bool, - download_progress_callback = None) -> int: + force_overwrite: bool, download_progress_callback = None) -> int: download_path = manifest.get_o3de_cache_folder() / default_folder_name / object_name download_path.mkdir(parents=True, exist_ok=True) @@ -124,9 +124,11 @@ def download_o3de_object(object_name: str, default_folder_name: str, dest_path: if not dest_path: logger.error(f'Destination path cannot be empty.') return 1 - if dest_path.exists(): + if dest_path.exists() and not force_overwrite: logger.error(f'Destination path {dest_path} already exists.') return 1 + elif dest_path.exists(): + shutil.rmtree(dest_path) dest_path.mkdir(exist_ok=True) @@ -149,38 +151,108 @@ def download_o3de_object(object_name: str, default_folder_name: str, dest_path: def download_engine(engine_name: str, dest_path: str or pathlib.Path, skip_auto_register: bool, + force_overwrite: bool, download_progress_callback = None) -> int: - return download_o3de_object(engine_name, 'engines', dest_path, 'engine', 'engine_name', skip_auto_register, download_progress_callback) + return download_o3de_object(engine_name, 'engines', dest_path, 'engine', 'engine_name', skip_auto_register, force_overwrite, download_progress_callback) def download_project(project_name: str, dest_path: str or pathlib.Path, skip_auto_register: bool, + force_overwrite: bool, download_progress_callback = None) -> int: - return download_o3de_object(project_name, 'projects', dest_path, 'project', 'project_name', skip_auto_register, download_progress_callback) + return download_o3de_object(project_name, 'projects', dest_path, 'project', 'project_name', skip_auto_register, force_overwrite, download_progress_callback) def download_gem(gem_name: str, dest_path: str or pathlib.Path, skip_auto_register: bool, + force_overwrite: bool, download_progress_callback = None) -> int: - return download_o3de_object(gem_name, 'gems', dest_path, 'gem', 'gem_name', skip_auto_register, download_progress_callback) + return download_o3de_object(gem_name, 'gems', dest_path, 'gem', 'gem_name', skip_auto_register, force_overwrite, download_progress_callback) def download_template(template_name: str, dest_path: str or pathlib.Path, skip_auto_register: bool, + force_overwrite: bool, download_progress_callback = None) -> int: - return download_o3de_object(template_name, 'templates', dest_path, 'template', 'template_name', skip_auto_register, download_progress_callback) + return download_o3de_object(template_name, 'templates', dest_path, 'template', 'template_name', skip_auto_register, force_overwrite, download_progress_callback) def download_restricted(restricted_name: str, dest_path: str or pathlib.Path, skip_auto_register: bool, + force_overwrite: bool, download_progress_callback = None) -> int: - return download_o3de_object(restricted_name, 'restricted', dest_path, 'restricted', 'restricted_name', skip_auto_register, download_progress_callback) + return download_o3de_object(restricted_name, 'restricted', dest_path, 'restricted', 'restricted_name', skip_auto_register, force_overwrite, download_progress_callback) +def is_o3de_object_update_available(object_name: str, downloadable_kwarg_key, current_date: datetime) -> bool: + downloadable_object_data = get_downloadable(**{downloadable_kwarg_key : object_name}) + if not downloadable_object_data: + logger.error(f'Downloadable o3de object {object_name} not found.') + return False + + repo_copy_updated_string = 0 + try: + repo_copy_updated_string = downloadable_object_data['last_updated'] + except KeyError: + logger.warn(f'last_updated field not found for {object_name}.') + return False + + try: + repo_copy_updated_date = datetime.fromisoformat(repo_copy_updated_string) + except ValueError: + logger.error(f'last_updated field in incorrect format for {object_name}.') + return False + + return repo_copy_updated_date > current_date + +def is_o3de_engine_update_available(engine_name: str, local_last_updated: str): + try: + current_updated_time = datetime.fromisoformat(local_last_updated) + except ValueError: + logger.warn(f'last_updated field has incorrect format for engine {engine_name}.') + # Possible that an earlier version did not have this field so still want to check against cached downloadable version + current_updated_time = datetime.min + return is_o3de_object_update_available(engine_name, 'engine_name', current_updated_time) + +def is_o3de_project_update_available(project_name: str, local_last_updated: str): + try: + current_updated_time = datetime.fromisoformat(local_last_updated) + except ValueError: + logger.warn(f'last_updated field has incorrect format for project {project_name}.') + # Possible that an earlier version did not have this field so still want to check against cached downloadable version + current_updated_time = datetime.min + return is_o3de_object_update_available(project_name, 'project_name', current_updated_time) + +def is_o3de_gem_update_available(gem_name: str, local_last_updated: str): + try: + current_updated_time = datetime.fromisoformat(local_last_updated) + except ValueError: + logger.warn(f'last_updated field has incorrect format for gem {gem_name}.') + # Possible that an earlier version did not have this field so still want to check against cached downloadable version + current_updated_time = datetime.min + return is_o3de_object_update_available(gem_name, 'gem_name', current_updated_time) + +def is_o3de_template_update_available(template_name: str, local_last_updated: str): + try: + current_updated_time = datetime.fromisoformat(local_last_updated) + except ValueError: + logger.warn(f'last_updated field has incorrect format for template {template_name}.') + # Possible that an earlier version did not have this field so still want to check against cached downloadable version + current_updated_time = datetime.min + return is_o3de_object_update_available(template_name, 'template_name', current_updated_time) + +def is_o3de_restricted_update_available(restricted_name: str, local_last_updated: str): + try: + current_updated_time = datetime.fromisoformat(local_last_updated) + except ValueError: + logger.warn(f'last_updated field has incorrect format for restricted {restricted_name}.') + # Possible that an earlier version did not have this field so still want to check against cached downloadable version + current_updated_time = datetime.min + return is_o3de_object_update_available(restricted_name, 'restricted_name', current_updated_time) def _run_download(args: argparse) -> int: if args.override_home_folder: @@ -189,19 +261,23 @@ def _run_download(args: argparse) -> int: if args.engine_name: return download_engine(args.engine_name, args.dest_path, - args.skip_auto_register) + args.skip_auto_register, + args.force_overwrite) elif args.project_name: return download_project(args.project_name, args.dest_path, - args.skip_auto_register) + args.skip_auto_register, + args.force_overwrite) elif args.gem_name: return download_gem(args.gem_name, args.dest_path, - args.skip_auto_register) + args.skip_auto_register, + args.force_overwrite) elif args.template_name: return download_template(args.template_name, args.dest_path, - args.skip_auto_register) + args.skip_auto_register, + args.force_overwrite) return 1 @@ -230,6 +306,9 @@ def add_parser_args(parser): parser.add_argument('-sar', '--skip-auto-register', action='store_true', required=False, default=False, help = 'Skip the automatic registration of new object download') + parser.add_argument('-fce', '--force-overwrite', action='store_true', required=False, + default=False, + help = 'Force overwrite the current object') parser.add_argument('-ohf', '--override-home-folder', type=str, required=False, help='By default the home folder is the user folder, override it to this folder.') diff --git a/scripts/o3de/o3de/utils.py b/scripts/o3de/o3de/utils.py index 8663502a3f..df2ea67666 100755 --- a/scripts/o3de/o3de/utils.py +++ b/scripts/o3de/o3de/utils.py @@ -117,15 +117,18 @@ def backup_folder(folder: str or pathlib.Path) -> None: if backup_folder_name.is_dir(): renamed = True -def download_file(parsed_uri, download_path: pathlib.Path, download_progress_callback = None) -> int: +def download_file(parsed_uri, download_path: pathlib.Path, force_overwrite, download_progress_callback = None) -> int: """ :param parsed_uri: uniform resource identifier to zip file to download :param download_path: location path on disk to download file :download_progress_callback: callback called with the download progress as a percentage, returns true to request to cancel the download """ - if download_path.is_file(): + if download_path.is_file() and not force_overwrite: logger.warn(f'File already downloaded to {download_path}.') - elif parsed_uri.scheme in ['http', 'https', 'ftp', 'ftps']: + elif download_path.is_file(): + shutil.rmtree(download_path) + + if parsed_uri.scheme in ['http', 'https', 'ftp', 'ftps']: with urllib.request.urlopen(parsed_uri.geturl()) as s: download_file_size = 0 try: From 97b0eddcb4f139dcac4c9f716ab1301c2a76cd00 Mon Sep 17 00:00:00 2001 From: Mike Balfour <82224783+mbalfour-amzn@users.noreply.github.com> Date: Thu, 4 Nov 2021 17:56:55 -0500 Subject: [PATCH 15/53] Hook up the "Use Ground Plane" toggle. The "Use Ground Plane" toggle is now functional. When disabled, the terrain layer spawner will say "terrain exists = false" for any point in its bounds unless there's also a Terrain Height Gradient List component with a valid entry. When enabled, it will always say "terrain exists = true", and it will return the min height of the spawner box as the ground plane if there's no valid Terrain Height Gradient List height provider. Signed-off-by: Mike Balfour <82224783+mbalfour-amzn@users.noreply.github.com> --- .../TerrainHeightGradientListComponent.cpp | 17 ++++--- .../Source/TerrainSystem/TerrainSystem.cpp | 44 +++++++++++++------ .../Code/Source/TerrainSystem/TerrainSystem.h | 9 +++- 3 files changed, 48 insertions(+), 22 deletions(-) diff --git a/Gems/Terrain/Code/Source/Components/TerrainHeightGradientListComponent.cpp b/Gems/Terrain/Code/Source/Components/TerrainHeightGradientListComponent.cpp index 231d5abc28..c4415007b5 100644 --- a/Gems/Terrain/Code/Source/Components/TerrainHeightGradientListComponent.cpp +++ b/Gems/Terrain/Code/Source/Components/TerrainHeightGradientListComponent.cpp @@ -161,14 +161,17 @@ namespace Terrain // make this list a prioritized list from top to bottom for any points that overlap. for (auto& gradientId : m_configuration.m_gradientEntities) { - // If gradients ever provide bounds, or if we add a value threshold in this component, it would be possible for terrain - // to *not* exist at a specific point. - terrainExists = true; + if (gradientId.IsValid()) + { + // If gradients ever provide bounds, or if we add a value threshold in this component, it would be possible for terrain + // to *not* exist at a specific point. + terrainExists = true; - float sample = 0.0f; - GradientSignal::GradientRequestBus::EventResult( - sample, gradientId, &GradientSignal::GradientRequestBus::Events::GetValue, params); - maxSample = AZ::GetMax(maxSample, sample); + float sample = 0.0f; + GradientSignal::GradientRequestBus::EventResult( + sample, gradientId, &GradientSignal::GradientRequestBus::Events::GetValue, params); + maxSample = AZ::GetMax(maxSample, sample); + } } const float height = AZ::Lerp(m_cachedShapeBounds.GetMin().GetZ(), m_cachedShapeBounds.GetMax().GetZ(), maxSample); diff --git a/Gems/Terrain/Code/Source/TerrainSystem/TerrainSystem.cpp b/Gems/Terrain/Code/Source/TerrainSystem/TerrainSystem.cpp index 8d39340b06..20041e2fc8 100644 --- a/Gems/Terrain/Code/Source/TerrainSystem/TerrainSystem.cpp +++ b/Gems/Terrain/Code/Source/TerrainSystem/TerrainSystem.cpp @@ -222,20 +222,31 @@ float TerrainSystem::GetHeightSynchronous(float x, float y, Sampler sampler, boo float TerrainSystem::GetTerrainAreaHeight(float x, float y, bool& terrainExists) const { - AZ::Vector3 inPosition((float)x, (float)y, m_currentSettings.m_worldBounds.GetMin().GetZ()); - float height = m_currentSettings.m_worldBounds.GetMin().GetZ(); + const float worldMin = m_currentSettings.m_worldBounds.GetMin().GetZ(); + AZ::Vector3 inPosition(x, y, worldMin); + float height = worldMin; + terrainExists = false; AZStd::shared_lock lock(m_areaMutex); - for (auto& [areaId, areaBounds] : m_registeredAreas) + for (auto& [areaId, areaData] : m_registeredAreas) { - inPosition.SetZ(areaBounds.GetMin().GetZ()); - if (areaBounds.Contains(inPosition)) + const float areaMin = areaData.m_areaBounds.GetMin().GetZ(); + inPosition.SetZ(areaMin); + if (areaData.m_areaBounds.Contains(inPosition)) { AZ::Vector3 outPosition; Terrain::TerrainAreaHeightRequestBus::Event( areaId, &Terrain::TerrainAreaHeightRequestBus::Events::GetHeight, inPosition, outPosition, terrainExists); height = outPosition.GetZ(); + if (!terrainExists) + { + // If the terrain height provider doesn't have any data, then check the area's "use ground plane" setting. + // If it's set, then create a default ground plane by saying terrain exists at the minimum height for the area. + // Otherwise, we'll set the height at the terrain world minimum and say it doesn't exist. + terrainExists = areaData.m_useGroundPlane; + height = areaData.m_useGroundPlane ? areaMin : worldMin; + } break; } } @@ -395,12 +406,12 @@ AZ::EntityId TerrainSystem::FindBestAreaEntityAtPosition(float x, float y, AZ::A AZStd::shared_lock lock(m_areaMutex); // The areas are sorted into priority order: the first area that contains inPosition is the most suitable. - for (const auto& [areaId, areaBounds] : m_registeredAreas) + for (const auto& [areaId, areaData] : m_registeredAreas) { - inPosition.SetZ(areaBounds.GetMin().GetZ()); - if (areaBounds.Contains(inPosition)) + inPosition.SetZ(areaData.m_areaBounds.GetMin().GetZ()); + if (areaData.m_areaBounds.Contains(inPosition)) { - bounds = areaBounds; + bounds = areaData.m_areaBounds; return areaId; } } @@ -548,7 +559,12 @@ void TerrainSystem::RegisterArea(AZ::EntityId areaId) AZStd::unique_lock lock(m_areaMutex); AZ::Aabb aabb = AZ::Aabb::CreateNull(); LmbrCentral::ShapeComponentRequestsBus::EventResult(aabb, areaId, &LmbrCentral::ShapeComponentRequestsBus::Events::GetEncompassingAabb); - m_registeredAreas[areaId] = aabb; + + // Cache off whether or not this layer spawner should have a default ground plane when no other terrain height data exists. + bool useGroundPlane = false; + Terrain::TerrainSpawnerRequestBus::EventResult(useGroundPlane, areaId, &Terrain::TerrainSpawnerRequestBus::Events::GetUseGroundPlane); + + m_registeredAreas[areaId] = { aabb, useGroundPlane }; m_dirtyRegion.AddAabb(aabb); m_terrainHeightDirty = true; m_terrainSurfacesDirty = true; @@ -565,10 +581,10 @@ void TerrainSystem::UnregisterArea(AZ::EntityId areaId) m_registeredAreas, [areaId, this](const auto& item) { - auto const& [entityId, aabb] = item; + auto const& [entityId, areaData] = item; if (areaId == entityId) { - m_dirtyRegion.AddAabb(aabb); + m_dirtyRegion.AddAabb(areaData.m_areaBounds); m_terrainHeightDirty = true; m_terrainSurfacesDirty = true; return true; @@ -585,10 +601,10 @@ void TerrainSystem::RefreshArea(AZ::EntityId areaId, AzFramework::Terrain::Terra auto areaAabb = m_registeredAreas.find(areaId); - AZ::Aabb oldAabb = (areaAabb != m_registeredAreas.end()) ? areaAabb->second : AZ::Aabb::CreateNull(); + AZ::Aabb oldAabb = (areaAabb != m_registeredAreas.end()) ? areaAabb->second.m_areaBounds : AZ::Aabb::CreateNull(); AZ::Aabb newAabb = AZ::Aabb::CreateNull(); LmbrCentral::ShapeComponentRequestsBus::EventResult(newAabb, areaId, &LmbrCentral::ShapeComponentRequestsBus::Events::GetEncompassingAabb); - m_registeredAreas[areaId] = newAabb; + m_registeredAreas[areaId].m_areaBounds = newAabb; AZ::Aabb expandedAabb = oldAabb; expandedAabb.AddAabb(newAabb); diff --git a/Gems/Terrain/Code/Source/TerrainSystem/TerrainSystem.h b/Gems/Terrain/Code/Source/TerrainSystem/TerrainSystem.h index 022cd218cc..c6bd19fdda 100644 --- a/Gems/Terrain/Code/Source/TerrainSystem/TerrainSystem.h +++ b/Gems/Terrain/Code/Source/TerrainSystem/TerrainSystem.h @@ -168,7 +168,14 @@ namespace Terrain bool m_terrainSurfacesDirty = false; AZ::Aabb m_dirtyRegion; + // Cached data for each terrain area to use when looking up terrain data. + struct TerrainAreaData + { + AZ::Aabb m_areaBounds{ AZ::Aabb::CreateNull() }; + bool m_useGroundPlane{ false }; + }; + mutable AZStd::shared_mutex m_areaMutex; - AZStd::map m_registeredAreas; + AZStd::map m_registeredAreas; }; } // namespace Terrain From 31382d080e94548b5d71702e44de5e9951191dd8 Mon Sep 17 00:00:00 2001 From: AMZN-Phil Date: Thu, 4 Nov 2021 17:07:02 -0700 Subject: [PATCH 16/53] Remove duplication, additional readability and added missed file Signed-off-by: AMZN-Phil --- .../ProjectManager/Source/PythonBindings.cpp | 1 + scripts/o3de/o3de/download.py | 79 +++++++------------ scripts/o3de/o3de/utils.py | 13 ++- 3 files changed, 40 insertions(+), 53 deletions(-) diff --git a/Code/Tools/ProjectManager/Source/PythonBindings.cpp b/Code/Tools/ProjectManager/Source/PythonBindings.cpp index 740393fec0..0be0d02ca0 100644 --- a/Code/Tools/ProjectManager/Source/PythonBindings.cpp +++ b/Code/Tools/ProjectManager/Source/PythonBindings.cpp @@ -1173,6 +1173,7 @@ namespace O3DE::ProjectManager QString_To_Py_String(gemName), // gem name pybind11::none(), // destination path false, // skip auto register + false, // force pybind11::cpp_function( [this, gemProgressCallback](int progress) { diff --git a/scripts/o3de/o3de/download.py b/scripts/o3de/o3de/download.py index 5d15c4d0b3..b6d6233559 100644 --- a/scripts/o3de/o3de/download.py +++ b/scripts/o3de/o3de/download.py @@ -124,11 +124,16 @@ def download_o3de_object(object_name: str, default_folder_name: str, dest_path: if not dest_path: logger.error(f'Destination path cannot be empty.') return 1 - if dest_path.exists() and not force_overwrite: - logger.error(f'Destination path {dest_path} already exists.') - return 1 - elif dest_path.exists(): - shutil.rmtree(dest_path) + if dest_path.exists(): + if not force_overwrite: + logger.error(f'Destination path {dest_path} already exists.') + return 1 + else: + try: + shutil.rmtree(dest_path) + except OSError: + logger.error(f'Could not remove existing destination path {dest_path}.') + return 1 dest_path.mkdir(exist_ok=True) @@ -188,71 +193,47 @@ def download_restricted(restricted_name: str, download_progress_callback = None) -> int: return download_o3de_object(restricted_name, 'restricted', dest_path, 'restricted', 'restricted_name', skip_auto_register, force_overwrite, download_progress_callback) -def is_o3de_object_update_available(object_name: str, downloadable_kwarg_key, current_date: datetime) -> bool: +def is_o3de_object_update_available(object_name: str, downloadable_kwarg_key, local_last_updated: str) -> bool: downloadable_object_data = get_downloadable(**{downloadable_kwarg_key : object_name}) if not downloadable_object_data: logger.error(f'Downloadable o3de object {object_name} not found.') return False - repo_copy_updated_string = 0 try: repo_copy_updated_string = downloadable_object_data['last_updated'] except KeyError: logger.warn(f'last_updated field not found for {object_name}.') return False + try: + local_last_updated_time = datetime.fromisoformat(local_last_updated) + except ValueError: + logger.warn(f'last_updated field has incorrect format for local copy of {downloadable_kwarg_key} {object_name}.') + # Possible that an earlier version did not have this field so still want to check against cached downloadable version + local_last_updated_time = datetime.min + try: repo_copy_updated_date = datetime.fromisoformat(repo_copy_updated_string) except ValueError: - logger.error(f'last_updated field in incorrect format for {object_name}.') + logger.error(f'last_updated field in incorrect format for repository copy of {downloadable_kwarg_key} {object_name}.') return False - return repo_copy_updated_date > current_date + return repo_copy_updated_date > local_last_updated_time def is_o3de_engine_update_available(engine_name: str, local_last_updated: str): - try: - current_updated_time = datetime.fromisoformat(local_last_updated) - except ValueError: - logger.warn(f'last_updated field has incorrect format for engine {engine_name}.') - # Possible that an earlier version did not have this field so still want to check against cached downloadable version - current_updated_time = datetime.min - return is_o3de_object_update_available(engine_name, 'engine_name', current_updated_time) + return is_o3de_object_update_available(engine_name, 'engine_name', local_last_updated) def is_o3de_project_update_available(project_name: str, local_last_updated: str): - try: - current_updated_time = datetime.fromisoformat(local_last_updated) - except ValueError: - logger.warn(f'last_updated field has incorrect format for project {project_name}.') - # Possible that an earlier version did not have this field so still want to check against cached downloadable version - current_updated_time = datetime.min - return is_o3de_object_update_available(project_name, 'project_name', current_updated_time) + return is_o3de_object_update_available(project_name, 'project_name', local_last_updated) def is_o3de_gem_update_available(gem_name: str, local_last_updated: str): - try: - current_updated_time = datetime.fromisoformat(local_last_updated) - except ValueError: - logger.warn(f'last_updated field has incorrect format for gem {gem_name}.') - # Possible that an earlier version did not have this field so still want to check against cached downloadable version - current_updated_time = datetime.min - return is_o3de_object_update_available(gem_name, 'gem_name', current_updated_time) + return is_o3de_object_update_available(gem_name, 'gem_name', local_last_updated) def is_o3de_template_update_available(template_name: str, local_last_updated: str): - try: - current_updated_time = datetime.fromisoformat(local_last_updated) - except ValueError: - logger.warn(f'last_updated field has incorrect format for template {template_name}.') - # Possible that an earlier version did not have this field so still want to check against cached downloadable version - current_updated_time = datetime.min - return is_o3de_object_update_available(template_name, 'template_name', current_updated_time) + return is_o3de_object_update_available(template_name, 'template_name', local_last_updated) def is_o3de_restricted_update_available(restricted_name: str, local_last_updated: str): - try: - current_updated_time = datetime.fromisoformat(local_last_updated) - except ValueError: - logger.warn(f'last_updated field has incorrect format for restricted {restricted_name}.') - # Possible that an earlier version did not have this field so still want to check against cached downloadable version - current_updated_time = datetime.min - return is_o3de_object_update_available(restricted_name, 'restricted_name', current_updated_time) + return is_o3de_object_update_available(restricted_name, 'restricted_name', local_last_updated) def _run_download(args: argparse) -> int: if args.override_home_folder: @@ -262,22 +243,22 @@ def _run_download(args: argparse) -> int: return download_engine(args.engine_name, args.dest_path, args.skip_auto_register, - args.force_overwrite) + args.force) elif args.project_name: return download_project(args.project_name, args.dest_path, args.skip_auto_register, - args.force_overwrite) + args.force) elif args.gem_name: return download_gem(args.gem_name, args.dest_path, args.skip_auto_register, - args.force_overwrite) + args.force) elif args.template_name: return download_template(args.template_name, args.dest_path, args.skip_auto_register, - args.force_overwrite) + args.force) return 1 @@ -306,7 +287,7 @@ def add_parser_args(parser): parser.add_argument('-sar', '--skip-auto-register', action='store_true', required=False, default=False, help = 'Skip the automatic registration of new object download') - parser.add_argument('-fce', '--force-overwrite', action='store_true', required=False, + parser.add_argument('-f', '--force', action='store_true', required=False, default=False, help = 'Force overwrite the current object') parser.add_argument('-ohf', '--override-home-folder', type=str, required=False, diff --git a/scripts/o3de/o3de/utils.py b/scripts/o3de/o3de/utils.py index df2ea67666..56f9ae4bcd 100755 --- a/scripts/o3de/o3de/utils.py +++ b/scripts/o3de/o3de/utils.py @@ -123,10 +123,15 @@ def download_file(parsed_uri, download_path: pathlib.Path, force_overwrite, down :param download_path: location path on disk to download file :download_progress_callback: callback called with the download progress as a percentage, returns true to request to cancel the download """ - if download_path.is_file() and not force_overwrite: - logger.warn(f'File already downloaded to {download_path}.') - elif download_path.is_file(): - shutil.rmtree(download_path) + if download_path.is_file(): + if not force_overwrite: + logger.warn(f'File already downloaded to {download_path}.') + else: + try: + shutil.rmtree(download_path) + except OSError: + logger.error(f'Could not remove existing download path {download_path}.') + return 1 if parsed_uri.scheme in ['http', 'https', 'ftp', 'ftps']: with urllib.request.urlopen(parsed_uri.geturl()) as s: From 81515b922f34cc5841a378fea3f47a8b50591e14 Mon Sep 17 00:00:00 2001 From: AMZN-Phil Date: Thu, 4 Nov 2021 17:10:44 -0700 Subject: [PATCH 17/53] Additional readability Signed-off-by: AMZN-Phil --- scripts/o3de/o3de/download.py | 45 +++++++++++++++++++++++++++++++---- 1 file changed, 40 insertions(+), 5 deletions(-) diff --git a/scripts/o3de/o3de/download.py b/scripts/o3de/o3de/download.py index b6d6233559..9e576d64b5 100644 --- a/scripts/o3de/o3de/download.py +++ b/scripts/o3de/o3de/download.py @@ -158,7 +158,14 @@ def download_engine(engine_name: str, skip_auto_register: bool, force_overwrite: bool, download_progress_callback = None) -> int: - return download_o3de_object(engine_name, 'engines', dest_path, 'engine', 'engine_name', skip_auto_register, force_overwrite, download_progress_callback) + return download_o3de_object(engine_name, + 'engines', + dest_path, + 'engine', + 'engine_name', + skip_auto_register, + force_overwrite, + download_progress_callback) def download_project(project_name: str, @@ -166,7 +173,14 @@ def download_project(project_name: str, skip_auto_register: bool, force_overwrite: bool, download_progress_callback = None) -> int: - return download_o3de_object(project_name, 'projects', dest_path, 'project', 'project_name', skip_auto_register, force_overwrite, download_progress_callback) + return download_o3de_object(project_name, + 'projects', + dest_path, + 'project', + 'project_name', + skip_auto_register, + force_overwrite, + download_progress_callback) def download_gem(gem_name: str, @@ -174,7 +188,14 @@ def download_gem(gem_name: str, skip_auto_register: bool, force_overwrite: bool, download_progress_callback = None) -> int: - return download_o3de_object(gem_name, 'gems', dest_path, 'gem', 'gem_name', skip_auto_register, force_overwrite, download_progress_callback) + return download_o3de_object(gem_name, + 'gems', + dest_path, + 'gem', + 'gem_name', + skip_auto_register, + force_overwrite, + download_progress_callback) def download_template(template_name: str, @@ -182,7 +203,14 @@ def download_template(template_name: str, skip_auto_register: bool, force_overwrite: bool, download_progress_callback = None) -> int: - return download_o3de_object(template_name, 'templates', dest_path, 'template', 'template_name', skip_auto_register, force_overwrite, download_progress_callback) + return download_o3de_object(template_name, + 'templates', + dest_path, + 'template', + 'template_name', + skip_auto_register, + force_overwrite, + download_progress_callback) @@ -191,7 +219,14 @@ def download_restricted(restricted_name: str, skip_auto_register: bool, force_overwrite: bool, download_progress_callback = None) -> int: - return download_o3de_object(restricted_name, 'restricted', dest_path, 'restricted', 'restricted_name', skip_auto_register, force_overwrite, download_progress_callback) + return download_o3de_object(restricted_name, + 'restricted', + dest_path, + 'restricted', + 'restricted_name', + skip_auto_register, + force_overwrite, + download_progress_callback) def is_o3de_object_update_available(object_name: str, downloadable_kwarg_key, local_last_updated: str) -> bool: downloadable_object_data = get_downloadable(**{downloadable_kwarg_key : object_name}) From fbc35a8169dfcadaf622acc862791d6a3744073f Mon Sep 17 00:00:00 2001 From: santorac <55155825+santorac@users.noreply.github.com> Date: Thu, 4 Nov 2021 22:09:11 -0700 Subject: [PATCH 18/53] Applied a fix from @jeremyong-az to get ThinObject transmission working. Also added a new test material for ThinObject transmission. Signed-off-by: santorac <55155825+santorac@users.noreply.github.com> --- .../Atom/Features/PBR/BackLighting.azsli | 9 ++++-- ...rfaceScattering_Transmission_Thin.material | 29 +++++++++++++++++++ 2 files changed, 36 insertions(+), 2 deletions(-) create mode 100644 Gems/Atom/TestData/TestData/Materials/StandardPbrTestCases/015_SubsurfaceScattering_Transmission_Thin.material diff --git a/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/PBR/BackLighting.azsli b/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/PBR/BackLighting.azsli index a4a747d42c..83cf79ed61 100644 --- a/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/PBR/BackLighting.azsli +++ b/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/PBR/BackLighting.azsli @@ -50,8 +50,13 @@ float3 GetBackLighting(Surface surface, LightingData lightingData, float3 lightI // Thin object mode, using thin-film assumption proposed by Jimenez J. et al, 2010, "Real-Time Realistic Skin Translucency" // http://www.iryoku.com/translucency/downloads/Real-Time-Realistic-Skin-Translucency.pdf - result = shadowRatio ? float3(0.0, 0.0, 0.0) : TransmissionKernel(surface.transmission.thickness * transmissionParams.w, rcp(transmissionParams.xyz)) * - saturate(dot(-surface.normal, dirToLight)) * lightIntensity * shadowRatio; + float litRatio = 1.0 - shadowRatio; + if (litRatio) + { + result = TransmissionKernel(surface.transmission.thickness * transmissionParams.w, rcp(transmissionParams.xyz)) * + saturate(dot(-surface.normal, dirToLight)) * lightIntensity * litRatio; + } + break; } diff --git a/Gems/Atom/TestData/TestData/Materials/StandardPbrTestCases/015_SubsurfaceScattering_Transmission_Thin.material b/Gems/Atom/TestData/TestData/Materials/StandardPbrTestCases/015_SubsurfaceScattering_Transmission_Thin.material new file mode 100644 index 0000000000..ee9bb1f4a5 --- /dev/null +++ b/Gems/Atom/TestData/TestData/Materials/StandardPbrTestCases/015_SubsurfaceScattering_Transmission_Thin.material @@ -0,0 +1,29 @@ +{ + "description": "", + "parentMaterial": "", + "materialType": "Materials/Types/EnhancedPBR.materialtype", + "materialTypeVersion": 4, + "properties": { + "baseColor": { + "color": [ + 0.027664607390761375, + 0.1926604062318802, + 0.013916227966547012, + 1.0 + ] + }, + "general": { + "doubleSided": true + }, + "subsurfaceScattering": { + "thickness": 0.20000000298023224, + "transmissionMode": "ThinObject", + "transmissionTint": [ + 0.009140154346823692, + 0.19806210696697235, + 0.01095597818493843, + 1.0 + ] + } + } +} \ No newline at end of file From 356fec54901a11f19eb48fa749b1a966001673e1 Mon Sep 17 00:00:00 2001 From: moraaar Date: Fri, 5 Nov 2021 15:17:00 +0000 Subject: [PATCH 19/53] bugfix: resolve crash with FBX Settings (#4813) (#4944) (#5365) -prevent export of ModuleInitISystem and ModuleShutdownISystem Signed-off-by: Michael Pollind Co-authored-by: Michael Pollind --- Code/Legacy/CryCommon/ISystem.h | 4 ++-- Code/Legacy/CryCommon/platform_impl.cpp | 4 ++-- Code/Legacy/CrySystem/SystemInit.cpp | 23 ----------------------- 3 files changed, 4 insertions(+), 27 deletions(-) diff --git a/Code/Legacy/CryCommon/ISystem.h b/Code/Legacy/CryCommon/ISystem.h index 948977d02a..dd29209b24 100644 --- a/Code/Legacy/CryCommon/ISystem.h +++ b/Code/Legacy/CryCommon/ISystem.h @@ -1121,8 +1121,8 @@ inline ISystem* GetISystem() // Description: // This function must be called once by each module at the beginning, to setup global pointers. -extern "C" AZ_DLL_EXPORT void ModuleInitISystem(ISystem* pSystem, const char* moduleName); -extern "C" AZ_DLL_EXPORT void ModuleShutdownISystem(ISystem* pSystem); +void ModuleInitISystem(ISystem* pSystem, const char* moduleName); +void ModuleShutdownISystem(ISystem* pSystem); extern "C" AZ_DLL_EXPORT void InjectEnvironment(void* env); extern "C" AZ_DLL_EXPORT void DetachEnvironment(); diff --git a/Code/Legacy/CryCommon/platform_impl.cpp b/Code/Legacy/CryCommon/platform_impl.cpp index a68a5150db..845a1101a4 100644 --- a/Code/Legacy/CryCommon/platform_impl.cpp +++ b/Code/Legacy/CryCommon/platform_impl.cpp @@ -74,7 +74,7 @@ void InitCRTHandlers() {} ////////////////////////////////////////////////////////////////////////// // This is an entry to DLL initialization function that must be called for each loaded module ////////////////////////////////////////////////////////////////////////// -extern "C" AZ_DLL_EXPORT void ModuleInitISystem(ISystem* pSystem, [[maybe_unused]] const char* moduleName) +void ModuleInitISystem(ISystem* pSystem, [[maybe_unused]] const char* moduleName) { if (gEnv) // Already registered. { @@ -96,7 +96,7 @@ extern "C" AZ_DLL_EXPORT void ModuleInitISystem(ISystem* pSystem, [[maybe_unused } // if pSystem } -extern "C" AZ_DLL_EXPORT void ModuleShutdownISystem([[maybe_unused]] ISystem* pSystem) +void ModuleShutdownISystem([[maybe_unused]] ISystem* pSystem) { // Unregister with AZ environment. AZ::Environment::Detach(); diff --git a/Code/Legacy/CrySystem/SystemInit.cpp b/Code/Legacy/CrySystem/SystemInit.cpp index ac0683cf1b..99cc92ee6a 100644 --- a/Code/Legacy/CrySystem/SystemInit.cpp +++ b/Code/Legacy/CrySystem/SystemInit.cpp @@ -173,8 +173,6 @@ void CryEngineSignalHandler(int signal) ////////////////////////////////////////////////////////////////////////// #if defined(WIN32) || defined(LINUX) || defined(APPLE) -# define DLL_MODULE_INIT_ISYSTEM "ModuleInitISystem" -# define DLL_MODULE_SHUTDOWN_ISYSTEM "ModuleShutdownISystem" # define DLL_INITFUNC_RENDERER "PackageRenderConstructor" # define DLL_INITFUNC_SOUND "CreateSoundSystem" # define DLL_INITFUNC_FONT "CreateCryFontInterface" @@ -188,8 +186,6 @@ void CryEngineSignalHandler(int signal) #if defined(AZ_RESTRICTED_SECTION_IMPLEMENTED) #undef AZ_RESTRICTED_SECTION_IMPLEMENTED #else -# define DLL_MODULE_INIT_ISYSTEM (LPCSTR)2 -# define DLL_MODULE_SHUTDOWN_ISYSTEM (LPCSTR)3 # define DLL_INITFUNC_RENDERER (LPCSTR)1 # define DLL_INITFUNC_RENDERER (LPCSTR)1 # define DLL_INITFUNC_SOUND (LPCSTR)1 @@ -445,18 +441,6 @@ AZStd::unique_ptr CSystem::LoadDLL(const char* dllName) return handle; } - ////////////////////////////////////////////////////////////////////////// - // After loading DLL initialize it by calling ModuleInitISystem - ////////////////////////////////////////////////////////////////////////// - AZStd::string moduleName = PathUtil::GetFileName(dllName); - - typedef void*(*PtrFunc_ModuleInitISystem)(ISystem* pSystem, const char* moduleName); - PtrFunc_ModuleInitISystem pfnModuleInitISystem = handle->GetFunction(DLL_MODULE_INIT_ISYSTEM); - if (pfnModuleInitISystem) - { - pfnModuleInitISystem(this, moduleName.c_str()); - } - return handle; } @@ -497,13 +481,6 @@ void CSystem::ShutdownModuleLibraries() #if !defined(AZ_MONOLITHIC_BUILD) for (auto iterator = m_moduleDLLHandles.begin(); iterator != m_moduleDLLHandles.end(); ++iterator) { - typedef void*( * PtrFunc_ModuleShutdownISystem )(ISystem* pSystem); - - PtrFunc_ModuleShutdownISystem pfnModuleShutdownISystem = iterator->second->GetFunction(DLL_MODULE_SHUTDOWN_ISYSTEM); - if (pfnModuleShutdownISystem) - { - pfnModuleShutdownISystem(this); - } if (iterator->second->IsLoaded()) { iterator->second->Unload(); From 9c28d134db2441b6c92eefdb839a8b68d1f8fb7c Mon Sep 17 00:00:00 2001 From: Ken Pruiksma Date: Fri, 5 Nov 2021 10:40:34 -0500 Subject: [PATCH 20/53] Fix for alignment issue with terrain heights. (#5274) Signed-off-by: Ken Pruiksma --- Gems/Terrain/Assets/Shaders/Terrain/TerrainCommon.azsli | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Gems/Terrain/Assets/Shaders/Terrain/TerrainCommon.azsli b/Gems/Terrain/Assets/Shaders/Terrain/TerrainCommon.azsli index 72c1af953c..cd680f721a 100644 --- a/Gems/Terrain/Assets/Shaders/Terrain/TerrainCommon.azsli +++ b/Gems/Terrain/Assets/Shaders/Terrain/TerrainCommon.azsli @@ -218,9 +218,10 @@ float4x4 GetObject_WorldMatrix() float GetHeight(float2 origUv) { - float2 uv = clamp(origUv + (ObjectSrg::m_terrainData.m_uvStep * 0.5f), 0.0f, 1.0f); - float height = 0.0f; + float2 halfStep = ObjectSrg::m_terrainData.m_uvStep * 0.5; + float2 uv = origUv * (1.0 - ObjectSrg::m_terrainData.m_uvStep) + halfStep; + float height = 0.0f; if (o_useTerrainSmoothing) { float2 textureSize; From f8f9fb96d135df9b25083138239dc386182a82bf Mon Sep 17 00:00:00 2001 From: Qing Tao <55564570+VickyAtAZ@users.noreply.github.com> Date: Fri, 5 Nov 2021 10:20:21 -0700 Subject: [PATCH 21/53] ATOM-15086 Image Pipeline Unexpectedly Pre-Multiplying Alpha into Color Channels (#5358) Applied the discard alpha in the begining of converting. Also deleted some unused processing settings and steps. Signed-off-by: Qing Tao <55564570+VickyAtAZ@users.noreply.github.com> --- .../Atom/ImageProcessing/ImageObject.h | 10 - .../Source/BuilderSettings/PresetSettings.cpp | 9 - .../Source/BuilderSettings/PresetSettings.h | 15 +- .../Code/Source/Converters/ColorChart.cpp | 307 ------------------ .../Code/Source/Converters/Cubemap.cpp | 2 +- .../Code/Source/Converters/HighPass.cpp | 100 ------ .../Code/Source/Editor/PresetInfoPopup.cpp | 3 - .../Code/Source/ImageBuilderComponent.cpp | 2 +- .../Code/Source/Processing/ImageConvert.cpp | 182 +++-------- .../Code/Source/Processing/ImageConvert.h | 6 - .../Source/Processing/ImageConvertJob.cpp | 5 +- .../Code/Source/Processing/ImageFlags.h | 2 +- .../Source/Processing/ImageObjectImpl.cpp | 212 ------------ .../Code/Source/Processing/ImageObjectImpl.h | 5 - .../Code/Source/Processing/ImageToProcess.h | 7 - .../Code/Tests/ImageProcessing_Test.cpp | 1 - .../Code/imageprocessing_files.cmake | 2 - 17 files changed, 57 insertions(+), 813 deletions(-) delete mode 100644 Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Converters/ColorChart.cpp delete mode 100644 Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Converters/HighPass.cpp diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Code/Include/Atom/ImageProcessing/ImageObject.h b/Gems/Atom/Asset/ImageProcessingAtom/Code/Include/Atom/ImageProcessing/ImageObject.h index 5796a0c84d..475c72c0eb 100644 --- a/Gems/Atom/Asset/ImageProcessingAtom/Code/Include/Atom/ImageProcessing/ImageObject.h +++ b/Gems/Atom/Asset/ImageProcessingAtom/Code/Include/Atom/ImageProcessing/ImageObject.h @@ -100,13 +100,6 @@ namespace ImageProcessingAtom //compare whether two images are same. return true if they are same. virtual bool CompareImage(const IImageObjectPtr otherImage) const = 0; - // Writes this image to file used for runtime, overwrites any existing file. - // It may write alpha image as attached image into the same file - // outFilePaths will save filenames finally saved to since the image might be split and saved to multiple files - virtual bool SaveImage(const char* filename, IImageObjectPtr alphaImage, AZStd::vector& outFilePaths) const = 0; - virtual bool SaveImage(AZ::IO::SystemFileStream& out) const = 0; - virtual bool SaveMipToFile(AZ::u32 mip, const AZStd::string& filename) const = 0; - //get total image data size in memory of all mipmaps. Not includs header and flags. virtual AZ::u32 GetTextureMemory() const = 0; @@ -135,9 +128,6 @@ namespace ImageProcessingAtom // The algorithm is based on the Frequency Domain Normal Mapping implementation presented by Neubelt and Pettineo at Siggraph 2013. virtual void GlossFromNormals(bool hasAuthoredGloss) = 0; - //convert gloss map from legacy distribution to new one. New World is still using legacy gloss map. - virtual void ConvertLegacyGloss() = 0; - //clear image with color virtual void ClearColor(float r, float g, float b, float a) = 0; }; diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/BuilderSettings/PresetSettings.cpp b/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/BuilderSettings/PresetSettings.cpp index 3812b86026..046c4faa87 100644 --- a/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/BuilderSettings/PresetSettings.cpp +++ b/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/BuilderSettings/PresetSettings.cpp @@ -45,10 +45,7 @@ namespace ImageProcessingAtom ->Field("MinTextureSize", &PresetSettings::m_minTextureSize) ->Field("IsPowerOf2", &PresetSettings::m_isPowerOf2) ->Field("SizeReduceLevel", &PresetSettings::m_sizeReduceLevel) - ->Field("IsColorChart", &PresetSettings::m_isColorChart) - ->Field("HighPassMip", &PresetSettings::m_highPassMip) ->Field("GlossFromNormal", &PresetSettings::m_glossFromNormals) - ->Field("UseLegacyGloss", &PresetSettings::m_isLegacyGloss) ->Field("MipRenormalize", &PresetSettings::m_isMipRenormalize) ->Field("NumberResidentMips", &PresetSettings::m_numResidentMips) ->Field("Swizzle", &PresetSettings::m_swizzle) @@ -200,10 +197,7 @@ namespace ImageProcessingAtom m_maxTextureSize == other.m_maxTextureSize && m_isPowerOf2 == other.m_isPowerOf2 && m_sizeReduceLevel == other.m_sizeReduceLevel && - m_isColorChart == other.m_isColorChart && - m_highPassMip == other.m_highPassMip && m_glossFromNormals == other.m_glossFromNormals && - m_isLegacyGloss == other.m_isLegacyGloss && m_swizzle == other.m_swizzle && m_isMipRenormalize == other.m_isMipRenormalize && m_numResidentMips == other.m_numResidentMips; @@ -239,10 +233,7 @@ namespace ImageProcessingAtom m_maxTextureSize = other.m_maxTextureSize; m_isPowerOf2 = other.m_isPowerOf2; m_sizeReduceLevel = other.m_sizeReduceLevel; - m_isColorChart = other.m_isColorChart; - m_highPassMip = other.m_highPassMip; m_glossFromNormals = other.m_glossFromNormals; - m_isLegacyGloss = other.m_isLegacyGloss; m_swizzle = other.m_swizzle; m_isMipRenormalize = other.m_isMipRenormalize; m_numResidentMips = other.m_numResidentMips; diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/BuilderSettings/PresetSettings.h b/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/BuilderSettings/PresetSettings.h index 941437bbf4..3dc223cf80 100644 --- a/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/BuilderSettings/PresetSettings.h +++ b/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/BuilderSettings/PresetSettings.h @@ -84,16 +84,7 @@ namespace ImageProcessingAtom //settings for mipmap generation. it's null if this preset disable mipmap. AZStd::unique_ptr m_mipmapSetting; - - //some specific settings - // "colorchart". This is to indicate if need to extract color chart from the image and output the color chart data. - // This is very specific usage for cryEngine. Check ColorChart.cpp for better explanation. - bool m_isColorChart = false; - - //"highpass". Defines which mip level is subtracted when applying the high pass filter - //this is only used for terrain asset. we might remove it later since it can be done with source image directly - AZ::u32 m_highPassMip = 0; - + //"glossfromnormals". Bake normal variance into smoothness stored in alpha channel AZ::u32 m_glossFromNormals = 0; @@ -109,10 +100,6 @@ namespace ImageProcessingAtom //that add up to 64K or lower AZ::u8 m_numResidentMips = 0; - //legacy options might be removed later - //"glosslegacydist". If the gloss map use legacy distribution. NW is still using legacy dist - bool m_isLegacyGloss = false; - //"swizzle". need to be 4 character and each character need to be one of "rgba01" AZStd::string m_swizzle; diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Converters/ColorChart.cpp b/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Converters/ColorChart.cpp deleted file mode 100644 index b6e9cf4c8c..0000000000 --- a/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Converters/ColorChart.cpp +++ /dev/null @@ -1,307 +0,0 @@ -/* - * 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 - -namespace ImageProcessingAtom -{ - const int COLORCHART_IMAGE_WIDTH = 78; - const int COLORCHART_IMAGE_HEIGHT = 66; - - // color chart in cry engine is a special image data, with size 78x66, you may see in game screenshot which is defined by a rectangle - // area with a yellow-black dash line boarder - // Create color chart function is to read that block of image data and convert it to a color table then save it to another image - // with size 256x16. - - class C3dLutColorChart - { - public: - C3dLutColorChart() {} - ~C3dLutColorChart() {}; - - //generate default color chart data - void GenerateDefault(); - - //generate color chart data from input image - bool GenerateFromInput(IImageObjectPtr image); - - //ouput the color chart data to an image object - IImageObjectPtr GenerateChartImage(); - - protected: - //extract color chart data from specified location in an image - void ExtractFromImageAt(IImageObjectPtr pImg, AZ::u32 x, AZ::u32 y); - - //find color chart location in an image - static bool FindColorChart(const IImageObjectPtr pImg, AZ::u32& outLocX, AZ::u32& outLocY); - - //if there is a color chart at specified location - static bool IsColorChartAt(AZ::u32 x, AZ::u32 y, void* pData, AZ::u32 pitch); - - private: - enum EPrimaryShades - { - ePS_Red = 16, - ePS_Green = 16, - ePS_Blue = 16, - - ePS_NumColors = ePS_Red * ePS_Green * ePS_Blue - }; - - struct SColor - { - unsigned char r, g, b, _padding; - }; - - typedef AZStd::vector ColorMapping; - - ColorMapping m_mapping; - }; - - void C3dLutColorChart::GenerateDefault() - { - m_mapping.reserve(ePS_NumColors); - - for (int b = 0; b < ePS_Blue; ++b) - { - for (int g = 0; g < ePS_Green; ++g) - { - for (int r = 0; r < ePS_Red; ++r) - { - SColor col; - col.r = static_cast(255 * r / (ePS_Red)); - col.g = static_cast(255 * g / (ePS_Green)); - col.b = static_cast(255 * b / (ePS_Blue)); - int l = 255 - (col.r * 3 + col.g * 6 + col.b) / 10; - col.r = col.g = col.b = (unsigned char)l; - m_mapping.push_back(col); - } - } - } - } - - //find color chart location in a image - bool C3dLutColorChart::FindColorChart(const IImageObjectPtr pImg, AZ::u32& outLocX, AZ::u32& outLocY) - { - const AZ::u32 width = pImg->GetWidth(0); - const AZ::u32 height = pImg->GetHeight(0); - - //the origin image is too small to have a color chart - if (width < COLORCHART_IMAGE_WIDTH || height < COLORCHART_IMAGE_HEIGHT) - { - return false; - } - - AZ::u8* pData; - AZ::u32 pitch; - pImg->GetImagePointer(0, pData, pitch); - - //check all the posible start location on whether there might be a color chart - for (AZ::u32 y = 0; y <= height - COLORCHART_IMAGE_HEIGHT; ++y) - { - for (AZ::u32 x = 0; x <= width - COLORCHART_IMAGE_WIDTH; ++x) - { - if (IsColorChartAt(x, y, pData, pitch)) - { - outLocX = x; - outLocY = y; - return true; - } - } - } - - return false; - } - - bool C3dLutColorChart::GenerateFromInput(IImageObjectPtr image) - { - AZ::u32 outLocX, outLocY; - if (FindColorChart(image, outLocX, outLocY)) - { - ExtractFromImageAt(image, outLocX, outLocY); - return true; - } - return false; - } - - IImageObjectPtr C3dLutColorChart::GenerateChartImage() - { - IImageObjectPtr image(IImageObject::CreateImage(ePS_Red* ePS_Blue, ePS_Green, 1, ePixelFormat_R8G8B8A8)); - - { - AZ::u8* pData; - AZ::u32 pitch; - image->GetImagePointer(0, pData, pitch); - - size_t nSlicePitch = (pitch / ePS_Blue); - AZ::u32 src = 0; - for (int b = 0; b < ePS_Blue; ++b) - { - for (int g = 0; g < ePS_Green; ++g) - { - AZ::u8* p = pData + g * pitch + b * nSlicePitch; - for (int r = 0; r < ePS_Red; ++r) - { - const SColor& c = m_mapping[src]; - p[0] = c.r; - p[1] = c.g; - p[2] = c.b; - p[3] = 255; - ++src; - p += 4; - } - } - } - } - - return image; - } - - void C3dLutColorChart::ExtractFromImageAt(IImageObjectPtr image, AZ::u32 x, AZ::u32 y) - { - int ox = x + 1; - int oy = y + 1; - - AZ::u8* pData; - AZ::u32 pitch; - image->GetImagePointer(0, pData, pitch); - - m_mapping.reserve(ePS_NumColors); - - for (int b = 0; b < ePS_Blue; ++b) - { - int px = ox + ePS_Red * (b % 4); - int py = oy + ePS_Green * (b / 4); - - for (int g = 0; g < ePS_Green; ++g) - { - for (int r = 0; r < ePS_Red; ++r) - { - AZ::u8* p = pData + pitch * (py + g) + (px + r) * 4; - - SColor col; - col.r = p[0]; - col.g = p[1]; - col.b = p[2]; - m_mapping.push_back(col); - } - } - } - } - - //check if image data at location x and y could be a color chart - //based on if the boarder is dash lines with two pixel each segement - //the idea and implementation are both coming from CryEngine. - bool C3dLutColorChart::IsColorChartAt(AZ::u32 x, AZ::u32 y, void* pData, AZ::u32 pitch) - { - struct Color - { - private: - int c[3]; - - public: - Color(AZ::u32 x, AZ::u32 y, void* pPixels, AZ::u32 pitch) - { - const uint8* p = (const uint8*)pPixels + pitch * y + x * 4; - c[0] = p[0]; - c[1] = p[1]; - c[2] = p[2]; - } - - bool isSimilar(const Color& a, int maxDiff) const - { - return - abs(a.c[0] - c[0]) <= maxDiff && - abs(a.c[1] - c[1]) <= maxDiff && - abs(a.c[2] - c[2]) <= maxDiff; - } - }; - - const Color colorRef[2] = - { - Color(x, y, pData, pitch), - Color(x + 2, y, pData, pitch) - }; - - // We require two colors of the border to be at least a bit different - if (colorRef[0].isSimilar(colorRef[1], 15)) - { - return false; - } - - static const int kMaxDiff = 3; - - int refIdx = 0; - //rectangle's top - for (int i = 0; i < COLORCHART_IMAGE_WIDTH; i += 2) - { - if (!colorRef[refIdx].isSimilar(Color(x + i, y, pData, pitch), kMaxDiff) || - !colorRef[refIdx].isSimilar(Color(x + i + 1, y, pData, pitch), kMaxDiff)) - { - return false; - } - refIdx ^= 1; - } - - refIdx = 0; - //left - for (int i = 0; i < COLORCHART_IMAGE_HEIGHT; i += 2) - { - if (!colorRef[refIdx].isSimilar(Color(x, y + i, pData, pitch), kMaxDiff) || - !colorRef[refIdx].isSimilar(Color(x, y + i + 1, pData, pitch), kMaxDiff)) - { - return false; - } - refIdx ^= 1; - } - - refIdx = 0; - //right - for (int i = 0; i < COLORCHART_IMAGE_HEIGHT; i += 2) - { - if (!colorRef[refIdx].isSimilar(Color(x + COLORCHART_IMAGE_WIDTH - 1, y + i, pData, pitch), kMaxDiff) || - !colorRef[refIdx].isSimilar(Color(x + COLORCHART_IMAGE_WIDTH - 1, y + i + 1, pData, pitch), kMaxDiff)) - { - return false; - } - refIdx ^= 1; - } - - refIdx = 0; - //bottom - for (int i = 0; i < COLORCHART_IMAGE_WIDTH; i += 2) - { - if (!colorRef[refIdx].isSimilar(Color(x + i, y + COLORCHART_IMAGE_HEIGHT - 1, pData, pitch), kMaxDiff) || - !colorRef[refIdx].isSimilar(Color(x + i + 1, y + COLORCHART_IMAGE_HEIGHT - 1, pData, pitch), kMaxDiff)) - { - return false; - } - refIdx ^= 1; - } - - return true; - } - - - void ImageToProcess::CreateColorChart() - { - C3dLutColorChart colorChart; - - //get color chart data from source image. - if (!colorChart.GenerateFromInput(m_img)) - { - //if load from image failed then generate default color data - colorChart.GenerateDefault(); - } - - //save color chart data to an image and save as current - m_img = colorChart.GenerateChartImage(); - } -} diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Converters/Cubemap.cpp b/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Converters/Cubemap.cpp index 4f13c6f9bf..d373f399e1 100644 --- a/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Converters/Cubemap.cpp +++ b/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Converters/Cubemap.cpp @@ -547,7 +547,7 @@ namespace ImageProcessingAtom } //generate box filtered source image mip chain - IImageObjectPtr mippedSourceImage(IImageObject::CreateImage(outWidth, outHeight, maxMipCount, ePixelFormat_R32G32B32A32F)); + IImageObjectPtr mippedSourceImage(IImageObject::CreateImage(outWidth, outHeight, maxMipCount, srcPixelFormat)); mippedSourceImage->CopyPropertiesFrom(m_image->Get()); for (int iSide = 0; iSide < 6; ++iSide) diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Converters/HighPass.cpp b/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Converters/HighPass.cpp deleted file mode 100644 index e2071fb586..0000000000 --- a/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Converters/HighPass.cpp +++ /dev/null @@ -1,100 +0,0 @@ -/* - * 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 -#include -#include -#include - -namespace ImageProcessingAtom -{ - // higher mip level is subtracted by lower mip level when applying the [cheap] high pass filter - void ImageToProcess::CreateHighPass(AZ::u32 dwMipDown) - { - //no need to convert if mip go down 0 - if (dwMipDown == 0) - { - return; - } - - const EPixelFormat ePixelFormat = m_img->GetPixelFormat(); - - if (ePixelFormat != ePixelFormat_R32G32B32A32F) - { - AZ_Assert(false, "You need convert the orginal image to ePixelFormat_R32G32B32A32F before call this function"); - return; - } - - - AZ::u32 dwWidth, dwHeight, dwMips; - dwWidth = m_img->GetWidth(0); - dwHeight = m_img->GetHeight(0); - dwMips = m_img->GetMipCount(); - - if (dwMipDown >= dwMips) - { - AZ_Warning("Image Processing", false, "CreateHighPass can't go down %i MIP levels for high pass as there are not\ - enough MIP levels available, going down by %i instead", dwMipDown, dwMips - 1); - dwMipDown = dwMips - 1; - } - - IImageObjectPtr newImage(IImageObject::CreateImage(dwWidth, dwHeight, dwMips, ePixelFormat)); - newImage->CopyPropertiesFrom(m_img); - - IPixelOperationPtr pixelOp = CreatePixelOperation(ePixelFormat); - AZ::u32 pixelBytes = CPixelFormats::GetInstance().GetPixelFormatInfo(ePixelFormat)->bitsPerBlock / 8; - - AZ::u32 dstMips = newImage->GetMipCount(); - for (AZ::u32 dstMip = 0; dstMip < dwMipDown; ++dstMip) - { - // linear interpolation - FilterImage(MipGenType::triangle, MipGenEvalType::sum, 0.0f, 0.0f, m_img, dwMipDown, newImage, dstMip, NULL, NULL); - - //substraction - AZ::u8* srcPixelBuf; - AZ::u32 srcPitch; - m_img->GetImagePointer(dstMip, srcPixelBuf, srcPitch); - AZ::u8* dstPixelBuf; - AZ::u32 dstPitch; - newImage->GetImagePointer(dstMip, dstPixelBuf, dstPitch); - const AZ::u32 pixelCount = newImage->GetPixelCount(dstMip); - - for (AZ::u32 i = 0; i < pixelCount; ++i, srcPixelBuf += pixelBytes, dstPixelBuf += pixelBytes) - { - float r1, g1, b1, a1, r2, g2, b2, a2; - pixelOp->GetRGBA(srcPixelBuf, r1, g1, b1, a1); - pixelOp->GetRGBA(dstPixelBuf, r2, g2, b2, a2); - - r2 = AZ::GetClamp(r1 - r2 + 0.5f, 0.0f, 1.0f); - g2 = AZ::GetClamp(g1 - g2 + 0.5f, 0.0f, 1.0f); - b2 = AZ::GetClamp(b1 - b2 + 0.5f, 0.0f, 1.0f); - a2 = AZ::GetClamp(a1 - a2 + 0.5f, 0.0f, 1.0f); - pixelOp->SetRGBA(dstPixelBuf, r2, g2, b2, a2); - } - } - - // mips below the chosen highpass mip are grey - for (AZ::u32 dstMip = dwMipDown; dstMip < dstMips; ++dstMip) - { - AZ::u8* dstPixelBuf; - AZ::u32 dstPitch; - newImage->GetImagePointer(dstMip, dstPixelBuf, dstPitch); - const AZ::u32 pixelCount = newImage->GetPixelCount(dstMip); - - for (AZ::u32 i = 0; i < pixelCount; ++i, dstPixelBuf += pixelBytes) - { - pixelOp->SetRGBA(dstPixelBuf, 0.5f, 0.5f, 0.5f, 1.0f); - } - } - - m_img = newImage; - } -} // namespace ImageProcessingAtom diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Editor/PresetInfoPopup.cpp b/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Editor/PresetInfoPopup.cpp index a5b942fa58..fe5703ceb6 100644 --- a/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Editor/PresetInfoPopup.cpp +++ b/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Editor/PresetInfoPopup.cpp @@ -82,10 +82,7 @@ namespace ImageProcessingAtomEditor presetInfoText += "\n"; presetInfoText += QString("Suppress Engine Reduce: %1\n").arg(presetSettings->m_suppressEngineReduce ? "True" : "False"); presetInfoText += QString("Discard Alpha: %1\n").arg(presetSettings->m_discardAlpha ? "True" : "False"); - presetInfoText += QString("Is Color Chart: %1\n").arg(presetSettings->m_isColorChart ? "True" : "False"); - presetInfoText += QString("High Pass Mip: %1\n").arg(presetSettings->m_highPassMip); presetInfoText += QString("Gloss From Normal: %1\n").arg(presetSettings->m_glossFromNormals); - presetInfoText += QString("Use Legacy Gloss: %1\n").arg(presetSettings->m_isLegacyGloss ? "True" : "False"); presetInfoText += QString("Mip Re-normalize: %1\n").arg(presetSettings->m_isMipRenormalize ? "True" : "False"); presetInfoText += QString("Resident Mips Number: %1\n").arg(presetSettings->m_numResidentMips); presetInfoText += QString("Swizzle: %1\n").arg(presetSettings->m_swizzle.c_str()); diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/ImageBuilderComponent.cpp b/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/ImageBuilderComponent.cpp index a489c8da5e..90d45ae65a 100644 --- a/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/ImageBuilderComponent.cpp +++ b/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/ImageBuilderComponent.cpp @@ -74,7 +74,7 @@ namespace ImageProcessingAtom builderDescriptor.m_busId = azrtti_typeid(); builderDescriptor.m_createJobFunction = AZStd::bind(&ImageBuilderWorker::CreateJobs, &m_imageBuilder, AZStd::placeholders::_1, AZStd::placeholders::_2); builderDescriptor.m_processJobFunction = AZStd::bind(&ImageBuilderWorker::ProcessJob, &m_imageBuilder, AZStd::placeholders::_1, AZStd::placeholders::_2); - builderDescriptor.m_version = 25; // [ATOM-16575] + builderDescriptor.m_version = 26; // [ATOM-15086] builderDescriptor.m_analysisFingerprint = ImageProcessingAtom::BuilderSettingManager::Instance()->GetAnalysisFingerprint(); m_imageBuilder.BusConnect(builderDescriptor.m_busId); AssetBuilderSDK::AssetBuilderBus::Broadcast(&AssetBuilderSDK::AssetBuilderBusTraits::RegisterBuilderInformation, builderDescriptor); diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Processing/ImageConvert.cpp b/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Processing/ImageConvert.cpp index 977359e4f6..5b23009cff 100644 --- a/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Processing/ImageConvert.cpp +++ b/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Processing/ImageConvert.cpp @@ -46,7 +46,6 @@ namespace ImageProcessingAtom enum ConvertStep { StepValidateInput = 0, - StepGenerateColorChart, StepConvertToLinear, StepSwizzle, StepCubemapLayout, @@ -55,9 +54,7 @@ namespace ImageProcessingAtom StepMipmap, StepGlossFromNormal, StepPostNormalize, - StepCreateHighPass, StepConvertOutputColorSpace, - StepAlphaImage, StepConvertPixelFormat, StepSaveToFile, StepAll @@ -66,7 +63,6 @@ namespace ImageProcessingAtom [[maybe_unused]] const char ProcessStepNames[StepAll][64] = { "ValidateInput", - "GenerateColorChart", "ConvertToLinear", "Swizzle", "CubemapLayout", @@ -75,9 +71,7 @@ namespace ImageProcessingAtom "Mipmap", "GlossFromNormal", "PostNormalize", - "CreateHighPass", "ConvertOutputColorSpace", - "AlphaImage", "ConvertPixelFormat", "SaveToFile", }; @@ -94,11 +88,6 @@ namespace ImageProcessingAtom return nullptr; } - IImageObjectPtr ImageConvertProcess::GetOutputAlphaImage() - { - return m_alphaImage; - } - IImageObjectPtr ImageConvertProcess::GetOutputIBLSpecularCubemap() { return m_iblSpecularCubemapImage; @@ -180,6 +169,58 @@ namespace ImageProcessingAtom m_image = new ImageToProcess(IImageObjectPtr(m_input->m_inputImage->Clone(mipsToClone))); } + break; + case StepConvertToLinear: + // convert to linear space and the output image pixel format should be rgba32f + ConvertToLinear(); + break; + case StepSwizzle: + { + // swizzle if swizzle was set or decard alpha + bool swizzleWasSet = m_input->m_presetSetting.m_swizzle.size() >= 4; + if (swizzleWasSet || m_input->m_presetSetting.m_discardAlpha) + { + AZStd::string swizzle = "rgba"; + if (swizzleWasSet) + { + swizzle = m_input->m_presetSetting.m_swizzle.substr(0, 4); + } + + if (m_input->m_presetSetting.m_discardAlpha) + { + swizzle[3] = '1'; + } + + m_image->Get()->Swizzle(swizzle.c_str()); + if (!m_input->m_presetSetting.m_discardAlpha) + { + m_alphaContent = EAlphaContent::eAlphaContent_Absent; + } + else + { + m_alphaContent = m_image->Get()->GetAlphaContent(); + } + } + } + break; + case StepCubemapLayout: + // convert cubemap image's layout to vertical strip used in game. + if (IsConvertToCubemap()) + { + if (!m_image->ConvertCubemapLayout(CubemapLayoutVertical)) + { + m_image->Set(nullptr); + } + } + break; + case StepPreNormalize: + // normalize base image before mipmap generation if glossfromnormals is enabled and require normalize + if (m_input->m_presetSetting.m_isMipRenormalize && m_input->m_presetSetting.m_glossFromNormals) + { + // Normalize the base mip map. This has to be done explicitly because we need to disable mip renormalization to + // preserve the normal length when deriving the normal variance + m_image->Get()->NormalizeVectors(0, 1); + } break; case StepGenerateIBL: if (IsConvertToCubemap()) @@ -204,56 +245,6 @@ namespace ImageProcessingAtom m_isFinished = true; } break; - case StepGenerateColorChart: - // GenerateColorChart. - if (m_input->m_presetSetting.m_isColorChart) - { - // Convert to uncompressed format if it's compressed format. For example, loaded from DDS file. - if (!CPixelFormats::GetInstance().IsPixelFormatUncompressed(m_image->Get()->GetPixelFormat())) - { - m_image->ConvertFormat(ePixelFormat_R32G32B32A32F); - } - - m_image->CreateColorChart(); - } - break; - case StepConvertToLinear: - // convert to linear space and the output image pixel format should be rgba32f - ConvertToLinear(); - break; - case StepSwizzle: - // convert texture format. - if (m_input->m_presetSetting.m_swizzle.size() >= 4) - { - m_image->Get()->Swizzle(m_input->m_presetSetting.m_swizzle.substr(0, 4).c_str()); - m_alphaContent = m_image->Get()->GetAlphaContent(); - } - - // convert gloss map (alhpa channel) from legacy distribution to new one - if (m_input->m_presetSetting.m_isLegacyGloss) - { - m_image->Get()->ConvertLegacyGloss(); - } - break; - case StepCubemapLayout: - // convert cubemap image's layout to vertical strip used in game. - if (IsConvertToCubemap()) - { - if (!m_image->ConvertCubemapLayout(CubemapLayoutVertical)) - { - m_image->Set(nullptr); - } - } - break; - case StepPreNormalize: - // normalize base image before mipmap generation if glossfromnormals is enabled and require normalize - if (m_input->m_presetSetting.m_isMipRenormalize && m_input->m_presetSetting.m_glossFromNormals) - { - // Normalize the base mip map. This has to be done explicitly because we need to disable mip renormalization to - // preserve the normal length when deriving the normal variance - m_image->Get()->NormalizeVectors(0, 1); - } - break; case StepMipmap: // generate mipmaps if (IsConvertToCubemap()) @@ -304,20 +295,10 @@ namespace ImageProcessingAtom m_image->Get()->AddImageFlags(EIF_RenormalizedTexture); } break; - case StepCreateHighPass: - if (m_input->m_presetSetting.m_highPassMip > 0) - { - m_image->CreateHighPass(m_input->m_presetSetting.m_highPassMip); - } - break; case StepConvertOutputColorSpace: // convert image from linear space to desired output color space ConvertToOuputColorSpace(); break; - case StepAlphaImage: - // save alpha channel to separate image if it's needed - CreateAlphaImage(); - break; case StepConvertPixelFormat: // convert pixel format ConvertPixelformat(); @@ -411,12 +392,6 @@ namespace ImageProcessingAtom return; } - // don't do any reduce for color chart - if (presetSettings->m_isColorChart) - { - return; - } - // get suitable size for dest pixel format CPixelFormats::GetInstance().GetSuitableImageSize(presetSettings->m_pixelFormat, inputWidth, inputHeight, outWidth, outHeight); @@ -510,52 +485,6 @@ namespace ImageProcessingAtom return true; } - void ImageConvertProcess::CreateAlphaImage() - { - // if alpha content doesn't have alpha or we need to discard alpha, skip - // we won't create alpha image for cubemap too - if (m_alphaContent == EAlphaContent::eAlphaContent_Absent - || m_alphaContent == EAlphaContent::eAlphaContent_OnlyWhite - || m_input->m_presetSetting.m_discardAlpha || IsConvertToCubemap()) - { - return; - } - - // if dest format could save alpha, skip too - if (!CPixelFormats::GetInstance().IsPixelFormatWithoutAlpha(m_input->m_presetSetting.m_pixelFormat)) - { - return; - } - - // now create alpha image - ImageToProcess alphaImage(m_image->Get()); - alphaImage.ConvertFormat(ePixelFormat_A8); - - // validate pixelformatalpha - if (CPixelFormats::GetInstance().IsFormatSingleChannel(m_input->m_presetSetting.m_pixelFormatAlpha)) - { - alphaImage.ConvertFormat(m_input->m_presetSetting.m_pixelFormatAlpha); - } - else - { - //For ASTC compression we need to clear out the alpha to get accurate rgb compression. - if (IsASTCFormat(m_input->m_presetSetting.m_pixelFormat)) - { - alphaImage.ConvertFormat(ePixelFormat_R8G8B8X8); - alphaImage.ConvertFormat(m_input->m_presetSetting.m_pixelFormatAlpha); - } - else - { - AZ_Assert(false, "PixelFormatAlpha only supports single channel pixel formats or ASTC formats"); - } - } - - // get final result and save it to member variable for later use - m_alphaImage = alphaImage.Get(); - - m_image->Get()->AddImageFlags(EIF_AttachedAlpha); - } - // pixel format conversion bool ImageConvertProcess::ConvertPixelformat() { @@ -575,12 +504,6 @@ namespace ImageProcessingAtom m_image->GetCompressOption().rgbWeight = m_input->m_presetSetting.GetColorWeight(); m_image->GetCompressOption().discardAlpha = m_input->m_presetSetting.m_discardAlpha; - //For ASTC compression we need to clear out the alpha to get accurate rgb compression. - if(m_alphaImage && IsASTCFormat(m_input->m_presetSetting.m_pixelFormat)) - { - m_image->GetCompressOption().discardAlpha = true; - } - m_image->ConvertFormat(m_input->m_presetSetting.m_pixelFormat); return true; @@ -762,7 +685,6 @@ namespace ImageProcessingAtom if (ImageProcess##PrivateName::DoesSupport(m_input->m_platform)) \ { \ ImageProcess##PrivateName::PrepareImageForExport(m_image->Get()); \ - ImageProcess##PrivateName::PrepareImageForExport(m_alphaImage); \ } AZ_TOOLS_EXPAND_FOR_RESTRICTED_PLATFORMS #undef AZ_RESTRICTED_PLATFORM_EXPANSION diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Processing/ImageConvert.h b/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Processing/ImageConvert.h index eaf05c3280..fe57b1a89f 100644 --- a/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Processing/ImageConvert.h +++ b/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Processing/ImageConvert.h @@ -115,7 +115,6 @@ namespace ImageProcessingAtom //get output images IImageObjectPtr GetOutputImage(); - IImageObjectPtr GetOutputAlphaImage(); IImageObjectPtr GetOutputIBLSpecularCubemap(); IImageObjectPtr GetOutputIBLDiffuseCubemap(); @@ -131,8 +130,6 @@ namespace ImageProcessingAtom //for alpha //to indicate the current alpha channel content EAlphaContent m_alphaContent; - //An image object to hold alpha channel in a separate image - IImageObjectPtr m_alphaImage; //output results of IBL cubemap generation, used in unit tests IImageObjectPtr m_iblSpecularCubemapImage; @@ -171,9 +168,6 @@ namespace ImageProcessingAtom //convert to output color space before compression bool ConvertToOuputColorSpace(); - //create alpha image if it's needed - void CreateAlphaImage(); - //pixel format convertion/compression bool ConvertPixelformat(); diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Processing/ImageConvertJob.cpp b/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Processing/ImageConvertJob.cpp index 1465e7993f..0e4521ab24 100644 --- a/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Processing/ImageConvertJob.cpp +++ b/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Processing/ImageConvertJob.cpp @@ -108,17 +108,14 @@ namespace ImageProcessingAtom } IImageObjectPtr outputImage = m_process->GetOutputImage(); - IImageObjectPtr outputImageAlpha = m_process->GetOutputAlphaImage(); m_output->SetOutputImage(outputImage, ImageConvertOutput::Base); - m_output->SetOutputImage(outputImageAlpha, ImageConvertOutput::Alpha); if (!IsJobCancelled()) { // For preview, combine image output with alpha if any m_output->SetProgress(1.0f / static_cast(m_previewProcessStep)); - IImageObjectPtr combinedImage = MergeOutputImageForPreview(outputImage, outputImageAlpha); - m_output->SetOutputImage(combinedImage, ImageConvertOutput::Preview); + m_output->SetOutputImage(outputImage, ImageConvertOutput::Preview); } m_output->SetReady(true); diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Processing/ImageFlags.h b/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Processing/ImageFlags.h index 99e752c90a..d25533cccd 100644 --- a/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Processing/ImageFlags.h +++ b/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Processing/ImageFlags.h @@ -20,7 +20,7 @@ namespace ImageProcessingAtom const static AZ::u32 EIF_Greyscale = 0x8; // hint for the engine (e.g. greyscale light beams can be applied to shadow mask), can be for DXT1 because compression artfacts don't count as color const static AZ::u32 EIF_SupressEngineReduce = 0x10; // info for the engine: don't reduce texture resolution on this texture const static AZ::u32 EIF_UNUSED_BIT = 0x40; // Free to use - const static AZ::u32 EIF_AttachedAlpha = 0x400; // info for the engine: it's a texture with attached alpha channel + const static AZ::u32 EIF_AttachedAlpha = 0x400; // deprecated: info for the engine: it's a texture with attached alpha channel const static AZ::u32 EIF_SRGBRead = 0x800; // info for the engine: if gamma corrected rendering is on, this texture requires SRGBRead (it's not stored in linear) const static AZ::u32 EIF_DontResize = 0x8000; // info for the engine: for dds textures that shouldn't be resized const static AZ::u32 EIF_RenormalizedTexture = 0x10000; // info for the engine: for dds textures that have renormalized color range diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Processing/ImageObjectImpl.cpp b/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Processing/ImageObjectImpl.cpp index 8504f5e074..465d992ef6 100644 --- a/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Processing/ImageObjectImpl.cpp +++ b/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Processing/ImageObjectImpl.cpp @@ -316,130 +316,6 @@ namespace ImageProcessingAtom m_mips.clear(); } - //note: there are some unreasonable parts of the save files formats for cry textures. We might need to rethink about - // it for new renderer - bool CImageObject::SaveImage(const char* filename, IImageObjectPtr alphaImage, AZStd::vector& outFilePaths) const - { - AZ::IO::SystemFile file; - file.Open(filename, AZ::IO::SystemFile::SF_OPEN_CREATE | AZ::IO::SystemFile::SF_OPEN_CREATE_PATH | AZ::IO::SystemFile::SF_OPEN_WRITE_ONLY); - - AZ::IO::SystemFileStream fileSaveStream(&file, true); - if (!fileSaveStream.IsOpen()) - { - AZ_Warning("Image Processing", false, "%s: failed to create file %s", __FUNCTION__, filename); - return false; - } - - if (alphaImage) - { - AZ_Assert(HasImageFlags(EIF_AttachedAlpha), "attached alpha image flag wasn't set"); - AZ_Assert(!alphaImage->HasImageFlags(EIF_AttachedAlpha), "alpha image shouldn't have attached alpha image flag"); - - // inherit cubemap and decal image flags to attached alpha image - alphaImage->AddImageFlags(GetImageFlags() & (EIF_Cubemap - | EIF_Decal | EIF_Splitted)); - alphaImage->SetNumPersistentMips(m_numPersistentMips); - } - - bool bOk = SaveImage(fileSaveStream); - bool hasSplitFlag = HasImageFlags(EIF_Splitted); - - //append alpha image data in the end if there is no split - if (bOk && alphaImage && !hasSplitFlag) - { - //4 bytes extension tag, 4 bytes attached alpha tag, then 4 bytes of chunk size - fileSaveStream.Write(sizeof(FOURCC_CExt), &FOURCC_CExt); // marker for the start of O3DE Extended data - fileSaveStream.Write(sizeof(FOURCC_AttC), &FOURCC_AttC); // Attached Channel chunk - - uint32_t size = 0; - uint32_t sizeBytes = sizeof(size); - fileSaveStream.Write(sizeBytes, &size); //size of attached chunk - - //save alpha image and get the size - AZ::IO::SizeType startPos = fileSaveStream.GetCurPos(); - bOk = alphaImage->SaveImage(fileSaveStream); - AZ::IO::SizeType endPos = fileSaveStream.GetCurPos(); - size = static_cast(endPos - startPos); - - //move back to beginning of chunk and write chunk size then move back to end - fileSaveStream.Seek(startPos - sizeBytes, AZ::IO::GenericStream::ST_SEEK_BEGIN); - fileSaveStream.Write(sizeBytes, &size); - fileSaveStream.Seek(endPos, AZ::IO::GenericStream::ST_SEEK_BEGIN); - - // marker for the end of O3DE Extended data - fileSaveStream.Write(sizeof(FOURCC_CEnd), &FOURCC_CEnd); - } - - if (!bOk) - { - AZ::IO::SystemFile::Delete(filename); - return false; - } - - // It's important to maintain the product output sequence. Asset Database/Browser will use the first product to determine the source type! - outFilePaths.push_back(filename); - - // save stand alone products - if (hasSplitFlag) - { - // alpha - if (alphaImage) - { - AZStd::string alphaFile = AZStd::string::format("%s.a", filename); - - AZ::IO::SystemFile outAlphaFile; - outAlphaFile.Open(alphaFile.c_str(), AZ::IO::SystemFile::SF_OPEN_CREATE | AZ::IO::SystemFile::SF_OPEN_CREATE_PATH | AZ::IO::SystemFile::SF_OPEN_WRITE_ONLY); - - AZ::IO::SystemFileStream alphaFileSaveStream(&outAlphaFile, true); - - if (alphaFileSaveStream.IsOpen()) - { - alphaImage->SaveImage(alphaFileSaveStream); - outFilePaths.push_back(alphaFile); - } - else - { - AZ_Warning("Image Processing", false, "%s: failed to create file %s", __FUNCTION__, alphaFile.c_str()); - } - } - - // mips - AZ::u32 numStreamable = GetMipCount() - m_numPersistentMips; - for (AZ::u32 mip = 0; mip < numStreamable; mip++) - { - AZ::u32 nameIdx = numStreamable - mip; - AZStd::string mipFileName = AZStd::string::format("%s.%d", filename, nameIdx); - SaveMipToFile(mip, mipFileName); - outFilePaths.push_back(mipFileName); - if (alphaImage) - { - AZStd::string mipAlphaFileName = mipFileName + "a"; - alphaImage->SaveMipToFile(mip, mipAlphaFileName); - outFilePaths.push_back(mipAlphaFileName); - } - } - } - - return bOk; - } - - bool CImageObject::SaveMipToFile(AZ::u32 mip, const AZStd::string& filename) const - { - AZ::IO::SystemFile saveFile; - saveFile.Open(filename.c_str(), AZ::IO::SystemFile::SF_OPEN_CREATE | AZ::IO::SystemFile::SF_OPEN_CREATE_PATH | AZ::IO::SystemFile::SF_OPEN_WRITE_ONLY); - - AZ::IO::SystemFileStream saveFileStream(&saveFile, true); - - if (!saveFileStream.IsOpen()) - { - AZ_Warning("Image Processing", false, "%s: failed to create file %s", __FUNCTION__, filename.c_str()); - return false; - } - - saveFileStream.Write(GetMipBufSize(mip), m_mips[mip]->m_pData); - return true; - } - float CImageObject::CalculateAverageBrightness() const { //if it's compressed format, return a default value @@ -642,63 +518,6 @@ namespace ImageProcessingAtom return true; } - bool CImageObject::SaveImage(AZ::IO::SystemFileStream& saveFileStream) const - { - DDS_FILE_DESC_LEGACY desc; - DDS_HEADER_DXT10 exthead; - - desc.dwMagic = FOURCC_DDS; - - if (!BuildSurfaceHeader(desc.header)) - { - return false; - } - - if (desc.header.IsDX10Ext() && !BuildSurfaceExtendedHeader(exthead)) - { - return false; - } - - saveFileStream.Write(sizeof(desc), &desc); - - if (desc.header.IsDX10Ext()) - { - saveFileStream.Write(sizeof(exthead), &exthead); - } - - AZ::u32 faces = 1; - - //for cubemap. export each face and its mipmap - if (HasImageFlags(EIF_Cubemap)) - { - faces = 6; - } - - AZ::u32 mipStart = 0; - if (HasImageFlags(EIF_Splitted)) - { - if (m_numPersistentMips < m_mips.size()) - { - mipStart = (AZ::u32)m_mips.size() - m_numPersistentMips; - } - else - { - AZ_Assert(false, "numPersistentMips wasn't setup correctly"); - } - } - - for (AZ::u32 face = 0; face < faces; face++) - { - for (AZ::u32 mip = mipStart; mip < m_mips.size(); ++mip) - { - const MipLevel& level = *m_mips[mip]; - AZ::u32 faceBufSize = level.m_pitch * level.m_rowCount / faces; - saveFileStream.Write(faceBufSize, level.m_pData + faceBufSize * face); - } - } - return true; - } - void CImageObject::GetExtent(AZ::u32& width, AZ::u32& height, AZ::u32& mipCount) const { mipCount = (AZ::u32)m_mips.size(); @@ -953,35 +772,4 @@ namespace ImageProcessingAtom } } } - - void CImageObject::ConvertLegacyGloss() - { - if (!(CPixelFormats::GetInstance().IsPixelFormatUncompressed(m_pixelFormat))) - { - AZ_Assert(false, "%s function only works with uncompressed pixel format", __FUNCTION__); - return; - } - - //create pixel operation function - IPixelOperationPtr pixelOp = CreatePixelOperation(m_pixelFormat); - - //get count of bytes per pixel - AZ::u32 pixelBytes = CPixelFormats::GetInstance().GetPixelFormatInfo(m_pixelFormat)->bitsPerBlock / 8; - - const AZ::u32 mips = (AZ::u32)m_mips.size(); - float color[4]; - for (AZ::u32 mip = 0; mip < mips; ++mip) - { - AZ::u8* pixelBuf = m_mips[mip]->m_pData; - const AZ::u32 pixelCount = GetPixelCount(mip); - - for (AZ::u32 i = 0; i < pixelCount; ++i, pixelBuf += pixelBytes) - { - pixelOp->GetRGBA(pixelBuf, color[0], color[1], color[2], color[3]); - // Convert from (1 - s * 0.7)^6 to (1 - s)^2 - color[3] = 1 - pow(1.0f - color[3] * 0.7f, 3.0f); - pixelOp->SetRGBA(pixelBuf, color[0], color[1], color[2], color[3]); - } - } - } } // namespace ImageProcessingAtom diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Processing/ImageObjectImpl.h b/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Processing/ImageObjectImpl.h index c8b8ced496..7fa02f464e 100644 --- a/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Processing/ImageObjectImpl.h +++ b/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Processing/ImageObjectImpl.h @@ -57,10 +57,6 @@ namespace ImageProcessingAtom bool CompareImage(const IImageObjectPtr otherImage) const override; - bool SaveImage(const char* filename, IImageObjectPtr alphaImage, AZStd::vector& outFilePaths) const override; - bool SaveImage(AZ::IO::SystemFileStream& out) const override; - bool SaveMipToFile(AZ::u32 mip, const AZStd::string& filename) const override; - uint32_t GetTextureMemory() const override; EAlphaContent GetAlphaContent() const override; @@ -79,7 +75,6 @@ namespace ImageProcessingAtom void SetNumPersistentMips(AZ::u32 nMips) override; void GlossFromNormals(bool hasAuthoredGloss) override; - void ConvertLegacyGloss() override; void ClearColor(float r, float g, float b, float a) override; //end virtual functions from IImageObject diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Processing/ImageToProcess.h b/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Processing/ImageToProcess.h index e6fe6ce142..ed0b21b56c 100644 --- a/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Processing/ImageToProcess.h +++ b/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Processing/ImageToProcess.h @@ -66,13 +66,6 @@ namespace ImageProcessingAtom bool GammaToLinearRGBA32F(bool bDeGamma); void LinearToGamma(); - // --------------------------------------------------------------------------------- - // Tools for A32B32G32R32F - - void CreateHighPass(uint32 dwMipDown); - - void CreateColorChart(); - //convert various original cubemap layouts to new layout bool ConvertCubemapLayout(CubemapLayoutType newLayout); }; diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Code/Tests/ImageProcessing_Test.cpp b/Gems/Atom/Asset/ImageProcessingAtom/Code/Tests/ImageProcessing_Test.cpp index 3e0bbd89eb..d5b795a1fa 100644 --- a/Gems/Atom/Asset/ImageProcessingAtom/Code/Tests/ImageProcessing_Test.cpp +++ b/Gems/Atom/Asset/ImageProcessingAtom/Code/Tests/ImageProcessing_Test.cpp @@ -988,7 +988,6 @@ namespace UnitTest ASSERT_TRUE(process->IsSucceed()); SaveImageToFile(process->GetOutputImage(), "rgb", 10); - SaveImageToFile(process->GetOutputAlphaImage(), "alpha", 10); process->GetAppendOutputProducts(outProducts); diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Code/imageprocessing_files.cmake b/Gems/Atom/Asset/ImageProcessingAtom/Code/imageprocessing_files.cmake index aad400518d..a6fe09bfa6 100644 --- a/Gems/Atom/Asset/ImageProcessingAtom/Code/imageprocessing_files.cmake +++ b/Gems/Atom/Asset/ImageProcessingAtom/Code/imageprocessing_files.cmake @@ -103,8 +103,6 @@ set(FILES Source/Converters/ConvertPixelFormat.cpp Source/Converters/Cubemap.h Source/Converters/Cubemap.cpp - Source/Converters/ColorChart.cpp - Source/Converters/HighPass.cpp Source/Converters/Histogram.cpp Source/Converters/Histogram.h ../External/CubeMapGen/CBBoxInt32.cpp From 0b061d2e0038bc462de83c1c4a20fdf79637be7c Mon Sep 17 00:00:00 2001 From: Ken Pruiksma Date: Fri, 5 Nov 2021 12:39:58 -0500 Subject: [PATCH 22/53] GHI-5338 - Fixing incorrect calculation of sector bounds for negative values (#5352) Signed-off-by: Ken Pruiksma --- .../Source/TerrainRenderer/TerrainFeatureProcessor.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Gems/Terrain/Code/Source/TerrainRenderer/TerrainFeatureProcessor.cpp b/Gems/Terrain/Code/Source/TerrainRenderer/TerrainFeatureProcessor.cpp index 73f1c3967c..55713e696a 100644 --- a/Gems/Terrain/Code/Source/TerrainRenderer/TerrainFeatureProcessor.cpp +++ b/Gems/Terrain/Code/Source/TerrainRenderer/TerrainFeatureProcessor.cpp @@ -417,10 +417,10 @@ namespace Terrain m_areaData.m_rebuildSectors = false; m_sectorData.clear(); - const float xFirstPatchStart = terrainBounds.GetMin().GetX() - fmod(terrainBounds.GetMin().GetX(), GridMeters); - const float xLastPatchStart = terrainBounds.GetMax().GetX() - fmod(terrainBounds.GetMax().GetX(), GridMeters); - const float yFirstPatchStart = terrainBounds.GetMin().GetY() - fmod(terrainBounds.GetMin().GetY(), GridMeters); - const float yLastPatchStart = terrainBounds.GetMax().GetY() - fmod(terrainBounds.GetMax().GetY(), GridMeters); + const float xFirstPatchStart = AZStd::floorf(terrainBounds.GetMin().GetX() / GridMeters) * GridMeters; + const float xLastPatchStart = AZStd::floorf(terrainBounds.GetMax().GetX() / GridMeters) * GridMeters; + const float yFirstPatchStart = AZStd::floorf(terrainBounds.GetMin().GetY() / GridMeters) * GridMeters; + const float yLastPatchStart = AZStd::floorf(terrainBounds.GetMax().GetY() / GridMeters) * GridMeters; const auto& materialAsset = m_materialInstance->GetAsset(); const auto& shaderAsset = materialAsset->GetMaterialTypeAsset()->GetShaderAssetForObjectSrg(); @@ -603,7 +603,7 @@ namespace Terrain // For every distance doubling beyond a minDistanceForLod0, we only need half the mesh density. Each LOD // is exactly half the resolution of the last. - const float lodForCamera = floorf(AZ::GetMax(0.0f, log2f(sectorDistance / minDistanceForLod0))); + const float lodForCamera = AZStd::floorf(AZ::GetMax(0.0f, log2f(sectorDistance / minDistanceForLod0))); // All cameras should render the same LOD so effects like shadows are consistent. lodChoice = AZ::GetMin(lodChoice, aznumeric_cast(lodForCamera)); From 6cba64f2265d06ef4244aa387c9e6b2164f093a9 Mon Sep 17 00:00:00 2001 From: amzn-phist <52085794+amzn-phist@users.noreply.github.com> Date: Fri, 5 Nov 2021 13:47:24 -0500 Subject: [PATCH 23/53] Fix issue with Server Launcher debug console not accepting keystrokes (#5325) * Fix issue with debug console ignoring some keys This problem was reported for Server only, the Enter/Backspace keys were being ignored in the ImGui Debug Console. This wasn't an issue if the Server had loaded a map. The problem was with XConsole explicitly setting a bool in dedicated server mode. This caused text input to be processed by XConsole code and not passed further along to DebugConsole where it should have been handling it via ImGui. Signed-off-by: amzn-phist <52085794+amzn-phist@users.noreply.github.com> * Fix missing runtime dependency of ServerLauncher ServerLauncher in non-monolithic config was missing a runtime dependency on Legacy::CrySystem. Signed-off-by: amzn-phist <52085794+amzn-phist@users.noreply.github.com> --- Code/LauncherUnified/launcher_generator.cmake | 6 ++++++ Code/Legacy/CrySystem/XConsole.cpp | 5 ----- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/Code/LauncherUnified/launcher_generator.cmake b/Code/LauncherUnified/launcher_generator.cmake index 5c9ee68e27..550a67bc49 100644 --- a/Code/LauncherUnified/launcher_generator.cmake +++ b/Code/LauncherUnified/launcher_generator.cmake @@ -76,6 +76,12 @@ foreach(project_name project_path IN ZIP_LISTS LY_PROJECTS_TARGET_NAME LY_PROJEC Legacy::CrySystem ) + if(PAL_TRAIT_BUILD_SERVER_SUPPORTED) + set(server_runtime_dependencies + Legacy::CrySystem + ) + endif() + endif() ################################################################################ diff --git a/Code/Legacy/CrySystem/XConsole.cpp b/Code/Legacy/CrySystem/XConsole.cpp index 9f60a9dd8d..22c61d3f22 100644 --- a/Code/Legacy/CrySystem/XConsole.cpp +++ b/Code/Legacy/CrySystem/XConsole.cpp @@ -333,11 +333,6 @@ void CXConsole::Init(ISystem* pSystem) m_nLoadingBackTexID = -1; - if (gEnv->IsDedicated()) - { - m_bConsoleActive = true; - } - REGISTER_COMMAND("ConsoleShow", &ConsoleShow, VF_NULL, "Opens the console"); REGISTER_COMMAND("ConsoleHide", &ConsoleHide, VF_NULL, "Closes the console"); From d484d358d166e5f82eab109f6670b4129b03bf8b Mon Sep 17 00:00:00 2001 From: "rgba16f [Amazon]" <82187279+rgba16f@users.noreply.github.com> Date: Fri, 5 Nov 2021 14:00:40 -0500 Subject: [PATCH 24/53] Modify AtomDebugDisplayViewportInterface::DrawWireCircle2d to account for viewport aspect ratio (#5375) Signed-off-by: rgba16f <82187279+rgba16f@users.noreply.github.com> --- .../Code/Source/AtomDebugDisplayViewportInterface.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Gems/AtomLyIntegration/AtomBridge/Code/Source/AtomDebugDisplayViewportInterface.cpp b/Gems/AtomLyIntegration/AtomBridge/Code/Source/AtomDebugDisplayViewportInterface.cpp index 39d8933863..1ccc36ab4d 100644 --- a/Gems/AtomLyIntegration/AtomBridge/Code/Source/AtomDebugDisplayViewportInterface.cpp +++ b/Gems/AtomLyIntegration/AtomBridge/Code/Source/AtomDebugDisplayViewportInterface.cpp @@ -800,7 +800,8 @@ namespace AZ::AtomBridge const float startAngle = DegToRad(startAngleDegrees); const float stopAngle = DegToRad(sweepAngleDegrees) + startAngle; SingleColorDynamicSizeLineHelper lines(1+static_cast(sweepAngleDegrees/angularStepDegrees)); - AZ::Vector3 radiusV3 = AZ::Vector3(radius); + float aspectRadius = radius / GetAspectRatio(); + AZ::Vector3 radiusV3 = AZ::Vector3(aspectRadius, radius, radius); AZ::Vector3 pos = AZ::Vector3(center.GetX(), center.GetY(), z); CreateAxisAlignedArc( lines, From 139915990849e2297ddff0194cc6d8a439cd0cfc Mon Sep 17 00:00:00 2001 From: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Date: Fri, 5 Nov 2021 14:39:11 -0500 Subject: [PATCH 25/53] Fix Assert Absorber being leaked due to one of the tests setting m_errorAbsorber to nullptr without deleting the object (#5176) (#5348) Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> (cherry picked from commit 916fb413c93f92d3c4aea46dac4d7908b48a10fa) --- .../AssetProcessor/native/tests/AssetProcessorTest.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Code/Tools/AssetProcessor/native/tests/AssetProcessorTest.h b/Code/Tools/AssetProcessor/native/tests/AssetProcessorTest.h index 719b04610c..8f26155fd3 100644 --- a/Code/Tools/AssetProcessor/native/tests/AssetProcessorTest.h +++ b/Code/Tools/AssetProcessor/native/tests/AssetProcessorTest.h @@ -25,7 +25,7 @@ namespace AssetProcessor : public ::testing::Test { protected: - UnitTestUtils::AssertAbsorber* m_errorAbsorber; + AZStd::unique_ptr m_errorAbsorber{}; FileStatePassthrough m_fileStateCache; void SetUp() override @@ -40,7 +40,7 @@ namespace AssetProcessor m_ownsSysAllocator = true; AZ::AllocatorInstance::Create(); } - m_errorAbsorber = new UnitTestUtils::AssertAbsorber(); + m_errorAbsorber = AZStd::make_unique(); m_application = AZStd::make_unique(); @@ -62,8 +62,8 @@ namespace AssetProcessor AssetUtilities::ResetAssetRoot(); m_application.reset(); - delete m_errorAbsorber; - m_errorAbsorber = nullptr; + m_errorAbsorber.reset(); + if (m_ownsSysAllocator) { AZ::AllocatorInstance::Destroy(); From 060c2178522e0c9a5d3664370593a43ec81a17b6 Mon Sep 17 00:00:00 2001 From: Jonny Gallowy Date: Fri, 5 Nov 2021 15:00:35 -0500 Subject: [PATCH 26/53] Fixed .bat chain for launching maya for AtomContent gems Signed-off-by: Jonny Gallowy --- .../ReferenceMaterials/Tools/Launch_Cmd.bat | 9 +++-- .../ReferenceMaterials/Tools/Launch_Maya.bat | 11 +++---- .../ReferenceMaterials/Tools/Project_Env.bat | 33 +++++++++---------- Gems/AtomContent/Sponza/Tools/Launch_Cmd.bat | 7 ++-- Gems/AtomContent/Sponza/Tools/Launch_Maya.bat | 8 +++-- Gems/AtomContent/Sponza/Tools/Project_Env.bat | 33 +++++++++---------- .../Tools/Dev/Windows/Env_Maya.bat | 2 +- 7 files changed, 48 insertions(+), 55 deletions(-) diff --git a/Gems/AtomContent/ReferenceMaterials/Tools/Launch_Cmd.bat b/Gems/AtomContent/ReferenceMaterials/Tools/Launch_Cmd.bat index d100c9ddc7..0b94be5bea 100644 --- a/Gems/AtomContent/ReferenceMaterials/Tools/Launch_Cmd.bat +++ b/Gems/AtomContent/ReferenceMaterials/Tools/Launch_Cmd.bat @@ -1,4 +1,6 @@ @echo off +:: Keep changes local +SETLOCAL enableDelayedExpansion REM REM Copyright (c) Contributors to the Open 3D Engine Project @@ -13,7 +15,7 @@ REM :: Puts you in the CMD within the dev environment :: Set up window -TITLE O3DE Asset Gem Cmd +TITLE O3DE DCC Scripting Interface Cmd :: Use obvious color to prevent confusion (Grey with Yellow Text) COLOR 8E @@ -21,15 +23,12 @@ COLOR 8E cd %~dp0 PUSHD %~dp0 -:: Keep changes local -SETLOCAL enableDelayedExpansion - CALL %~dp0\Project_Env.bat echo. echo _____________________________________________________________________ echo. -echo ~ O3DE Asset Gem CMD ... +echo ~ O3DE %O3DE_PROJECT% Asset Gem CMD ... echo _____________________________________________________________________ echo. diff --git a/Gems/AtomContent/ReferenceMaterials/Tools/Launch_Maya.bat b/Gems/AtomContent/ReferenceMaterials/Tools/Launch_Maya.bat index b9a6b399f3..c0f5f589d7 100644 --- a/Gems/AtomContent/ReferenceMaterials/Tools/Launch_Maya.bat +++ b/Gems/AtomContent/ReferenceMaterials/Tools/Launch_Maya.bat @@ -1,6 +1,3 @@ -:: Launches maya wityh a bunch of local hooks for Lumberyard -:: ToDo: move all of this to a .json data driven boostrapping system - @echo off REM @@ -37,7 +34,7 @@ echo DCCSI_MAYA_VERSION = %DCCSI_MAYA_VERSION% IF EXIST "%~dp0Project_Env.bat" CALL %~dp0Project_Env.bat echo ________________________________ -echo Launching Maya %DCCSI_MAYA_VERSION% for Lumberyard... +echo Launching Maya %DCCSI_MAYA_VERSION% for O3DE: %O#DE_PROJECT%... :::: Set Maya native project acess to this project ::set MAYA_PROJECT=%LY_PROJECT% @@ -47,8 +44,10 @@ echo Launching Maya %DCCSI_MAYA_VERSION% for Lumberyard... Set MAYA_VP2_DEVICE_OVERRIDE = VirtualDeviceDx11 :: Default to the right version of Maya if we can detect it... and launch -IF EXIST "%MAYA_LOCATION%\bin\Maya.exe" ( - start "" "%MAYA_LOCATION%\bin\Maya.exe" %* +echo MAYA_BIN_PATH = %MAYA_BIN_PATH% + +IF EXIST "%MAYA_BIN_PATH%\Maya.exe" ( + start "" "%MAYA_BIN_PATH%\Maya.exe" %* ) ELSE ( Where maya.exe 2> NUL IF ERRORLEVEL 1 ( diff --git a/Gems/AtomContent/ReferenceMaterials/Tools/Project_Env.bat b/Gems/AtomContent/ReferenceMaterials/Tools/Project_Env.bat index 6e2c8b5914..134e238384 100644 --- a/Gems/AtomContent/ReferenceMaterials/Tools/Project_Env.bat +++ b/Gems/AtomContent/ReferenceMaterials/Tools/Project_Env.bat @@ -29,23 +29,23 @@ PUSHD %~dp0 set ABS_PATH=%~dp0 :: project name as a str tag -IF "%LY_PROJECT_NAME%"=="" ( - for %%I in ("%~dp0.") do for %%J in ("%%~dpI.") do set LY_PROJECT_NAME=%%~nxJ +IF "%O3DE_PROJECT%"=="" ( + for %%I in ("%~dp0.") do for %%J in ("%%~dpI.") do set O3DE_PROJECT=%%~nxJ ) echo. echo _____________________________________________________________________ echo. -echo ~ Setting up O3DE %LY_PROJECT_NAME% Environment ... +echo ~ Setting up O3DE %O3DE_PROJECT% Environment ... echo _____________________________________________________________________ echo. -echo LY_PROJECT_NAME = %LY_PROJECT_NAME% +echo O3DE_PROJECT = %O3DE_PROJECT% :: if the user has set up a custom env call it :: this should allow the user to locally -:: set env hooks like LY_DEV or LY_PROJECT +:: set env hooks like O3DE_DEV or O3DE_PROJECT_PATH IF EXIST "%~dp0User_Env.bat" CALL %~dp0User_Env.bat -echo LY_DEV = %LY_DEV% +echo O3DE_DEV = %O3DE_DEV% :: Constant Vars (Global) :: global debug flag (propogates) @@ -74,23 +74,20 @@ echo DCCSI_LOGLEVEL = %DCCSI_LOGLEVEL% IF "%DCCSI_MAYA_VERSION%"=="" (set DCCSI_MAYA_VERSION=2020) echo DCCSI_MAYA_VERSION = %DCCSI_MAYA_VERSION% -:: LY_PROJECT is ideally treated as a full path in the env launchers +:: O3DE_PROJECT_PATH is ideally treated as a full path in the env launchers :: do to changes in o3de, external engine/project/gem folder structures, etc. -IF "%LY_PROJECT%"=="" ( - for %%i in ("%~dp0..") do set "LY_PROJECT=%%~fi" +IF "%O3DE_PROJECT_PATH%"=="" ( + for %%i in ("%~dp0..") do set "O3DE_PROJECT_PATH=%%~fi" ) -echo LY_PROJECT = %LY_PROJECT% - -:: this is here for archaic reasons, WILL DEPRECATE -IF "%LY_PROJECT_PATH%"=="" (set LY_PROJECT_PATH=%LY_PROJECT%) -echo LY_PROJECT_PATH = %LY_PROJECT_PATH% +echo O3DE_PROJECT_PATH = %O3DE_PROJECT_PATH% :: Change to root Lumberyard dev dir -:: You must set this in a User_Env.bat to match youe engine repo location! -IF "%LY_DEV%"=="" (set LY_DEV=C:\Depot\o3de-engine) -echo LY_DEV = %LY_DEV% +IF "%O3DE_DEV%"=="" echo ~ You must set O3DE_DEV in a User_Env.bat to match your local engine repo! +IF "%O3DE_DEV%"=="" echo ~ Using default O3DE_DEV=C:\Depot\o3de-engine +IF "%O3DE_DEV%"=="" (set O3DE_DEV=C:\Depot\o3de-engine) +echo O3DE_DEV = %O3DE_DEV% -CALL %LY_DEV%\Gems\AtomLyIntegration\TechnicalArt\DccScriptingInterface\Launchers\Windows\Env_Maya.bat +CALL %O3DE_DEV%\Gems\AtomLyIntegration\TechnicalArt\DccScriptingInterface\Tools\Dev\Windows\Env_Maya.bat :: Restore original directory popd diff --git a/Gems/AtomContent/Sponza/Tools/Launch_Cmd.bat b/Gems/AtomContent/Sponza/Tools/Launch_Cmd.bat index 99c2c12c51..0b94be5bea 100644 --- a/Gems/AtomContent/Sponza/Tools/Launch_Cmd.bat +++ b/Gems/AtomContent/Sponza/Tools/Launch_Cmd.bat @@ -1,4 +1,6 @@ @echo off +:: Keep changes local +SETLOCAL enableDelayedExpansion REM REM Copyright (c) Contributors to the Open 3D Engine Project @@ -21,15 +23,12 @@ COLOR 8E cd %~dp0 PUSHD %~dp0 -:: Keep changes local -SETLOCAL enableDelayedExpansion - CALL %~dp0\Project_Env.bat echo. echo _____________________________________________________________________ echo. -echo ~ LY DCC Scripting Interface CMD ... +echo ~ O3DE %O3DE_PROJECT% Asset Gem CMD ... echo _____________________________________________________________________ echo. diff --git a/Gems/AtomContent/Sponza/Tools/Launch_Maya.bat b/Gems/AtomContent/Sponza/Tools/Launch_Maya.bat index d774adf79b..c0f5f589d7 100644 --- a/Gems/AtomContent/Sponza/Tools/Launch_Maya.bat +++ b/Gems/AtomContent/Sponza/Tools/Launch_Maya.bat @@ -34,7 +34,7 @@ echo DCCSI_MAYA_VERSION = %DCCSI_MAYA_VERSION% IF EXIST "%~dp0Project_Env.bat" CALL %~dp0Project_Env.bat echo ________________________________ -echo Launching Maya %DCCSI_MAYA_VERSION% for Lumberyard... +echo Launching Maya %DCCSI_MAYA_VERSION% for O3DE: %O#DE_PROJECT%... :::: Set Maya native project acess to this project ::set MAYA_PROJECT=%LY_PROJECT% @@ -44,8 +44,10 @@ echo Launching Maya %DCCSI_MAYA_VERSION% for Lumberyard... Set MAYA_VP2_DEVICE_OVERRIDE = VirtualDeviceDx11 :: Default to the right version of Maya if we can detect it... and launch -IF EXIST "%MAYA_LOCATION%\bin\Maya.exe" ( - start "" "%MAYA_LOCATION%\bin\Maya.exe" %* +echo MAYA_BIN_PATH = %MAYA_BIN_PATH% + +IF EXIST "%MAYA_BIN_PATH%\Maya.exe" ( + start "" "%MAYA_BIN_PATH%\Maya.exe" %* ) ELSE ( Where maya.exe 2> NUL IF ERRORLEVEL 1 ( diff --git a/Gems/AtomContent/Sponza/Tools/Project_Env.bat b/Gems/AtomContent/Sponza/Tools/Project_Env.bat index 6e2c8b5914..134e238384 100644 --- a/Gems/AtomContent/Sponza/Tools/Project_Env.bat +++ b/Gems/AtomContent/Sponza/Tools/Project_Env.bat @@ -29,23 +29,23 @@ PUSHD %~dp0 set ABS_PATH=%~dp0 :: project name as a str tag -IF "%LY_PROJECT_NAME%"=="" ( - for %%I in ("%~dp0.") do for %%J in ("%%~dpI.") do set LY_PROJECT_NAME=%%~nxJ +IF "%O3DE_PROJECT%"=="" ( + for %%I in ("%~dp0.") do for %%J in ("%%~dpI.") do set O3DE_PROJECT=%%~nxJ ) echo. echo _____________________________________________________________________ echo. -echo ~ Setting up O3DE %LY_PROJECT_NAME% Environment ... +echo ~ Setting up O3DE %O3DE_PROJECT% Environment ... echo _____________________________________________________________________ echo. -echo LY_PROJECT_NAME = %LY_PROJECT_NAME% +echo O3DE_PROJECT = %O3DE_PROJECT% :: if the user has set up a custom env call it :: this should allow the user to locally -:: set env hooks like LY_DEV or LY_PROJECT +:: set env hooks like O3DE_DEV or O3DE_PROJECT_PATH IF EXIST "%~dp0User_Env.bat" CALL %~dp0User_Env.bat -echo LY_DEV = %LY_DEV% +echo O3DE_DEV = %O3DE_DEV% :: Constant Vars (Global) :: global debug flag (propogates) @@ -74,23 +74,20 @@ echo DCCSI_LOGLEVEL = %DCCSI_LOGLEVEL% IF "%DCCSI_MAYA_VERSION%"=="" (set DCCSI_MAYA_VERSION=2020) echo DCCSI_MAYA_VERSION = %DCCSI_MAYA_VERSION% -:: LY_PROJECT is ideally treated as a full path in the env launchers +:: O3DE_PROJECT_PATH is ideally treated as a full path in the env launchers :: do to changes in o3de, external engine/project/gem folder structures, etc. -IF "%LY_PROJECT%"=="" ( - for %%i in ("%~dp0..") do set "LY_PROJECT=%%~fi" +IF "%O3DE_PROJECT_PATH%"=="" ( + for %%i in ("%~dp0..") do set "O3DE_PROJECT_PATH=%%~fi" ) -echo LY_PROJECT = %LY_PROJECT% - -:: this is here for archaic reasons, WILL DEPRECATE -IF "%LY_PROJECT_PATH%"=="" (set LY_PROJECT_PATH=%LY_PROJECT%) -echo LY_PROJECT_PATH = %LY_PROJECT_PATH% +echo O3DE_PROJECT_PATH = %O3DE_PROJECT_PATH% :: Change to root Lumberyard dev dir -:: You must set this in a User_Env.bat to match youe engine repo location! -IF "%LY_DEV%"=="" (set LY_DEV=C:\Depot\o3de-engine) -echo LY_DEV = %LY_DEV% +IF "%O3DE_DEV%"=="" echo ~ You must set O3DE_DEV in a User_Env.bat to match your local engine repo! +IF "%O3DE_DEV%"=="" echo ~ Using default O3DE_DEV=C:\Depot\o3de-engine +IF "%O3DE_DEV%"=="" (set O3DE_DEV=C:\Depot\o3de-engine) +echo O3DE_DEV = %O3DE_DEV% -CALL %LY_DEV%\Gems\AtomLyIntegration\TechnicalArt\DccScriptingInterface\Launchers\Windows\Env_Maya.bat +CALL %O3DE_DEV%\Gems\AtomLyIntegration\TechnicalArt\DccScriptingInterface\Tools\Dev\Windows\Env_Maya.bat :: Restore original directory popd diff --git a/Gems/AtomLyIntegration/TechnicalArt/DccScriptingInterface/Tools/Dev/Windows/Env_Maya.bat b/Gems/AtomLyIntegration/TechnicalArt/DccScriptingInterface/Tools/Dev/Windows/Env_Maya.bat index 5e3c600124..0ed46e9400 100644 --- a/Gems/AtomLyIntegration/TechnicalArt/DccScriptingInterface/Tools/Dev/Windows/Env_Maya.bat +++ b/Gems/AtomLyIntegration/TechnicalArt/DccScriptingInterface/Tools/Dev/Windows/Env_Maya.bat @@ -46,7 +46,7 @@ echo DCCSI_PY_VERSION_RELEASE = %DCCSI_PY_VERSION_RELEASE% echo DCCSI_MAYA_VERSION = %DCCSI_MAYA_VERSION% :::: Set Maya native project acess to this project -IF "%MAYA_PROJECT%"=="" (set MAYA_PROJECT=%O3DE_PROJECT%) +IF "%MAYA_PROJECT%"=="" (set MAYA_PROJECT=%O3DE_PROJECT_PATH%) echo MAYA_PROJECT = %MAYA_PROJECT% :: maya sdk path From a2efc587ccbfee147e562348082386cfbe852d44 Mon Sep 17 00:00:00 2001 From: Ken Pruiksma Date: Fri, 5 Nov 2021 15:31:31 -0500 Subject: [PATCH 27/53] Rendered World Size in the Terrain World Render component set to invisible (#5378) It's not currently hooked up, so setting invisible for now until it does something. Signed-off-by: Ken Pruiksma --- .../Code/Source/Components/TerrainWorldRendererComponent.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/Gems/Terrain/Code/Source/Components/TerrainWorldRendererComponent.cpp b/Gems/Terrain/Code/Source/Components/TerrainWorldRendererComponent.cpp index 9cd9ce9fb2..5afaedc517 100644 --- a/Gems/Terrain/Code/Source/Components/TerrainWorldRendererComponent.cpp +++ b/Gems/Terrain/Code/Source/Components/TerrainWorldRendererComponent.cpp @@ -46,6 +46,7 @@ namespace Terrain ->EnumAttribute(TerrainWorldRendererConfig::WorldSize::_4096Meters, "4 Kilometers") ->EnumAttribute(TerrainWorldRendererConfig::WorldSize::_8192Meters, "8 Kilometers") ->EnumAttribute(TerrainWorldRendererConfig::WorldSize::_16384Meters, "16 Kilometers") + ->Attribute(AZ::Edit::Attributes::Visibility, false) // Keeping invisible until it's hooked up under the hood ; } } From 7d1e1474b5075e70064db25d22cce15509bddf22 Mon Sep 17 00:00:00 2001 From: Jonny Gallowy Date: Fri, 5 Nov 2021 15:50:54 -0500 Subject: [PATCH 28/53] fixed typo Signed-off-by: Jonny Gallowy --- Gems/AtomContent/ReferenceMaterials/Tools/Launch_Maya.bat | 2 +- Gems/AtomContent/Sponza/Tools/Launch_Maya.bat | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Gems/AtomContent/ReferenceMaterials/Tools/Launch_Maya.bat b/Gems/AtomContent/ReferenceMaterials/Tools/Launch_Maya.bat index c0f5f589d7..0af25905a0 100644 --- a/Gems/AtomContent/ReferenceMaterials/Tools/Launch_Maya.bat +++ b/Gems/AtomContent/ReferenceMaterials/Tools/Launch_Maya.bat @@ -34,7 +34,7 @@ echo DCCSI_MAYA_VERSION = %DCCSI_MAYA_VERSION% IF EXIST "%~dp0Project_Env.bat" CALL %~dp0Project_Env.bat echo ________________________________ -echo Launching Maya %DCCSI_MAYA_VERSION% for O3DE: %O#DE_PROJECT%... +echo Launching Maya %DCCSI_MAYA_VERSION% for O3DE: %O3DE_PROJECT%... :::: Set Maya native project acess to this project ::set MAYA_PROJECT=%LY_PROJECT% diff --git a/Gems/AtomContent/Sponza/Tools/Launch_Maya.bat b/Gems/AtomContent/Sponza/Tools/Launch_Maya.bat index c0f5f589d7..0af25905a0 100644 --- a/Gems/AtomContent/Sponza/Tools/Launch_Maya.bat +++ b/Gems/AtomContent/Sponza/Tools/Launch_Maya.bat @@ -34,7 +34,7 @@ echo DCCSI_MAYA_VERSION = %DCCSI_MAYA_VERSION% IF EXIST "%~dp0Project_Env.bat" CALL %~dp0Project_Env.bat echo ________________________________ -echo Launching Maya %DCCSI_MAYA_VERSION% for O3DE: %O#DE_PROJECT%... +echo Launching Maya %DCCSI_MAYA_VERSION% for O3DE: %O3DE_PROJECT%... :::: Set Maya native project acess to this project ::set MAYA_PROJECT=%LY_PROJECT% From 5138170d8c037104b50b65dc15e116ef55528b2c Mon Sep 17 00:00:00 2001 From: Jonny Gallowy Date: Fri, 5 Nov 2021 15:54:57 -0500 Subject: [PATCH 29/53] fixed typo Signed-off-by: Jonny Gallowy --- Gems/AtomContent/ReferenceMaterials/Tools/Project_Env.bat | 2 +- Gems/AtomContent/Sponza/Tools/Project_Env.bat | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Gems/AtomContent/ReferenceMaterials/Tools/Project_Env.bat b/Gems/AtomContent/ReferenceMaterials/Tools/Project_Env.bat index 134e238384..ddf934d206 100644 --- a/Gems/AtomContent/ReferenceMaterials/Tools/Project_Env.bat +++ b/Gems/AtomContent/ReferenceMaterials/Tools/Project_Env.bat @@ -81,7 +81,7 @@ IF "%O3DE_PROJECT_PATH%"=="" ( ) echo O3DE_PROJECT_PATH = %O3DE_PROJECT_PATH% -:: Change to root Lumberyard dev dir +:: Change to root O3DE dev dir IF "%O3DE_DEV%"=="" echo ~ You must set O3DE_DEV in a User_Env.bat to match your local engine repo! IF "%O3DE_DEV%"=="" echo ~ Using default O3DE_DEV=C:\Depot\o3de-engine IF "%O3DE_DEV%"=="" (set O3DE_DEV=C:\Depot\o3de-engine) diff --git a/Gems/AtomContent/Sponza/Tools/Project_Env.bat b/Gems/AtomContent/Sponza/Tools/Project_Env.bat index 134e238384..ddf934d206 100644 --- a/Gems/AtomContent/Sponza/Tools/Project_Env.bat +++ b/Gems/AtomContent/Sponza/Tools/Project_Env.bat @@ -81,7 +81,7 @@ IF "%O3DE_PROJECT_PATH%"=="" ( ) echo O3DE_PROJECT_PATH = %O3DE_PROJECT_PATH% -:: Change to root Lumberyard dev dir +:: Change to root O3DE dev dir IF "%O3DE_DEV%"=="" echo ~ You must set O3DE_DEV in a User_Env.bat to match your local engine repo! IF "%O3DE_DEV%"=="" echo ~ Using default O3DE_DEV=C:\Depot\o3de-engine IF "%O3DE_DEV%"=="" (set O3DE_DEV=C:\Depot\o3de-engine) From 4ce39ea1675e6ba2b102bef02e4226f5b99ed081 Mon Sep 17 00:00:00 2001 From: Alex Peterson <26804013+AMZN-alexpete@users.noreply.github.com> Date: Fri, 5 Nov 2021 17:17:11 -0700 Subject: [PATCH 30/53] Fix tags, downloads, and several vector copies Signed-off-by: Alex Peterson <26804013+AMZN-alexpete@users.noreply.github.com> --- .../Source/CreateProjectCtrl.cpp | 12 +-- .../Source/DownloadController.cpp | 3 +- .../Source/DownloadController.h | 2 +- .../GemCatalog/GemCatalogHeaderWidget.cpp | 24 +++--- .../GemCatalog/GemCatalogHeaderWidget.h | 2 +- .../Source/GemCatalog/GemCatalogScreen.cpp | 78 +++++++++++++++---- .../Source/GemCatalog/GemCatalogScreen.h | 4 +- .../Source/GemCatalog/GemInspector.cpp | 8 +- .../Source/GemCatalog/GemInspector.h | 2 +- .../Source/GemCatalog/GemModel.cpp | 32 ++++---- .../Source/GemCatalog/GemModel.h | 4 +- .../Source/GemRepo/GemRepoInspector.cpp | 2 +- .../Source/GemRepo/GemRepoModel.cpp | 12 +-- .../Source/GemRepo/GemRepoModel.h | 2 +- .../ProjectManager/Source/GemsSubWidget.cpp | 6 +- .../ProjectManager/Source/GemsSubWidget.h | 4 +- .../Tools/ProjectManager/Source/TagWidget.cpp | 39 +++++++--- Code/Tools/ProjectManager/Source/TagWidget.h | 22 +++++- .../Source/UpdateProjectCtrl.cpp | 3 +- .../ProjectManager/Source/UpdateProjectCtrl.h | 1 + 20 files changed, 171 insertions(+), 91 deletions(-) diff --git a/Code/Tools/ProjectManager/Source/CreateProjectCtrl.cpp b/Code/Tools/ProjectManager/Source/CreateProjectCtrl.cpp index 1aad4a7206..6b19e839d7 100644 --- a/Code/Tools/ProjectManager/Source/CreateProjectCtrl.cpp +++ b/Code/Tools/ProjectManager/Source/CreateProjectCtrl.cpp @@ -55,11 +55,7 @@ namespace O3DE::ProjectManager vLayout->addWidget(m_stack); connect(m_gemCatalogScreen, &ScreenWidget::ChangeScreenRequest, this, &CreateProjectCtrl::OnChangeScreenRequest); - connect(m_gemRepoScreen, &GemRepoScreen::OnRefresh, [this]() - { - const QString projectTemplatePath = m_newProjectSettingsScreen->GetProjectTemplatePath(); - m_gemCatalogScreen->Refresh(projectTemplatePath + "/Template"); - }); + connect(m_gemRepoScreen, &GemRepoScreen::OnRefresh, m_gemCatalogScreen, &GemCatalogScreen::Refresh); // When there are multiple project templates present, we re-gather the gems when changing the selected the project template. connect(m_newProjectSettingsScreen, &NewProjectSettingsScreen::OnTemplateSelectionChanged, this, [=](int oldIndex, [[maybe_unused]] int newIndex) @@ -257,6 +253,12 @@ namespace O3DE::ProjectManager { if (m_newProjectSettingsScreen->Validate()) { + if (!m_gemCatalogScreen->GetDownloadController()->IsDownloadQueueEmpty()) + { + QMessageBox::critical(this, tr("Gems downloading"), tr("You must wait for gems to finish downloading before continuing.")); + return; + } + ProjectInfo projectInfo = m_newProjectSettingsScreen->GetProjectInfo(); QString projectTemplatePath = m_newProjectSettingsScreen->GetProjectTemplatePath(); diff --git a/Code/Tools/ProjectManager/Source/DownloadController.cpp b/Code/Tools/ProjectManager/Source/DownloadController.cpp index 224b90299c..a8eecffd78 100644 --- a/Code/Tools/ProjectManager/Source/DownloadController.cpp +++ b/Code/Tools/ProjectManager/Source/DownloadController.cpp @@ -82,8 +82,9 @@ namespace O3DE::ProjectManager succeeded = false; } + const QString gemName = m_gemNames[0]; m_gemNames.erase(m_gemNames.begin()); - emit Done(succeeded); + emit Done(succeeded, gemName); if (!m_gemNames.empty()) { diff --git a/Code/Tools/ProjectManager/Source/DownloadController.h b/Code/Tools/ProjectManager/Source/DownloadController.h index 11ceaacddb..8afe8ef029 100644 --- a/Code/Tools/ProjectManager/Source/DownloadController.h +++ b/Code/Tools/ProjectManager/Source/DownloadController.h @@ -58,7 +58,7 @@ namespace O3DE::ProjectManager signals: void StartGemDownload(const QString& gemName); - void Done(bool success = true); + void Done(bool success, const QString& gemName); void GemDownloadProgress(int percentage); private: diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogHeaderWidget.cpp b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogHeaderWidget.cpp index 5d65c740af..0db2b088c1 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogHeaderWidget.cpp +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogHeaderWidget.cpp @@ -145,7 +145,7 @@ namespace O3DE::ProjectManager } else { - tagContainer->Update(ConvertFromModelIndices(tagIndices)); + tagContainer->Update(GetTagsFromModelIndices(tagIndices)); label->setText(QString("%1 %2").arg(tagIndices.size()).arg(tagIndices.size() == 1 ? singularTitle : pluralTitle)); widget->show(); } @@ -234,17 +234,23 @@ namespace O3DE::ProjectManager for (int downloadingGemNumber = 0; downloadingGemNumber < downloadQueue.size(); ++downloadingGemNumber) { QHBoxLayout* nameProgressLayout = new QHBoxLayout(); - TagWidget* newTag = new TagWidget(downloadQueue[downloadingGemNumber]); + + const QString& gemName = downloadQueue[downloadingGemNumber]; + TagWidget* newTag = new TagWidget({gemName, gemName}); nameProgressLayout->addWidget(newTag); + QLabel* progress = new QLabel(downloadingGemNumber == 0? QString("%1%").arg(downloadProgress) : tr("Queued")); nameProgressLayout->addWidget(progress); + QSpacerItem* spacer = new QSpacerItem(0, 0, QSizePolicy::Expanding, QSizePolicy::Minimum); nameProgressLayout->addSpacerItem(spacer); - QLabel* cancelText = new QLabel(QString("Cancel").arg(downloadQueue[downloadingGemNumber])); + + QLabel* cancelText = new QLabel(QString("Cancel")); cancelText->setTextInteractionFlags(Qt::LinksAccessibleByMouse); connect(cancelText, &QLabel::linkActivated, this, &CartOverlayWidget::OnCancelDownloadActivated); nameProgressLayout->addWidget(cancelText); downloadingItemLayout->addLayout(nameProgressLayout); + QProgressBar* downloadProgessBar = new QProgressBar(); downloadingItemLayout->addWidget(downloadProgessBar); downloadProgessBar->setValue(downloadingGemNumber == 0 ? downloadProgress : 0); @@ -255,7 +261,7 @@ namespace O3DE::ProjectManager } }; - auto downloadEnded = [=](bool /*success*/) + auto downloadEnded = [=](bool /*success*/, const QString& /*gemName*/) { update(0); // update the list to remove the gem that has finished }; @@ -265,15 +271,15 @@ namespace O3DE::ProjectManager update(0); } - QStringList CartOverlayWidget::ConvertFromModelIndices(const QVector& gems) const + QVector CartOverlayWidget::GetTagsFromModelIndices(const QVector& gems) const { - QStringList gemNames; - gemNames.reserve(gems.size()); + QVector tags; + tags.reserve(gems.size()); for (const QModelIndex& modelIndex : gems) { - gemNames.push_back(GemModel::GetDisplayName(modelIndex)); + tags.push_back({ GemModel::GetDisplayName(modelIndex), GemModel::GetName(modelIndex) }); } - return gemNames; + return tags; } CartButton::CartButton(GemModel* gemModel, DownloadController* downloadController, QWidget* parent) diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogHeaderWidget.h b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogHeaderWidget.h index 4d17259840..6da78cce7a 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogHeaderWidget.h +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogHeaderWidget.h @@ -36,7 +36,7 @@ namespace O3DE::ProjectManager CartOverlayWidget(GemModel* gemModel, DownloadController* downloadController, QWidget* parent = nullptr); private: - QStringList ConvertFromModelIndices(const QVector& gems) const; + QVector GetTagsFromModelIndices(const QVector& gems) const; using GetTagIndicesCallback = AZStd::function()>; void CreateGemSection(const QString& singularTitle, const QString& pluralTitle, GetTagIndicesCallback getTagIndices); diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp index 4574e8509b..b0e4fa73e1 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp @@ -49,6 +49,7 @@ namespace O3DE::ProjectManager connect(m_gemModel, &GemModel::gemStatusChanged, this, &GemCatalogScreen::OnGemStatusChanged); connect(m_headerWidget, &GemCatalogHeaderWidget::OpenGemsRepo, this, &GemCatalogScreen::HandleOpenGemRepo); connect(m_headerWidget, &GemCatalogHeaderWidget::AddGem, this, &GemCatalogScreen::OnAddGemClicked); + connect(m_downloadController, &DownloadController::Done, this, &GemCatalogScreen::OnGemDownloadResult); QHBoxLayout* hLayout = new QHBoxLayout(); hLayout->setMargin(0); @@ -58,7 +59,7 @@ namespace O3DE::ProjectManager m_gemInspector = new GemInspector(m_gemModel, this); m_gemInspector->setFixedWidth(240); - connect(m_gemInspector, &GemInspector::TagClicked, this, &GemCatalogScreen::SelectGem); + connect(m_gemInspector, &GemInspector::TagClicked, [=](const Tag& tag) { SelectGem(tag.id); }); QWidget* filterWidget = new QWidget(this); filterWidget->setFixedWidth(240); @@ -86,6 +87,7 @@ namespace O3DE::ProjectManager void GemCatalogScreen::ReinitForProject(const QString& projectPath) { + m_projectPath = projectPath; m_gemModel->Clear(); m_gemsToRegisterWithProject.clear(); FillModel(projectPath); @@ -155,15 +157,15 @@ namespace O3DE::ProjectManager } } - void GemCatalogScreen::Refresh(const QString& projectPath) + void GemCatalogScreen::Refresh() { QHash gemInfoHash; // create a hash with the gem name as key - AZ::Outcome, AZStd::string> allGemInfosResult = PythonBindingsInterface::Get()->GetAllGemInfos(projectPath); + const AZ::Outcome, AZStd::string>& allGemInfosResult = PythonBindingsInterface::Get()->GetAllGemInfos(m_projectPath); if (allGemInfosResult.IsSuccess()) { - QVector gemInfos = allGemInfosResult.GetValue(); + const QVector& gemInfos = allGemInfosResult.GetValue(); for (const GemInfo& gemInfo : gemInfos) { gemInfoHash.insert(gemInfo.m_name, gemInfo); @@ -171,10 +173,10 @@ namespace O3DE::ProjectManager } // add all the gem repos into the hash - AZ::Outcome, AZStd::string> allRepoGemInfosResult = PythonBindingsInterface::Get()->GetAllGemRepoGemsInfos(); + const AZ::Outcome, AZStd::string>& allRepoGemInfosResult = PythonBindingsInterface::Get()->GetAllGemRepoGemsInfos(); if (allRepoGemInfosResult.IsSuccess()) { - const QVector allRepoGemInfos = allRepoGemInfosResult.GetValue(); + const QVector& allRepoGemInfos = allRepoGemInfosResult.GetValue(); for (const GemInfo& gemInfo : allRepoGemInfos) { if (!gemInfoHash.contains(gemInfo.m_name)) @@ -310,20 +312,22 @@ namespace O3DE::ProjectManager void GemCatalogScreen::FillModel(const QString& projectPath) { - AZ::Outcome, AZStd::string> allGemInfosResult = PythonBindingsInterface::Get()->GetAllGemInfos(projectPath); + m_projectPath = projectPath; + + const AZ::Outcome, AZStd::string>& allGemInfosResult = PythonBindingsInterface::Get()->GetAllGemInfos(projectPath); if (allGemInfosResult.IsSuccess()) { // Add all available gems to the model. - const QVector allGemInfos = allGemInfosResult.GetValue(); + const QVector& allGemInfos = allGemInfosResult.GetValue(); for (const GemInfo& gemInfo : allGemInfos) { m_gemModel->AddGem(gemInfo); } - AZ::Outcome, AZStd::string> allRepoGemInfosResult = PythonBindingsInterface::Get()->GetAllGemRepoGemsInfos(); + const AZ::Outcome, AZStd::string>& allRepoGemInfosResult = PythonBindingsInterface::Get()->GetAllGemRepoGemsInfos(); if (allRepoGemInfosResult.IsSuccess()) { - const QVector allRepoGemInfos = allRepoGemInfosResult.GetValue(); + const QVector& allRepoGemInfos = allRepoGemInfosResult.GetValue(); for (const GemInfo& gemInfo : allRepoGemInfos) { // do not add gems that have already been downloaded @@ -342,10 +346,10 @@ namespace O3DE::ProjectManager m_notificationsEnabled = false; // Gather enabled gems for the given project. - auto enabledGemNamesResult = PythonBindingsInterface::Get()->GetEnabledGemNames(projectPath); + const auto& enabledGemNamesResult = PythonBindingsInterface::Get()->GetEnabledGemNames(projectPath); if (enabledGemNamesResult.IsSuccess()) { - const QVector enabledGemNames = enabledGemNamesResult.GetValue(); + const QVector& enabledGemNames = enabledGemNamesResult.GetValue(); for (const AZStd::string& enabledGemName : enabledGemNames) { const QModelIndex modelIndex = m_gemModel->FindIndexByNameString(enabledGemName.c_str()); @@ -405,12 +409,24 @@ namespace O3DE::ProjectManager for (const QModelIndex& modelIndex : toBeAdded) { - const QString gemPath = GemModel::GetPath(modelIndex); + const QString& gemPath = GemModel::GetPath(modelIndex); + + // make sure any remote gems we added were downloaded successfully + if (GemModel::GetGemOrigin(modelIndex) == GemInfo::Remote && GemModel::GetDownloadStatus(modelIndex) != GemInfo::Downloaded) + { + QMessageBox::critical( + nullptr, "Cannot add gem that isn't downloaded", + tr("Cannot add gem %1 to project because it isn't downloaded yet or failed to download.") + .arg(GemModel::GetDisplayName(modelIndex))); + + return EnableDisableGemsResult::Failed; + } + const AZ::Outcome result = pythonBindings->AddGemToProject(gemPath, projectPath); if (!result.IsSuccess()) { - QMessageBox::critical(nullptr, "Operation failed", - QString("Cannot add gem %1 to project.\n\nError:\n%2").arg(GemModel::GetDisplayName(modelIndex), result.GetError().c_str())); + QMessageBox::critical(nullptr, "Failed to add gem to project", + tr("Cannot add gem %1 to project.

Error:
%2").arg(GemModel::GetDisplayName(modelIndex), result.GetError().c_str())); return EnableDisableGemsResult::Failed; } @@ -428,8 +444,8 @@ namespace O3DE::ProjectManager const AZ::Outcome result = pythonBindings->RemoveGemFromProject(gemPath, projectPath); if (!result.IsSuccess()) { - QMessageBox::critical(nullptr, "Operation failed", - QString("Cannot remove gem %1 from project.\n\nError:\n%2").arg(GemModel::GetDisplayName(modelIndex), result.GetError().c_str())); + QMessageBox::critical(nullptr, "Failed to remove gem from project", + tr("Cannot remove gem %1 from project.

Error:
%2").arg(GemModel::GetDisplayName(modelIndex), result.GetError().c_str())); return EnableDisableGemsResult::Failed; } @@ -443,6 +459,34 @@ namespace O3DE::ProjectManager emit ChangeScreenRequest(ProjectManagerScreen::GemRepos); } + void GemCatalogScreen::OnGemDownloadResult(bool succeeded, const QString& gemName) + { + if (succeeded) + { + // refresh the information for downloaded gems + const AZ::Outcome, AZStd::string>& allGemInfosResult = PythonBindingsInterface::Get()->GetAllGemInfos(m_projectPath); + if (allGemInfosResult.IsSuccess()) + { + // we should find the gem name now in all gem infos + for (const GemInfo& gemInfo : allGemInfosResult.GetValue()) + { + if (gemInfo.m_name == gemName) + { + QModelIndex index = m_gemModel->FindIndexByNameString(gemName); + if (index.isValid()) + { + m_gemModel->setData(index, GemInfo::Downloaded, GemModel::RoleDownloadStatus); + m_gemModel->setData(index, gemInfo.m_path, GemModel::RolePath); + m_gemModel->setData(index, gemInfo.m_path, GemModel::RoleDirectoryLink); + } + + return; + } + } + } + } + } + ProjectManagerScreen GemCatalogScreen::GetScreenEnum() { return ProjectManagerScreen::GemCatalog; diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.h b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.h index 69ec85586d..6acf43b3eb 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.h +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.h @@ -33,7 +33,6 @@ namespace O3DE::ProjectManager ProjectManagerScreen GetScreenEnum() override; void ReinitForProject(const QString& projectPath); - void Refresh(const QString& projectPath); enum class EnableDisableGemsResult { @@ -50,6 +49,8 @@ namespace O3DE::ProjectManager void OnGemStatusChanged(const QString& gemName, uint32_t numChangedDependencies); void OnAddGemClicked(); void SelectGem(const QString& gemName); + void OnGemDownloadResult(bool succeeded, const QString& gemName); + void Refresh(); protected: void hideEvent(QHideEvent* event) override; @@ -76,5 +77,6 @@ namespace O3DE::ProjectManager DownloadController* m_downloadController = nullptr; bool m_notificationsEnabled = true; QSet m_gemsToRegisterWithProject; + QString m_projectPath = nullptr; }; } // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemInspector.cpp b/Code/Tools/ProjectManager/Source/GemCatalog/GemInspector.cpp index b0b8cca29a..afbac189ad 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemInspector.cpp +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemInspector.cpp @@ -106,10 +106,10 @@ namespace O3DE::ProjectManager } // Depending gems - QStringList dependingGems = m_model->GetDependingGemNames(modelIndex); - if (!dependingGems.isEmpty()) + const QVector& dependingGemTags = m_model->GetDependingGemTags(modelIndex); + if (!dependingGemTags.isEmpty()) { - m_dependingGems->Update(tr("Depending Gems"), tr("The following Gems will be automatically enabled with this Gem."), dependingGems); + m_dependingGems->Update(tr("Depending Gems"), tr("The following Gems will be automatically enabled with this Gem."), dependingGemTags); m_dependingGems->show(); } else @@ -222,7 +222,7 @@ namespace O3DE::ProjectManager // Depending gems m_dependingGems = new GemsSubWidget(); - connect(m_dependingGems, &GemsSubWidget::TagClicked, this, [=](const QString& tag){ emit TagClicked(tag); }); + connect(m_dependingGems, &GemsSubWidget::TagClicked, this, [=](const Tag& tag){ emit TagClicked(tag); }); m_mainLayout->addWidget(m_dependingGems); m_mainLayout->addSpacing(20); diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemInspector.h b/Code/Tools/ProjectManager/Source/GemCatalog/GemInspector.h index c6548527ab..9a6ad84dea 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemInspector.h +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemInspector.h @@ -44,7 +44,7 @@ namespace O3DE::ProjectManager inline constexpr static const char* s_textColor = "#DDDDDD"; signals: - void TagClicked(const QString& tag); + void TagClicked(const Tag& tag); private slots: void OnSelectionChanged(const QItemSelection& selected, const QItemSelection& deselected); diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.cpp b/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.cpp index 7c217db65b..88c54de0b3 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.cpp +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.cpp @@ -65,7 +65,6 @@ namespace O3DE::ProjectManager appendRow(item); const QModelIndex modelIndex = index(rowCount()-1, 0); - m_nameToIndexMap[gemInfo.m_displayName] = modelIndex; m_nameToIndexMap[gemInfo.m_name] = modelIndex; } @@ -178,18 +177,6 @@ namespace O3DE::ProjectManager return {}; } - void GemModel::FindGemDisplayNamesByNameStrings(QStringList& inOutGemNames) - { - for (QString& name : inOutGemNames) - { - QModelIndex modelIndex = FindIndexByNameString(name); - if (modelIndex.isValid()) - { - name = GetDisplayName(modelIndex); - } - } - } - QStringList GemModel::GetDependingGems(const QModelIndex& modelIndex) { return modelIndex.data(RoleDependingGems).toStringList(); @@ -209,16 +196,23 @@ namespace O3DE::ProjectManager } } - QStringList GemModel::GetDependingGemNames(const QModelIndex& modelIndex) + QVector GemModel::GetDependingGemTags(const QModelIndex& modelIndex) { - QStringList result = GetDependingGems(modelIndex); - if (result.isEmpty()) + QVector tags; + + QStringList dependingGemNames = GetDependingGems(modelIndex); + tags.reserve(dependingGemNames.size()); + + for (QString& gemName : dependingGemNames) { - return {}; + const QModelIndex& dependingIndex = FindIndexByNameString(gemName); + if (dependingIndex.isValid()) + { + tags.push_back({ GetDisplayName(dependingIndex), GetName(dependingIndex) }); + } } - FindGemDisplayNamesByNameStrings(result); - return result; + return tags; } QString GemModel::GetVersion(const QModelIndex& modelIndex) diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.h b/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.h index e548d9d3f7..e25a1c7703 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.h +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.h @@ -10,6 +10,7 @@ #if !defined(Q_MOC_RUN) #include +#include #include #include #include @@ -58,7 +59,7 @@ namespace O3DE::ProjectManager void UpdateGemDependencies(); QModelIndex FindIndexByNameString(const QString& nameString) const; - QStringList GetDependingGemNames(const QModelIndex& modelIndex); + QVector GetDependingGemTags(const QModelIndex& modelIndex); bool HasDependentGems(const QModelIndex& modelIndex) const; static QString GetName(const QModelIndex& modelIndex); @@ -113,7 +114,6 @@ namespace O3DE::ProjectManager void OnRowsAboutToBeRemoved(const QModelIndex& parent, int first, int last); private: - void FindGemDisplayNamesByNameStrings(QStringList& inOutGemNames); void GetAllDependingGems(const QModelIndex& modelIndex, QSet& inOutGems); QStringList GetDependingGems(const QModelIndex& modelIndex); diff --git a/Code/Tools/ProjectManager/Source/GemRepo/GemRepoInspector.cpp b/Code/Tools/ProjectManager/Source/GemRepo/GemRepoInspector.cpp index 6655aef86d..f816e86733 100644 --- a/Code/Tools/ProjectManager/Source/GemRepo/GemRepoInspector.cpp +++ b/Code/Tools/ProjectManager/Source/GemRepo/GemRepoInspector.cpp @@ -86,7 +86,7 @@ namespace O3DE::ProjectManager } // Included Gems - m_includedGems->Update(tr("Included Gems"), "", m_model->GetIncludedGemNames(modelIndex)); + m_includedGems->Update(tr("Included Gems"), "", m_model->GetIncludedGemTags(modelIndex)); m_mainWidget->adjustSize(); m_mainWidget->show(); diff --git a/Code/Tools/ProjectManager/Source/GemRepo/GemRepoModel.cpp b/Code/Tools/ProjectManager/Source/GemRepo/GemRepoModel.cpp index 7a9617e6c1..6189b6d8bf 100644 --- a/Code/Tools/ProjectManager/Source/GemRepo/GemRepoModel.cpp +++ b/Code/Tools/ProjectManager/Source/GemRepo/GemRepoModel.cpp @@ -103,17 +103,17 @@ namespace O3DE::ProjectManager return modelIndex.data(RoleIncludedGems).toStringList(); } - QStringList GemRepoModel::GetIncludedGemNames(const QModelIndex& modelIndex) + QVector GemRepoModel::GetIncludedGemTags(const QModelIndex& modelIndex) { - QStringList gemNames; - QVector gemInfos = GetIncludedGemInfos(modelIndex); - + QVector tags; + const QVector& gemInfos = GetIncludedGemInfos(modelIndex); + tags.reserve(gemInfos.size()); for (const GemInfo& gemInfo : gemInfos) { - gemNames.append(gemInfo.m_displayName); + tags.append({ gemInfo.m_displayName, gemInfo.m_name }); } - return gemNames; + return tags; } QVector GemRepoModel::GetIncludedGemInfos(const QModelIndex& modelIndex) diff --git a/Code/Tools/ProjectManager/Source/GemRepo/GemRepoModel.h b/Code/Tools/ProjectManager/Source/GemRepo/GemRepoModel.h index f36b66ca48..66fe972a95 100644 --- a/Code/Tools/ProjectManager/Source/GemRepo/GemRepoModel.h +++ b/Code/Tools/ProjectManager/Source/GemRepo/GemRepoModel.h @@ -40,7 +40,7 @@ namespace O3DE::ProjectManager static QString GetPath(const QModelIndex& modelIndex); static QStringList GetIncludedGemPaths(const QModelIndex& modelIndex); - static QStringList GetIncludedGemNames(const QModelIndex& modelIndex); + static QVector GetIncludedGemTags(const QModelIndex& modelIndex); static QVector GetIncludedGemInfos(const QModelIndex& modelIndex); static bool IsEnabled(const QModelIndex& modelIndex); diff --git a/Code/Tools/ProjectManager/Source/GemsSubWidget.cpp b/Code/Tools/ProjectManager/Source/GemsSubWidget.cpp index 8b7b183008..2572a39db3 100644 --- a/Code/Tools/ProjectManager/Source/GemsSubWidget.cpp +++ b/Code/Tools/ProjectManager/Source/GemsSubWidget.cpp @@ -33,14 +33,14 @@ namespace O3DE::ProjectManager m_layout->addWidget(m_textLabel); m_tagWidget = new TagContainerWidget(); - connect(m_tagWidget, &TagContainerWidget::TagClicked, this, [=](const QString& tag){ emit TagClicked(tag); }); + connect(m_tagWidget, &TagContainerWidget::TagClicked, this, [=](const Tag& tag){ emit TagClicked(tag); }); m_layout->addWidget(m_tagWidget); } - void GemsSubWidget::Update(const QString& title, const QString& text, const QStringList& gemNames) + void GemsSubWidget::Update(const QString& title, const QString& text, const QVector& tags) { m_titleLabel->setText(title); m_textLabel->setText(text); - m_tagWidget->Update(gemNames); + m_tagWidget->Update(tags); } } // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/Source/GemsSubWidget.h b/Code/Tools/ProjectManager/Source/GemsSubWidget.h index a9fabf5e92..5e670b930a 100644 --- a/Code/Tools/ProjectManager/Source/GemsSubWidget.h +++ b/Code/Tools/ProjectManager/Source/GemsSubWidget.h @@ -26,10 +26,10 @@ namespace O3DE::ProjectManager public: GemsSubWidget(QWidget* parent = nullptr); - void Update(const QString& title, const QString& text, const QStringList& gemNames); + void Update(const QString& title, const QString& text, const QVector& tags); signals: - void TagClicked(const QString& tag); + void TagClicked(const Tag& tag); private: QLabel* m_titleLabel = nullptr; diff --git a/Code/Tools/ProjectManager/Source/TagWidget.cpp b/Code/Tools/ProjectManager/Source/TagWidget.cpp index 39231ace4b..007f0839d1 100644 --- a/Code/Tools/ProjectManager/Source/TagWidget.cpp +++ b/Code/Tools/ProjectManager/Source/TagWidget.cpp @@ -12,15 +12,16 @@ namespace O3DE::ProjectManager { - TagWidget::TagWidget(const QString& text, QWidget* parent) - : QLabel(text, parent) + TagWidget::TagWidget(const Tag& tag, QWidget* parent) + : QLabel(tag.text, parent) + , m_tag(tag) { setObjectName("TagWidget"); } void TagWidget::mousePressEvent([[maybe_unused]] QMouseEvent* event) { - emit(TagClicked(text())); + emit TagClicked(m_tag); } TagContainerWidget::TagContainerWidget(QWidget* parent) @@ -39,20 +40,34 @@ namespace O3DE::ProjectManager void TagContainerWidget::Update(const QStringList& tags) { - FlowLayout* flowLayout = static_cast(layout()); + Clear(); - // remove old tags + foreach (const QString& tag, tags) + { + TagWidget* tagWidget = new TagWidget({tag, tag}); + connect(tagWidget, &TagWidget::TagClicked, this, [=](const Tag& clickedTag){ emit TagClicked(clickedTag); }); + layout()->addWidget(tagWidget); + } + } + + void TagContainerWidget::Update(const QVector& tags) + { + Clear(); + + foreach (const Tag& tag, tags) + { + TagWidget* tagWidget = new TagWidget(tag); + connect(tagWidget, &TagWidget::TagClicked, this, [=](const Tag& clickedTag){ emit TagClicked(clickedTag); }); + layout()->addWidget(tagWidget); + } + } + + void TagContainerWidget::Clear() + { QLayoutItem* layoutItem = nullptr; while ((layoutItem = layout()->takeAt(0)) != nullptr) { layoutItem->widget()->deleteLater(); } - - foreach (const QString& tag, tags) - { - TagWidget* tagWidget = new TagWidget(tag); - connect(tagWidget, &TagWidget::TagClicked, this, [=](const QString& tag){ emit TagClicked(tag); }); - flowLayout->addWidget(tagWidget); - } } } // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/Source/TagWidget.h b/Code/Tools/ProjectManager/Source/TagWidget.h index 7b4a5b1aaa..fce6eaf863 100644 --- a/Code/Tools/ProjectManager/Source/TagWidget.h +++ b/Code/Tools/ProjectManager/Source/TagWidget.h @@ -10,12 +10,19 @@ #if !defined(Q_MOC_RUN) #include -#include #include +#include +#include #endif namespace O3DE::ProjectManager { + struct Tag + { + QString text; + QString id; + }; + // Single tag class TagWidget : public QLabel @@ -23,14 +30,17 @@ namespace O3DE::ProjectManager Q_OBJECT // AUTOMOC public: - explicit TagWidget(const QString& text, QWidget* parent = nullptr); + explicit TagWidget(const Tag& id, QWidget* parent = nullptr); ~TagWidget() = default; signals: - void TagClicked(const QString& tag); + void TagClicked(const Tag& tag); protected: void mousePressEvent(QMouseEvent* event) override; + + private: + Tag m_tag; }; // Widget containing multiple tags, automatically wrapping based on the size @@ -43,9 +53,13 @@ namespace O3DE::ProjectManager explicit TagContainerWidget(QWidget* parent = nullptr); ~TagContainerWidget() = default; + void Update(const QVector& tags); void Update(const QStringList& tags); signals: - void TagClicked(const QString& tag); + void TagClicked(const Tag& tag); + + private: + void Clear(); }; } // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/Source/UpdateProjectCtrl.cpp b/Code/Tools/ProjectManager/Source/UpdateProjectCtrl.cpp index e76b4093a9..fb16484961 100644 --- a/Code/Tools/ProjectManager/Source/UpdateProjectCtrl.cpp +++ b/Code/Tools/ProjectManager/Source/UpdateProjectCtrl.cpp @@ -43,7 +43,7 @@ namespace O3DE::ProjectManager m_gemRepoScreen = new GemRepoScreen(this); connect(m_gemCatalogScreen, &ScreenWidget::ChangeScreenRequest, this, &UpdateProjectCtrl::OnChangeScreenRequest); - connect(m_gemRepoScreen, &GemRepoScreen::OnRefresh, [this](){ m_gemCatalogScreen->Refresh(m_projectInfo.m_path); }); + connect(m_gemRepoScreen, &GemRepoScreen::OnRefresh, m_gemCatalogScreen, &GemCatalogScreen::Refresh); m_stack = new QStackedWidget(this); m_stack->setObjectName("body"); @@ -163,6 +163,7 @@ namespace O3DE::ProjectManager QMessageBox::critical(this, tr("Gems downloading"), tr("You must wait for gems to finish downloading before continuing.")); return; } + // Enable or disable the gems that got adjusted in the gem catalog and apply them to the given project. const GemCatalogScreen::EnableDisableGemsResult result = m_gemCatalogScreen->EnableDisableGemsForProject(m_projectInfo.m_path); if (result == GemCatalogScreen::EnableDisableGemsResult::Failed) diff --git a/Code/Tools/ProjectManager/Source/UpdateProjectCtrl.h b/Code/Tools/ProjectManager/Source/UpdateProjectCtrl.h index 5fef296ee7..ee6fc792f2 100644 --- a/Code/Tools/ProjectManager/Source/UpdateProjectCtrl.h +++ b/Code/Tools/ProjectManager/Source/UpdateProjectCtrl.h @@ -26,6 +26,7 @@ namespace O3DE::ProjectManager class UpdateProjectCtrl : public ScreenWidget { + Q_OBJECT public: explicit UpdateProjectCtrl(QWidget* parent = nullptr); ~UpdateProjectCtrl() = default; From 21c02b195f9e5ee39b6e9d90aa8a41a69a50a7dd Mon Sep 17 00:00:00 2001 From: Alex Peterson <26804013+AMZN-alexpete@users.noreply.github.com> Date: Fri, 5 Nov 2021 17:24:08 -0700 Subject: [PATCH 31/53] Update signals/slots to match upstream changes Signed-off-by: Alex Peterson <26804013+AMZN-alexpete@users.noreply.github.com> --- Code/Tools/ProjectManager/Source/DownloadController.cpp | 6 +++--- Code/Tools/ProjectManager/Source/DownloadController.h | 2 +- .../Source/GemCatalog/GemCatalogHeaderWidget.cpp | 2 +- .../ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp | 2 +- .../ProjectManager/Source/GemCatalog/GemCatalogScreen.h | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Code/Tools/ProjectManager/Source/DownloadController.cpp b/Code/Tools/ProjectManager/Source/DownloadController.cpp index a8eecffd78..d30e1bbc7c 100644 --- a/Code/Tools/ProjectManager/Source/DownloadController.cpp +++ b/Code/Tools/ProjectManager/Source/DownloadController.cpp @@ -82,13 +82,13 @@ namespace O3DE::ProjectManager succeeded = false; } - const QString gemName = m_gemNames[0]; + QString gemName = m_gemNames.front(); m_gemNames.erase(m_gemNames.begin()); - emit Done(succeeded, gemName); + emit Done(gemName, succeeded); if (!m_gemNames.empty()) { - emit StartGemDownload(m_gemNames[0]); + emit StartGemDownload(m_gemNames.front()); } else { diff --git a/Code/Tools/ProjectManager/Source/DownloadController.h b/Code/Tools/ProjectManager/Source/DownloadController.h index 8afe8ef029..5b2d230379 100644 --- a/Code/Tools/ProjectManager/Source/DownloadController.h +++ b/Code/Tools/ProjectManager/Source/DownloadController.h @@ -58,7 +58,7 @@ namespace O3DE::ProjectManager signals: void StartGemDownload(const QString& gemName); - void Done(bool success, const QString& gemName); + void Done(const QString& gemName, bool success = true); void GemDownloadProgress(int percentage); private: diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogHeaderWidget.cpp b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogHeaderWidget.cpp index 0db2b088c1..71d5086fff 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogHeaderWidget.cpp +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogHeaderWidget.cpp @@ -261,7 +261,7 @@ namespace O3DE::ProjectManager } }; - auto downloadEnded = [=](bool /*success*/, const QString& /*gemName*/) + auto downloadEnded = [=](const QString& /*gemName*/, bool /*success*/) { update(0); // update the list to remove the gem that has finished }; diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp index b0e4fa73e1..79935ed235 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp @@ -459,7 +459,7 @@ namespace O3DE::ProjectManager emit ChangeScreenRequest(ProjectManagerScreen::GemRepos); } - void GemCatalogScreen::OnGemDownloadResult(bool succeeded, const QString& gemName) + void GemCatalogScreen::OnGemDownloadResult(const QString& gemName, bool succeeded) { if (succeeded) { diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.h b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.h index 6acf43b3eb..da6d2efa7b 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.h +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.h @@ -49,7 +49,7 @@ namespace O3DE::ProjectManager void OnGemStatusChanged(const QString& gemName, uint32_t numChangedDependencies); void OnAddGemClicked(); void SelectGem(const QString& gemName); - void OnGemDownloadResult(bool succeeded, const QString& gemName); + void OnGemDownloadResult(const QString& gemName, bool succeeded = true); void Refresh(); protected: From 0295aa7070154d53c00b8ac4680d23ebb9a4e202 Mon Sep 17 00:00:00 2001 From: Alex Peterson <26804013+AMZN-alexpete@users.noreply.github.com> Date: Fri, 5 Nov 2021 17:31:01 -0700 Subject: [PATCH 32/53] revert change to cancel label href Signed-off-by: Alex Peterson <26804013+AMZN-alexpete@users.noreply.github.com> --- .../ProjectManager/Source/GemCatalog/GemCatalogHeaderWidget.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogHeaderWidget.cpp b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogHeaderWidget.cpp index 71d5086fff..8c875e4846 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogHeaderWidget.cpp +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogHeaderWidget.cpp @@ -245,7 +245,7 @@ namespace O3DE::ProjectManager QSpacerItem* spacer = new QSpacerItem(0, 0, QSizePolicy::Expanding, QSizePolicy::Minimum); nameProgressLayout->addSpacerItem(spacer); - QLabel* cancelText = new QLabel(QString("Cancel")); + QLabel* cancelText = new QLabel(QString("Cancel").arg(gemName)); cancelText->setTextInteractionFlags(Qt::LinksAccessibleByMouse); connect(cancelText, &QLabel::linkActivated, this, &CartOverlayWidget::OnCancelDownloadActivated); nameProgressLayout->addWidget(cancelText); From 621194e593bf26d85e709b61c77b7923c637773a Mon Sep 17 00:00:00 2001 From: galibzon <66021303+galibzon@users.noreply.github.com> Date: Sat, 6 Nov 2021 07:25:42 -0500 Subject: [PATCH 33/53] StandardMultilayerPBR_ForwardPass.azsl. the type of input.m_normal is (#5385) float Github issue: https://github.com/o3de/o3de/issues/2522 Change to float3. The current ASV tests are not affected but using the RPI/Mesh example with Mesh: objects/suzanne.azmodel and the material: StandardMultilayerPbrTestCases/005_UseDisplacement.material Showed a clear improvement. Signed-off-by: galibzon <66021303+galibzon@users.noreply.github.com> --- .../Materials/Types/StandardMultilayerPBR_ForwardPass.azsl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardMultilayerPBR_ForwardPass.azsl b/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardMultilayerPBR_ForwardPass.azsl index a53dab7a01..8f58c6dd33 100644 --- a/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardMultilayerPBR_ForwardPass.azsl +++ b/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardMultilayerPBR_ForwardPass.azsl @@ -153,7 +153,7 @@ struct StandardMaterialInputs float2 m_vertexUv[UvSetCount]; float3x3 m_uvMatrix; - float m_normal; + float3 m_normal; float3 m_tangents[UvSetCount]; float3 m_bitangents[UvSetCount]; From 00cf9ebfd801b0fde709fdda3b9fe6219d1deefd Mon Sep 17 00:00:00 2001 From: Guthrie Adams Date: Sun, 7 Nov 2021 18:36:38 -0600 Subject: [PATCH 34/53] Queuing inspector invalidate all to boost performance opening/closing several documents Signed-off-by: Guthrie Adams --- .../Code/Source/Inspector/InspectorPropertyGroupWidget.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Inspector/InspectorPropertyGroupWidget.cpp b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Inspector/InspectorPropertyGroupWidget.cpp index 6b9aee17f7..af71954737 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Inspector/InspectorPropertyGroupWidget.cpp +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Inspector/InspectorPropertyGroupWidget.cpp @@ -43,7 +43,7 @@ namespace AtomToolsFramework m_propertyEditor->Setup(context, instanceNotificationHandler, false); m_propertyEditor->AddInstance(instance, instanceClassId, nullptr, instanceToCompare); m_propertyEditor->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred); - m_propertyEditor->InvalidateAll(); + m_propertyEditor->QueueInvalidation(AzToolsFramework::PropertyModificationRefreshLevel::Refresh_EntireTree); m_layout->addWidget(m_propertyEditor); setLayout(m_layout); From 803039c302558335035b33f50f4dbcfb1435a653 Mon Sep 17 00:00:00 2001 From: moraaar Date: Mon, 8 Nov 2021 09:14:01 +0000 Subject: [PATCH 35/53] Fixed casing of .fbx.asset info files in cloth to match the fbx (#5371) Signed-off-by: moraaar --- .../{cloth_blinds.fbx.assetinfo => Cloth_Blinds.fbx.assetinfo} | 0 ...nds_broken.fbx.assetinfo => Cloth_Blinds_Broken.fbx.assetinfo} | 0 ...four.fbx.assetinfo => Cloth_Locked_Corners_Four.fbx.assetinfo} | 0 ...s_two.fbx.assetinfo => Cloth_Locked_Corners_Two.fbx.assetinfo} | 0 ..._locked_edge.fbx.assetinfo => Cloth_Locked_Edge.fbx.assetinfo} | 0 5 files changed, 0 insertions(+), 0 deletions(-) rename Gems/NvCloth/Assets/Objects/cloth/Environment/{cloth_blinds.fbx.assetinfo => Cloth_Blinds.fbx.assetinfo} (100%) rename Gems/NvCloth/Assets/Objects/cloth/Environment/{cloth_blinds_broken.fbx.assetinfo => Cloth_Blinds_Broken.fbx.assetinfo} (100%) rename Gems/NvCloth/Assets/Objects/cloth/Environment/{cloth_locked_corners_four.fbx.assetinfo => Cloth_Locked_Corners_Four.fbx.assetinfo} (100%) rename Gems/NvCloth/Assets/Objects/cloth/Environment/{cloth_locked_corners_two.fbx.assetinfo => Cloth_Locked_Corners_Two.fbx.assetinfo} (100%) rename Gems/NvCloth/Assets/Objects/cloth/Environment/{cloth_locked_edge.fbx.assetinfo => Cloth_Locked_Edge.fbx.assetinfo} (100%) diff --git a/Gems/NvCloth/Assets/Objects/cloth/Environment/cloth_blinds.fbx.assetinfo b/Gems/NvCloth/Assets/Objects/cloth/Environment/Cloth_Blinds.fbx.assetinfo similarity index 100% rename from Gems/NvCloth/Assets/Objects/cloth/Environment/cloth_blinds.fbx.assetinfo rename to Gems/NvCloth/Assets/Objects/cloth/Environment/Cloth_Blinds.fbx.assetinfo diff --git a/Gems/NvCloth/Assets/Objects/cloth/Environment/cloth_blinds_broken.fbx.assetinfo b/Gems/NvCloth/Assets/Objects/cloth/Environment/Cloth_Blinds_Broken.fbx.assetinfo similarity index 100% rename from Gems/NvCloth/Assets/Objects/cloth/Environment/cloth_blinds_broken.fbx.assetinfo rename to Gems/NvCloth/Assets/Objects/cloth/Environment/Cloth_Blinds_Broken.fbx.assetinfo diff --git a/Gems/NvCloth/Assets/Objects/cloth/Environment/cloth_locked_corners_four.fbx.assetinfo b/Gems/NvCloth/Assets/Objects/cloth/Environment/Cloth_Locked_Corners_Four.fbx.assetinfo similarity index 100% rename from Gems/NvCloth/Assets/Objects/cloth/Environment/cloth_locked_corners_four.fbx.assetinfo rename to Gems/NvCloth/Assets/Objects/cloth/Environment/Cloth_Locked_Corners_Four.fbx.assetinfo diff --git a/Gems/NvCloth/Assets/Objects/cloth/Environment/cloth_locked_corners_two.fbx.assetinfo b/Gems/NvCloth/Assets/Objects/cloth/Environment/Cloth_Locked_Corners_Two.fbx.assetinfo similarity index 100% rename from Gems/NvCloth/Assets/Objects/cloth/Environment/cloth_locked_corners_two.fbx.assetinfo rename to Gems/NvCloth/Assets/Objects/cloth/Environment/Cloth_Locked_Corners_Two.fbx.assetinfo diff --git a/Gems/NvCloth/Assets/Objects/cloth/Environment/cloth_locked_edge.fbx.assetinfo b/Gems/NvCloth/Assets/Objects/cloth/Environment/Cloth_Locked_Edge.fbx.assetinfo similarity index 100% rename from Gems/NvCloth/Assets/Objects/cloth/Environment/cloth_locked_edge.fbx.assetinfo rename to Gems/NvCloth/Assets/Objects/cloth/Environment/Cloth_Locked_Edge.fbx.assetinfo From 425e172079eff05ddee18c8b46958ce08a4cdf46 Mon Sep 17 00:00:00 2001 From: moraaar Date: Mon, 8 Nov 2021 09:14:26 +0000 Subject: [PATCH 36/53] Cloth automated tests only check for cloth gem errors and warnings (#5374) Signed-off-by: moraaar --- .../NvCloth_AddClothSimulationToActor.py | 19 +++++++++++-------- .../tests/NvCloth_AddClothSimulationToMesh.py | 19 +++++++++++-------- 2 files changed, 22 insertions(+), 16 deletions(-) diff --git a/AutomatedTesting/Gem/PythonTests/NvCloth/tests/NvCloth_AddClothSimulationToActor.py b/AutomatedTesting/Gem/PythonTests/NvCloth/tests/NvCloth_AddClothSimulationToActor.py index 357067b176..e4150f7af8 100644 --- a/AutomatedTesting/Gem/PythonTests/NvCloth/tests/NvCloth_AddClothSimulationToActor.py +++ b/AutomatedTesting/Gem/PythonTests/NvCloth/tests/NvCloth_AddClothSimulationToActor.py @@ -50,6 +50,7 @@ def NvCloth_AddClothSimulationToActor(): # Constants FRAMES_IN_GAME_MODE = 200 + CLOTH_GEM_ERROR_WARNING_LIST = ["Cloth", "NvCloth", "ClothComponentMesh", "ActorClothSkinning", "ActorClothSkinning", "TangentSpaceHelper", "MeshAssetHelper", "ActorAssetHelper", "ClothDebugDisplay"] helper.init_idle() # 1) Load the level @@ -64,14 +65,16 @@ def NvCloth_AddClothSimulationToActor(): general.idle_wait_frames(FRAMES_IN_GAME_MODE) # 5) Verify there are no errors and warnings in the logs - success_condition = not (section_tracer.has_errors or section_tracer.has_warnings) - Report.result(Tests.no_errors_and_warnings_found, success_condition) - if not success_condition: - if section_tracer.has_warnings: - Report.info(f"Warnings found: {section_tracer.warnings}") - if section_tracer.has_errors: - Report.info(f"Errors found: {section_tracer.errors}") - Report.failure(Tests.no_errors_and_warnings_found) + has_errors_or_warnings = False + for error_msg in section_tracer.errors: + if error_msg.window in CLOTH_GEM_ERROR_WARNING_LIST: + has_errors_or_warnings = True + Report.info(f"Cloth error found: {error_msg}") + for warning_msg in section_tracer.warnings: + if warning_msg.window in CLOTH_GEM_ERROR_WARNING_LIST: + has_errors_or_warnings = True + Report.info(f"Cloth warning found: {warning_msg}") + Report.result(Tests.no_errors_and_warnings_found, not has_errors_or_warnings) # 6) Exit game mode helper.exit_game_mode(Tests.exit_game_mode) diff --git a/AutomatedTesting/Gem/PythonTests/NvCloth/tests/NvCloth_AddClothSimulationToMesh.py b/AutomatedTesting/Gem/PythonTests/NvCloth/tests/NvCloth_AddClothSimulationToMesh.py index 0f9d8448f7..707f745cea 100644 --- a/AutomatedTesting/Gem/PythonTests/NvCloth/tests/NvCloth_AddClothSimulationToMesh.py +++ b/AutomatedTesting/Gem/PythonTests/NvCloth/tests/NvCloth_AddClothSimulationToMesh.py @@ -50,6 +50,7 @@ def NvCloth_AddClothSimulationToMesh(): # Constants FRAMES_IN_GAME_MODE = 200 + CLOTH_GEM_ERROR_WARNING_LIST = ["Cloth", "NvCloth", "ClothComponentMesh", "ActorClothSkinning", "ActorClothSkinning", "TangentSpaceHelper", "MeshAssetHelper", "ActorAssetHelper", "ClothDebugDisplay"] helper.init_idle() # 1) Load the level @@ -64,14 +65,16 @@ def NvCloth_AddClothSimulationToMesh(): general.idle_wait_frames(FRAMES_IN_GAME_MODE) # 5) Verify there are no errors and warnings in the logs - success_condition = not (section_tracer.has_errors or section_tracer.has_warnings) - Report.result(Tests.no_errors_and_warnings_found, success_condition) - if not success_condition: - if section_tracer.has_warnings: - Report.info(f"Warnings found: {section_tracer.warnings}") - if section_tracer.has_errors: - Report.info(f"Errors found: {section_tracer.errors}") - Report.failure(Tests.no_errors_and_warnings_found) + has_errors_or_warnings = False + for error_msg in section_tracer.errors: + if error_msg.window in CLOTH_GEM_ERROR_WARNING_LIST: + has_errors_or_warnings = True + Report.info(f"Cloth error found: {error_msg}") + for warning_msg in section_tracer.warnings: + if warning_msg.window in CLOTH_GEM_ERROR_WARNING_LIST: + has_errors_or_warnings = True + Report.info(f"Cloth warning found: {warning_msg}") + Report.result(Tests.no_errors_and_warnings_found, not has_errors_or_warnings) # 6) Exit game mode helper.exit_game_mode(Tests.exit_game_mode) From 783186fa7e4a1d6b0ff8f0f9c129b343b4e900bf Mon Sep 17 00:00:00 2001 From: Tom Hulton-Harrop <82228511+hultonha@users.noreply.github.com> Date: Mon, 8 Nov 2021 09:19:40 +0000 Subject: [PATCH 37/53] Update default camera orbit behavior (#5301) * add new default orbit point behavior Signed-off-by: Tom Hulton-Harrop <82228511+hultonha@users.noreply.github.com> * add default orbit distance to settings registry Signed-off-by: Tom Hulton-Harrop <82228511+hultonha@users.noreply.github.com> * add new default orbit point behavior Signed-off-by: Tom Hulton-Harrop <82228511+hultonha@users.noreply.github.com> * add default orbit distance to settings registry Signed-off-by: Tom Hulton-Harrop <82228511+hultonha@users.noreply.github.com> * expose default orbit distance to editor settings menu and update how we display default camera position Signed-off-by: Tom Hulton-Harrop <82228511+hultonha@users.noreply.github.com> * add improve orbit changes for focus Signed-off-by: Tom Hulton-Harrop <82228511+hultonha@users.noreply.github.com> --- .../EditorModularViewportCameraComposer.cpp | 15 +++++--- .../EditorPreferencesPageViewportCamera.cpp | 34 +++++++------------ .../EditorPreferencesPageViewportCamera.h | 12 ++++--- Code/Editor/EditorViewportSettings.cpp | 23 +++++++++---- Code/Editor/EditorViewportSettings.h | 9 +++-- Code/Editor/EditorViewportWidget.cpp | 10 +++--- .../AzFramework/Viewport/CameraInput.cpp | 12 +++++-- .../AzFramework/Viewport/CameraInput.h | 2 +- 8 files changed, 68 insertions(+), 49 deletions(-) diff --git a/Code/Editor/EditorModularViewportCameraComposer.cpp b/Code/Editor/EditorModularViewportCameraComposer.cpp index ce4a0a2e33..08ca0df221 100644 --- a/Code/Editor/EditorModularViewportCameraComposer.cpp +++ b/Code/Editor/EditorModularViewportCameraComposer.cpp @@ -174,7 +174,7 @@ namespace SandboxEditor return SandboxEditor::CameraScrollSpeed(); }; - const auto pivotFn = [] + const auto pivotFn = []() -> AZStd::optional { // use the manipulator transform as the pivot point AZStd::optional entityPivot; @@ -187,8 +187,13 @@ namespace SandboxEditor return entityPivot->GetTranslation(); } - // otherwise just use the identity - return AZ::Vector3::CreateZero(); + return AZStd::nullopt; + }; + + const auto orbitFn = [pivotFn](const AZ::Vector3& pivotFallback = AZ::Vector3::CreateZero()) + { + // return the pivot otherwise use the fallback + return pivotFn().value_or(pivotFallback); }; m_firstPersonFocusCamera = @@ -199,9 +204,9 @@ namespace SandboxEditor m_orbitCamera = AZStd::make_shared(SandboxEditor::CameraOrbitChannelId()); m_orbitCamera->SetPivotFn( - [pivotFn]([[maybe_unused]] const AZ::Vector3& position, [[maybe_unused]] const AZ::Vector3& direction) + [orbitFn]([[maybe_unused]] const AZ::Vector3& position, [[maybe_unused]] const AZ::Vector3& direction) { - return pivotFn(); + return orbitFn(position + direction * SandboxEditor::CameraDefaultOrbitDistance()); }); m_orbitRotateCamera = AZStd::make_shared(SandboxEditor::CameraOrbitLookChannelId()); diff --git a/Code/Editor/EditorPreferencesPageViewportCamera.cpp b/Code/Editor/EditorPreferencesPageViewportCamera.cpp index 2f6e6b1b9d..c81eac0414 100644 --- a/Code/Editor/EditorPreferencesPageViewportCamera.cpp +++ b/Code/Editor/EditorPreferencesPageViewportCamera.cpp @@ -61,7 +61,7 @@ static AZStd::vector GetEditorInputNames() void CEditorPreferencesPage_ViewportCamera::Reflect(AZ::SerializeContext& serialize) { serialize.Class() - ->Version(3) + ->Version(4) ->Field("TranslateSpeed", &CameraMovementSettings::m_translateSpeed) ->Field("RotateSpeed", &CameraMovementSettings::m_rotateSpeed) ->Field("BoostMultiplier", &CameraMovementSettings::m_boostMultiplier) @@ -76,9 +76,8 @@ void CEditorPreferencesPage_ViewportCamera::Reflect(AZ::SerializeContext& serial ->Field("OrbitYawRotationInverted", &CameraMovementSettings::m_orbitYawRotationInverted) ->Field("PanInvertedX", &CameraMovementSettings::m_panInvertedX) ->Field("PanInvertedY", &CameraMovementSettings::m_panInvertedY) - ->Field("DefaultPositionX", &CameraMovementSettings::m_defaultCameraPositionX) - ->Field("DefaultPositionY", &CameraMovementSettings::m_defaultCameraPositionY) - ->Field("DefaultPositionZ", &CameraMovementSettings::m_defaultCameraPositionZ); + ->Field("DefaultPosition", &CameraMovementSettings::m_defaultPosition) + ->Field("DefaultOrbitDistance", &CameraMovementSettings::m_defaultOrbitDistance); serialize.Class() ->Version(2) @@ -159,14 +158,12 @@ void CEditorPreferencesPage_ViewportCamera::Reflect(AZ::SerializeContext& serial AZ::Edit::UIHandlers::CheckBox, &CameraMovementSettings::m_captureCursorLook, "Camera Capture Look Cursor", "Should the cursor be captured (hidden) while performing free look") ->DataElement( - AZ::Edit::UIHandlers::SpinBox, &CameraMovementSettings::m_defaultCameraPositionX, "Default X Camera Position", - "Default X Camera Position when a level is opened") + AZ::Edit::UIHandlers::Vector3, &CameraMovementSettings::m_defaultPosition, "Default Camera Position", + "Default Camera Position when a level is first opened") ->DataElement( - AZ::Edit::UIHandlers::SpinBox, &CameraMovementSettings::m_defaultCameraPositionY, "Default Y Camera Position", - "Default Y Camera Position when a level is opened") - ->DataElement( - AZ::Edit::UIHandlers::SpinBox, &CameraMovementSettings::m_defaultCameraPositionZ, "Default Z Camera Position", - "Default Z Camera Position when a level is opened"); + AZ::Edit::UIHandlers::SpinBox, &CameraMovementSettings::m_defaultOrbitDistance, "Default Orbit Distance", + "The default distance to orbit about when there is no entity selected") + ->Attribute(AZ::Edit::Attributes::Min, minValue); editContext->Class("Camera Input Settings", "") ->DataElement( @@ -283,12 +280,8 @@ void CEditorPreferencesPage_ViewportCamera::OnApply() SandboxEditor::SetCameraOrbitYawRotationInverted(m_cameraMovementSettings.m_orbitYawRotationInverted); SandboxEditor::SetCameraPanInvertedX(m_cameraMovementSettings.m_panInvertedX); SandboxEditor::SetCameraPanInvertedY(m_cameraMovementSettings.m_panInvertedY); - SandboxEditor::SetDefaultCameraEditorPosition( - AZ::Vector3( - m_cameraMovementSettings.m_defaultCameraPositionX, - m_cameraMovementSettings.m_defaultCameraPositionY, - m_cameraMovementSettings.m_defaultCameraPositionZ - )); + SandboxEditor::SetCameraDefaultEditorPosition(m_cameraMovementSettings.m_defaultPosition); + SandboxEditor::SetCameraDefaultOrbitDistance(m_cameraMovementSettings.m_defaultOrbitDistance); SandboxEditor::SetCameraTranslateForwardChannelId(m_cameraInputSettings.m_translateForwardChannelId); SandboxEditor::SetCameraTranslateBackwardChannelId(m_cameraInputSettings.m_translateBackwardChannelId); @@ -325,11 +318,8 @@ void CEditorPreferencesPage_ViewportCamera::InitializeSettings() m_cameraMovementSettings.m_orbitYawRotationInverted = SandboxEditor::CameraOrbitYawRotationInverted(); m_cameraMovementSettings.m_panInvertedX = SandboxEditor::CameraPanInvertedX(); m_cameraMovementSettings.m_panInvertedY = SandboxEditor::CameraPanInvertedY(); - - AZ::Vector3 defaultCameraPosition = SandboxEditor::DefaultEditorCameraPosition(); - m_cameraMovementSettings.m_defaultCameraPositionX = defaultCameraPosition.GetX(); - m_cameraMovementSettings.m_defaultCameraPositionY = defaultCameraPosition.GetY(); - m_cameraMovementSettings.m_defaultCameraPositionZ = defaultCameraPosition.GetZ(); + m_cameraMovementSettings.m_defaultPosition = SandboxEditor::CameraDefaultEditorPosition(); + m_cameraMovementSettings.m_defaultOrbitDistance = SandboxEditor::CameraDefaultOrbitDistance(); m_cameraInputSettings.m_translateForwardChannelId = SandboxEditor::CameraTranslateForwardChannelId().GetName(); m_cameraInputSettings.m_translateBackwardChannelId = SandboxEditor::CameraTranslateBackwardChannelId().GetName(); diff --git a/Code/Editor/EditorPreferencesPageViewportCamera.h b/Code/Editor/EditorPreferencesPageViewportCamera.h index a2705bfd24..41816de51c 100644 --- a/Code/Editor/EditorPreferencesPageViewportCamera.h +++ b/Code/Editor/EditorPreferencesPageViewportCamera.h @@ -9,9 +9,12 @@ #pragma once #include "Include/IPreferencesPage.h" + +#include #include #include #include + #include inline AZ::Crc32 EditorPropertyVisibility(const bool enabled) @@ -43,6 +46,7 @@ private: { AZ_TYPE_INFO(CameraMovementSettings, "{60B8C07E-5F48-4171-A50B-F45558B5CCA1}") + AZ::Vector3 m_defaultPosition; float m_translateSpeed; float m_rotateSpeed; float m_scrollSpeed; @@ -50,16 +54,14 @@ private: float m_panSpeed; float m_boostMultiplier; float m_rotateSmoothness; - bool m_rotateSmoothing; float m_translateSmoothness; - bool m_translateSmoothing; + float m_defaultOrbitDistance; bool m_captureCursorLook; bool m_orbitYawRotationInverted; bool m_panInvertedX; bool m_panInvertedY; - float m_defaultCameraPositionX; - float m_defaultCameraPositionY; - float m_defaultCameraPositionZ; + bool m_rotateSmoothing; + bool m_translateSmoothing; AZ::Crc32 RotateSmoothingVisibility() const { diff --git a/Code/Editor/EditorViewportSettings.cpp b/Code/Editor/EditorViewportSettings.cpp index 8f2be1de6c..ae188c7d98 100644 --- a/Code/Editor/EditorViewportSettings.cpp +++ b/Code/Editor/EditorViewportSettings.cpp @@ -38,6 +38,7 @@ namespace SandboxEditor constexpr AZStd::string_view CameraTranslateSmoothingSetting = "/Amazon/Preferences/Editor/Camera/TranslateSmoothing"; constexpr AZStd::string_view CameraRotateSmoothingSetting = "/Amazon/Preferences/Editor/Camera/RotateSmoothing"; constexpr AZStd::string_view CameraCaptureCursorLookSetting = "/Amazon/Preferences/Editor/Camera/CaptureCursorLook"; + constexpr AZStd::string_view CameraDefaultOrbitDistanceSetting = "/Amazon/Preferences/Editor/Camera/DefaultOrbitDistance"; constexpr AZStd::string_view CameraTranslateForwardIdSetting = "/Amazon/Preferences/Editor/Camera/CameraTranslateForwardId"; constexpr AZStd::string_view CameraTranslateBackwardIdSetting = "/Amazon/Preferences/Editor/Camera/CameraTranslateBackwardId"; constexpr AZStd::string_view CameraTranslateLeftIdSetting = "/Amazon/Preferences/Editor/Camera/CameraTranslateLeftId"; @@ -114,15 +115,15 @@ namespace SandboxEditor return AZStd::make_unique(); } - AZ::Vector3 DefaultEditorCameraPosition() + AZ::Vector3 CameraDefaultEditorPosition() { - float xPosition = aznumeric_cast(GetRegistry(CameraDefaultStartingPositionX, 0.0)); - float yPosition = aznumeric_cast(GetRegistry(CameraDefaultStartingPositionY, -10.0)); - float zPosition = aznumeric_cast(GetRegistry(CameraDefaultStartingPositionZ, 4.0)); - return AZ::Vector3(xPosition, yPosition, zPosition); + return AZ::Vector3( + aznumeric_cast(GetRegistry(CameraDefaultStartingPositionX, 0.0)), + aznumeric_cast(GetRegistry(CameraDefaultStartingPositionY, -10.0)), + aznumeric_cast(GetRegistry(CameraDefaultStartingPositionZ, 4.0))); } - void SetDefaultCameraEditorPosition(const AZ::Vector3 defaultCameraPosition) + void SetCameraDefaultEditorPosition(const AZ::Vector3& defaultCameraPosition) { SetRegistry(CameraDefaultStartingPositionX, defaultCameraPosition.GetX()); SetRegistry(CameraDefaultStartingPositionY, defaultCameraPosition.GetY()); @@ -359,6 +360,16 @@ namespace SandboxEditor SetRegistry(CameraCaptureCursorLookSetting, capture); } + float CameraDefaultOrbitDistance() + { + return aznumeric_cast(GetRegistry(CameraDefaultOrbitDistanceSetting, 20.0)); + } + + void SetCameraDefaultOrbitDistance(const float distance) + { + SetRegistry(CameraDefaultOrbitDistanceSetting, distance); + } + AzFramework::InputChannelId CameraTranslateForwardChannelId() { return AzFramework::InputChannelId( diff --git a/Code/Editor/EditorViewportSettings.h b/Code/Editor/EditorViewportSettings.h index 9c3f0a46e5..fe1253ed0c 100644 --- a/Code/Editor/EditorViewportSettings.h +++ b/Code/Editor/EditorViewportSettings.h @@ -33,9 +33,6 @@ namespace SandboxEditor //! event will fire when a value in the settings registry (editorpreferences.setreg) is modified. SANDBOX_API AZStd::unique_ptr CreateEditorViewportSettingsCallbacks(); - SANDBOX_API AZ::Vector3 DefaultEditorCameraPosition(); - SANDBOX_API void SetDefaultCameraEditorPosition(AZ::Vector3 defaultCameraPosition); - SANDBOX_API AZ::u64 MaxItemsShownInAssetBrowserSearch(); SANDBOX_API void SetMaxItemsShownInAssetBrowserSearch(AZ::u64 numberOfItemsShown); @@ -105,6 +102,12 @@ namespace SandboxEditor SANDBOX_API bool CameraCaptureCursorForLook(); SANDBOX_API void SetCameraCaptureCursorForLook(bool capture); + SANDBOX_API AZ::Vector3 CameraDefaultEditorPosition(); + SANDBOX_API void SetCameraDefaultEditorPosition(const AZ::Vector3& position); + + SANDBOX_API float CameraDefaultOrbitDistance(); + SANDBOX_API void SetCameraDefaultOrbitDistance(float distance); + SANDBOX_API AzFramework::InputChannelId CameraTranslateForwardChannelId(); SANDBOX_API void SetCameraTranslateForwardChannelId(AZStd::string_view cameraTranslateForwardId); diff --git a/Code/Editor/EditorViewportWidget.cpp b/Code/Editor/EditorViewportWidget.cpp index 8e6983a9d7..5c5ab87058 100644 --- a/Code/Editor/EditorViewportWidget.cpp +++ b/Code/Editor/EditorViewportWidget.cpp @@ -620,9 +620,9 @@ void EditorViewportWidget::OnEditorNotifyEvent(EEditorNotifyEvent event) break; case eNotify_OnEndNewScene: - PopDisableRendering(); - { + PopDisableRendering(); + Matrix34 viewTM; viewTM.SetIdentity(); @@ -638,9 +638,9 @@ void EditorViewportWidget::OnEditorNotifyEvent(EEditorNotifyEvent event) break; case eNotify_OnEndTerrainCreate: - PopDisableRendering(); - { + PopDisableRendering(); + Matrix34 viewTM; viewTM.SetIdentity(); @@ -2527,7 +2527,7 @@ bool EditorViewportSettings::StickySelectEnabled() const AZ::Vector3 EditorViewportSettings::DefaultEditorCameraPosition() const { - return SandboxEditor::DefaultEditorCameraPosition(); + return SandboxEditor::CameraDefaultEditorPosition(); } AZ_CVAR_EXTERNED(bool, ed_previewGameInFullscreen_once); diff --git a/Code/Framework/AzFramework/AzFramework/Viewport/CameraInput.cpp b/Code/Framework/AzFramework/AzFramework/Viewport/CameraInput.cpp index ddee63e191..26c9db64aa 100644 --- a/Code/Framework/AzFramework/AzFramework/Viewport/CameraInput.cpp +++ b/Code/Framework/AzFramework/AzFramework/Viewport/CameraInput.cpp @@ -806,12 +806,20 @@ namespace AzFramework [[maybe_unused]] float scrollDelta, [[maybe_unused]] float deltaTime) { + const auto pivot = m_pivotFn(); + + if (!pivot.has_value()) + { + EndActivation(); + return targetCamera; + } + if (Beginning()) { // as the camera starts, record the camera we would like to end up as - m_nextCamera.m_offset = m_offsetFn(m_pivotFn().GetDistance(targetCamera.Translation())); + m_nextCamera.m_offset = m_offsetFn(pivot.value().GetDistance(targetCamera.Translation())); const auto angles = - EulerAngles(AZ::Matrix3x3::CreateFromMatrix3x4(AZ::Matrix3x4::CreateLookAt(targetCamera.Translation(), m_pivotFn()))); + EulerAngles(AZ::Matrix3x3::CreateFromMatrix3x4(AZ::Matrix3x4::CreateLookAt(targetCamera.Translation(), pivot.value()))); m_nextCamera.m_pitch = angles.GetX(); m_nextCamera.m_yaw = angles.GetZ(); m_nextCamera.m_pivot = targetCamera.m_pivot; diff --git a/Code/Framework/AzFramework/AzFramework/Viewport/CameraInput.h b/Code/Framework/AzFramework/AzFramework/Viewport/CameraInput.h index 2b7cc3ea9e..2d02bb0b6d 100644 --- a/Code/Framework/AzFramework/AzFramework/Viewport/CameraInput.h +++ b/Code/Framework/AzFramework/AzFramework/Viewport/CameraInput.h @@ -651,7 +651,7 @@ namespace AzFramework class FocusCameraInput : public CameraInput { public: - using PivotFn = AZStd::function; + using PivotFn = AZStd::function()>; FocusCameraInput(const InputChannelId& focusChannelId, FocusOffsetFn offsetFn); From a1d9a2cc586a641c94a9ce18e6a1ae87cdd07f3c Mon Sep 17 00:00:00 2001 From: AMZN-Igarri <82394219+AMZN-Igarri@users.noreply.github.com> Date: Mon, 8 Nov 2021 10:56:51 +0100 Subject: [PATCH 38/53] Asset Browser Tests (#4948) * Added AssetBrowser Tests Signed-off-by: igarri * Added Entries to test AssetBrowser Signed-off-by: igarri * Added Print info. Signed-off-by: igarri * Added more folders Signed-off-by: igarri * Added Asset Browser Tests for the Search View Signed-off-by: igarri * Fixed Entry creation Signed-off-by: igarri * Removed optimize Signed-off-by: igarri * Cleanup AssetBrowserModel Signed-off-by: igarri * RowCount made public Signed-off-by: igarri * Delegated entry creation to RootAssetBrowserEntry and added Code review feedback Signed-off-by: igarri * removed unused helper class and fixed demo tests Signed-off-by: igarri * Fixed bus connections Signed-off-by: igarri * Refactored test environment and added basic tests Signed-off-by: igarri * Applied some code review feedback and added basic tests Signed-off-by: igarri * fixed naming Signed-off-by: igarri * Refactored Tests Signed-off-by: igarri * removed pointer reset, now handled by the AssetBrowserComponent Signed-off-by: igarri * Fixed conversion unsigned-signed Signed-off-by: igarri * Cleaned includes Signed-off-by: igarri * fixed test setup Signed-off-by: igarri * Fixed unused variables Signed-off-by: AMZN-Igarri <82394219+AMZN-Igarri@users.noreply.github.com> * Added printer function Signed-off-by: AMZN-Igarri <82394219+AMZN-Igarri@users.noreply.github.com> * cleaned up code Signed-off-by: AMZN-Igarri <82394219+AMZN-Igarri@users.noreply.github.com> * Added Test to check the correctness of the setup Signed-off-by: AMZN-Igarri <82394219+AMZN-Igarri@users.noreply.github.com> * Fixed basic tests Signed-off-by: AMZN-Igarri <82394219+AMZN-Igarri@users.noreply.github.com> * Fixed Tests Signed-off-by: AMZN-Igarri <82394219+AMZN-Igarri@users.noreply.github.com> --- .../AssetBrowser/AssetBrowserTableModel.h | 4 +- .../Tests/UI/AssetBrowserTests.cpp | 344 ++++++++++++++++++ .../Tests/aztoolsframeworktests_files.cmake | 1 + 3 files changed, 347 insertions(+), 2 deletions(-) create mode 100644 Code/Framework/AzToolsFramework/Tests/UI/AssetBrowserTests.cpp diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/AssetBrowserTableModel.h b/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/AssetBrowserTableModel.h index 4048156b60..ee1ec49456 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/AssetBrowserTableModel.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/AssetBrowserTableModel.h @@ -40,9 +40,9 @@ namespace AzToolsFramework QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override; QModelIndex parent(const QModelIndex& child) const override; QModelIndex sibling(int row, int column, const QModelIndex& idx) const override; + int rowCount(const QModelIndex& parent = QModelIndex()) const override; protected: - int rowCount(const QModelIndex& parent = QModelIndex()) const override; QVariant headerData(int section, Qt::Orientation orientation, int role /* = Qt::DisplayRole */) const override; //////////////////////////////////////////////////////////////////// @@ -55,7 +55,7 @@ namespace AzToolsFramework private slots: void SourceDataChanged(const QModelIndex& topLeft, const QModelIndex& bottomRight); private: - AZ::u64 m_numberOfItemsDisplayed = 0; + AZ::u64 m_numberOfItemsDisplayed = 50; int m_displayedItemsCounter = 0; QPointer m_filterModel; QMap m_indexMap; diff --git a/Code/Framework/AzToolsFramework/Tests/UI/AssetBrowserTests.cpp b/Code/Framework/AzToolsFramework/Tests/UI/AssetBrowserTests.cpp new file mode 100644 index 0000000000..ae5ea5f0ae --- /dev/null +++ b/Code/Framework/AzToolsFramework/Tests/UI/AssetBrowserTests.cpp @@ -0,0 +1,344 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace UnitTest +{ + // Test fixture for the AssetBrowser model that uses a QAbstractItemModelTester to validate the state of the model + // when QAbstractItemModel signals fire. Tests will exit with a fatal error if an invalid state is detected. + class AssetBrowserTest + : public ToolsApplicationFixture + , public testing::WithParamInterface + { + protected: + enum class AssetEntryType + { + Root, + Folder, + Source, + Product + }; + + enum class FolderType + { + Root, + File + }; + + void SetUpEditorFixtureImpl() override; + void TearDownEditorFixtureImpl() override; + + //! Creates a Mock Scan Folder + void AddScanFolder(AZ::s64 folderID, AZStd::string folderPath, AZStd::string displayName, FolderType folderType = FolderType::File); + + //! Creates a Source entry from a mock file + AZ::Uuid CreateSourceEntry( + AZ::s64 fileID, AZ::s64 parentFolderID, AZStd::string filename, AssetEntryType sourceType = AssetEntryType::Source); + + //! Creates a product from a given sourceEntry + void CreateProduct(AZ::s64 productID, AZ::Uuid sourceUuid, AZStd::string productName); + + void SetupAssetBrowser(); + void PrintModel(const QAbstractItemModel* model, AZStd::function printer); + QModelIndex GetModelIndex(const QAbstractItemModel* model, int targetDepth, int row = 0); + AZStd::shared_ptr GetRootEntry(); + AZStd::vector GetVectorFromFormattedString(const QString& formattedString); + + protected: + QString m_assetBrowserHierarchy = QString(); + + AZStd::unique_ptr m_searchWidget; + AZStd::unique_ptr m_assetBrowserComponent; + + AZStd::unique_ptr m_filterModel; + AZStd::unique_ptr m_tableModel; + + AZStd::unique_ptr m_modelTesterAssetBrowser; + AZStd::unique_ptr m_modelTesterFilterModel; + AZStd::unique_ptr m_modelTesterTableModel; + + QVector m_folderIds = { 13, 14, 15 }; + QVector m_sourceIDs = { 1, 2, 3, 4, 5 }; + QVector m_productIDs = { 1, 2, 3, 4, 5 }; + }; + + void AssetBrowserTest::SetUpEditorFixtureImpl() + { + GetApplication()->RegisterComponentDescriptor(AzToolsFramework::EditorEntityContextComponent::CreateDescriptor()); + + m_assetBrowserComponent = AZStd::make_unique(); + m_assetBrowserComponent->Activate(); + + m_filterModel = AZStd::make_unique(); + m_tableModel = AZStd::make_unique(); + + m_filterModel->setSourceModel(m_assetBrowserComponent->GetAssetBrowserModel()); + m_tableModel->setSourceModel(m_filterModel.get()); + + m_modelTesterAssetBrowser = AZStd::make_unique(m_assetBrowserComponent->GetAssetBrowserModel()); + m_modelTesterFilterModel = AZStd::make_unique(m_filterModel.get()); + m_modelTesterTableModel = AZStd::make_unique(m_tableModel.get()); + m_searchWidget = AZStd::make_unique(); + + // Setup String filters + m_searchWidget->Setup(true, true); + m_filterModel->SetFilter(m_searchWidget->GetFilter()); + + SetupAssetBrowser(); + } + + void AssetBrowserTest::TearDownEditorFixtureImpl() + { + m_modelTesterAssetBrowser.reset(); + m_modelTesterFilterModel.reset(); + m_modelTesterTableModel.reset(); + + m_tableModel.reset(); + m_filterModel.reset(); + m_assetBrowserComponent->Deactivate(); + + m_assetBrowserComponent.reset(); + m_searchWidget.reset(); + } + + void AssetBrowserTest::AddScanFolder( + AZ::s64 folderID, AZStd::string folderPath, AZStd::string displayName, FolderType folderType /*= FolderType::File*/) + { + AzToolsFramework::AssetDatabase::ScanFolderDatabaseEntry scanFolder = AzToolsFramework::AssetDatabase::ScanFolderDatabaseEntry(); + scanFolder.m_scanFolderID = folderID; + scanFolder.m_scanFolder = folderPath; + scanFolder.m_displayName = displayName; + scanFolder.m_isRoot = folderType == FolderType::Root; + GetRootEntry()->AddScanFolder(scanFolder); + } + + AZ::Uuid AssetBrowserTest::CreateSourceEntry( + AZ::s64 fileID, AZ::s64 parentFolderID, AZStd::string filename, AssetEntryType sourceType /*= AssetEntryType::Source*/) + { + AzToolsFramework::AssetDatabase::FileDatabaseEntry entry = AzToolsFramework::AssetDatabase::FileDatabaseEntry(); + entry.m_scanFolderPK = parentFolderID; + entry.m_fileID = fileID; + entry.m_fileName = filename; + entry.m_isFolder = sourceType == AssetEntryType::Folder; + GetRootEntry()->AddFile(entry); + + if (!entry.m_isFolder) + { + AzToolsFramework::AssetBrowser::SourceWithFileID entrySource = AzToolsFramework::AssetBrowser::SourceWithFileID(); + entrySource.first = entry.m_fileID; + entrySource.second = AzToolsFramework::AssetDatabase::SourceDatabaseEntry(); + entrySource.second.m_scanFolderPK = parentFolderID; + entrySource.second.m_sourceName = filename; + entrySource.second.m_sourceID = fileID; + entrySource.second.m_sourceGuid = AZ::Uuid::CreateRandom(); + + GetRootEntry()->AddSource(entrySource); + + return entrySource.second.m_sourceGuid; + } + + return AZ::Uuid::CreateNull(); + } + + void AssetBrowserTest::CreateProduct(AZ::s64 productID, AZ::Uuid sourceUuid, AZStd::string productName) + { + AzToolsFramework::AssetBrowser::ProductWithUuid product = AzToolsFramework::AssetBrowser::ProductWithUuid(); + product.first = sourceUuid; + product.second = AzToolsFramework::AssetDatabase::ProductDatabaseEntry(); + product.second.m_productID = productID; + + product.second.m_subID = aznumeric_cast(productID); + product.second.m_productName = productName; + + GetRootEntry()->AddProduct(product); + } + + void AssetBrowserTest::SetupAssetBrowser() + { + // RootEntries : 1 | Folders : 4 | SourceEntries : 5 | ProductEntries : 9 + m_assetBrowserHierarchy = R"( + D: + \ + dev + o3de + GameProject + Assets + Source_1 + Product_1_1 + Product_1_0 + Source_0 + Product_0_3 + Product_0_2 + Product_0_1 + Product_0_0 + Scripts + Source_3 + Source_2 + Product_2_2 + Product_2_1 + Product_2_0 + Misc + Source_4 + Product_4_2 + Product_4_1 + Product_4_0 )"; + + namespace AzAssetBrowser = AzToolsFramework::AssetBrowser; + + AddScanFolder(m_folderIds.at(2), "D:/dev/o3de/GameProject/Misc", "Misc"); + AZ::Uuid sourceUuid_4 = CreateSourceEntry(m_sourceIDs.at(4), m_folderIds.at(2), "Source_4"); + CreateProduct(m_productIDs.at(0), sourceUuid_4, "Product_4_0"); + CreateProduct(m_productIDs.at(1), sourceUuid_4, "Product_4_1"); + CreateProduct(m_productIDs.at(2), sourceUuid_4, "Product_4_2"); + + AddScanFolder(m_folderIds.at(1), "D:/dev/o3de/GameProject/Scripts", "Scripts"); + + AZ::Uuid sourceUuid_2 = CreateSourceEntry(m_sourceIDs.at(2), m_folderIds.at(1), "Source_2"); + CreateProduct(m_productIDs.at(0), sourceUuid_2, "Product_2_0"); + CreateProduct(m_productIDs.at(1), sourceUuid_2, "Product_2_1"); + CreateProduct(m_productIDs.at(2), sourceUuid_2, "Product_2_2"); + + CreateSourceEntry(m_sourceIDs.at(3), m_folderIds.at(1), "Source_3"); + + AddScanFolder(m_folderIds.at(0), "D:/dev/o3de/GameProject/Assets", "Assets"); + + AZ::Uuid sourceUuid_0 = CreateSourceEntry(m_sourceIDs.at(0), m_folderIds.at(0), "Source_0"); + CreateProduct(m_productIDs.at(0), sourceUuid_0, "Product_0_0"); + CreateProduct(m_productIDs.at(1), sourceUuid_0, "Product_0_1"); + CreateProduct(m_productIDs.at(2), sourceUuid_0, "Product_0_2"); + CreateProduct(m_productIDs.at(3), sourceUuid_0, "Product_0_3"); + + AZ::Uuid sourceUuid_1 = CreateSourceEntry(m_sourceIDs.at(1), m_folderIds.at(0), "Source_1"); + CreateProduct(m_productIDs.at(0), sourceUuid_1, "Product_1_0"); + CreateProduct(m_productIDs.at(1), sourceUuid_1, "Product_1_1"); + } + + void AssetBrowserTest::PrintModel(const QAbstractItemModel* model, AZStd::function printer) + { + AZStd::deque> indices; + indices.push_back({ model->index(0, 0), 0 }); + while (!indices.empty()) + { + auto [index, depth] = indices.front(); + indices.pop_front(); + + QString indentString; + for (int i = 0; i < depth; ++i) + { + indentString += " "; + } + const QString message = indentString + index.data(Qt::DisplayRole).toString(); + printer(message); + + for (int i = 0; i < model->rowCount(index); ++i) + { + indices.emplace_front(model->index(i, 0, index), depth + 1); + } + } + } + + QModelIndex AssetBrowserTest::GetModelIndex(const QAbstractItemModel* model, int targetDepth, int row) + { + AZStd::deque> indices; + indices.push_back({ model->index(0, 0), 0 }); + while (!indices.empty()) + { + auto [index, depth] = indices.front(); + indices.pop_front(); + + for (int i = 0; i < model->rowCount(index); ++i) + { + if (depth + 1 == targetDepth && row == i) + { + return model->index(i, 0, index); + } + indices.emplace_front(model->index(i, 0, index), depth + 1); + } + } + return QModelIndex(); + } + + AZStd::shared_ptr AssetBrowserTest::GetRootEntry() + { + return m_assetBrowserComponent->GetAssetBrowserModel()->GetRootEntry(); + } + + AZStd::vector AssetBrowserTest::GetVectorFromFormattedString(const QString& formattedString) + { + AZStd::vector hierarchySections; + QStringList splittedList = formattedString.split('\n', Qt::SkipEmptyParts); + + for (auto& str : splittedList) + { + str.replace(" ", ""); + hierarchySections.push_back(str); + } + return hierarchySections; + } + + TEST_F(AssetBrowserTest, CheckCorrectNumberOfEntriesInTableView) + { + m_filterModel->FilterUpdatedSlotImmediate(); + const int tableViewRowcount = m_tableModel->rowCount(); + + // RowCount should be 17 -> 5 SourceEntries + 12 ProductEntries) + EXPECT_EQ(tableViewRowcount, 17); + } + + TEST_F(AssetBrowserTest, CheckCorrectNumberOfEntriesInTableViewAfterStringFilter) + { + /* + *-Source_1 + * | + * |-product_1_0 + * |-product_1_1 + * + * + * Matching entries = 3 + */ + + // Apply string filter + m_searchWidget->SetTextFilter(QString("source_1")); + m_filterModel->FilterUpdatedSlotImmediate(); + + const int tableViewRowcount = m_tableModel->rowCount(); + EXPECT_EQ(tableViewRowcount, 3); + } + + TEST_F(AssetBrowserTest, CheckScanFolderAddition) + { + EXPECT_EQ(m_assetBrowserComponent->GetAssetBrowserModel()->rowCount(), 1); + const int newFolderId = 20; + AddScanFolder(newFolderId, "E:/TestFolder/TestFolder2", "TestFolder"); + + // Since the folder is empty it shouldn't be added to the model. + EXPECT_EQ(m_assetBrowserComponent->GetAssetBrowserModel()->rowCount(), 1); + + CreateSourceEntry(123, newFolderId, "DummyFile"); + + // When we add a file to the folder it should be added to the model + EXPECT_EQ(m_assetBrowserComponent->GetAssetBrowserModel()->rowCount(), 2); + } + +} // namespace UnitTest diff --git a/Code/Framework/AzToolsFramework/Tests/aztoolsframeworktests_files.cmake b/Code/Framework/AzToolsFramework/Tests/aztoolsframeworktests_files.cmake index 008c09188b..d597c9b570 100644 --- a/Code/Framework/AzToolsFramework/Tests/aztoolsframeworktests_files.cmake +++ b/Code/Framework/AzToolsFramework/Tests/aztoolsframeworktests_files.cmake @@ -123,6 +123,7 @@ set(FILES UI/EntityIdQLineEditTests.cpp UI/EntityOutlinerTests.cpp UI/EntityPropertyEditorTests.cpp + UI/AssetBrowserTests.cpp UndoStack.cpp Viewport/ClusterTests.cpp Viewport/ViewportEditorModeTests.cpp From c0d36399db2c7e14c0c5e4886621bb669d6aed88 Mon Sep 17 00:00:00 2001 From: Tom Hulton-Harrop <82228511+hultonha@users.noreply.github.com> Date: Mon, 8 Nov 2021 13:37:35 +0000 Subject: [PATCH 39/53] Improvements to feedback for default camera orbit point (when no entity is selected) (#5397) * improvements to camera orbit feedback Signed-off-by: Tom Hulton-Harrop <82228511+hultonha@users.noreply.github.com> * minor tidy-up before publishing PR Signed-off-by: Tom Hulton-Harrop <82228511+hultonha@users.noreply.github.com> * updates following review feedback Signed-off-by: Tom Hulton-Harrop <82228511+hultonha@users.noreply.github.com> --- .../EditorModularViewportCameraComposer.cpp | 113 ++++++++++++++++-- .../EditorModularViewportCameraComposer.h | 14 +++ 2 files changed, 119 insertions(+), 8 deletions(-) diff --git a/Code/Editor/EditorModularViewportCameraComposer.cpp b/Code/Editor/EditorModularViewportCameraComposer.cpp index 08ca0df221..72fd37605a 100644 --- a/Code/Editor/EditorModularViewportCameraComposer.cpp +++ b/Code/Editor/EditorModularViewportCameraComposer.cpp @@ -13,9 +13,32 @@ #include #include #include +#include #include #include +AZ_CVAR( + bool, + ed_cameraPinDefaultOrbit, + true, + nullptr, + AZ::ConsoleFunctorFlags::Null, + "Sets whether the default orbit point moves with the camera or not"); +AZ_CVAR( + bool, + ed_cameraDefaultOrbitAxesOrtho, + true, + nullptr, + AZ::ConsoleFunctorFlags::Null, + "Sets whether to draw the default orbit point as orthographic or not"); +AZ_CVAR( + float, + ed_cameraDefaultOrbitFadeDuration, + 0.5f, + nullptr, + AZ::ConsoleFunctorFlags::Null, + "Sets how long the default orbit point should take to appear and disappear"); + namespace SandboxEditor { static AzFramework::TranslateCameraInputChannelIds BuildTranslateCameraInputChannelIds() @@ -190,12 +213,6 @@ namespace SandboxEditor return AZStd::nullopt; }; - const auto orbitFn = [pivotFn](const AZ::Vector3& pivotFallback = AZ::Vector3::CreateZero()) - { - // return the pivot otherwise use the fallback - return pivotFn().value_or(pivotFallback); - }; - m_firstPersonFocusCamera = AZStd::make_shared(SandboxEditor::CameraFocusChannelId(), AzFramework::FocusLook); @@ -204,9 +221,26 @@ namespace SandboxEditor m_orbitCamera = AZStd::make_shared(SandboxEditor::CameraOrbitChannelId()); m_orbitCamera->SetPivotFn( - [orbitFn]([[maybe_unused]] const AZ::Vector3& position, [[maybe_unused]] const AZ::Vector3& direction) + [this, pivotFn](const AZ::Vector3& position, const AZ::Vector3& direction) { - return orbitFn(position + direction * SandboxEditor::CameraDefaultOrbitDistance()); + // return the pivot + if (auto pivot = pivotFn()) + { + return pivot.value(); + } + + // start ticking and drawing (for the default pivot) + AZ::TickBus::Handler::BusConnect(); + AzFramework::ViewportDebugDisplayEventBus::Handler::BusConnect(AzToolsFramework::GetEntityContextId()); + + m_defaultOrbiting = true; + // calculate the default orbit point + if (!ed_cameraPinDefaultOrbit || m_orbitCamera->Beginning()) + { + m_defaultOrbitPoint = position + direction * SandboxEditor::CameraDefaultOrbitDistance(); + } + + return m_defaultOrbitPoint; }); m_orbitRotateCamera = AZStd::make_shared(SandboxEditor::CameraOrbitLookChannelId()); @@ -311,4 +345,67 @@ namespace SandboxEditor m_viewportId, &AtomToolsFramework::ModularViewportCameraControllerRequestBus::Events::ClearReferenceFrame); } } + + void EditorModularViewportCameraComposer::OnTick(const float deltaTime, [[maybe_unused]] AZ::ScriptTimePoint time) + { + const float delta = [duration = &ed_cameraDefaultOrbitFadeDuration, deltaTime] { + if (*duration == 0.0f) { + return 1.0f; + } + return deltaTime / *duration; + }(); + + if (m_defaultOrbiting) + { + m_defaultOrbitOpacity = AZStd::min(m_defaultOrbitOpacity + delta, 1.0f); + } + else + { + m_defaultOrbitOpacity = AZStd::max(m_defaultOrbitOpacity - delta, 0.0f); + if (m_defaultOrbitOpacity == 0.0f) + { + AZ::TickBus::Handler::BusDisconnect(); + AzFramework::ViewportDebugDisplayEventBus::Handler::BusDisconnect(); + } + } + + m_defaultOrbiting = false; + } + + static void DrawTransformAxis( + AzFramework::DebugDisplayRequests& display, + const AzFramework::CameraState& cameraState, + const AZ::Vector3& pivot, + const float axisLength, + const float alpha) + { + const int prevState = display.GetState(); + + display.DepthWriteOff(); + display.DepthTestOff(); + display.CullOff(); + + const float orthoScale = + ed_cameraDefaultOrbitAxesOrtho ? AzToolsFramework::CalculateScreenToWorldMultiplier(pivot, cameraState) : 1.0f; + + display.SetColor(AZ::Color::CreateFromVector3AndFloat(AZ::Colors::Red.GetAsVector3(), alpha)); + display.DrawLine(pivot, pivot + AZ::Vector3::CreateAxisX() * axisLength * orthoScale); + display.SetColor(AZ::Color::CreateFromVector3AndFloat(AZ::Colors::LawnGreen.GetAsVector3(), alpha)); + display.DrawLine(pivot, pivot + AZ::Vector3::CreateAxisY() * axisLength * orthoScale); + display.SetColor(AZ::Color::CreateFromVector3AndFloat(AZ::Colors::Blue.GetAsVector3(), alpha)); + display.DrawLine(pivot, pivot + AZ::Vector3::CreateAxisZ() * axisLength * orthoScale); + + display.DepthWriteOn(); + display.DepthTestOn(); + display.CullOn(); + + display.SetState(prevState); + } + + void EditorModularViewportCameraComposer::DisplayViewport( + [[maybe_unused]] const AzFramework::ViewportInfo& viewportInfo, AzFramework::DebugDisplayRequests& debugDisplay) + { + DrawTransformAxis( + debugDisplay, AzToolsFramework::GetCameraState(viewportInfo.m_viewportId), m_defaultOrbitPoint, 1.0f, m_defaultOrbitOpacity); + } } // namespace SandboxEditor diff --git a/Code/Editor/EditorModularViewportCameraComposer.h b/Code/Editor/EditorModularViewportCameraComposer.h index 9cfd6f3554..6cd5df533c 100644 --- a/Code/Editor/EditorModularViewportCameraComposer.h +++ b/Code/Editor/EditorModularViewportCameraComposer.h @@ -9,6 +9,8 @@ #pragma once #include +#include +#include #include #include #include @@ -20,6 +22,8 @@ namespace SandboxEditor class EditorModularViewportCameraComposer : private EditorModularViewportCameraComposerNotificationBus::Handler , private Camera::EditorCameraNotificationBus::Handler + , private AzFramework::ViewportDebugDisplayEventBus::Handler + , private AZ::TickBus::Handler { public: SANDBOX_API explicit EditorModularViewportCameraComposer(AzFramework::ViewportId viewportId); @@ -29,6 +33,12 @@ namespace SandboxEditor SANDBOX_API AZStd::shared_ptr CreateModularViewportCameraController(); private: + // AzFramework::ViewportDebugDisplayEventBus overrides ... + void DisplayViewport(const AzFramework::ViewportInfo& viewportInfo, AzFramework::DebugDisplayRequests& debugDisplay) override; + + // AZ::TickBus overrides ... + void OnTick(float deltaTime, AZ::ScriptTimePoint time) override; + //! Setup all internal camera inputs. void SetupCameras(); @@ -52,5 +62,9 @@ namespace SandboxEditor AZStd::shared_ptr m_orbitFocusCamera; AzFramework::ViewportId m_viewportId; + + float m_defaultOrbitOpacity = 0.0f; //!< The default orbit axes opacity (to fade in and out). + AZ::Vector3 m_defaultOrbitPoint = AZ::Vector3::CreateZero(); //!< The orbit point to use when no entity is selected. + bool m_defaultOrbiting = false; //!< Is the camera default orbiting (orbiting when there's no selected entity). }; } // namespace SandboxEditor From 5a39361f777a4aa8e217bf3a899d2a3bf12e70bb Mon Sep 17 00:00:00 2001 From: Qing Tao <55564570+VickyAtAZ@users.noreply.github.com> Date: Mon, 8 Nov 2021 07:49:30 -0800 Subject: [PATCH 40/53] =?UTF-8?q?ATOM-16747=20RPISystemInterface::GetDefau?= =?UTF-8?q?ltScene=20returns=20the=20scene=20crea=E2=80=A6=20(#5153)=20(#5?= =?UTF-8?q?389)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * ATOM-16747 RPISystemInterface::GetDefaultScene returns the scene created by PreviewRenderer but not the Main Scene Deprecate GetDefaultScene() function. Update all the places which use GetDefaultScene to use Scene::GetFeatureProcessorFromEntityId or GetMainScene. Tested with Editor, UI Editor, Material Editor, game launcher. Signed-off-by: Qing Tao <55564570+VickyAtAZ@users.noreply.github.com> (cherry picked from commit 8da6bea0733aa43c19937fc8ba46d5ab3e514968) --- .../Code/Source/BootstrapSystemComponent.cpp | 1 + .../Code/Source/LuxCore/LuxCoreTexture.cpp | 10 +++-- .../Code/Include/Atom/RPI.Public/RPISystem.h | 3 +- .../Atom/RPI.Public/RPISystemInterface.h | 12 ++++-- .../RPI/Code/Include/Atom/RPI.Public/Scene.h | 17 +++++--- .../Atom/RPI.Reflect/System/SceneDescriptor.h | 4 ++ .../RPI/Code/Source/RPI.Public/Culling.cpp | 4 +- .../RPI/Code/Source/RPI.Public/RPISystem.cpp | 41 ++++++++++++++----- .../Atom/RPI/Code/Source/RPI.Public/Scene.cpp | 25 +++++++++-- .../PreviewRenderer/PreviewRenderer.cpp | 1 + .../MaterialEditorViewportInputController.cpp | 4 +- .../RotateEnvironmentBehavior.cpp | 3 +- .../Viewport/MaterialViewportRenderer.cpp | 1 + .../Code/Source/AtomBridgeSystemComponent.cpp | 6 +-- .../AtomDebugDisplayViewportInterface.cpp | 3 +- .../AtomDebugDisplayViewportInterface.h | 2 +- .../AtomLyIntegration/AtomFont/FFont.h | 12 ------ ...eGlobalIlluminationComponentController.cpp | 6 +-- .../Source/Grid/GridComponentController.cpp | 2 +- .../DisplayMapperComponentController.cpp | 3 +- .../SkinnedMesh/SkinnedMeshDebugDisplay.h | 2 +- .../Tools/EMStudio/AnimViewportRenderer.cpp | 4 +- .../Components/BlastSystemComponent.cpp | 25 ++++++----- Gems/LyShine/Code/Source/Draw2d.cpp | 12 +++--- Gems/LyShine/Code/Source/LyShine.cpp | 4 +- Gems/LyShine/Code/Source/UiRenderer.cpp | 13 +++--- Gems/LyShine/Code/Source/UiRenderer.h | 4 +- 27 files changed, 133 insertions(+), 91 deletions(-) diff --git a/Gems/Atom/Bootstrap/Code/Source/BootstrapSystemComponent.cpp b/Gems/Atom/Bootstrap/Code/Source/BootstrapSystemComponent.cpp index c232d4bba7..84fc58718c 100644 --- a/Gems/Atom/Bootstrap/Code/Source/BootstrapSystemComponent.cpp +++ b/Gems/Atom/Bootstrap/Code/Source/BootstrapSystemComponent.cpp @@ -272,6 +272,7 @@ namespace AZ // Create and register a scene with all available feature processors RPI::SceneDescriptor sceneDesc; + sceneDesc.m_nameId = AZ::Name("Main"); AZ::RPI::ScenePtr atomScene = RPI::Scene::CreateScene(sceneDesc); atomScene->EnableAllFeatureProcessors(); atomScene->Activate(); diff --git a/Gems/Atom/Feature/Common/Code/Source/LuxCore/LuxCoreTexture.cpp b/Gems/Atom/Feature/Common/Code/Source/LuxCore/LuxCoreTexture.cpp index aa906a06f7..1fd8f0d91c 100644 --- a/Gems/Atom/Feature/Common/Code/Source/LuxCore/LuxCoreTexture.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/LuxCore/LuxCoreTexture.cpp @@ -32,7 +32,7 @@ namespace AZ { if (m_rtPipeline) { - AZ::RPI::RPISystemInterface::Get()->GetDefaultScene()->RemoveRenderPipeline(m_rtPipeline->GetId()); + m_rtPipeline->RemoveFromScene(); m_rtPipeline = nullptr; } @@ -111,8 +111,12 @@ namespace AZ parentPass->SetSourceTexture(m_texture, RHI::Format::R8G8B8A8_UNORM); break; } - - AZ::RPI::RPISystemInterface::Get()->GetDefaultScene()->AddRenderPipeline(m_rtPipeline); + + const auto mainScene = AZ::RPI::RPISystemInterface::Get()->GetSceneByName(AZ::Name("RPI")); + if (mainScene) + { + mainScene->AddRenderPipeline(m_rtPipeline); + } } bool LuxCoreTexture::IsIBLTexture() diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/RPISystem.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/RPISystem.h index 4914e4b6fe..92370c5a82 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/RPISystem.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/RPISystem.h @@ -70,7 +70,8 @@ namespace AZ void InitializeSystemAssets() override; void RegisterScene(ScenePtr scene) override; void UnregisterScene(ScenePtr scene) override; - ScenePtr GetScene(const SceneId& sceneId) const override; + Scene* GetScene(const SceneId& sceneId) const override; + Scene* GetSceneByName(const AZ::Name& name) const override; ScenePtr GetDefaultScene() const override; RenderPipelinePtr GetRenderPipelineForWindow(AzFramework::NativeWindowHandle windowHandle) override; Data::Asset GetCommonShaderAssetForSrgs() const override; diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/RPISystemInterface.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/RPISystemInterface.h index fe81596bd7..3f30d498cf 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/RPISystemInterface.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/RPISystemInterface.h @@ -13,6 +13,7 @@ #include +#include #include namespace AZ @@ -46,11 +47,14 @@ namespace AZ //! Unregister a scene from RPISystem. The scene won't be simulated or rendered. virtual void UnregisterScene(ScenePtr scene) = 0; - // [GFX TODO] to be removed when we have scene setup in AZ Core - virtual ScenePtr GetDefaultScene() const = 0; - + //! Deprecated. Use GetSceneByName(name), GetSceneForEntityContextId(entityContextId) or Scene::GetSceneForEntityId(AZ::EntityId entityId) instead + AZ_DEPRECATED(virtual ScenePtr GetDefaultScene() const = 0;, "This method has been deprecated. Please use GetSceneByName(name), GetSceneForEntityContextId(entityContextId) or Scene::GetSceneForEntityId(AZ::EntityId entityId) instead."); + //! Get scene by using scene id. - virtual ScenePtr GetScene(const SceneId& sceneId) const = 0; + virtual Scene* GetScene(const SceneId& sceneId) const = 0; + + //! Get scene by using scene name. + virtual Scene* GetSceneByName(const AZ::Name& name) const = 0; //! Get the render pipeline created for a window virtual RenderPipelinePtr GetRenderPipelineForWindow(AzFramework::NativeWindowHandle windowHandle) = 0; diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Scene.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Scene.h index fc81368331..f86383101a 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Scene.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Scene.h @@ -80,6 +80,9 @@ namespace AZ //! Gets the RPI::Scene for a given entityContextId. //! May return nullptr if there is no RPI::Scene created for that entityContext. static Scene* GetSceneForEntityContextId(AzFramework::EntityContextId entityContextId); + + //! Gets the RPI::Scene for a given entityId. + static Scene* GetSceneForEntityId(AZ::EntityId entityId); ~Scene(); @@ -135,6 +138,8 @@ namespace AZ const SceneId& GetId() const; + AZ::Name GetName() const; + //! Set default pipeline by render pipeline ID. //! It returns true if the default render pipeline was set from the input ID. //! If the specified render pipeline doesn't exist in this scene then it won't do anything and returns false. @@ -245,6 +250,9 @@ namespace AZ // The uuid to identify this scene. SceneId m_id; + // Scene's name which is set at initialization. Can be empty + AZ::Name m_name; + bool m_activated = false; bool m_taskGraphActive = false; // update during tick, to ensure it only changes on frame boundaries @@ -286,13 +294,10 @@ namespace AZ template FeatureProcessorType* Scene::GetFeatureProcessorForEntity(AZ::EntityId entityId) { - // Find the entity context for the entity ID. - AzFramework::EntityContextId entityContextId = AzFramework::EntityContextId::CreateNull(); - AzFramework::EntityIdContextQueryBus::EventResult(entityContextId, entityId, &AzFramework::EntityIdContextQueryBus::Events::GetOwningContextId); - - if (!entityContextId.IsNull()) + RPI::Scene* renderScene = GetSceneForEntityId(entityId); + if (renderScene) { - return GetFeatureProcessorForEntityContextId(entityContextId); + return renderScene->GetFeatureProcessor(); } return nullptr; }; diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/System/SceneDescriptor.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/System/SceneDescriptor.h index 2072568d59..eb7a2b6cb7 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/System/SceneDescriptor.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/System/SceneDescriptor.h @@ -9,6 +9,7 @@ #pragma once #include +#include #include #include @@ -25,6 +26,9 @@ namespace AZ //! List of feature processors which the scene will initially enable. AZStd::vector m_featureProcessorNames; + + //! A name used as scene id. It can be used to search a registered scene via RPISystemInterface::GetScene() + AZ::Name m_nameId; }; } // namespace RPI } // namespace AZ diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Culling.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Culling.cpp index 348f0aa57a..ac6b10694e 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Culling.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Culling.cpp @@ -699,9 +699,7 @@ namespace AZ m_parentScene = parentScene; AZ_Assert(m_visScene == nullptr, "IVisibilityScene already created for this RPI::Scene"); - char sceneIdBuf[40] = ""; - m_parentScene->GetId().ToString(sceneIdBuf); - AZ::Name visSceneName(AZStd::string::format("RenderCullScene[%s]", sceneIdBuf)); + AZ::Name visSceneName(AZStd::string::format("RenderCullScene[%s]", m_parentScene->GetName().GetCStr())); m_visScene = AZ::Interface::Get()->CreateVisibilityScene(visSceneName); #ifdef AZ_CULL_DEBUG_ENABLED diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/RPISystem.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/RPISystem.cpp index eb74a81e3e..943966c13b 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/RPISystem.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/RPISystem.cpp @@ -159,6 +159,11 @@ namespace AZ AZ_Assert(false, "Scene was already registered"); return; } + else if (!scene->GetName().IsEmpty() && scene->GetName() == sceneItem->GetName()) + { + // only report a warning if there is a scene with duplicated name + AZ_Warning("RPISystem", false, "There is a registered scene with same name [%s]", scene->GetName().GetCStr()); + } } m_scenes.push_back(scene); @@ -177,11 +182,35 @@ namespace AZ AZ_Assert(false, "Can't unregister scene which wasn't registered"); } - ScenePtr RPISystem::GetScene(const SceneId& sceneId) const + Scene* RPISystem::GetScene(const SceneId& sceneId) const { for (const auto& scene : m_scenes) { if (scene->GetId() == sceneId) + { + return scene.get(); + } + } + return nullptr; + } + + Scene* RPISystem::GetSceneByName(const AZ::Name& name) const + { + for (const auto& scene : m_scenes) + { + if (scene->GetName() == name) + { + return scene.get(); + } + } + return nullptr; + } + + ScenePtr RPISystem::GetDefaultScene() const + { + for (const auto& scene : m_scenes) + { + if (scene->GetName() == AZ::Name("Main")) { return scene; } @@ -189,16 +218,6 @@ namespace AZ return nullptr; } - ScenePtr RPISystem::GetDefaultScene() const - { - if (m_scenes.size() > 0) - { - return m_scenes[0]; - } - return nullptr; - } - - RenderPipelinePtr RPISystem::GetRenderPipelineForWindow(AzFramework::NativeWindowHandle windowHandle) { RenderPipelinePtr renderPipeline; diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Scene.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Scene.cpp index c5d82c6f29..41fefda656 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Scene.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Scene.cpp @@ -45,7 +45,9 @@ namespace AZ auto shaderAsset = RPISystemInterface::Get()->GetCommonShaderAssetForSrgs(); scene->m_srg = ShaderResourceGroup::Create(shaderAsset, sceneSrgLayout->GetName()); } - + + scene->m_name = sceneDescriptor.m_nameId; + return ScenePtr(scene); } @@ -83,10 +85,23 @@ namespace AZ return nullptr; } + Scene* Scene::GetSceneForEntityId(AZ::EntityId entityId) + { + // Find the entity context for the entity ID. + AzFramework::EntityContextId entityContextId = AzFramework::EntityContextId::CreateNull(); + AzFramework::EntityIdContextQueryBus::EventResult(entityContextId, entityId, &AzFramework::EntityIdContextQueryBus::Events::GetOwningContextId); + + if (!entityContextId.IsNull()) + { + return GetSceneForEntityContextId(entityContextId); + } + return nullptr; + } + Scene::Scene() { - m_id = Uuid::CreateRandom(); + m_id = AZ::Uuid::CreateRandom(); m_cullingScene = aznew CullingScene(); SceneRequestBus::Handler::BusConnect(m_id); m_drawFilterTagRegistry = RHI::DrawFilterTagRegistry::Create(); @@ -299,7 +314,6 @@ namespace AZ // Force to update the lookup table since adding render pipeline would effect any pipeline states created before pass system tick RebuildPipelineStatesLookup(); - AZ_Assert(!m_id.IsNull(), "RPI::Scene needs to have a valid uuid."); SceneNotificationBus::Event(m_id, &SceneNotification::OnRenderPipelineAdded, pipeline); } @@ -785,6 +799,11 @@ namespace AZ { return m_id; } + + AZ::Name Scene::GetName() const + { + return m_name; + } bool Scene::SetDefaultRenderPipeline(const RenderPipelineId& pipelineId) { diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRenderer.cpp b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRenderer.cpp index 2b39a87623..27d468e64b 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRenderer.cpp +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRenderer.cpp @@ -43,6 +43,7 @@ namespace AtomToolsFramework &PreviewerFeatureProcessorProviderBus::Handler::GetRequiredFeatureProcessors, featureProcessors); AZ::RPI::SceneDescriptor sceneDesc; + sceneDesc.m_nameId = AZ::Name("PreviewRenderer"); sceneDesc.m_featureProcessorNames.assign(featureProcessors.begin(), featureProcessors.end()); m_scene = AZ::RPI::Scene::CreateScene(sceneDesc); diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/InputController/MaterialEditorViewportInputController.cpp b/Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/InputController/MaterialEditorViewportInputController.cpp index 932e2e7436..1784405ffa 100644 --- a/Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/InputController/MaterialEditorViewportInputController.cpp +++ b/Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/InputController/MaterialEditorViewportInputController.cpp @@ -279,9 +279,9 @@ namespace MaterialEditor // reset environment AZ::Transform iblTransform = AZ::Transform::CreateIdentity(); AZ::TransformBus::Event(m_iblEntityId, &AZ::TransformBus::Events::SetLocalTM, iblTransform); + const AZ::Matrix4x4 rotationMatrix = AZ::Matrix4x4::CreateIdentity(); - AZ::RPI::ScenePtr scene = AZ::RPI::RPISystemInterface::Get()->GetDefaultScene(); - auto skyBoxFeatureProcessorInterface = scene->GetFeatureProcessor(); + auto skyBoxFeatureProcessorInterface = AZ::RPI::Scene::GetFeatureProcessorForEntity(m_iblEntityId); skyBoxFeatureProcessorInterface->SetCubemapRotationMatrix(rotationMatrix); if (m_behavior) diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/InputController/RotateEnvironmentBehavior.cpp b/Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/InputController/RotateEnvironmentBehavior.cpp index 21d7dee51b..17fb3f3e52 100644 --- a/Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/InputController/RotateEnvironmentBehavior.cpp +++ b/Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/InputController/RotateEnvironmentBehavior.cpp @@ -25,8 +25,7 @@ namespace MaterialEditor m_iblEntityId, &MaterialEditorViewportInputControllerRequestBus::Handler::GetIblEntityId); AZ_Assert(m_iblEntityId.IsValid(), "Failed to find m_iblEntityId"); - AZ::RPI::ScenePtr scene = AZ::RPI::RPISystemInterface::Get()->GetDefaultScene(); - m_skyBoxFeatureProcessorInterface = scene->GetFeatureProcessor(); + m_skyBoxFeatureProcessorInterface = AZ::RPI::Scene::GetFeatureProcessorForEntity(m_iblEntityId); } void RotateEnvironmentBehavior::TickInternal(float x, float y, float z) diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/MaterialViewportRenderer.cpp b/Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/MaterialViewportRenderer.cpp index 6d6fd377e3..4ad87492e3 100644 --- a/Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/MaterialViewportRenderer.cpp +++ b/Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/MaterialViewportRenderer.cpp @@ -67,6 +67,7 @@ namespace MaterialEditor // Create and register a scene with all available feature processors AZ::RPI::SceneDescriptor sceneDesc; + sceneDesc.m_nameId = AZ::Name("MaterialViewport"); m_scene = AZ::RPI::Scene::CreateScene(sceneDesc); m_scene->EnableAllFeatureProcessors(); diff --git a/Gems/AtomLyIntegration/AtomBridge/Code/Source/AtomBridgeSystemComponent.cpp b/Gems/AtomLyIntegration/AtomBridge/Code/Source/AtomBridgeSystemComponent.cpp index b439ac475c..d822b16486 100644 --- a/Gems/AtomLyIntegration/AtomBridge/Code/Source/AtomBridgeSystemComponent.cpp +++ b/Gems/AtomLyIntegration/AtomBridge/Code/Source/AtomBridgeSystemComponent.cpp @@ -108,7 +108,7 @@ namespace AZ { m_dynamicDrawManager.reset(); AZ::RPI::ViewportContextManagerNotificationsBus::Handler::BusDisconnect(); - RPI::Scene* scene = RPI::RPISystemInterface::Get()->GetDefaultScene().get(); + RPI::Scene* scene = AZ::RPI::Scene::GetSceneForEntityContextId(m_entityContextId); // Check if scene is emptry since scene might be released already when running AtomSampleViewer if (scene) { @@ -157,9 +157,9 @@ namespace AZ void AtomBridgeSystemComponent::OnBootstrapSceneReady(AZ::RPI::Scene* bootstrapScene) { - AZ_UNUSED(bootstrapScene); // Make default AtomDebugDisplayViewportInterface - AZStd::shared_ptr mainEntityDebugDisplay = AZStd::make_shared(AzFramework::g_defaultSceneEntityDebugDisplayId); + AZStd::shared_ptr mainEntityDebugDisplay = + AZStd::make_shared(AzFramework::g_defaultSceneEntityDebugDisplayId, bootstrapScene); m_activeViewportsList[AzFramework::g_defaultSceneEntityDebugDisplayId] = mainEntityDebugDisplay; } diff --git a/Gems/AtomLyIntegration/AtomBridge/Code/Source/AtomDebugDisplayViewportInterface.cpp b/Gems/AtomLyIntegration/AtomBridge/Code/Source/AtomDebugDisplayViewportInterface.cpp index 1ccc36ab4d..12e4ccd8ad 100644 --- a/Gems/AtomLyIntegration/AtomBridge/Code/Source/AtomDebugDisplayViewportInterface.cpp +++ b/Gems/AtomLyIntegration/AtomBridge/Code/Source/AtomDebugDisplayViewportInterface.cpp @@ -256,12 +256,11 @@ namespace AZ::AtomBridge viewportContextPtr->ConnectSceneChangedHandler(m_sceneChangeHandler); } - AtomDebugDisplayViewportInterface::AtomDebugDisplayViewportInterface(uint32_t defaultInstanceAddress) + AtomDebugDisplayViewportInterface::AtomDebugDisplayViewportInterface(uint32_t defaultInstanceAddress, RPI::Scene* scene) { ResetRenderState(); m_viewportId = defaultInstanceAddress; m_defaultInstance = true; - RPI::Scene* scene = RPI::RPISystemInterface::Get()->GetDefaultScene().get(); InitInternal(scene, nullptr); } diff --git a/Gems/AtomLyIntegration/AtomBridge/Code/Source/AtomDebugDisplayViewportInterface.h b/Gems/AtomLyIntegration/AtomBridge/Code/Source/AtomDebugDisplayViewportInterface.h index 07f4efdf50..5f902c5884 100644 --- a/Gems/AtomLyIntegration/AtomBridge/Code/Source/AtomDebugDisplayViewportInterface.h +++ b/Gems/AtomLyIntegration/AtomBridge/Code/Source/AtomDebugDisplayViewportInterface.h @@ -124,7 +124,7 @@ namespace AZ::AtomBridge AZ_RTTI(AtomDebugDisplayViewportInterface, "{09AF6A46-0100-4FBF-8F94-E6B221322D14}", AzFramework::DebugDisplayRequestBus::Handler); explicit AtomDebugDisplayViewportInterface(AZ::RPI::ViewportContextPtr viewportContextPtr); - explicit AtomDebugDisplayViewportInterface(uint32_t defaultInstanceAddress); + explicit AtomDebugDisplayViewportInterface(uint32_t defaultInstanceAddress, RPI::Scene* scene); ~AtomDebugDisplayViewportInterface(); void ResetRenderState(); diff --git a/Gems/AtomLyIntegration/AtomFont/Code/Include/AtomLyIntegration/AtomFont/FFont.h b/Gems/AtomLyIntegration/AtomFont/Code/Include/AtomLyIntegration/AtomFont/FFont.h index 2cc8a67cfa..ff6ad7c151 100644 --- a/Gems/AtomLyIntegration/AtomFont/Code/Include/AtomLyIntegration/AtomFont/FFont.h +++ b/Gems/AtomLyIntegration/AtomFont/Code/Include/AtomLyIntegration/AtomFont/FFont.h @@ -133,18 +133,6 @@ namespace AZ typedef std::vector FontEffects; typedef FontEffects::iterator FontEffectsIterator; - struct FontPipelineStateMapKey - { - AZ::RPI::SceneId m_sceneId; // which scene pipeline state is attached to (via Render Pipeline) - AZ::RHI::DrawListTag m_drawListTag; // which render pass this pipeline draws in by default - - bool operator<(const FontPipelineStateMapKey& other) const - { - return m_sceneId < other.m_sceneId - || (m_sceneId == other.m_sceneId && m_drawListTag < other.m_drawListTag); - } - }; - struct FontShaderData { AZ::RHI::ShaderInputNameIndex m_imageInputIndex = "m_texture"; diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/DiffuseGlobalIllumination/DiffuseGlobalIlluminationComponentController.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/DiffuseGlobalIllumination/DiffuseGlobalIlluminationComponentController.cpp index ee322c8afd..e844219811 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/DiffuseGlobalIllumination/DiffuseGlobalIlluminationComponentController.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/DiffuseGlobalIllumination/DiffuseGlobalIlluminationComponentController.cpp @@ -48,11 +48,7 @@ namespace AZ void DiffuseGlobalIlluminationComponentController::Activate(EntityId entityId) { - AZ_UNUSED(entityId); - - const RPI::Scene* scene = AZ::RPI::RPISystemInterface::Get()->GetDefaultScene().get(); - m_featureProcessor = scene->GetFeatureProcessor(); - + m_featureProcessor = AZ::RPI::Scene::GetFeatureProcessorForEntity(entityId); OnConfigChanged(); } diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Grid/GridComponentController.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Grid/GridComponentController.cpp index b4131894f4..2611021359 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Grid/GridComponentController.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Grid/GridComponentController.cpp @@ -79,7 +79,7 @@ namespace AZ m_entityId = entityId; m_dirty = true; - RPI::ScenePtr scene = RPI::RPISystemInterface::Get()->GetDefaultScene(); + RPI::Scene* scene = RPI::Scene::GetSceneForEntityId(m_entityId); if (scene) { AZ::RPI::SceneNotificationBus::Handler::BusConnect(scene->GetId()); diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/PostProcess/DisplayMapper/DisplayMapperComponentController.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/PostProcess/DisplayMapper/DisplayMapperComponentController.cpp index e86c909121..a0577c6240 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/PostProcess/DisplayMapper/DisplayMapperComponentController.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/PostProcess/DisplayMapper/DisplayMapperComponentController.cpp @@ -357,8 +357,7 @@ namespace AZ void DisplayMapperComponentController::OnConfigChanged() { // Register the configuration with the AcesDisplayMapperFeatureProcessor for this scene. - const AZ::RPI::Scene* scene = AZ::RPI::RPISystemInterface::Get()->GetDefaultScene().get(); - DisplayMapperFeatureProcessorInterface* fp = scene->GetFeatureProcessor(); + DisplayMapperFeatureProcessorInterface* fp = AZ::RPI::Scene::GetFeatureProcessorForEntity(m_entityId); DisplayMapperConfigurationDescriptor desc; desc.m_operationType = m_configuration.m_displayMapperOperation; desc.m_ldrGradingLutEnabled = m_configuration.m_ldrColorGradingLutEnabled; diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SkinnedMesh/SkinnedMeshDebugDisplay.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SkinnedMesh/SkinnedMeshDebugDisplay.h index e789b6dc80..5b060198dc 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SkinnedMesh/SkinnedMeshDebugDisplay.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SkinnedMesh/SkinnedMeshDebugDisplay.h @@ -48,7 +48,7 @@ namespace AZ // CVar for toggling the display of the scene stats int r_skinnedMeshDisplaySceneStats = 0; // SceneId to query for the stats - RPI::SceneId m_sceneId = RPI::SceneId::CreateNull(); + RPI::SceneId m_sceneId; }; }// namespace Render }// namespace AZ diff --git a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportRenderer.cpp b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportRenderer.cpp index faa033956a..eb99b8171a 100644 --- a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportRenderer.cpp +++ b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportRenderer.cpp @@ -60,6 +60,7 @@ namespace EMStudio // Create and register a scene with all available feature processors AZ::RPI::SceneDescriptor sceneDesc; + sceneDesc.m_nameId = AZ::Name("AnimViewport"); m_scene = AZ::RPI::Scene::CreateScene(sceneDesc); m_scene->EnableAllFeatureProcessors(); @@ -213,8 +214,7 @@ namespace EMStudio AZ::TransformBus::Event(m_iblEntity->GetId(), &AZ::TransformBus::Events::SetLocalTM, iblTransform); const AZ::Matrix4x4 rotationMatrix = AZ::Matrix4x4::CreateIdentity(); - AZ::RPI::ScenePtr scene = AZ::RPI::RPISystemInterface::Get()->GetDefaultScene(); - auto skyBoxFeatureProcessorInterface = scene->GetFeatureProcessor(); + auto skyBoxFeatureProcessorInterface = m_scene->GetFeatureProcessor(); skyBoxFeatureProcessorInterface->SetCubemapRotationMatrix(rotationMatrix); } diff --git a/Gems/Blast/Code/Source/Components/BlastSystemComponent.cpp b/Gems/Blast/Code/Source/Components/BlastSystemComponent.cpp index 00629eb65d..4c0f15463a 100644 --- a/Gems/Blast/Code/Source/Components/BlastSystemComponent.cpp +++ b/Gems/Blast/Code/Source/Components/BlastSystemComponent.cpp @@ -255,19 +255,22 @@ namespace Blast BlastFamilyComponentRequestBus::Broadcast( &BlastFamilyComponentRequests::FillDebugRenderBuffer, buffer, m_debugRenderMode); - // This is a system component, and thus is not associated with a specific scene, so use the default scene + // This is a system component, and thus is not associated with a specific scene, so use the bootstrap scene // for the debug drawing - const auto defaultScene = AZ::RPI::RPISystemInterface::Get()->GetDefaultScene(); - auto drawQueue = AZ::RPI::AuxGeomFeatureProcessorInterface::GetDrawQueueForScene(defaultScene); - - for (DebugLine& line : buffer.m_lines) + const auto mainScene = AZ::RPI::RPISystemInterface::Get()->GetSceneByName(AZ::Name("Main")); + if (mainScene) { - AZ::RPI::AuxGeomDraw::AuxGeomDynamicDrawArguments drawArguments; - drawArguments.m_verts = &line.m_p0; - drawArguments.m_vertCount = 2; - drawArguments.m_colors = &line.m_color; - drawArguments.m_colorCount = 1; - drawQueue->DrawLines(drawArguments); + auto drawQueue = AZ::RPI::AuxGeomFeatureProcessorInterface::GetDrawQueueForScene(mainScene); + + for (DebugLine& line : buffer.m_lines) + { + AZ::RPI::AuxGeomDraw::AuxGeomDynamicDrawArguments drawArguments; + drawArguments.m_verts = &line.m_p0; + drawArguments.m_vertCount = 2; + drawArguments.m_colors = &line.m_color; + drawArguments.m_colorCount = 1; + drawQueue->DrawLines(drawArguments); + } } } } diff --git a/Gems/LyShine/Code/Source/Draw2d.cpp b/Gems/LyShine/Code/Source/Draw2d.cpp index b0539900e2..3476c530b2 100644 --- a/Gems/LyShine/Code/Source/Draw2d.cpp +++ b/Gems/LyShine/Code/Source/Draw2d.cpp @@ -65,7 +65,7 @@ CDraw2d::~CDraw2d() } //////////////////////////////////////////////////////////////////////////////////////////////////// -void CDraw2d::OnBootstrapSceneReady([[maybe_unused]] AZ::RPI::Scene* bootstrapScene) +void CDraw2d::OnBootstrapSceneReady(AZ::RPI::Scene* bootstrapScene) { // At this point the RPI is ready for use @@ -74,16 +74,16 @@ void CDraw2d::OnBootstrapSceneReady([[maybe_unused]] AZ::RPI::Scene* bootstrapSc AZ::Data::Instance shader = AZ::RPI::LoadCriticalShader(shaderFilepath); // Set scene to be associated with the dynamic draw context - AZ::RPI::ScenePtr scene; + AZ::RPI::Scene* scene = nullptr; if (m_viewportContext) { // Use scene associated with the specified viewport context - scene = m_viewportContext->GetRenderScene(); + scene = m_viewportContext->GetRenderScene().get(); } else { - // No viewport context specified, use default scene - scene = AZ::RPI::RPISystemInterface::Get()->GetDefaultScene(); + // No viewport context specified, use main scene + scene = bootstrapScene; } AZ_Assert(scene != nullptr, "Attempting to create a DynamicDrawContext for a viewport context that has not been associated with a scene yet."); @@ -113,7 +113,7 @@ void CDraw2d::OnBootstrapSceneReady([[maybe_unused]] AZ::RPI::Scene* bootstrapSc else { // Render target support is disabled - m_dynamicDraw->SetOutputScope(scene.get()); + m_dynamicDraw->SetOutputScope(scene); } m_dynamicDraw->EndInit(); diff --git a/Gems/LyShine/Code/Source/LyShine.cpp b/Gems/LyShine/Code/Source/LyShine.cpp index 2cee4e92eb..19c6e4281e 100644 --- a/Gems/LyShine/Code/Source/LyShine.cpp +++ b/Gems/LyShine/Code/Source/LyShine.cpp @@ -653,12 +653,12 @@ void CLyShine::OnRenderTick() } //////////////////////////////////////////////////////////////////////////////////////////////////// -void CLyShine::OnBootstrapSceneReady([[maybe_unused]] AZ::RPI::Scene* bootstrapScene) +void CLyShine::OnBootstrapSceneReady(AZ::RPI::Scene* bootstrapScene) { // Load cursor if its path was set before RPI was initialized LoadUiCursor(); - LyShinePassDataRequestBus::Handler::BusConnect(AZ::RPI::RPISystemInterface::Get()->GetDefaultScene()->GetId()); + LyShinePassDataRequestBus::Handler::BusConnect(bootstrapScene->GetId()); } //////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/Gems/LyShine/Code/Source/UiRenderer.cpp b/Gems/LyShine/Code/Source/UiRenderer.cpp index 3111f31615..98b376ec8b 100644 --- a/Gems/LyShine/Code/Source/UiRenderer.cpp +++ b/Gems/LyShine/Code/Source/UiRenderer.cpp @@ -52,7 +52,7 @@ bool UiRenderer::IsReady() return m_isRPIReady; } -void UiRenderer::OnBootstrapSceneReady([[maybe_unused]] AZ::RPI::Scene* bootstrapScene) +void UiRenderer::OnBootstrapSceneReady(AZ::RPI::Scene* bootstrapScene) { // At this point the RPI is ready for use @@ -64,16 +64,17 @@ void UiRenderer::OnBootstrapSceneReady([[maybe_unused]] AZ::RPI::Scene* bootstra if (m_viewportContext) { // Create a new scene based on the user specified viewport context - m_scene = CreateScene(m_viewportContext); + m_ownedScene = CreateScene(m_viewportContext); + m_scene = m_ownedScene.get(); } else { // No viewport context specified, use default scene - m_scene = AZ::RPI::RPISystemInterface::Get()->GetDefaultScene(); + m_scene = bootstrapScene; } // Create a dynamic draw context for UI Canvas drawing for the scene - m_dynamicDraw = CreateDynamicDrawContext(m_scene, uiShader); + m_dynamicDraw = CreateDynamicDrawContext(uiShader); if (m_dynamicDraw) { @@ -93,6 +94,7 @@ AZ::RPI::ScenePtr UiRenderer::CreateScene(AZStd::shared_ptrEnableAllFeatureProcessors(); // LYSHINE_ATOM_TODO - have a UI pipeline and enable only needed fps @@ -116,7 +118,6 @@ AZ::RPI::ScenePtr UiRenderer::CreateScene(AZStd::shared_ptr UiRenderer::CreateDynamicDrawContext( - AZ::RPI::ScenePtr scene, AZ::Data::Instance uiShader) { // Find the pass that renders the UI canvases after the rtt passes @@ -144,7 +145,7 @@ AZ::RHI::Ptr UiRenderer::CreateDynamicDrawContext( else { // Render target support is disabled - dynamicDraw->SetOutputScope(m_scene.get()); + dynamicDraw->SetOutputScope(m_scene); } dynamicDraw->EndInit(); diff --git a/Gems/LyShine/Code/Source/UiRenderer.h b/Gems/LyShine/Code/Source/UiRenderer.h index 3be3c832d3..0e15d41907 100644 --- a/Gems/LyShine/Code/Source/UiRenderer.h +++ b/Gems/LyShine/Code/Source/UiRenderer.h @@ -152,7 +152,6 @@ private: // member functions //! Create a dynamic draw context for this renderer AZ::RHI::Ptr CreateDynamicDrawContext( - AZ::RPI::ScenePtr scene, AZ::Data::Instance uiShader); //! Bind the global white texture for all the texture units we use @@ -175,7 +174,8 @@ protected: // attributes // Set by user when viewport context is not the main/default viewport AZStd::shared_ptr m_viewportContext; - AZ::RPI::ScenePtr m_scene; + AZ::RPI::ScenePtr m_ownedScene; + AZ::RPI::Scene* m_scene = nullptr; #ifndef _RELEASE int m_debugTextureDataRecordLevel = 0; From 652e35b0ca2314e825ebd48a266e5b58caa5920a Mon Sep 17 00:00:00 2001 From: srikappa-amzn <82230713+srikappa-amzn@users.noreply.github.com> Date: Mon, 8 Nov 2021 21:31:57 +0530 Subject: [PATCH 41/53] Fix camera transforms being reset when switching to default editor camera (#5326) Signed-off-by: srikappa-amzn --- Code/Editor/EditorViewportWidget.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Code/Editor/EditorViewportWidget.cpp b/Code/Editor/EditorViewportWidget.cpp index 5c5ab87058..290f0fd17f 100644 --- a/Code/Editor/EditorViewportWidget.cpp +++ b/Code/Editor/EditorViewportWidget.cpp @@ -2021,10 +2021,6 @@ void EditorViewportWidget::SetDefaultCamera() GetViewManager()->SetCameraObjectId(GUID_NULL); SetName(m_defaultViewName); - // Set the default Editor Camera position. - m_defaultViewTM.SetTranslation(Vec3(m_editorViewportSettings.DefaultEditorCameraPosition())); - SetViewTM(m_defaultViewTM); - // Synchronize the configured editor viewport FOV to the default camera if (m_viewPane) { @@ -2041,6 +2037,10 @@ void EditorViewportWidget::SetDefaultCamera() atomViewportRequests->PushView(contextName, m_defaultView); } + // Set the default Editor Camera position. + m_defaultViewTM.SetTranslation(Vec3(m_editorViewportSettings.DefaultEditorCameraPosition())); + SetViewTM(m_defaultViewTM); + PostCameraSet(); } From 14a120627415a0b295ba4d486b00467d71540b55 Mon Sep 17 00:00:00 2001 From: nggieber Date: Mon, 8 Nov 2021 08:17:28 -0800 Subject: [PATCH 42/53] Add additional info handling and proper display for gems Signed-off-by: nggieber --- .../Tools/ProjectManager/Source/GemCatalog/GemInspector.cpp | 3 ++- Code/Tools/ProjectManager/Source/PythonBindings.cpp | 6 +++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemInspector.cpp b/Code/Tools/ProjectManager/Source/GemCatalog/GemInspector.cpp index b0b8cca29a..6c61e280f3 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemInspector.cpp +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemInspector.cpp @@ -120,7 +120,8 @@ namespace O3DE::ProjectManager // Additional information m_versionLabel->setText(tr("Gem Version: %1").arg(m_model->GetVersion(modelIndex))); m_lastUpdatedLabel->setText(tr("Last Updated: %1").arg(m_model->GetLastUpdated(modelIndex))); - m_binarySizeLabel->setText(tr("Binary Size: %1 KB").arg(m_model->GetBinarySizeInKB(modelIndex))); + const int binarySize = m_model->GetBinarySizeInKB(modelIndex); + m_binarySizeLabel->setText(tr("Binary Size: %1").arg(binarySize ? tr("%1 KB").arg(binarySize) : tr("Unknown"))); m_mainWidget->adjustSize(); m_mainWidget->show(); diff --git a/Code/Tools/ProjectManager/Source/PythonBindings.cpp b/Code/Tools/ProjectManager/Source/PythonBindings.cpp index 905139a4f2..4a73b39ea0 100644 --- a/Code/Tools/ProjectManager/Source/PythonBindings.cpp +++ b/Code/Tools/ProjectManager/Source/PythonBindings.cpp @@ -53,6 +53,8 @@ namespace Platform #define Py_To_String(obj) pybind11::str(obj).cast().c_str() #define Py_To_String_Optional(dict, key, default_string) dict.contains(key) ? Py_To_String(dict[key]) : default_string +#define Py_To_Int(obj) obj.cast() +#define Py_To_Int_Optional(dict, key, default_int) dict.contains(key) ? Py_To_Int(dict[key]) : default_int #define QString_To_Py_String(value) pybind11::str(value.toStdString()) #define QString_To_Py_Path(value) m_pathlib.attr("Path")(value.toStdString()) @@ -705,7 +707,9 @@ namespace O3DE::ProjectManager // optional gemInfo.m_displayName = Py_To_String_Optional(data, "display_name", gemInfo.m_name); gemInfo.m_summary = Py_To_String_Optional(data, "summary", ""); - gemInfo.m_version = ""; + gemInfo.m_version = Py_To_String_Optional(data, "version", gemInfo.m_version); + gemInfo.m_lastUpdatedDate = Py_To_String_Optional(data, "last_updated", gemInfo.m_lastUpdatedDate); + gemInfo.m_binarySizeInKB = Py_To_Int_Optional(data, "binary_size", gemInfo.m_binarySizeInKB); gemInfo.m_requirement = Py_To_String_Optional(data, "requirements", ""); gemInfo.m_creator = Py_To_String_Optional(data, "origin", ""); gemInfo.m_documentationLink = Py_To_String_Optional(data, "documentation_url", ""); From 97bb01122fd0c02b5ba354ad41ba58dffaee873f Mon Sep 17 00:00:00 2001 From: Guthrie Adams Date: Mon, 8 Nov 2021 11:01:02 -0600 Subject: [PATCH 43/53] Add missing runtime dependency to atom ly integration Signed-off-by: Guthrie Adams --- Gems/AtomLyIntegration/CommonFeatures/Code/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/CMakeLists.txt b/Gems/AtomLyIntegration/CommonFeatures/Code/CMakeLists.txt index 95331a2f3f..7b685ece13 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/CMakeLists.txt +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/CMakeLists.txt @@ -111,6 +111,7 @@ if(PAL_TRAIT_BUILD_HOST_TOOLS) RUNTIME_DEPENDENCIES Gem::Atom_RPI.Editor Gem::Atom_Feature_Common.Editor + Gem::AtomToolsFramework.Editor Legacy::EditorCommon ) From 16f59809837ed9f1f5cf3a2bf145915c565287f5 Mon Sep 17 00:00:00 2001 From: Nicholas Van Sickle Date: Mon, 8 Nov 2021 09:11:13 -0800 Subject: [PATCH 44/53] Fix Prefab builder test (#5377) We were destructively moving the DOM template into the builder, leaving the Prefab system with an invalid DOM when teardown occurs. For now, this just copies the document to fix this specific test failure, but we may want to consider making `FindTemplateDom` return a const document and requiring that mutations get routed through the prefab system component to avoid similar situations in the future. Signed-off-by: nvsickle --- Gems/Prefab/PrefabBuilder/PrefabBuilderTests.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Gems/Prefab/PrefabBuilder/PrefabBuilderTests.cpp b/Gems/Prefab/PrefabBuilder/PrefabBuilderTests.cpp index d33b453c01..2ed05b4dfe 100644 --- a/Gems/Prefab/PrefabBuilder/PrefabBuilderTests.cpp +++ b/Gems/Prefab/PrefabBuilder/PrefabBuilderTests.cpp @@ -102,7 +102,9 @@ namespace UnitTest prefabBuilderComponent.Activate(); AZStd::vector jobProducts; - auto&& prefabDom = prefabSystemComponentInterface->FindTemplateDom(parentInstance->GetTemplateId()); + // Make a copy of the template DOM, as the prefab system still owns the existing template + AzToolsFramework::Prefab::PrefabDom prefabDom; + prefabDom.CopyFrom(prefabSystemComponentInterface->FindTemplateDom(parentInstance->GetTemplateId()), prefabDom.GetAllocator(), false); ASSERT_TRUE(prefabBuilderComponent.ProcessPrefab({AZ::Crc32("pc")}, "parent.prefab", "unused", AZ::Uuid(), prefabDom, jobProducts)); From 18847fb3ccc4f65a8c57530f368c1414df20cd6f Mon Sep 17 00:00:00 2001 From: hershey5045 <43485729+hershey5045@users.noreply.github.com> Date: Mon, 8 Nov 2021 11:09:07 -0800 Subject: [PATCH 45/53] Improve handling of cached data limits. (#5232) * Remove size limit on cached profile regions. Signed-off-by: rbarrand <43485729+hershey5045@users.noreply.github.com> * Discard excess profiling data once limit has been reached. Warn users only the first time the limit is reached. Signed-off-by: rbarrand <43485729+hershey5045@users.noreply.github.com> * Fix bug that was clearing cached time regions instead of the cached time regions map. Signed-off-by: rbarrand <43485729+hershey5045@users.noreply.github.com> --- Gems/Profiler/Code/Source/CpuProfilerImpl.cpp | 28 ++++++++++++++++--- Gems/Profiler/Code/Source/CpuProfilerImpl.h | 6 ++++ 2 files changed, 30 insertions(+), 4 deletions(-) diff --git a/Gems/Profiler/Code/Source/CpuProfilerImpl.cpp b/Gems/Profiler/Code/Source/CpuProfilerImpl.cpp index c88afdecd0..f0d39d48e4 100644 --- a/Gems/Profiler/Code/Source/CpuProfilerImpl.cpp +++ b/Gems/Profiler/Code/Source/CpuProfilerImpl.cpp @@ -282,7 +282,7 @@ namespace Profiler m_stackLevel = 0; m_cachedTimeRegionMap.clear(); m_timeRegionStack.clear(); - m_cachedTimeRegions.clear(); + ResetCachedData(); } timeRegion.m_stackDepth = aznumeric_cast(m_stackLevel); @@ -329,8 +329,21 @@ namespace Profiler { return; } - // Add an entry to the cached region - m_cachedTimeRegions.push_back(timeRegionCached); + // Add an entry to the cached region. Discard excess data in case there is too much to handle. + if (m_cachedTimeRegions.size() < TimeRegionStackSize) + { + m_cachedTimeRegions.push_back(timeRegionCached); + } + // Warn only once per thread if the cached data limit has been reached. + else if (!m_cachedDataLimitReached) + { + AZ_Warning( + "Profiler", false, + "Limit for profiling data has been reached by thread %i. Excess data will be discarded. Considering moving or reducing " + "profiler markers to prevent data loss.", + m_executingThreadId); + m_cachedDataLimitReached = true; + } // If the stack is empty, add it to the local cache map. Only gets called when the stack is empty // NOTE: this is where the largest overhead will be, but due to it only being called when the stack is empty @@ -354,7 +367,7 @@ namespace Profiler } // Clear the cached regions - m_cachedTimeRegions.clear(); + ResetCachedData(); } } @@ -371,10 +384,17 @@ namespace Profiler m_cachedTimeRegionMap.clear(); m_hitSizeLimitMap.clear(); } + m_cachedTimeRegionMutex.unlock(); } } + void CpuTimingLocalStorage::ResetCachedData() + { + m_cachedTimeRegions.clear(); + m_cachedDataLimitReached = false; + } + // --- CpuProfilingStatisticsSerializer --- CpuProfilingStatisticsSerializer::CpuProfilingStatisticsSerializer(const AZStd::ring_buffer& continuousData) diff --git a/Gems/Profiler/Code/Source/CpuProfilerImpl.h b/Gems/Profiler/Code/Source/CpuProfilerImpl.h index 1046b72cff..6611fbd1e5 100644 --- a/Gems/Profiler/Code/Source/CpuProfilerImpl.h +++ b/Gems/Profiler/Code/Source/CpuProfilerImpl.h @@ -50,6 +50,9 @@ namespace Profiler // Tries to flush the map to the passed parameter, only if the thread's mutex is unlocked void TryFlushCachedMap(CpuProfiler::ThreadTimeRegionMap& cachedRegionMap); + // Clears m_cachedTimeRegions and resets m_cachedDataLimitReached flag. + void ResetCachedData(); + AZStd::thread_id m_executingThreadId; // Keeps track of the current thread's stack depth uint32_t m_stackLevel = 0u; @@ -75,6 +78,9 @@ namespace Profiler // Keep track of the regions that have hit the size limit so we don't have to lock to check AZStd::map m_hitSizeLimitMap; + + // Keeps track of the first time cached data limit was reached. + bool m_cachedDataLimitReached = false; }; //! CpuProfiler will keep track of the registered threads, and From a5e11efda12c0d50df754b8999feac61ecaae516 Mon Sep 17 00:00:00 2001 From: nvsickle Date: Mon, 8 Nov 2021 16:21:35 -0800 Subject: [PATCH 46/53] Add a safety check to Prefab/PrefabPublicHandler (potential AR fix) Signed-off-by: nvsickle --- .../AzToolsFramework/Prefab/PrefabPublicHandler.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.cpp index 5ac9f772dc..32600853fd 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.cpp @@ -1144,6 +1144,10 @@ namespace AzToolsFramework AZ::EntityId firstEntityIdToDelete = entityIdsNoFocusContainer[0]; InstanceOptionalReference commonOwningInstance = GetOwnerInstanceByEntityId(firstEntityIdToDelete); + if (!commonOwningInstance.has_value()) + { + return AZ::Failure(AZStd::string("Cannot delete entities belonging to an invalid instance")); + } // If the first entity id is a container entity id, then we need to mark its parent as the common owning instance because you // cannot delete an instance from itself. From 487ac2b516fd27b39e5cd18d68e44990afe9a9dd Mon Sep 17 00:00:00 2001 From: nvsickle Date: Mon, 8 Nov 2021 17:37:32 -0800 Subject: [PATCH 47/53] Force prefabs off for Editor smoke test Signed-off-by: nvsickle --- .../PythonTests/smoke/test_Editor_NewExistingLevels_Works.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AutomatedTesting/Gem/PythonTests/smoke/test_Editor_NewExistingLevels_Works.py b/AutomatedTesting/Gem/PythonTests/smoke/test_Editor_NewExistingLevels_Works.py index 6f654b9107..72e548615c 100644 --- a/AutomatedTesting/Gem/PythonTests/smoke/test_Editor_NewExistingLevels_Works.py +++ b/AutomatedTesting/Gem/PythonTests/smoke/test_Editor_NewExistingLevels_Works.py @@ -28,4 +28,4 @@ class TestAutomation(TestAutomationBase): from . import Editor_NewExistingLevels_Works as test_module - self._run_test(request, workspace, editor, test_module) + self._run_test(request, workspace, editor, test_module, extra_cmdline_args=["--regset=/Amazon/Preferences/EnablePrefabSystem=false"]) From c5cb90ddb79d94df5b663aec27311a70c9925209 Mon Sep 17 00:00:00 2001 From: santorac <55155825+santorac@users.noreply.github.com> Date: Mon, 8 Nov 2021 20:24:53 -0800 Subject: [PATCH 48/53] Merge pull request #4426 from aws-lumberyard-dev/Atom/santorac/FixSceneSrgTime Fixed potential render scene time precision issues. The timestamp was simply converted from GetTimeAtCurrentTick to a float. Since this value is backed by QueryPerformanceCounter which is 0 at boot, you could see broken animations on the GPU when your system has been on for a long time. So I simplified the RPI's time API (removed unused code), and subtracted the application start time each frame before converting the time value to a float. Also moved FindShaderInputConstantIndex("m_time") to be called only once, instead of every frame. Testing: Originally: I had a local material shader that did vertex animation and it wasn't working at all before, and now it works. More recently, I made local changes to StandardPBR to add a simple sin wave animation. I also modified GetTimeNowMicroSecond() to artificially add 30 days to the clock. This showed choppy animation before my changes, and smooth animation after. AtomSampleViewer passed dx12 and vulkan (other than pre-existing issues) Signed-off-by: santorac <55155825+santorac@users.noreply.github.com> --- .../Code/Include/Atom/RPI.Public/RPISystem.h | 6 +++--- .../Include/Atom/RPI.Public/RenderPipeline.h | 3 +-- .../RPI/Code/Include/Atom/RPI.Public/Scene.h | 15 +++++--------- .../RPI/Code/Source/RPI.Public/RPISystem.cpp | 20 ++++++++++--------- .../Code/Source/RPI.Public/RenderPipeline.cpp | 2 +- .../Atom/RPI/Code/Source/RPI.Public/Scene.cpp | 17 ++++++++-------- 6 files changed, 30 insertions(+), 33 deletions(-) diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/RPISystem.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/RPISystem.h index 92370c5a82..9138c0b418 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/RPISystem.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/RPISystem.h @@ -97,8 +97,7 @@ namespace AZ // SystemTickBus::OnTick void OnSystemTick() override; - // Fill system time and game time information for simulation or rendering - void FillTickTimeInfo(); + float GetCurrentTime(); // The set of core asset handlers registered by the system. AZStd::vector> m_assetHandlers; @@ -124,7 +123,8 @@ namespace AZ // The job policy used for feature processor's rendering prepare RHI::JobPolicy m_prepareRenderJobPolicy = RHI::JobPolicy::Parallel; - TickTimeInfo m_tickTime; + ScriptTimePoint m_startTime; + float m_currentSimulationTime = 0.0f; RPISystemDescriptor m_descriptor; diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/RenderPipeline.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/RenderPipeline.h index fcf812cc38..6cba0c774f 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/RenderPipeline.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/RenderPipeline.h @@ -32,7 +32,6 @@ namespace AZ namespace RPI { class Scene; - struct TickTimeInfo; class ShaderResourceGroup; class AnyAsset; class WindowContext; @@ -203,7 +202,7 @@ namespace AZ void OnRemovedFromScene(Scene* scene); // Called when this pipeline is about to be rendered - void OnStartFrame(const TickTimeInfo& tick); + void OnStartFrame(float time); // Called when the rendering of current frame is finished. void OnFrameEnd(); diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Scene.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Scene.h index f86383101a..1411a8d996 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Scene.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Scene.h @@ -48,14 +48,6 @@ namespace AZ // Callback function to modify values of a ShaderResourceGroup using ShaderResourceGroupCallback = AZStd::function; - //! A structure for ticks which contains system time and game time. - struct TickTimeInfo - { - float m_currentGameTime; - float m_gameDeltaTime = 0; - }; - - class Scene final : public SceneRequestBus::Handler { @@ -179,12 +171,14 @@ namespace AZ // Cpu simulation which runs all active FeatureProcessor Simulate() functions. // @param jobPolicy if it's JobPolicy::Parallel, the function will spawn a job thread for each FeatureProcessor's simulation. - void Simulate(const TickTimeInfo& tickInfo, RHI::JobPolicy jobPolicy); + // @param simulationTime the number of seconds since the application started + void Simulate(RHI::JobPolicy jobPolicy, float simulationTime); // Collect DrawPackets from FeatureProcessors // @param jobPolicy if it's JobPolicy::Parallel, the function will spawn a job thread for each FeatureProcessor's // PrepareRender. - void PrepareRender(const TickTimeInfo& tickInfo, RHI::JobPolicy jobPolicy); + // @param simulationTime the number of seconds since the application started; this is the same time value that was passed to Simulate() + void PrepareRender(RHI::JobPolicy jobPolicy, float simulationTime); // Function called when the current frame is finished rendering. void OnFrameEnd(); @@ -267,6 +261,7 @@ namespace AZ // Registry which allocates draw filter tag for RenderPipeline RHI::Ptr m_drawFilterTagRegistry; + RHI::ShaderInputConstantIndex m_timeInputIndex; float m_simulationTime; }; diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/RPISystem.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/RPISystem.cpp index 943966c13b..2b32503838 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/RPISystem.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/RPISystem.cpp @@ -268,21 +268,23 @@ namespace AZ AssetInitBus::Broadcast(&AssetInitBus::Events::PostLoadInit); - // Update tick time info - FillTickTimeInfo(); + m_currentSimulationTime = GetCurrentTime(); for (auto& scene : m_scenes) { - scene->Simulate(m_tickTime, m_simulationJobPolicy); + scene->Simulate(m_simulationJobPolicy, m_currentSimulationTime); } } - void RPISystem::FillTickTimeInfo() + float RPISystem::GetCurrentTime() { - AZ::TickRequestBus::BroadcastResult(m_tickTime.m_gameDeltaTime, &AZ::TickRequestBus::Events::GetTickDeltaTime); - ScriptTimePoint currentTime; - AZ::TickRequestBus::BroadcastResult(currentTime, &AZ::TickRequestBus::Events::GetTimeAtCurrentTick); - m_tickTime.m_currentGameTime = static_cast(currentTime.GetSeconds()); + ScriptTimePoint timeAtCurrentTick; + AZ::TickRequestBus::BroadcastResult(timeAtCurrentTick, &AZ::TickRequestBus::Events::GetTimeAtCurrentTick); + + // We subtract the start time to maximize precision of the time value, since we will be converting it to a float. + double currentTime = timeAtCurrentTick.GetSeconds() - m_startTime.GetSeconds(); + + return aznumeric_cast(currentTime); } void RPISystem::RenderTick() @@ -301,7 +303,7 @@ namespace AZ // [GFX TODO] We may parallel scenes' prepare render. for (auto& scenePtr : m_scenes) { - scenePtr->PrepareRender(m_tickTime, m_prepareRenderJobPolicy); + scenePtr->PrepareRender(m_prepareRenderJobPolicy, m_currentSimulationTime); } m_rhiSystem.FrameUpdate( diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/RenderPipeline.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/RenderPipeline.cpp index 6378a249a4..8d4303f187 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/RenderPipeline.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/RenderPipeline.cpp @@ -375,7 +375,7 @@ namespace AZ m_scene->RemoveRenderPipeline(m_nameId); } - void RenderPipeline::OnStartFrame([[maybe_unused]] const TickTimeInfo& tick) + void RenderPipeline::OnStartFrame([[maybe_unused]] float time) { AZ_PROFILE_SCOPE(RPI, "RenderPipeline: OnStartFrame"); diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Scene.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Scene.cpp index 41fefda656..b27e3518e1 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Scene.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Scene.cpp @@ -44,6 +44,9 @@ namespace AZ { auto shaderAsset = RPISystemInterface::Get()->GetCommonShaderAssetForSrgs(); scene->m_srg = ShaderResourceGroup::Create(shaderAsset, sceneSrgLayout->GetName()); + + // Set value for constants defined in SceneTimeSrg.azsli + scene->m_timeInputIndex = scene->m_srg->FindShaderInputConstantIndex(Name{ "m_time" }); } scene->m_name = sceneDescriptor.m_nameId; @@ -410,11 +413,11 @@ namespace AZ //[GFX TODO]: the completion job should start here } - void Scene::Simulate([[maybe_unused]] const TickTimeInfo& tickInfo, RHI::JobPolicy jobPolicy) + void Scene::Simulate(RHI::JobPolicy jobPolicy, float simulationTime) { AZ_PROFILE_SCOPE(RPI, "Scene: Simulate"); - m_simulationTime = tickInfo.m_currentGameTime; + m_simulationTime = simulationTime; // If previous simulation job wasn't done, wait for it to finish. if (m_taskGraphActive) @@ -483,11 +486,9 @@ namespace AZ { if (m_srg) { - // Set value for constants defined in SceneTimeSrg.azsli - RHI::ShaderInputConstantIndex timeIndex = m_srg->FindShaderInputConstantIndex(Name{ "m_time" }); - if (timeIndex.IsValid()) + if (m_timeInputIndex.IsValid()) { - m_srg->SetConstant(timeIndex, m_simulationTime); + m_srg->SetConstant(m_timeInputIndex, m_simulationTime); } // signal any handlers to update values for their partial scene srg @@ -620,7 +621,7 @@ namespace AZ WaitAndCleanCompletionJob(finalizeDrawListsCompletion); } - void Scene::PrepareRender(const TickTimeInfo& tickInfo, RHI::JobPolicy jobPolicy) + void Scene::PrepareRender(RHI::JobPolicy jobPolicy, float simulationTime) { AZ_PROFILE_SCOPE(RPI, "Scene: PrepareRender"); @@ -644,7 +645,7 @@ namespace AZ if (pipeline->NeedsRender()) { activePipelines.push_back(pipeline); - pipeline->OnStartFrame(tickInfo); + pipeline->OnStartFrame(simulationTime); } } } From 1998c53882e725ba99e4abd4ec60702b67535f1f Mon Sep 17 00:00:00 2001 From: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> Date: Tue, 9 Nov 2021 04:19:04 -0600 Subject: [PATCH 49/53] Non MSVC Release build fix (#5428) Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> --- .../AzCore/AzCore/Settings/SettingsRegistryMergeUtils.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryMergeUtils.cpp b/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryMergeUtils.cpp index 3668ab14fd..3902bd107c 100644 --- a/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryMergeUtils.cpp +++ b/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryMergeUtils.cpp @@ -668,7 +668,7 @@ namespace AZ::SettingsRegistryMergeUtils // NOTE: We make the project-path in the BootstrapSettingsRootKey absolute first AZ::IO::FixedMaxPath projectPath = FindProjectRoot(registry); - if (constexpr auto projectPathKey = FixedValueString(BootstrapSettingsRootKey) + "/project_path"; + if ([[maybe_unused]] constexpr auto projectPathKey = FixedValueString(BootstrapSettingsRootKey) + "/project_path"; !projectPath.empty()) { if (projectPath.IsRelative()) From 938899a49562da823c80063e14abc3018c0cef73 Mon Sep 17 00:00:00 2001 From: John Jones-Steele <82226755+jjjoness@users.noreply.github.com> Date: Tue, 9 Nov 2021 13:24:10 +0000 Subject: [PATCH 50/53] Minor fixups for terrain physics collide lyn 7692 (#5413) * First commit Signed-off-by: John Jones-Steele <82226755+jjjoness@users.noreply.github.com> * completed changes Signed-off-by: John Jones-Steele <82226755+jjjoness@users.noreply.github.com> --- .../Source/Components/TerrainPhysicsColliderComponent.cpp | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/Gems/Terrain/Code/Source/Components/TerrainPhysicsColliderComponent.cpp b/Gems/Terrain/Code/Source/Components/TerrainPhysicsColliderComponent.cpp index e9c235c1bd..9262937317 100644 --- a/Gems/Terrain/Code/Source/Components/TerrainPhysicsColliderComponent.cpp +++ b/Gems/Terrain/Code/Source/Components/TerrainPhysicsColliderComponent.cpp @@ -185,12 +185,12 @@ namespace Terrain void TerrainPhysicsColliderComponent::GetHeightfieldHeightBounds(float& minHeightBounds, float& maxHeightBounds) const { - AZ::Aabb heightfieldAabb = GetHeightfieldAabb(); + const AZ::Aabb heightfieldAabb = GetHeightfieldAabb(); // Because our terrain heights are relative to the center of the bounding box, the min and max allowable heights are also // relative to the center. They are also clamped to the size of the bounding box. - minHeightBounds = -(heightfieldAabb.GetZExtent() / 2.0f); maxHeightBounds = heightfieldAabb.GetZExtent() / 2.0f; + minHeightBounds = -maxHeightBounds; } AZ::Transform TerrainPhysicsColliderComponent::GetHeightfieldTransform() const @@ -199,9 +199,7 @@ namespace Terrain AZ::Vector3 translate; AZ::TransformBus::EventResult(translate, GetEntityId(), &AZ::TransformBus::Events::GetWorldTranslation); - AZ::Transform transform = AZ::Transform::CreateTranslation(translate); - - return transform; + return AZ::Transform::CreateTranslation(translate); } void TerrainPhysicsColliderComponent::GenerateHeightsInBounds(AZStd::vector& heights) const From c35f74e9cea14d1e07200a143aae172962df19e6 Mon Sep 17 00:00:00 2001 From: John Jones-Steele <82226755+jjjoness@users.noreply.github.com> Date: Tue, 9 Nov 2021 14:11:33 +0000 Subject: [PATCH 51/53] Physics/test axis aligned box shape configuration works #7378a (#5366) * Safety commit before merging Signed-off-by: John Jones-Steele <82226755+jjjoness@users.noreply.github.com> * Moved from Physics to Terrain Signed-off-by: John Jones-Steele <82226755+jjjoness@users.noreply.github.com> * Changes from PR + AR fix Signed-off-by: John Jones-Steele <82226755+jjjoness@users.noreply.github.com> * Fixed another AR bug Signed-off-by: John Jones-Steele <82226755+jjjoness@users.noreply.github.com> * Fixed another AR compilation bug Signed-off-by: John Jones-Steele <82226755+jjjoness@users.noreply.github.com> * More PR changes Signed-off-by: John Jones-Steele <82226755+jjjoness@users.noreply.github.com> * Added virtual destructor Signed-off-by: John Jones-Steele <82226755+jjjoness@users.noreply.github.com> * Added TestSuite_main_Optimized.py Signed-off-by: John Jones-Steele <82226755+jjjoness@users.noreply.github.com> * Changes from PR Signed-off-by: John Jones-Steele <82226755+jjjoness@users.noreply.github.com> * Further fixes for PR Signed-off-by: John Jones-Steele <82226755+jjjoness@users.noreply.github.com> * Fix to editor_test.py Signed-off-by: John Jones-Steele <82226755+jjjoness@users.noreply.github.com> * Testing prefab level Signed-off-by: John Jones-Steele <82226755+jjjoness@users.noreply.github.com> * Testing slice level Signed-off-by: John Jones-Steele <82226755+jjjoness@users.noreply.github.com> * Testing prefab level Signed-off-by: John Jones-Steele <82226755+jjjoness@users.noreply.github.com> * Disabled orefab loading for the time being. Signed-off-by: John Jones-Steele <82226755+jjjoness@users.noreply.github.com> --- AutomatedTesting/Gem/Code/enabled_gems.cmake | 1 + .../Gem/PythonTests/CMakeLists.txt | 3 + .../Gem/PythonTests/Terrain/CMakeLists.txt | 24 +++++ ...angesSizeWithAxisAlignedBoxShapeChanges.py | 90 +++++++++++++++++++ .../Gem/PythonTests/Terrain/TestSuite_Main.py | 25 ++++++ .../Gem/PythonTests/Terrain/__init__.py | 6 ++ AutomatedTesting/Levels/Base/Base.prefab | 53 +++++++++++ .../AzFramework/Application/Application.cpp | 3 + .../Physics/HeightfieldProviderBus.cpp | 46 ++++++++++ .../Physics/HeightfieldProviderBus.h | 33 +++++++ .../AzFramework/Physics/Material.cpp | 5 ++ .../AzFramework/azframework_files.cmake | 1 + .../MockPhysXHeightfieldProviderComponent.h | 4 + .../TerrainPhysicsColliderComponent.cpp | 34 +++++++ .../TerrainPhysicsColliderComponent.h | 4 + .../ly_test_tools/o3de/editor_test.py | 1 + system_windows_pc.cfg | 1 + 17 files changed, 334 insertions(+) create mode 100644 AutomatedTesting/Gem/PythonTests/Terrain/CMakeLists.txt create mode 100644 AutomatedTesting/Gem/PythonTests/Terrain/EditorScripts/TerrainPhysicsCollider_ChangesSizeWithAxisAlignedBoxShapeChanges.py create mode 100644 AutomatedTesting/Gem/PythonTests/Terrain/TestSuite_Main.py create mode 100644 AutomatedTesting/Gem/PythonTests/Terrain/__init__.py create mode 100644 AutomatedTesting/Levels/Base/Base.prefab create mode 100644 Code/Framework/AzFramework/AzFramework/Physics/HeightfieldProviderBus.cpp diff --git a/AutomatedTesting/Gem/Code/enabled_gems.cmake b/AutomatedTesting/Gem/Code/enabled_gems.cmake index f653a54505..7d33a65bc7 100644 --- a/AutomatedTesting/Gem/Code/enabled_gems.cmake +++ b/AutomatedTesting/Gem/Code/enabled_gems.cmake @@ -54,5 +54,6 @@ set(ENABLED_GEMS AWSMetrics PrefabBuilder AudioSystem + Terrain Profiler ) diff --git a/AutomatedTesting/Gem/PythonTests/CMakeLists.txt b/AutomatedTesting/Gem/PythonTests/CMakeLists.txt index fd3222ba83..d2b7075e22 100644 --- a/AutomatedTesting/Gem/PythonTests/CMakeLists.txt +++ b/AutomatedTesting/Gem/PythonTests/CMakeLists.txt @@ -56,6 +56,9 @@ add_subdirectory(streaming) ## Smoke ## add_subdirectory(smoke) +## Terrain ## +add_subdirectory(Terrain) + ## AWS ## add_subdirectory(AWS) diff --git a/AutomatedTesting/Gem/PythonTests/Terrain/CMakeLists.txt b/AutomatedTesting/Gem/PythonTests/Terrain/CMakeLists.txt new file mode 100644 index 0000000000..9f8ba06829 --- /dev/null +++ b/AutomatedTesting/Gem/PythonTests/Terrain/CMakeLists.txt @@ -0,0 +1,24 @@ +# +# 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 +# +# + +if(PAL_TRAIT_BUILD_TESTS_SUPPORTED AND PAL_TRAIT_BUILD_HOST_TOOLS) + + ly_add_pytest( + NAME AutomatedTesting::TerrainTests_Main + TEST_SUITE main + TEST_SERIAL + PATH ${CMAKE_CURRENT_LIST_DIR}/TestSuite_Main.py + RUNTIME_DEPENDENCIES + Legacy::Editor + AZ::AssetProcessor + AutomatedTesting.Assets + COMPONENT + Terrain + ) + +endif() diff --git a/AutomatedTesting/Gem/PythonTests/Terrain/EditorScripts/TerrainPhysicsCollider_ChangesSizeWithAxisAlignedBoxShapeChanges.py b/AutomatedTesting/Gem/PythonTests/Terrain/EditorScripts/TerrainPhysicsCollider_ChangesSizeWithAxisAlignedBoxShapeChanges.py new file mode 100644 index 0000000000..aba506ea20 --- /dev/null +++ b/AutomatedTesting/Gem/PythonTests/Terrain/EditorScripts/TerrainPhysicsCollider_ChangesSizeWithAxisAlignedBoxShapeChanges.py @@ -0,0 +1,90 @@ +""" +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 +""" + +#fmt: off +class Tests(): + create_test_entity = ("Entity created successfully", "Failed to create Entity") + add_axis_aligned_box_shape = ("Axis Aligned Box Shape component added", "Failed to add Axis Aligned Box Shape component") + add_terrain_collider = ("Terrain Physics Heightfield Collider component added", "Failed to add a Terrain Physics Heightfield Collider component") + box_dimensions_changed = ("Aabb dimensions changed successfully", "Failed change Aabb dimensions") + configuration_changed = ("Terrain size changed successfully", "Failed terrain size change") + no_errors_and_warnings_found = ("No errors and warnings found", "Found errors and warnings") +#fmt: on + +def TerrainPhysicsCollider_ChangesSizeWithAxisAlignedBoxShapeChanges(): + """ + Summary: + Test aspects of the TerrainHeightGradientList through the BehaviorContext and the Property Tree. + + Test Steps: + Expected Behavior: + The Editor is stable there are no warnings or errors. + + Test Steps: + 1) Load the base level + 2) Create test entity + 3) Start the Tracer to catch any errors and warnings + 4) Add the Axis Aligned Box Shape and Terrain Physics Heightfield Collider components + 5) Change the Axis Aligned Box Shape dimensions + 6) Check the Heightfield provider is returning the correct size + 7) Verify there are no errors and warnings in the logs + + + :return: None + """ + + from editor_python_test_tools.editor_entity_utils import EditorEntity + from editor_python_test_tools.utils import TestHelper as helper + from editor_python_test_tools.utils import Report, Tracer + import azlmbr.legacy.general as general + import azlmbr.physics as physics + import azlmbr.math as azmath + import azlmbr.bus as bus + import sys + import math + + SET_BOX_X_SIZE = 5.0 + SET_BOX_Y_SIZE = 6.0 + EXPECTED_COLUMN_SIZE = SET_BOX_X_SIZE + 1 + EXPECTED_ROW_SIZE = SET_BOX_Y_SIZE + 1 + helper.init_idle() + + # 1) Load the level + helper.open_level("", "Base") + + # 2) Create test entity + test_entity = EditorEntity.create_editor_entity("TestEntity") + Report.result(Tests.create_test_entity, test_entity.id.IsValid()) + + # 3) Start the Tracer to catch any errors and warnings + with Tracer() as section_tracer: + # 4) Add the Axis Aligned Box Shape and Terrain Physics Heightfield Collider components + aaBoxShape_component = test_entity.add_component("Axis Aligned Box Shape") + Report.result(Tests.add_axis_aligned_box_shape, test_entity.has_component("Axis Aligned Box Shape")) + terrainPhysics_component = test_entity.add_component("Terrain Physics Heightfield Collider") + Report.result(Tests.add_terrain_collider, test_entity.has_component("Terrain Physics Heightfield Collider")) + + # 5) Change the Axis Aligned Box Shape dimensions + aaBoxShape_component.set_component_property_value("Axis Aligned Box Shape|Box Configuration|Dimensions", azmath.Vector3(SET_BOX_X_SIZE, SET_BOX_Y_SIZE, 1.0)) + add_check = aaBoxShape_component.get_component_property_value("Axis Aligned Box Shape|Box Configuration|Dimensions") == azmath.Vector3(SET_BOX_X_SIZE, SET_BOX_Y_SIZE, 1.0) + Report.result(Tests.box_dimensions_changed, add_check) + + # 6) Check the Heightfield provider is returning the correct size + columns = physics.HeightfieldProviderRequestsBus(bus.Broadcast, "GetHeightfieldGridColumns") + rows = physics.HeightfieldProviderRequestsBus(bus.Broadcast, "GetHeightfieldGridRows") + Report.result(Tests.configuration_changed, math.isclose(columns, EXPECTED_COLUMN_SIZE) and math.isclose(rows, EXPECTED_ROW_SIZE)) + + helper.wait_for_condition(lambda: section_tracer.has_errors or section_tracer.has_asserts, 1.0) + for error_info in section_tracer.errors: + Report.info(f"Error: {error_info.filename} {error_info.function} | {error_info.message}") + for assert_info in section_tracer.asserts: + Report.info(f"Assert: {assert_info.filename} {assert_info.function} | {assert_info.message}") + +if __name__ == "__main__": + + from editor_python_test_tools.utils import Report + Report.start_test(TerrainPhysicsCollider_ChangesSizeWithAxisAlignedBoxShapeChanges) diff --git a/AutomatedTesting/Gem/PythonTests/Terrain/TestSuite_Main.py b/AutomatedTesting/Gem/PythonTests/Terrain/TestSuite_Main.py new file mode 100644 index 0000000000..620d84d7db --- /dev/null +++ b/AutomatedTesting/Gem/PythonTests/Terrain/TestSuite_Main.py @@ -0,0 +1,25 @@ +""" +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 + +""" + +# This suite consists of all test cases that are passing and have been verified. + +import pytest +import os +import sys + +from ly_test_tools import LAUNCHERS +from ly_test_tools.o3de.editor_test import EditorTestSuite, EditorSingleTest + +@pytest.mark.SUITE_main +@pytest.mark.parametrize("launcher_platform", ['windows_editor']) +@pytest.mark.parametrize("project", ["AutomatedTesting"]) +class TestAutomation(EditorTestSuite): + #global_extra_cmdline_args=["--regset=/Amazon/Preferences/EnablePrefabSystem=true"] + + class test_AxisAlignedBoxShape_ConfigurationWorks(EditorSingleTest): + from .EditorScripts import TerrainPhysicsCollider_ChangesSizeWithAxisAlignedBoxShapeChanges as test_module diff --git a/AutomatedTesting/Gem/PythonTests/Terrain/__init__.py b/AutomatedTesting/Gem/PythonTests/Terrain/__init__.py new file mode 100644 index 0000000000..f5193b300e --- /dev/null +++ b/AutomatedTesting/Gem/PythonTests/Terrain/__init__.py @@ -0,0 +1,6 @@ +""" +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 +""" diff --git a/AutomatedTesting/Levels/Base/Base.prefab b/AutomatedTesting/Levels/Base/Base.prefab new file mode 100644 index 0000000000..f7e42e7731 --- /dev/null +++ b/AutomatedTesting/Levels/Base/Base.prefab @@ -0,0 +1,53 @@ +{ + "ContainerEntity": { + "Id": "Entity_[1146574390643]", + "Name": "Level", + "Components": { + "Component_[10641544592923449938]": { + "$type": "EditorInspectorComponent", + "Id": 10641544592923449938 + }, + "Component_[12039882709170782873]": { + "$type": "EditorOnlyEntityComponent", + "Id": 12039882709170782873 + }, + "Component_[12265484671603697631]": { + "$type": "EditorPendingCompositionComponent", + "Id": 12265484671603697631 + }, + "Component_[14126657869720434043]": { + "$type": "EditorEntitySortComponent", + "Id": 14126657869720434043 + }, + "Component_[15230859088967841193]": { + "$type": "{27F1E1A1-8D9D-4C3B-BD3A-AFB9762449C0} TransformComponent", + "Id": 15230859088967841193, + "Parent Entity": "" + }, + "Component_[16239496886950819870]": { + "$type": "EditorDisabledCompositionComponent", + "Id": 16239496886950819870 + }, + "Component_[5688118765544765547]": { + "$type": "EditorEntityIconComponent", + "Id": 5688118765544765547 + }, + "Component_[6545738857812235305]": { + "$type": "SelectionComponent", + "Id": 6545738857812235305 + }, + "Component_[7247035804068349658]": { + "$type": "EditorPrefabComponent", + "Id": 7247035804068349658 + }, + "Component_[9307224322037797205]": { + "$type": "EditorLockComponent", + "Id": 9307224322037797205 + }, + "Component_[9562516168917670048]": { + "$type": "EditorVisibilityComponent", + "Id": 9562516168917670048 + } + } + } +} \ No newline at end of file diff --git a/Code/Framework/AzFramework/AzFramework/Application/Application.cpp b/Code/Framework/AzFramework/AzFramework/Application/Application.cpp index 323e834413..b6b09148eb 100644 --- a/Code/Framework/AzFramework/AzFramework/Application/Application.cpp +++ b/Code/Framework/AzFramework/AzFramework/Application/Application.cpp @@ -69,6 +69,7 @@ #include #include #include +#include #include "Application.h" #include @@ -318,6 +319,8 @@ namespace AzFramework AzFramework::SurfaceData::SurfaceTagWeight::Reflect(context); AzFramework::SurfaceData::SurfacePoint::Reflect(context); AzFramework::Terrain::TerrainDataRequests::Reflect(context); + Physics::HeightfieldProviderRequests::Reflect(context); + Physics::HeightMaterialPoint::Reflect(context); if (AZ::SerializeContext* serializeContext = azrtti_cast(context)) { diff --git a/Code/Framework/AzFramework/AzFramework/Physics/HeightfieldProviderBus.cpp b/Code/Framework/AzFramework/AzFramework/Physics/HeightfieldProviderBus.cpp new file mode 100644 index 0000000000..38fac9655c --- /dev/null +++ b/Code/Framework/AzFramework/AzFramework/Physics/HeightfieldProviderBus.cpp @@ -0,0 +1,46 @@ +/* + * 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 "HeightfieldProviderBus.h" +#include +#include +#include + +namespace Physics +{ + void HeightfieldProviderRequests::Reflect(AZ::ReflectContext* context) + { + if (AZ::BehaviorContext* behaviorContext = azrtti_cast(context)) + { + behaviorContext->EBus("HeightfieldProviderRequestsBus") + ->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common) + ->Attribute(AZ::Script::Attributes::Module, "physics") + ->Attribute(AZ::Script::Attributes::Category, "PhysX") + ->Event("GetHeightfieldGridSpacing", &Physics::HeightfieldProviderRequestsBus::Events::GetHeightfieldGridSpacing) + ->Event("GetHeightfieldAabb", &Physics::HeightfieldProviderRequestsBus::Events::GetHeightfieldAabb) + ->Event("GetHeightfieldTransform", &Physics::HeightfieldProviderRequestsBus::Events::GetHeightfieldTransform) + ->Event("GetMaterialList", &Physics::HeightfieldProviderRequestsBus::Events::GetMaterialList) + ->Event("GetHeights", &Physics::HeightfieldProviderRequestsBus::Events::GetHeights) + ->Event("GetHeightsAndMaterials", &Physics::HeightfieldProviderRequestsBus::Events::GetHeightsAndMaterials) + ->Event("GetHeightfieldMinHeight", &Physics::HeightfieldProviderRequestsBus::Events::GetHeightfieldMinHeight) + ->Event("GetHeightfieldMaxHeight", &Physics::HeightfieldProviderRequestsBus::Events::GetHeightfieldMaxHeight) + ->Event("GetHeightfieldGridColumns", &Physics::HeightfieldProviderRequestsBus::Events::GetHeightfieldGridColumns) + ->Event("GetHeightfieldGridRows", &Physics::HeightfieldProviderRequestsBus::Events::GetHeightfieldGridRows) + ; + } + } + + void HeightMaterialPoint::Reflect(AZ::ReflectContext* context) + { + if (AZ::BehaviorContext* behaviorContext = azrtti_cast(context)) + { + behaviorContext->Class()->Attribute(AZ::Script::Attributes::Category, "Physics"); + } + } + +} // namespace Physics diff --git a/Code/Framework/AzFramework/AzFramework/Physics/HeightfieldProviderBus.h b/Code/Framework/AzFramework/AzFramework/Physics/HeightfieldProviderBus.h index 73523ee1ba..da361f0a2b 100644 --- a/Code/Framework/AzFramework/AzFramework/Physics/HeightfieldProviderBus.h +++ b/Code/Framework/AzFramework/AzFramework/Physics/HeightfieldProviderBus.h @@ -26,10 +26,25 @@ namespace Physics struct HeightMaterialPoint { + HeightMaterialPoint( + float height = 0.0f, QuadMeshType type = QuadMeshType::SubdivideUpperLeftToBottomRight, uint8_t index = 0) + : m_height(height) + , m_quadMeshType(type) + , m_materialIndex(index) + , m_padding(0) + { + } + + virtual ~HeightMaterialPoint() = default; + + static void Reflect(AZ::ReflectContext* context); + + AZ_RTTI(HeightMaterialPoint, "{DF167ED4-24E6-4F7B-8AB7-42622F7DBAD3}"); float m_height{ 0.0f }; //!< Holds the height of this point in the heightfield relative to the heightfield entity location. QuadMeshType m_quadMeshType{ QuadMeshType::SubdivideUpperLeftToBottomRight }; //!< By default, create two triangles like this |\|, where this point is in the upper left corner. uint8_t m_materialIndex{ 0 }; //!< The surface material index for the upper left corner of this quad. uint16_t m_padding{ 0 }; //!< available for future use. + }; //! An interface to provide heightfield values. @@ -37,6 +52,8 @@ namespace Physics : public AZ::ComponentBus { public: + static void Reflect(AZ::ReflectContext* context); + //! Returns the distance between each height in the map. //! @return Vector containing Column Spacing, Rows Spacing. virtual AZ::Vector2 GetHeightfieldGridSpacing() const = 0; @@ -46,11 +63,27 @@ namespace Physics //! @param numRows contains the size of the grid in the y direction. virtual void GetHeightfieldGridSize(int32_t& numColumns, int32_t& numRows) const = 0; + //! Returns the height field gridsize columns. + //! @return the size of the grid in the x direction. + virtual int32_t GetHeightfieldGridColumns() const = 0; + + //! Returns the height field gridsize rows. + //! @return the size of the grid in the y direction. + virtual int32_t GetHeightfieldGridRows() const = 0; + //! Returns the height field min and max height bounds. //! @param minHeightBounds contains the minimum height that the heightfield can contain. //! @param maxHeightBounds contains the maximum height that the heightfield can contain. virtual void GetHeightfieldHeightBounds(float& minHeightBounds, float& maxHeightBounds) const = 0; + //! Returns the height field min height bounds. + //! @return the minimum height that the heightfield can contain. + virtual float GetHeightfieldMinHeight() const = 0; + + //! Returns the height field max height bounds. + //! @return the maximum height that the heightfield can contain. + virtual float GetHeightfieldMaxHeight() const = 0; + //! Returns the AABB of the heightfield. //! This is provided separately from the shape AABB because the heightfield might choose to modify the AABB bounds. //! @return AABB of the heightfield. diff --git a/Code/Framework/AzFramework/AzFramework/Physics/Material.cpp b/Code/Framework/AzFramework/AzFramework/Physics/Material.cpp index 222bc48dda..d78d4e0943 100644 --- a/Code/Framework/AzFramework/AzFramework/Physics/Material.cpp +++ b/Code/Framework/AzFramework/AzFramework/Physics/Material.cpp @@ -360,6 +360,11 @@ namespace Physics ->Field("MaterialId", &Physics::MaterialId::m_id) ; } + + if (AZ::BehaviorContext* behaviorContext = azrtti_cast(context)) + { + behaviorContext->Class()->Attribute(AZ::Script::Attributes::Category, "Physics"); + } } MaterialId MaterialId::Create() diff --git a/Code/Framework/AzFramework/AzFramework/azframework_files.cmake b/Code/Framework/AzFramework/AzFramework/azframework_files.cmake index e03d166cfc..13d9003031 100644 --- a/Code/Framework/AzFramework/AzFramework/azframework_files.cmake +++ b/Code/Framework/AzFramework/AzFramework/azframework_files.cmake @@ -229,6 +229,7 @@ set(FILES Physics/Configuration/SystemConfiguration.h Physics/Configuration/SystemConfiguration.cpp Physics/HeightfieldProviderBus.h + Physics/HeightfieldProviderBus.cpp Physics/SimulatedBodies/RigidBody.h Physics/SimulatedBodies/RigidBody.cpp Physics/SimulatedBodies/StaticRigidBody.h diff --git a/Gems/PhysX/Code/Mocks/PhysX/MockPhysXHeightfieldProviderComponent.h b/Gems/PhysX/Code/Mocks/PhysX/MockPhysXHeightfieldProviderComponent.h index 7e500881c0..d462c30158 100644 --- a/Gems/PhysX/Code/Mocks/PhysX/MockPhysXHeightfieldProviderComponent.h +++ b/Gems/PhysX/Code/Mocks/PhysX/MockPhysXHeightfieldProviderComponent.h @@ -69,6 +69,10 @@ namespace UnitTest MOCK_CONST_METHOD1(UpdateHeights, AZStd::vector(const AZ::Aabb& dirtyRegion)); MOCK_CONST_METHOD1(UpdateHeightsAndMaterials, AZStd::vector(const AZ::Aabb& dirtyRegion)); MOCK_CONST_METHOD0(GetHeightfieldAabb, AZ::Aabb()); + MOCK_CONST_METHOD0(GetHeightfieldMinHeight, float()); + MOCK_CONST_METHOD0(GetHeightfieldMaxHeight, float()); + MOCK_CONST_METHOD0(GetHeightfieldGridColumns, int32_t()); + MOCK_CONST_METHOD0(GetHeightfieldGridRows, int32_t()); }; } // namespace UnitTest diff --git a/Gems/Terrain/Code/Source/Components/TerrainPhysicsColliderComponent.cpp b/Gems/Terrain/Code/Source/Components/TerrainPhysicsColliderComponent.cpp index 9262937317..6c76e90fd0 100644 --- a/Gems/Terrain/Code/Source/Components/TerrainPhysicsColliderComponent.cpp +++ b/Gems/Terrain/Code/Source/Components/TerrainPhysicsColliderComponent.cpp @@ -193,6 +193,22 @@ namespace Terrain minHeightBounds = -maxHeightBounds; } + float TerrainPhysicsColliderComponent::GetHeightfieldMinHeight() const + { + float minHeightBounds{ 0.0f }; + float maxHeightBounds{ 0.0f }; + GetHeightfieldHeightBounds(minHeightBounds, maxHeightBounds); + return minHeightBounds; + } + + float TerrainPhysicsColliderComponent::GetHeightfieldMaxHeight() const + { + float minHeightBounds{ 0.0f }; + float maxHeightBounds{ 0.0f }; + GetHeightfieldHeightBounds(minHeightBounds, maxHeightBounds); + return maxHeightBounds; + } + AZ::Transform TerrainPhysicsColliderComponent::GetHeightfieldTransform() const { // We currently don't support rotation of terrain heightfields. @@ -296,6 +312,24 @@ namespace Terrain numRows = aznumeric_cast((bounds.GetMax().GetY() - bounds.GetMin().GetY()) / gridResolution.GetY()); } + int32_t TerrainPhysicsColliderComponent::GetHeightfieldGridColumns() const + { + int32_t numColumns{ 0 }; + int32_t numRows{ 0 }; + + GetHeightfieldGridSize(numColumns, numRows); + return numColumns; + } + + int32_t TerrainPhysicsColliderComponent::GetHeightfieldGridRows() const + { + int32_t numColumns{ 0 }; + int32_t numRows{ 0 }; + + GetHeightfieldGridSize(numColumns, numRows); + return numRows; + } + AZStd::vector TerrainPhysicsColliderComponent::GetMaterialList() const { return AZStd::vector(); diff --git a/Gems/Terrain/Code/Source/Components/TerrainPhysicsColliderComponent.h b/Gems/Terrain/Code/Source/Components/TerrainPhysicsColliderComponent.h index e268223689..6462909c89 100644 --- a/Gems/Terrain/Code/Source/Components/TerrainPhysicsColliderComponent.h +++ b/Gems/Terrain/Code/Source/Components/TerrainPhysicsColliderComponent.h @@ -58,7 +58,11 @@ namespace Terrain // HeightfieldProviderRequestsBus AZ::Vector2 GetHeightfieldGridSpacing() const override; void GetHeightfieldGridSize(int32_t& numColumns, int32_t& numRows) const override; + int32_t GetHeightfieldGridColumns() const override; + int32_t GetHeightfieldGridRows() const override; void GetHeightfieldHeightBounds(float& minHeightBounds, float& maxHeightBounds) const override; + float GetHeightfieldMinHeight() const override; + float GetHeightfieldMaxHeight() const override; AZ::Aabb GetHeightfieldAabb() const override; AZ::Transform GetHeightfieldTransform() const override; AZStd::vector GetMaterialList() const override; diff --git a/Tools/LyTestTools/ly_test_tools/o3de/editor_test.py b/Tools/LyTestTools/ly_test_tools/o3de/editor_test.py index 781977cf33..392838d180 100644 --- a/Tools/LyTestTools/ly_test_tools/o3de/editor_test.py +++ b/Tools/LyTestTools/ly_test_tools/o3de/editor_test.py @@ -634,6 +634,7 @@ class EditorTestSuite(): else: test_result = Result.Fail.create(test_spec, output, editor_log_content) except WaitTimeoutError: + output = editor.get_output() editor.kill() editor_log_content = editor_utils.retrieve_editor_log_content(run_id, log_name, workspace) test_result = Result.Timeout.create(test_spec, output, test_spec.timeout, editor_log_content) diff --git a/system_windows_pc.cfg b/system_windows_pc.cfg index aa53ed9323..e34c35e581 100644 --- a/system_windows_pc.cfg +++ b/system_windows_pc.cfg @@ -15,3 +15,4 @@ r_ShadersAllowCompilation = 1 -- Localization Settings sys_localization_format=0 +log_RemoteConsoleAllowedAddresses=127.0.0.1 From d053a03b5f0675735327aaaf870d076e9ac4d4be Mon Sep 17 00:00:00 2001 From: Alex Peterson <26804013+AMZN-alexpete@users.noreply.github.com> Date: Tue, 9 Nov 2021 09:38:23 -0800 Subject: [PATCH 52/53] Don't update status filter when filling gem model (#5427) Signed-off-by: Alex Peterson <26804013+AMZN-alexpete@users.noreply.github.com> --- .../ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp index 79935ed235..542da87196 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp @@ -90,6 +90,13 @@ namespace O3DE::ProjectManager m_projectPath = projectPath; m_gemModel->Clear(); m_gemsToRegisterWithProject.clear(); + + if (m_filterWidget) + { + // disconnect so we don't update the status filter for every gem we add + disconnect(m_gemModel, &GemModel::dataChanged, m_filterWidget, &GemFilterWidget::ResetGemStatusFilter); + } + FillModel(projectPath); m_proxyModel->ResetFilters(); From 5fc4551ac0db22e2c57144ad43afaf69255a6a36 Mon Sep 17 00:00:00 2001 From: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> Date: Tue, 9 Nov 2021 12:03:52 -0600 Subject: [PATCH 53/53] [LYN-8041] Enable relocation of the Project Game Release Layout (#5380) * Enable relocation of the Project Game Release Layout Relocating the Project Game Release Layout to another directory on the file system failed due to the querying of the engine root failing due to the ComponentApplication::m_engineRoot not using the project path stored in the SettingsRegisry if the engine root cannot be detected Removed the ApplicationRequestBus GetEngineRoot function. The ComponentApplicationRequestBus has a function of the same name that returns the same path. Removed the deprecated GetAppRoot function. The path it returns has no defined value. It was not the engine root or the project root. Removed unused CFileUtil and CFileUtil_impl functions that were invoking the ApplicationREquestBus GetEngineRoot function. On the way to update the functions it was discovered that they aren't called Added a CalculateBranchToken overload that can populate a fixed_string to avoid heap allocations Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Protect against an empty list of artifacts to remove when generating the engine.pak Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> --- Code/Editor/CryEdit.cpp | 7 +- Code/Editor/Include/IFileUtil.h | 2 - Code/Editor/Util/FileUtil.cpp | 140 +----------------- Code/Editor/Util/FileUtil.h | 5 - Code/Editor/Util/FileUtil_impl.cpp | 10 -- Code/Editor/Util/FileUtil_impl.h | 2 - Code/Editor/Util/PathUtil.cpp | 6 +- .../WelcomeScreen/WelcomeScreenDialog.cpp | 5 - .../AzCore/Component/ComponentApplication.cpp | 52 +++---- .../AzCore/Component/ComponentApplication.h | 19 +-- .../Component/ComponentApplicationBus.h | 4 - .../Settings/SettingsRegistryMergeUtils.cpp | 4 +- .../AzCore/AzCore/StringFunc/StringFunc.cpp | 44 +++--- .../AzCore/AzCore/StringFunc/StringFunc.h | 5 +- .../UnitTest/MockComponentApplication.h | 1 - .../AzCore/Tests/BehaviorContextFixture.h | 1 - Code/Framework/AzCore/Tests/Components.cpp | 20 +-- Code/Framework/AzCore/Tests/Serialization.cpp | 1 - .../AzFramework/API/ApplicationAPI.h | 6 - .../AzFramework/Application/Application.cpp | 42 +----- .../AzFramework/Application/Application.h | 12 +- .../AzToolsFramework/Asset/AssetUtils.cpp | 20 +-- .../AzToolsFramework/Asset/AssetUtils.h | 2 +- .../Thumbnails/SourceThumbnail.cpp | 10 +- .../Thumbnails/SourceControlThumbnail.cpp | 18 +-- .../Tests/ComponentAddRemove.cpp | 1 - .../Tests/UI/EntityPropertyEditorTests.cpp | 5 - .../source/utils/GUIApplicationManager.cpp | 4 +- .../source/utils/applicationManager.cpp | 1 - .../Tools/AssetBundler/source/utils/utils.cpp | 3 +- Code/Tools/AssetBundler/source/utils/utils.h | 1 - Code/Tools/AssetBundler/tests/UtilsTests.cpp | 16 +- .../tests/applicationManagerTests.cpp | 11 +- .../platformconfigurationtests.cpp | 36 +++-- .../utilities/PlatformConfiguration.cpp | 2 +- .../source/Application.cpp | 1 - .../Tests/Containers/SceneBehaviorTests.cpp | 1 - .../Tools/SerializeContextTools/Converter.cpp | 8 +- Code/Tools/SerializeContextTools/Converter.h | 2 +- .../Code/Tests/AWSClientAuthGemMock.h | 1 - .../Source/AssetValidationSystemComponent.cpp | 21 +-- .../Code/Tests/AssetValidationTestShared.h | 9 +- .../Code/Tests/ImageProcessing_Test.cpp | 1 - .../Code/Source/LuxCore/LuxCoreRenderer.cpp | 9 +- .../Code/Tests.Builders/BuilderTestFixture.h | 1 - .../Tests/Common/AssetManagerTestFixture.h | 1 - .../Code/Source/Util/Util.cpp | 27 +--- .../Code/Include/Atom/Utils/ImGuiPassTree.inl | 9 +- .../Source/Editor/ImplementationManager.cpp | 6 - .../Code/Source/PythonSystemComponent.cpp | 5 +- .../Code/Tests/PythonTestingUtility.h | 4 - .../Code/Tests/Builders/SliceBuilderTests.cpp | 1 - .../Code/Tests/CommonBenchmarkSetup.h | 1 - Gems/Multiplayer/Code/Tests/MockInterfaces.h | 1 - Gems/PhysX/Code/Source/Debug/PhysXDebug.cpp | 5 +- .../Code/Tests/ScriptCanvasBuilderTests.cpp | 1 - .../Framework/ScriptCanvasTestFixture.h | 8 - cmake/Projects.cmake | 4 +- 58 files changed, 168 insertions(+), 477 deletions(-) diff --git a/Code/Editor/CryEdit.cpp b/Code/Editor/CryEdit.cpp index 5cffedd774..0ea22e8ce3 100644 --- a/Code/Editor/CryEdit.cpp +++ b/Code/Editor/CryEdit.cpp @@ -3974,9 +3974,8 @@ void CCryEditApp::OpenLUAEditor(const char* files) } } - const char* engineRoot = nullptr; - AzFramework::ApplicationRequests::Bus::BroadcastResult(engineRoot, &AzFramework::ApplicationRequests::GetEngineRoot); - AZ_Assert(engineRoot != nullptr, "Unable to communicate to AzFramework::ApplicationRequests::Bus"); + AZ::IO::FixedMaxPathString engineRoot = AZ::Utils::GetEnginePath(); + AZ_Assert(!engineRoot.empty(), "Unable to query Engine Path"); AZStd::string_view exePath; AZ::ComponentApplicationBus::BroadcastResult(exePath, &AZ::ComponentApplicationRequests::GetExecutableFolder); @@ -3995,7 +3994,7 @@ void CCryEditApp::OpenLUAEditor(const char* files) #endif "%s", argumentQuoteString, aznumeric_cast(exePath.size()), exePath.data(), argumentQuoteString); - AZStd::string processArgs = AZStd::string::format("%s -engine-path \"%s\"", args.c_str(), engineRoot); + AZStd::string processArgs = AZStd::string::format("%s -engine-path \"%s\"", args.c_str(), engineRoot.c_str()); StartProcessDetached(process.c_str(), processArgs.c_str()); } diff --git a/Code/Editor/Include/IFileUtil.h b/Code/Editor/Include/IFileUtil.h index e179f892d9..4d5f6e23c4 100644 --- a/Code/Editor/Include/IFileUtil.h +++ b/Code/Editor/Include/IFileUtil.h @@ -114,9 +114,7 @@ struct IFileUtil virtual void ShowInExplorer(const QString& path) = 0; - virtual bool CompileLuaFile(const char* luaFilename) = 0; virtual bool ExtractFile(QString& file, bool bMsgBoxAskForExtraction = true, const char* pDestinationFilename = nullptr) = 0; - virtual void EditTextFile(const char* txtFile, int line = 0, ETextFileType fileType = FILE_TYPE_SCRIPT) = 0; virtual void EditTextureFile(const char* txtureFile, bool bUseGameFolder) = 0; //! dcc filename calculation and extraction sub-routines diff --git a/Code/Editor/Util/FileUtil.cpp b/Code/Editor/Util/FileUtil.cpp index baca69d628..36c1879407 100644 --- a/Code/Editor/Util/FileUtil.cpp +++ b/Code/Editor/Util/FileUtil.cpp @@ -23,9 +23,9 @@ // AzCore #include #include +#include // AzFramework -#include // AzQtComponents #include @@ -62,84 +62,6 @@ CAutoRestorePrimaryCDRoot::~CAutoRestorePrimaryCDRoot() QDir::setCurrent(GetIEditor()->GetPrimaryCDFolder()); } -bool CFileUtil::CompileLuaFile(const char* luaFilename) -{ - QString luaFile = luaFilename; - - if (luaFile.isEmpty()) - { - return false; - } - - // Check if this file is in Archive. - { - CCryFile file; - if (file.Open(luaFilename, "rb")) - { - // Check if in pack. - if (file.IsInPak()) - { - return true; - } - } - } - - luaFile = Path::GamePathToFullPath(luaFilename); - - // First try compiling script and see if it have any errors. - QString LuaCompiler; - QString CompilerOutput; - - // Create the filepath of the lua compiler - QString szExeFileName = qApp->applicationFilePath(); - QString exePath = Path::GetPath(szExeFileName); - -#if defined(AZ_PLATFORM_WINDOWS) - const char* luaCompiler = "LuaCompiler.exe"; -#else - const char* luaCompiler = "lua"; -#endif - LuaCompiler = Path::AddPathSlash(exePath) + luaCompiler + " "; - - AZStd::string path = luaFile.toUtf8().data(); - EBUS_EVENT(AzFramework::ApplicationRequests::Bus, NormalizePath, path); - - QString finalPath = path.c_str(); - finalPath = "\"" + finalPath + "\""; - - // Add the name of the Lua file - QString cmdLine = LuaCompiler + finalPath; - - // Execute the compiler and capture the output - if (!GetIEditor()->ExecuteConsoleApp(cmdLine, CompilerOutput)) - { - QMessageBox::critical(QApplication::activeWindow(), QString(), QObject::tr("Error while executing '%1', make sure the file is in" \ - " your Primary CD folder !").arg(luaCompiler)); - return false; - } - - // Check return string - if (!CompilerOutput.isEmpty()) - { - // Errors while compiling file. - - // Show output from Lua compiler - if (QMessageBox::critical(QApplication::activeWindow(), QObject::tr("Lua Compiler"), - QObject::tr("Error output from Lua compiler:\r\n%1\r\nDo you want to edit the file ?").arg(CompilerOutput), QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) - { - int line = 0; - int index = CompilerOutput.indexOf("at line"); - if (index >= 0) - { - azsscanf(CompilerOutput.mid(index).toUtf8().data(), "at line %d", &line); - } - // Open the Lua file for editing - EditTextFile(luaFile.toUtf8().data(), line); - } - return false; - } - return true; -} ////////////////////////////////////////////////////////////////////////// bool CFileUtil::ExtractFile(QString& file, bool bMsgBoxAskForExtraction, const char* pDestinationFilename) { @@ -205,7 +127,7 @@ void CFileUtil::EditTextFile(const char* txtFile, int line, IFileUtil::ETextFile { QString file = txtFile; - QString fullPathName = Path::GamePathToFullPath(file); + QString fullPathName = Path::GamePathToFullPath(file); ExtractFile(fullPathName); QString cmd(fullPathName); #if defined (AZ_PLATFORM_WINDOWS) @@ -301,64 +223,6 @@ void CFileUtil::EditTextureFile(const char* textureFile, [[maybe_unused]] bool b } } -////////////////////////////////////////////////////////////////////////// -bool CFileUtil::EditMayaFile(const char* filepath, const bool bExtractFromPak, const bool bUseGameFolder) -{ - QString dosFilepath = PathUtil::ToDosPath(filepath).c_str(); - if (bExtractFromPak) - { - ExtractFile(dosFilepath); - } - - if (bUseGameFolder) - { - const QString sGameFolder = Path::GetEditingGameDataFolder().c_str(); - int nLength = sGameFolder.toUtf8().count(); - if (azstrnicmp(filepath, sGameFolder.toUtf8().data(), nLength) != 0) - { - dosFilepath = sGameFolder + '\\' + filepath; - } - - dosFilepath = PathUtil::ToDosPath(dosFilepath.toUtf8().data()).c_str(); - } - - const char* engineRoot; - EBUS_EVENT_RESULT(engineRoot, AzFramework::ApplicationRequests::Bus, GetEngineRoot); - - const QString fullPath = QString(engineRoot) + '\\' + dosFilepath; - - if (gSettings.animEditor.isEmpty()) - { - AzQtComponents::ShowFileOnDesktop(fullPath); - } - else - { - if (!QProcess::startDetached(gSettings.animEditor, { fullPath })) - { - CryMessageBox("Can't open the file. You can specify a source editor in Sandbox Preferences or create an association in Windows.", "Cannot open file!", MB_OK | MB_ICONERROR); - } - } - return true; -} - -////////////////////////////////////////////////////////////////////////// -bool CFileUtil::EditFile(const char* filePath, const bool bExtrackFromPak, const bool bUseGameFolder) -{ - QString extension = filePath; - extension.remove(0, extension.lastIndexOf('.')); - - if (extension.compare(".ma") == 0) - { - return EditMayaFile(filePath, bExtrackFromPak, bUseGameFolder); - } - else if ((extension.compare(".bspace") == 0) || (extension.compare(".comb") == 0)) - { - EditTextFile(filePath, 0, IFileUtil::FILE_TYPE_BSPACE); - return true; - } - - return false; -} ////////////////////////////////////////////////////////////////////////// bool CFileUtil::CalculateDccFilename(const QString& assetFilename, QString& dccFilename) diff --git a/Code/Editor/Util/FileUtil.h b/Code/Editor/Util/FileUtil.h index 5820c32081..fc0fc942fe 100644 --- a/Code/Editor/Util/FileUtil.h +++ b/Code/Editor/Util/FileUtil.h @@ -25,14 +25,9 @@ public: static void ShowInExplorer(const QString& path); - // Try to compile the given lua file: returns true if compilation succeeded, false on failure. - static bool CompileLuaFile(const char* luaFilename); - static bool ExtractFile(QString& file, bool bMsgBoxAskForExtraction = true, const char* pDestinationFilename = nullptr); static void EditTextFile(const char* txtFile, int line = 0, IFileUtil::ETextFileType fileType = IFileUtil::FILE_TYPE_SCRIPT); static void EditTextureFile(const char* txtureFile, bool bUseGameFolder); - static bool EditMayaFile(const char* mayaFile, const bool bExtractFromPak, const bool bUseGameFolder); - static bool EditFile(const char* filePath, const bool bExtrackFromPak, const bool bUseGameFolder); //! dcc filename calculation and extraction sub-routines static bool CalculateDccFilename(const QString& assetFilename, QString& dccFilename); diff --git a/Code/Editor/Util/FileUtil_impl.cpp b/Code/Editor/Util/FileUtil_impl.cpp index 0dd3a0ca87..28090d28d5 100644 --- a/Code/Editor/Util/FileUtil_impl.cpp +++ b/Code/Editor/Util/FileUtil_impl.cpp @@ -20,21 +20,11 @@ void CFileUtil_impl::ShowInExplorer(const QString& path) CFileUtil::ShowInExplorer(path); } -bool CFileUtil_impl::CompileLuaFile(const char* luaFilename) -{ - return CFileUtil::CompileLuaFile(luaFilename); -} - bool CFileUtil_impl::ExtractFile(QString& file, bool bMsgBoxAskForExtraction, const char* pDestinationFilename) { return CFileUtil::ExtractFile(file, bMsgBoxAskForExtraction, pDestinationFilename); } -void CFileUtil_impl::EditTextFile(const char* txtFile, int line, ETextFileType fileType) -{ - CFileUtil::EditTextFile(txtFile, line, fileType); -} - void CFileUtil_impl::EditTextureFile(const char* txtureFile, bool bUseGameFolder) { CFileUtil::EditTextureFile(txtureFile, bUseGameFolder); diff --git a/Code/Editor/Util/FileUtil_impl.h b/Code/Editor/Util/FileUtil_impl.h index 04d9e829b9..aa8d0bf3b5 100644 --- a/Code/Editor/Util/FileUtil_impl.h +++ b/Code/Editor/Util/FileUtil_impl.h @@ -36,9 +36,7 @@ public: void ShowInExplorer(const QString& path) override; - bool CompileLuaFile(const char* luaFilename) override; bool ExtractFile(QString& file, bool bMsgBoxAskForExtraction = true, const char* pDestinationFilename = nullptr) override; - void EditTextFile(const char* txtFile, int line = 0, ETextFileType fileType = FILE_TYPE_SCRIPT) override; void EditTextureFile(const char* txtureFile, bool bUseGameFolder) override; //! dcc filename calculation and extraction sub-routines diff --git a/Code/Editor/Util/PathUtil.cpp b/Code/Editor/Util/PathUtil.cpp index ca3481ddae..8b745ee1bc 100644 --- a/Code/Editor/Util/PathUtil.cpp +++ b/Code/Editor/Util/PathUtil.cpp @@ -14,7 +14,6 @@ #include #include #include // for ebus events -#include #include #include @@ -175,9 +174,8 @@ namespace Path ////////////////////////////////////////////////////////////////////////// QString GetEngineRootPath() { - const char* engineRoot; - EBUS_EVENT_RESULT(engineRoot, AzFramework::ApplicationRequests::Bus, GetEngineRoot); - return QString(engineRoot); + const AZ::IO::FixedMaxPathString engineRoot = AZ::Utils::GetEnginePath(); + return QString::fromUtf8(engineRoot.c_str(), static_cast(engineRoot.size())); } ////////////////////////////////////////////////////////////////////////// diff --git a/Code/Editor/WelcomeScreen/WelcomeScreenDialog.cpp b/Code/Editor/WelcomeScreen/WelcomeScreenDialog.cpp index 17f576b5ee..89dfcaffd1 100644 --- a/Code/Editor/WelcomeScreen/WelcomeScreenDialog.cpp +++ b/Code/Editor/WelcomeScreen/WelcomeScreenDialog.cpp @@ -25,8 +25,6 @@ #include -// AzFramework -#include // AzToolsFramework #include @@ -173,9 +171,6 @@ void WelcomeScreenDialog::SetRecentFileList(RecentFileList* pList) m_pRecentList = pList; - const char* engineRoot; - EBUS_EVENT_RESULT(engineRoot, AzFramework::ApplicationRequests::Bus, GetEngineRoot); - auto projectPath = AZ::Utils::GetProjectPath(); QString gamePath{projectPath.c_str()}; Path::ConvertSlashToBackSlash(gamePath); diff --git a/Code/Framework/AzCore/AzCore/Component/ComponentApplication.cpp b/Code/Framework/AzCore/AzCore/Component/ComponentApplication.cpp index ad7e44c2ae..bd225cf634 100644 --- a/Code/Framework/AzCore/AzCore/Component/ComponentApplication.cpp +++ b/Code/Framework/AzCore/AzCore/Component/ComponentApplication.cpp @@ -485,16 +485,6 @@ namespace AZ constexpr bool executeRegDumpCommands = false; SettingsRegistryMergeUtils::MergeSettingsToRegistry_CommandLine(*m_settingsRegistry, m_commandLine, executeRegDumpCommands); - // Query for the Executable Path using OS specific functions - CalculateExecutablePath(); - - // Determine the path to the engine - CalculateEngineRoot(); - - // If the current platform returns an engaged optional from Utils::GetDefaultAppRootPath(), that is used - // for the application root. - CalculateAppRoot(); - SettingsRegistryMergeUtils::MergeSettingsToRegistry_O3deUserRegistry(*m_settingsRegistry, AZ_TRAIT_OS_PLATFORM_CODENAME, {}); SettingsRegistryMergeUtils::MergeSettingsToRegistry_CommandLine(*m_settingsRegistry, m_commandLine, executeRegDumpCommands); SettingsRegistryMergeUtils::MergeSettingsToRegistry_AddRuntimeFilePaths(*m_settingsRegistry); @@ -614,7 +604,8 @@ namespace AZ { AZ_Assert(!m_isStarted, "Component application already started!"); - if (m_engineRoot.empty()) + using Type = AZ::SettingsRegistryInterface::Type; + if (m_settingsRegistry->GetType(SettingsRegistryMergeUtils::FilePathKey_EngineRootFolder) == Type::NoType) { ReportBadEngineRoot(); return nullptr; @@ -1180,6 +1171,24 @@ namespace AZ return ReflectionEnvironment::GetReflectionManager() ? ReflectionEnvironment::GetReflectionManager()->GetReflectContext() : nullptr; } + /// Returns the path to the engine. + + const char* ComponentApplication::GetEngineRoot() const + { + static IO::FixedMaxPathString engineRoot; + engineRoot.clear(); + m_settingsRegistry->Get(engineRoot, SettingsRegistryMergeUtils::FilePathKey_EngineRootFolder); + return engineRoot.c_str(); + } + + const char* ComponentApplication::GetExecutableFolder() const + { + static IO::FixedMaxPathString exeFolder; + exeFolder.clear(); + m_settingsRegistry->Get(exeFolder, SettingsRegistryMergeUtils::FilePathKey_BinaryFolder); + return exeFolder.c_str(); + } + //========================================================================= // CreateReflectionManager //========================================================================= @@ -1485,27 +1494,6 @@ namespace AZ } } - //========================================================================= - // CalculateExecutablePath - //========================================================================= - void ComponentApplication::CalculateExecutablePath() - { - m_exeDirectory = Utils::GetExecutableDirectory(); - } - - void ComponentApplication::CalculateAppRoot() - { - if (AZStd::optional appRootPath = Utils::GetDefaultAppRootPath(); appRootPath) - { - m_appRoot = AZStd::move(*appRootPath); - } - } - - void ComponentApplication::CalculateEngineRoot() - { - m_engineRoot = AZ::SettingsRegistryMergeUtils::FindEngineRoot(*m_settingsRegistry).Native(); - } - void ComponentApplication::ResolveModulePath([[maybe_unused]] AZ::OSString& modulePath) { // No special parsing of the Module Path is done by the Component Application anymore diff --git a/Code/Framework/AzCore/AzCore/Component/ComponentApplication.h b/Code/Framework/AzCore/AzCore/Component/ComponentApplication.h index 6df93aff4e..4e551b6c47 100644 --- a/Code/Framework/AzCore/AzCore/Component/ComponentApplication.h +++ b/Code/Framework/AzCore/AzCore/Component/ComponentApplication.h @@ -221,13 +221,10 @@ namespace AZ BehaviorContext* GetBehaviorContext() override; /// Returns the json registration context that has been registered with the app, if there is one. JsonRegistrationContext* GetJsonRegistrationContext() override; - /// Returns the working root folder that has been registered with the app, if there is one. - /// It's expected that derived applications will implement an application root. - const char* GetAppRoot() const override { return m_appRoot.c_str(); } /// Returns the path to the engine. - const char* GetEngineRoot() const override { return m_engineRoot.c_str(); } + const char* GetEngineRoot() const override; /// Returns the path to the folder the executable is in. - const char* GetExecutableFolder() const override { return m_exeDirectory.c_str(); } + const char* GetExecutableFolder() const override; ////////////////////////////////////////////////////////////////////////// /// TickRequestBus @@ -352,15 +349,6 @@ namespace AZ /// Adds system components requested by modules and the application to the system entity. void AddRequiredSystemComponents(AZ::Entity* systemEntity); - /// Calculates the directory the application executable comes from. - void CalculateExecutablePath(); - - /// Calculates the root directory of the engine. - void CalculateEngineRoot(); - - /// Deprecated: The term "AppRoot" has no meaning - void CalculateAppRoot(); - template static void NormalizePath(Iterator begin, Iterator end, bool doLowercase = true) { @@ -388,9 +376,6 @@ namespace AZ void* m_fixedMemoryBlock{ nullptr }; //!< Pointer to the memory block allocator, so we can free it OnDestroy. IAllocatorAllocate* m_osAllocator{ nullptr }; EntitySetType m_entities; - AZ::IO::FixedMaxPath m_exeDirectory; - AZ::IO::FixedMaxPath m_engineRoot; - AZ::IO::FixedMaxPath m_appRoot; AZ::SettingsRegistryInterface::NotifyEventHandler m_projectPathChangedHandler; AZ::SettingsRegistryInterface::NotifyEventHandler m_projectNameChangedHandler; diff --git a/Code/Framework/AzCore/AzCore/Component/ComponentApplicationBus.h b/Code/Framework/AzCore/AzCore/Component/ComponentApplicationBus.h index 0c0977384a..feefa95973 100644 --- a/Code/Framework/AzCore/AzCore/Component/ComponentApplicationBus.h +++ b/Code/Framework/AzCore/AzCore/Component/ComponentApplicationBus.h @@ -175,10 +175,6 @@ namespace AZ //! the serializers used by the best-effort json serialization. virtual class JsonRegistrationContext* GetJsonRegistrationContext() = 0; - //! Gets the name of the working root folder that was registered with the app. - //! @return a pointer to the name of the app's root folder, if a root folder was registered. - virtual const char* GetAppRoot() const = 0; - //! Gets the path of the working engine folder that the app is a part of. //! @return a pointer to the engine path. virtual const char* GetEngineRoot() const = 0; diff --git a/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryMergeUtils.cpp b/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryMergeUtils.cpp index 3902bd107c..975217a131 100644 --- a/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryMergeUtils.cpp +++ b/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryMergeUtils.cpp @@ -266,7 +266,8 @@ namespace AZ::SettingsRegistryMergeUtils // Step 3 locate the project root and attempt to find the engine root using the registered engine // for the project in the project.json file - AZ::IO::FixedMaxPath projectRoot = FindProjectRoot(settingsRegistry); + AZ::IO::FixedMaxPath projectRoot; + settingsRegistry.Get(projectRoot.Native(), FilePathKey_ProjectPath); if (projectRoot.empty()) { return {}; @@ -693,6 +694,7 @@ namespace AZ::SettingsRegistryMergeUtils R"(Project path isn't set in the Settings Registry at "%.*s".)" " Project-related filepaths will be set relative to the executable directory\n", AZ_STRING_ARG(projectPathKey)); + projectPath = exePath; registry.Set(FilePathKey_ProjectPath, exePath.Native()); } diff --git a/Code/Framework/AzCore/AzCore/StringFunc/StringFunc.cpp b/Code/Framework/AzCore/AzCore/StringFunc/StringFunc.cpp index ff30291a70..a953d53c33 100644 --- a/Code/Framework/AzCore/AzCore/StringFunc/StringFunc.cpp +++ b/Code/Framework/AzCore/AzCore/StringFunc/StringFunc.cpp @@ -1427,26 +1427,36 @@ namespace AZ namespace AssetPath { - void CalculateBranchToken(const AZStd::string& appRootPath, AZStd::string& token) + namespace Internal { - // Normalize the token to prepare for CRC32 calculation - AZStd::string normalized = appRootPath; + AZ::u32 CalculateBranchTokenHash(AZStd::string_view engineRootPath) + { + // Normalize the token to prepare for CRC32 calculation + auto NormalizeEnginePath = [](const char element) -> char + { + // Substitute path separators with '_' and lower case + return element == AZ::IO::WindowsPathSeparator || element == AZ::IO::PosixPathSeparator + ? '_' : static_cast(std::tolower(element)); + }; - // Strip out any trailing path separators - AZ::StringFunc::Strip(normalized, AZ_CORRECT_FILESYSTEM_SEPARATOR_STRING AZ_WRONG_FILESYSTEM_SEPARATOR_STRING,false, false, true); + // Trim off trailing path separators + engineRootPath = RStrip(engineRootPath, AZ_CORRECT_AND_WRONG_FILESYSTEM_SEPARATOR); + AZ::IO::FixedMaxPathString enginePath; + AZStd::transform(engineRootPath.begin(), engineRootPath.end(), + AZStd::back_inserter(enginePath), AZStd::move(NormalizeEnginePath)); - // Lower case always - AZStd::to_lower(normalized.begin(), normalized.end()); - - // Substitute path separators with '_' - AZStd::replace(normalized.begin(), normalized.end(), '\\', '_'); - AZStd::replace(normalized.begin(), normalized.end(), '/', '_'); - - // Perform the CRC32 calculation - const AZ::Crc32 branchTokenCrc(normalized.c_str(), normalized.size(), true); - char branchToken[12]; - azsnprintf(branchToken, AZ_ARRAY_SIZE(branchToken), "0x%08X", static_cast(branchTokenCrc)); - token = AZStd::string(branchToken); + // Perform the CRC32 calculation + constexpr bool forceLowercase = true; + return static_cast(AZ::Crc32(enginePath.c_str(), enginePath.size(), forceLowercase)); + } + } + void CalculateBranchToken(AZStd::string_view engineRootPath, AZStd::string& token) + { + token = AZStd::string::format("0x%08X", Internal::CalculateBranchTokenHash(engineRootPath)); + } + void CalculateBranchToken(AZStd::string_view engineRootPath, AZ::IO::FixedMaxPathString& token) + { + token = AZ::IO::FixedMaxPathString::format("0x%08X", Internal::CalculateBranchTokenHash(engineRootPath)); } } diff --git a/Code/Framework/AzCore/AzCore/StringFunc/StringFunc.h b/Code/Framework/AzCore/AzCore/StringFunc/StringFunc.h index 1e651afc93..55236a0fff 100644 --- a/Code/Framework/AzCore/AzCore/StringFunc/StringFunc.h +++ b/Code/Framework/AzCore/AzCore/StringFunc/StringFunc.h @@ -485,10 +485,11 @@ namespace AZ //! CalculateBranchToken /*! Calculate the branch token that is used for asset processor connection negotiations * - * \param appRootPath - The absolute path of the app root to base the token calculation on + * \param engineRootPath - The absolute path to the engine root to base the token calculation on * \param token - The result of the branch token calculation */ - void CalculateBranchToken(const AZStd::string& appRootPath, AZStd::string& token); + void CalculateBranchToken(AZStd::string_view engineRootPath, AZStd::string& token); + void CalculateBranchToken(AZStd::string_view engineRootPath, AZ::IO::FixedMaxPathString& token); } ////////////////////////////////////////////////////////////////////////// diff --git a/Code/Framework/AzCore/AzCore/UnitTest/MockComponentApplication.h b/Code/Framework/AzCore/AzCore/UnitTest/MockComponentApplication.h index 8f069da9dd..190fa09cb7 100644 --- a/Code/Framework/AzCore/AzCore/UnitTest/MockComponentApplication.h +++ b/Code/Framework/AzCore/AzCore/UnitTest/MockComponentApplication.h @@ -41,7 +41,6 @@ namespace UnitTest MOCK_METHOD0(GetSerializeContext, AZ::SerializeContext* ()); MOCK_METHOD0(GetJsonRegistrationContext, AZ::JsonRegistrationContext* ()); MOCK_METHOD0(GetBehaviorContext, AZ::BehaviorContext* ()); - MOCK_CONST_METHOD0(GetAppRoot, const char* ()); MOCK_CONST_METHOD0(GetEngineRoot, const char* ()); MOCK_CONST_METHOD0(GetExecutableFolder, const char* ()); MOCK_CONST_METHOD1(QueryApplicationType, void(AZ::ApplicationTypeQuery&)); diff --git a/Code/Framework/AzCore/Tests/BehaviorContextFixture.h b/Code/Framework/AzCore/Tests/BehaviorContextFixture.h index 1895f2e35b..3c6d48add7 100644 --- a/Code/Framework/AzCore/Tests/BehaviorContextFixture.h +++ b/Code/Framework/AzCore/Tests/BehaviorContextFixture.h @@ -59,7 +59,6 @@ namespace UnitTest AZ::SerializeContext* GetSerializeContext() override { return nullptr; } AZ::BehaviorContext* GetBehaviorContext() override { return m_behaviorContext; } AZ::JsonRegistrationContext* GetJsonRegistrationContext() override { return nullptr; } - const char* GetAppRoot() const override { return nullptr; } const char* GetEngineRoot() const override { return nullptr; } const char* GetExecutableFolder() const override { return nullptr; } void EnumerateEntities(const EntityCallback& /*callback*/) override {} diff --git a/Code/Framework/AzCore/Tests/Components.cpp b/Code/Framework/AzCore/Tests/Components.cpp index 55b1c193b3..013d998c52 100644 --- a/Code/Framework/AzCore/Tests/Components.cpp +++ b/Code/Framework/AzCore/Tests/Components.cpp @@ -1060,26 +1060,21 @@ namespace UnitTest /** * UserSettingsComponent test */ - class UserSettingsTestApp - : public ComponentApplication - , public UserSettingsFileLocatorBus::Handler - { - public: - void SetExecutableFolder(const char* path) - { - m_exeDirectory = path; - } - + class UserSettingsTestApp + : public ComponentApplication + , public UserSettingsFileLocatorBus::Handler + { + public: AZStd::string ResolveFilePath(u32 providerId) override { AZStd::string filePath; if (providerId == UserSettings::CT_GLOBAL) { - filePath = (m_exeDirectory / "GlobalUserSettings.xml").String(); + filePath = (AZ::IO::Path(GetTestFolderPath()) / "GlobalUserSettings.xml").Native(); } else if (providerId == UserSettings::CT_LOCAL) { - filePath = (m_exeDirectory / "LocalUserSettings.xml").String(); + filePath = (AZ::IO::Path(GetTestFolderPath()) / "LocalUserSettings.xml").Native(); } return filePath; } @@ -1117,7 +1112,6 @@ namespace UnitTest ComponentApplication::Descriptor appDesc; appDesc.m_memoryBlocksByteSize = 10 * 1024 * 1024; Entity* systemEntity = app.Create(appDesc); - app.SetExecutableFolder(GetTestFolderPath().c_str()); app.UserSettingsFileLocatorBus::Handler::BusConnect(); // Make sure user settings file does not exist at this point diff --git a/Code/Framework/AzCore/Tests/Serialization.cpp b/Code/Framework/AzCore/Tests/Serialization.cpp index f1d5edc490..219744a480 100644 --- a/Code/Framework/AzCore/Tests/Serialization.cpp +++ b/Code/Framework/AzCore/Tests/Serialization.cpp @@ -1240,7 +1240,6 @@ namespace UnitTest SerializeContext* GetSerializeContext() override { return m_serializeContext.get(); } BehaviorContext* GetBehaviorContext() override { return nullptr; } JsonRegistrationContext* GetJsonRegistrationContext() override { return nullptr; } - const char* GetAppRoot() const override { return nullptr; } const char* GetEngineRoot() const override { return nullptr; } const char* GetExecutableFolder() const override { return nullptr; } void EnumerateEntities(const EntityCallback& /*callback*/) override {} diff --git a/Code/Framework/AzFramework/AzFramework/API/ApplicationAPI.h b/Code/Framework/AzFramework/AzFramework/API/ApplicationAPI.h index 1c5db0a82b..e536082d61 100644 --- a/Code/Framework/AzFramework/AzFramework/API/ApplicationAPI.h +++ b/Code/Framework/AzFramework/AzFramework/API/ApplicationAPI.h @@ -67,12 +67,6 @@ namespace AzFramework /// Make path relative to the provided root. virtual void MakePathRelative(AZStd::string& /*fullPath*/, const char* /*rootPath*/) {} - /// Gets the engine root path where the modules for the current engine are located. - virtual const char* GetEngineRoot() const { return nullptr; } - - /// Retrieves the app root path for the application. - virtual const char* GetAppRoot() const { return nullptr; } - /// Get the Command Line arguments passed in. virtual const CommandLine* GetCommandLine() { return nullptr; } diff --git a/Code/Framework/AzFramework/AzFramework/Application/Application.cpp b/Code/Framework/AzFramework/AzFramework/Application/Application.cpp index b6b09148eb..768ef1f0b6 100644 --- a/Code/Framework/AzFramework/AzFramework/Application/Application.cpp +++ b/Code/Framework/AzFramework/AzFramework/Application/Application.cpp @@ -225,13 +225,6 @@ namespace AzFramework } } - void Application::PreModuleLoad() - { - SetRootPath(RootPathType::EngineRoot, m_engineRoot.c_str()); - AZ_TracePrintf(s_azFrameworkWarningWindow, "Engine Path: %s\n", m_engineRoot.c_str()); - } - - void Application::Stop() { if (m_isStarted) @@ -397,11 +390,6 @@ namespace AzFramework outModules.emplace_back(aznew AzFrameworkModule()); } - const char* Application::GetAppRoot() const - { - return m_appRoot.c_str(); - } - const char* Application::GetCurrentConfigurationName() const { #if defined(_RELEASE) @@ -437,19 +425,19 @@ namespace AzFramework void Application::ResolveEnginePath(AZStd::string& engineRelativePath) const { - AZ::IO::FixedMaxPath fullPath = m_engineRoot / engineRelativePath; + auto fullPath = AZ::IO::FixedMaxPath(GetEngineRoot()) / engineRelativePath; engineRelativePath = fullPath.String(); } void Application::CalculateBranchTokenForEngineRoot(AZStd::string& token) const { - AzFramework::StringFunc::AssetPath::CalculateBranchToken(m_engineRoot.String(), token); + AZ::StringFunc::AssetPath::CalculateBranchToken(GetEngineRoot(), token); } //////////////////////////////////////////////////////////////////////////// void Application::MakePathRootRelative(AZStd::string& fullPath) { - MakePathRelative(fullPath, m_engineRoot.c_str()); + MakePathRelative(fullPath, GetEngineRoot()); } //////////////////////////////////////////////////////////////////////////// @@ -585,30 +573,6 @@ namespace AzFramework } } - void Application::SetRootPath(RootPathType type, const char* source) - { - [[maybe_unused]] const size_t sourceLen = strlen(source); - - // Copy the source path to the intended root path and correct the path separators as well - switch (type) - { - case RootPathType::AppRoot: - { - AZ_Assert(sourceLen < m_appRoot.Native().max_size(), "String overflow for App Root: %s", source); - m_appRoot = AZ::IO::PathView(source).LexicallyNormal(); - } - break; - case RootPathType::EngineRoot: - { - AZ_Assert(sourceLen < m_engineRoot.Native().max_size(), "String overflow for Engine Root: %s", source); - m_engineRoot = AZ::IO::PathView(source).LexicallyNormal(); - } - break; - default: - AZ_Assert(false, "Invalid RootPathType (%d)", static_cast(type)); - } - } - struct DeprecatedAliasesKeyVisitor : AZ::SettingsRegistryInterface::Visitor { diff --git a/Code/Framework/AzFramework/AzFramework/Application/Application.h b/Code/Framework/AzFramework/AzFramework/Application/Application.h index c6b1dfeaae..a318ede4a2 100644 --- a/Code/Framework/AzFramework/AzFramework/Application/Application.h +++ b/Code/Framework/AzFramework/AzFramework/Application/Application.h @@ -95,8 +95,6 @@ namespace AzFramework ////////////////////////////////////////////////////////////////////////// //! ApplicationRequests::Bus::Handler - const char* GetEngineRoot() const override { return m_engineRoot.c_str(); } - const char* GetAppRoot() const override; void ResolveEnginePath(AZStd::string& engineRelativePath) const override; void CalculateBranchTokenForEngineRoot(AZStd::string& token) const override; bool IsPrefabSystemEnabled() const override; @@ -146,8 +144,6 @@ namespace AzFramework */ void SetFileIOAliases(); - void PreModuleLoad() override; - ////////////////////////////////////////////////////////////////////////// //! AZ::ComponentApplication void RegisterCoreComponents() override; @@ -181,13 +177,7 @@ namespace AzFramework bool m_ownsConsole = false; bool m_exitMainLoopRequested = false; - - enum class RootPathType - { - AppRoot, - EngineRoot - }; - void SetRootPath(RootPathType type, const char* source); + }; } // namespace AzFramework diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Asset/AssetUtils.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Asset/AssetUtils.cpp index 139bbb563c..6fd881dbb9 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Asset/AssetUtils.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Asset/AssetUtils.cpp @@ -14,7 +14,7 @@ #include #include #include -#include +#include #include #include #include @@ -205,7 +205,7 @@ namespace AzToolsFramework::AssetUtils return platformConfigFilePathsAdded; } - AZStd::vector GetConfigFiles(AZStd::string_view engineRoot, AZStd::string_view assetRoot, AZStd::string_view projectPath, + AZStd::vector GetConfigFiles(AZStd::string_view engineRoot, AZStd::string_view projectPath, bool addPlatformConfigs, bool addGemsConfigs, AZ::SettingsRegistryInterface* settingsRegistry) { constexpr const char* AssetProcessorGamePlatformConfigFileName = "AssetProcessorGamePlatformConfig.ini"; @@ -232,14 +232,13 @@ namespace AzToolsFramework::AssetUtils Internal::AddGemConfigFiles(gemInfoList, configFiles); } - AZ::IO::Path assetRootDir(assetRoot); - assetRootDir /= projectPath; + AZ::IO::Path projectRoot(projectPath); - AZ::IO::Path projectConfigFile = assetRootDir / AssetProcessorGamePlatformConfigFileName; + AZ::IO::Path projectConfigFile = projectRoot / AssetProcessorGamePlatformConfigFileName; configFiles.push_back(projectConfigFile); // Add a file entry for the Project AssetProcessor setreg file - projectConfigFile = assetRootDir / AssetProcessorGamePlatformConfigSetreg; + projectConfigFile = projectRoot / AssetProcessorGamePlatformConfigSetreg; configFiles.push_back(projectConfigFile); return configFiles; @@ -251,10 +250,10 @@ namespace AzToolsFramework::AssetUtils AZStd::vector tokens; AZ::StringFunc::Tokenize(relPathFromRoot.c_str(), tokens, AZ_CORRECT_FILESYSTEM_SEPARATOR_STRING); - AZStd::string validatedPath; + AZ::IO::FixedMaxPath validatedPath; if (rootPath.empty()) { - AzFramework::ApplicationRequests::Bus::BroadcastResult(validatedPath, &AzFramework::ApplicationRequests::GetEngineRoot); + validatedPath = AZ::Utils::GetEnginePath(); } else { @@ -299,10 +298,7 @@ namespace AzToolsFramework::AssetUtils break; } - AZStd::string absoluteFilePath; - AZ::StringFunc::Path::ConstructFull(validatedPath.c_str(), element.c_str(), absoluteFilePath); - - validatedPath = absoluteFilePath; // go one step deeper. + validatedPath /= element; // go one step deeper. } if (success) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Asset/AssetUtils.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Asset/AssetUtils.h index 39aab4d3fb..31ee9dcf60 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Asset/AssetUtils.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Asset/AssetUtils.h @@ -40,7 +40,7 @@ namespace AzToolsFramework::AssetUtils //! Also note that if the project has any "game project gems", then those will also be inserted last, //! and thus have a higher priority than the root or non - project gems. //! Also note that the game project could be in a different location to the engine therefore we need the assetRoot param. - AZStd::vector GetConfigFiles(AZStd::string_view engineRoot, AZStd::string_view assetRoot, AZStd::string_view projectPath, + AZStd::vector GetConfigFiles(AZStd::string_view engineRoot, AZStd::string_view projectPath, bool addPlatformConfigs = true, bool addGemsConfigs = true, AZ::SettingsRegistryInterface* settingsRegistry = nullptr); //! A utility function which checks the given path starting at the root and updates the relative path to be the actual case correct path. diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/Thumbnails/SourceThumbnail.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/Thumbnails/SourceThumbnail.cpp index a5206c9608..4869e0d09f 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/Thumbnails/SourceThumbnail.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/Thumbnails/SourceThumbnail.cpp @@ -9,11 +9,11 @@ #include #include #include +#include #include #include #include #include -#include #include namespace AzToolsFramework @@ -113,11 +113,9 @@ namespace AzToolsFramework if (iconPathToUse.isEmpty()) { - const char* engineRoot = nullptr; - AzFramework::ApplicationRequests::Bus::BroadcastResult(engineRoot, &AzFramework::ApplicationRequests::GetEngineRoot); - AZ_Assert(engineRoot, "Engine Root not initialized"); - AZStd::string iconPath = AZStd::string::format("%s%s", engineRoot, DefaultFileIconPath); - iconPathToUse = iconPath.c_str(); + AZ::IO::FixedMaxPath engineRoot = AZ::Utils::GetEnginePath(); + AZ_Assert(!engineRoot.empty(), "Engine Root not initialized"); + iconPathToUse = (engineRoot / DefaultFileIconPath).c_str(); } m_pixmap.load(iconPathToUse); diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Thumbnails/SourceControlThumbnail.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Thumbnails/SourceControlThumbnail.cpp index 655fd27a0f..c2636d6d52 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Thumbnails/SourceControlThumbnail.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Thumbnails/SourceControlThumbnail.cpp @@ -6,10 +6,10 @@ * */ -#include +#include +#include #include #include -#include namespace AzToolsFramework { @@ -68,12 +68,12 @@ namespace AzToolsFramework SourceControlThumbnail::SourceControlThumbnail(SharedThumbnailKey key) : Thumbnail(key) { - const char* engineRoot = nullptr; - AzFramework::ApplicationRequests::Bus::BroadcastResult(engineRoot, &AzFramework::ApplicationRequests::GetEngineRoot); - AZ_Assert(engineRoot, "Engine Root not initialized"); + AZ::IO::FixedMaxPath engineRoot = AZ::Utils::GetEnginePath(); + AZ_Assert(!engineRoot.empty(), "Engine Root not initialized"); + + m_writableIconPath = (engineRoot / WRITABLE_ICON_PATH).String(); + m_nonWritableIconPath = (engineRoot / NONWRITABLE_ICON_PATH).String(); - AzFramework::StringFunc::Path::Join(engineRoot, WRITABLE_ICON_PATH, m_writableIconPath); - AzFramework::StringFunc::Path::Join(engineRoot, NONWRITABLE_ICON_PATH, m_nonWritableIconPath); BusConnect(); } @@ -90,8 +90,8 @@ namespace AzToolsFramework AZ_Assert(sourceControlKey, "Incorrect key type, excpected SourceControlThumbnailKey"); AZStd::string myFileName(sourceControlKey->GetFileName()); - AzFramework::StringFunc::Path::Normalize(myFileName); - if (AzFramework::StringFunc::Equal(myFileName.c_str(), filename)) + AZ::StringFunc::Path::Normalize(myFileName); + if (AZ::StringFunc::Equal(myFileName.c_str(), filename)) { Update(); } diff --git a/Code/Framework/AzToolsFramework/Tests/ComponentAddRemove.cpp b/Code/Framework/AzToolsFramework/Tests/ComponentAddRemove.cpp index 9d6c8a4bff..06353b17c5 100644 --- a/Code/Framework/AzToolsFramework/Tests/ComponentAddRemove.cpp +++ b/Code/Framework/AzToolsFramework/Tests/ComponentAddRemove.cpp @@ -1116,7 +1116,6 @@ namespace UnitTest SerializeContext* GetSerializeContext() override { return m_serializeContext.get(); } BehaviorContext* GetBehaviorContext() override { return nullptr; } JsonRegistrationContext* GetJsonRegistrationContext() override { return nullptr; } - const char* GetAppRoot() const override { return nullptr; } const char* GetEngineRoot() const override { return nullptr; } const char* GetExecutableFolder() const override { return nullptr; } void EnumerateEntities(const EntityCallback& /*callback*/) override {} diff --git a/Code/Framework/AzToolsFramework/Tests/UI/EntityPropertyEditorTests.cpp b/Code/Framework/AzToolsFramework/Tests/UI/EntityPropertyEditorTests.cpp index c24bab9299..a3c6666a40 100644 --- a/Code/Framework/AzToolsFramework/Tests/UI/EntityPropertyEditorTests.cpp +++ b/Code/Framework/AzToolsFramework/Tests/UI/EntityPropertyEditorTests.cpp @@ -36,11 +36,6 @@ namespace UnitTest : public ComponentApplication { public: - void SetExecutableFolder(const char* path) - { - m_exeDirectory = path; - } - void SetSettingsRegistrySpecializations(SettingsRegistryInterface::Specializations& specializations) override { ComponentApplication::SetSettingsRegistrySpecializations(specializations); diff --git a/Code/Tools/AssetBundler/source/utils/GUIApplicationManager.cpp b/Code/Tools/AssetBundler/source/utils/GUIApplicationManager.cpp index b17832526f..17e621f7d6 100644 --- a/Code/Tools/AssetBundler/source/utils/GUIApplicationManager.cpp +++ b/Code/Tools/AssetBundler/source/utils/GUIApplicationManager.cpp @@ -346,9 +346,7 @@ namespace AssetBundler } // Determine the enabled platforms - const char* appRoot = nullptr; - AzFramework::ApplicationRequests::Bus::BroadcastResult(appRoot, &AzFramework::ApplicationRequests::GetAppRoot); - m_enabledPlatforms = GetEnabledPlatformFlags(GetEngineRoot(), appRoot, AZ::Utils::GetProjectPath().c_str()); + m_enabledPlatforms = GetEnabledPlatformFlags(GetEngineRoot(), AZStd::string_view(AZ::Utils::GetProjectPath())); // Determine which Gems are enabled for the current project if (!AzFramework::GetGemsInfo(m_gemInfoList, *m_settingsRegistry)) diff --git a/Code/Tools/AssetBundler/source/utils/applicationManager.cpp b/Code/Tools/AssetBundler/source/utils/applicationManager.cpp index 0388570fdd..2df9e64ac5 100644 --- a/Code/Tools/AssetBundler/source/utils/applicationManager.cpp +++ b/Code/Tools/AssetBundler/source/utils/applicationManager.cpp @@ -1401,7 +1401,6 @@ namespace AssetBundler // If no platform was specified, defaulting to platforms specified in the asset processor config files AzFramework::PlatformFlags platformFlags = GetEnabledPlatformFlags( - AZStd::string_view{ AZ::Utils::GetEnginePath() }, AZStd::string_view{ AZ::Utils::GetEnginePath() }, AZStd::string_view{ AZ::Utils::GetProjectPath() }); [[maybe_unused]] auto platformsString = AzFramework::PlatformHelper::GetCommaSeparatedPlatformList(platformFlags); diff --git a/Code/Tools/AssetBundler/source/utils/utils.cpp b/Code/Tools/AssetBundler/source/utils/utils.cpp index 6daf3c571b..7e56f5450e 100644 --- a/Code/Tools/AssetBundler/source/utils/utils.cpp +++ b/Code/Tools/AssetBundler/source/utils/utils.cpp @@ -377,7 +377,6 @@ namespace AssetBundler AzFramework::PlatformFlags GetEnabledPlatformFlags( AZStd::string_view engineRoot, - AZStd::string_view assetRoot, AZStd::string_view projectPath) { auto settingsRegistry = AZ::SettingsRegistry::Get(); @@ -387,7 +386,7 @@ namespace AssetBundler return AzFramework::PlatformFlags::Platform_NONE; } - auto configFiles = AzToolsFramework::AssetUtils::GetConfigFiles(engineRoot, assetRoot, projectPath, true, true, settingsRegistry); + auto configFiles = AzToolsFramework::AssetUtils::GetConfigFiles(engineRoot, projectPath, true, true, settingsRegistry); auto enabledPlatformList = AzToolsFramework::AssetUtils::GetEnabledPlatforms(*settingsRegistry, configFiles); AzFramework::PlatformFlags platformFlags = AzFramework::PlatformFlags::Platform_NONE; for (const auto& enabledPlatform : enabledPlatformList) diff --git a/Code/Tools/AssetBundler/source/utils/utils.h b/Code/Tools/AssetBundler/source/utils/utils.h index bfdf252014..0986d70ca8 100644 --- a/Code/Tools/AssetBundler/source/utils/utils.h +++ b/Code/Tools/AssetBundler/source/utils/utils.h @@ -221,7 +221,6 @@ namespace AssetBundler //! Please note that the game project could be in a different location to the engine therefore we need the assetRoot param. AzFramework::PlatformFlags GetEnabledPlatformFlags( AZStd::string_view enginePath, - AZStd::string_view assetRoot, AZStd::string_view projectPath); QJsonObject ReadJson(const AZStd::string& filePath); diff --git a/Code/Tools/AssetBundler/tests/UtilsTests.cpp b/Code/Tools/AssetBundler/tests/UtilsTests.cpp index 560d399613..60fc79579b 100644 --- a/Code/Tools/AssetBundler/tests/UtilsTests.cpp +++ b/Code/Tools/AssetBundler/tests/UtilsTests.cpp @@ -67,7 +67,7 @@ namespace AssetBundler void NormalizePathKeepCase(AZStd::string& /*path*/) override {} void CalculateBranchTokenForEngineRoot(AZStd::string& /*token*/) const override {} - const char* GetEngineRoot() const override + const char* GetTempDir() const { return m_tempDir->GetDirectory(); } @@ -83,7 +83,7 @@ namespace AssetBundler TEST_F(MockUtilsTest, DISABLED_TestFilePath_StartsWithAFileSeparator_Valid) { AZ::IO::Path relFilePath = "Foo/foo.xml"; - AZ::IO::Path absoluteFilePath = AZ::IO::PathView(GetEngineRoot()).RootPath(); + AZ::IO::Path absoluteFilePath = AZ::IO::PathView(GetTempDir()).RootPath(); absoluteFilePath /= relFilePath; absoluteFilePath = absoluteFilePath.LexicallyNormal(); @@ -95,7 +95,7 @@ namespace AssetBundler TEST_F(MockUtilsTest, TestFilePath_RelativePath_Valid) { AZ::IO::Path relFilePath = "Foo\\foo.xml"; - AZ::IO::Path absoluteFilePath = (AZ::IO::Path(GetEngineRoot()) / relFilePath).LexicallyNormal(); + AZ::IO::Path absoluteFilePath = (AZ::IO::Path(GetTempDir()) / relFilePath).LexicallyNormal(); FilePath filePath(relFilePath.Native()); EXPECT_EQ(AZ::IO::PathView{ filePath.AbsolutePath() }, absoluteFilePath); } @@ -107,8 +107,8 @@ namespace AssetBundler AZ::IO::Path relFilePath = "Foo\\Foo.xml"; AZ::IO::Path wrongCaseRelFilePath = "Foo\\foo.xml"; - AZ::IO::Path correctAbsoluteFilePath = (AZ::IO::Path(GetEngineRoot()) / relFilePath).LexicallyNormal(); - AZ::IO::Path wrongCaseAbsoluteFilePath = (AZ::IO::Path(GetEngineRoot()) / wrongCaseRelFilePath).LexicallyNormal(); + AZ::IO::Path correctAbsoluteFilePath = (AZ::IO::Path(GetTempDir()) / relFilePath).LexicallyNormal(); + AZ::IO::Path wrongCaseAbsoluteFilePath = (AZ::IO::Path(GetTempDir()) / wrongCaseRelFilePath).LexicallyNormal(); AZ::IO::HandleType fileHandle = AZ::IO::InvalidHandle; AZ::IO::FileIOBase::GetInstance()->Open(correctAbsoluteFilePath.c_str(), AZ::IO::OpenMode::ModeWrite | AZ::IO::OpenMode::ModeCreatePath, fileHandle); @@ -121,7 +121,7 @@ namespace AssetBundler TEST_F(MockUtilsTest, TestFilePath_NoFileExists_NoError_valid) { AZ::IO::Path relFilePath = "Foo\\Foo.xml"; - AZ::IO::Path absoluteFilePath = (AZ::IO::Path(GetEngineRoot()) / relFilePath).LexicallyNormal(); + AZ::IO::Path absoluteFilePath = (AZ::IO::Path(GetTempDir()) / relFilePath).LexicallyNormal(); FilePath filePath(absoluteFilePath.Native(), true, false); EXPECT_TRUE(filePath.IsValid()); @@ -132,8 +132,8 @@ namespace AssetBundler { AZStd::string relFilePath = "Foo\\Foo.xml"; AZStd::string wrongCaseRelFilePath = "Foo\\foo.xml"; - AZ::IO::Path correctAbsoluteFilePath = (AZ::IO::Path(GetEngineRoot()) / relFilePath).LexicallyNormal(); - AZ::IO::Path wrongCaseAbsoluteFilePath = (AZ::IO::Path(GetEngineRoot()) / wrongCaseRelFilePath).LexicallyNormal(); + AZ::IO::Path correctAbsoluteFilePath = (AZ::IO::Path(GetTempDir()) / relFilePath).LexicallyNormal(); + AZ::IO::Path wrongCaseAbsoluteFilePath = (AZ::IO::Path(GetTempDir()) / wrongCaseRelFilePath).LexicallyNormal(); AZ::IO::HandleType fileHandle = AZ::IO::InvalidHandle; AZ::IO::FileIOBase::GetInstance()->Open(correctAbsoluteFilePath.c_str(), AZ::IO::OpenMode::ModeWrite | AZ::IO::OpenMode::ModeCreatePath, fileHandle); diff --git a/Code/Tools/AssetBundler/tests/applicationManagerTests.cpp b/Code/Tools/AssetBundler/tests/applicationManagerTests.cpp index 07eae67a81..fd587195af 100644 --- a/Code/Tools/AssetBundler/tests/applicationManagerTests.cpp +++ b/Code/Tools/AssetBundler/tests/applicationManagerTests.cpp @@ -16,6 +16,7 @@ #include #include #include +#include #include #include @@ -84,10 +85,9 @@ namespace AssetBundler // in the unit tests. AZ::UserSettingsComponentRequestBus::Broadcast(&AZ::UserSettingsComponentRequests::DisableSaveOnFinalize); - const char* engineRoot = nullptr; - AzFramework::ApplicationRequests::Bus::BroadcastResult(engineRoot, &AzFramework::ApplicationRequests::GetEngineRoot); - ASSERT_TRUE(engineRoot) << "Unable to locate engine root.\n"; - AzFramework::StringFunc::Path::Join(engineRoot, RelativeTestFolder, m_data->m_testEngineRoot); + AZ::IO::FixedMaxPath engineRoot = AZ::Utils::GetEnginePath(); + ASSERT_TRUE(!engineRoot.empty()) << "Unable to locate engine root.\n"; + m_data->m_testEngineRoot = (engineRoot / RelativeTestFolder).String(); m_data->m_localFileIO = aznew AZ::IO::LocalFileIO(); m_data->m_priorFileIO = AZ::IO::FileIOBase::GetInstance(); @@ -150,7 +150,8 @@ namespace AssetBundler EXPECT_EQ(0, gemsNameMap.size()); - AzFramework::PlatformFlags platformFlags = GetEnabledPlatformFlags(m_data->m_testEngineRoot.c_str(), m_data->m_testEngineRoot.c_str(), DummyProjectName); + const auto testProjectPath = AZ::IO::Path(m_data->m_testEngineRoot) / DummyProjectName; + AzFramework::PlatformFlags platformFlags = GetEnabledPlatformFlags(m_data->m_testEngineRoot, testProjectPath.Native()); AzFramework::PlatformFlags hostPlatformFlag = AzFramework::PlatformHelper::GetPlatformFlag(AzToolsFramework::AssetSystem::GetHostAssetPlatform()); AzFramework::PlatformFlags expectedFlags = AzFramework::PlatformFlags::Platform_ANDROID | AzFramework::PlatformFlags::Platform_IOS | AzFramework::PlatformFlags::Platform_PROVO | hostPlatformFlag; ASSERT_EQ(platformFlags, expectedFlags); diff --git a/Code/Tools/AssetProcessor/native/tests/platformconfiguration/platformconfigurationtests.cpp b/Code/Tools/AssetProcessor/native/tests/platformconfiguration/platformconfigurationtests.cpp index 69397745f1..e519f48ce5 100644 --- a/Code/Tools/AssetProcessor/native/tests/platformconfiguration/platformconfigurationtests.cpp +++ b/Code/Tools/AssetProcessor/native/tests/platformconfiguration/platformconfigurationtests.cpp @@ -52,11 +52,12 @@ TEST_F(PlatformConfigurationUnitTests, TestFailReadConfigFile_BadPlatform) using namespace AssetProcessor; const auto testExeFolder = AZ::IO::FileIOBase::GetInstance()->ResolvePath(TestAppRoot); + const AZ::IO::FixedMaxPath projectPath = (*testExeFolder) / EmptyDummyProjectName; auto configRoot = AZ::IO::FileIOBase::GetInstance()->ResolvePath("@exefolder@/testdata/config_broken_badplatform"); ASSERT_TRUE(configRoot); UnitTestPlatformConfiguration config; m_absorber.Clear(); - ASSERT_FALSE(config.InitializeFromConfigFiles(configRoot->c_str(), testExeFolder->c_str(), EmptyDummyProjectName, false, false)); + ASSERT_FALSE(config.InitializeFromConfigFiles(configRoot->c_str(), testExeFolder->c_str(), projectPath.c_str(), false, false)); ASSERT_GT(m_absorber.m_numErrorsAbsorbed, 0); } @@ -67,11 +68,12 @@ TEST_F(PlatformConfigurationUnitTests, TestFailReadConfigFile_NoPlatform) using namespace AssetProcessor; const auto testExeFolder = AZ::IO::FileIOBase::GetInstance()->ResolvePath(TestAppRoot); + const AZ::IO::FixedMaxPath projectPath = (*testExeFolder) / EmptyDummyProjectName; auto configRoot = AZ::IO::FileIOBase::GetInstance()->ResolvePath("@exefolder@/testdata/config_broken_noplatform"); ASSERT_TRUE(configRoot); UnitTestPlatformConfiguration config; m_absorber.Clear(); - ASSERT_FALSE(config.InitializeFromConfigFiles(configRoot->c_str(), testExeFolder->c_str(), EmptyDummyProjectName, false, false)); + ASSERT_FALSE(config.InitializeFromConfigFiles(configRoot->c_str(), testExeFolder->c_str(), projectPath.c_str(), false, false)); ASSERT_GT(m_absorber.m_numErrorsAbsorbed, 0); } @@ -81,11 +83,12 @@ TEST_F(PlatformConfigurationUnitTests, TestFailReadConfigFile_NoScanFolders) using namespace AssetProcessor; const auto testExeFolder = AZ::IO::FileIOBase::GetInstance()->ResolvePath(TestAppRoot); + const AZ::IO::FixedMaxPath projectPath = (*testExeFolder) / EmptyDummyProjectName; auto configRoot = AZ::IO::FileIOBase::GetInstance()->ResolvePath("@exefolder@/testdata/config_broken_noscans"); ASSERT_TRUE(configRoot); UnitTestPlatformConfiguration config; m_absorber.Clear(); - ASSERT_FALSE(config.InitializeFromConfigFiles(configRoot->c_str(), testExeFolder->c_str(), EmptyDummyProjectName, false, false)); + ASSERT_FALSE(config.InitializeFromConfigFiles(configRoot->c_str(), testExeFolder->c_str(), projectPath.c_str(), false, false)); ASSERT_GT(m_absorber.m_numErrorsAbsorbed, 0); } @@ -95,11 +98,12 @@ TEST_F(PlatformConfigurationUnitTests, TestFailReadConfigFile_BrokenRecognizers) using namespace AssetProcessor; const auto testExeFolder = AZ::IO::FileIOBase::GetInstance()->ResolvePath(TestAppRoot); + const AZ::IO::FixedMaxPath projectPath = (*testExeFolder) / EmptyDummyProjectName; auto configRoot = AZ::IO::FileIOBase::GetInstance()->ResolvePath("@exefolder@/testdata/config_broken_recognizers"); ASSERT_TRUE(configRoot); UnitTestPlatformConfiguration config; m_absorber.Clear(); - ASSERT_FALSE(config.InitializeFromConfigFiles(configRoot->c_str(), testExeFolder->c_str(), EmptyDummyProjectName, false, false)); + ASSERT_FALSE(config.InitializeFromConfigFiles(configRoot->c_str(), testExeFolder->c_str(), projectPath.c_str(), false, false)); ASSERT_GT(m_absorber.m_numErrorsAbsorbed, 0); } @@ -109,11 +113,12 @@ TEST_F(PlatformConfigurationUnitTests, TestFailReadConfigFile_Regular_Platforms) using namespace AssetProcessor; const auto testExeFolder = AZ::IO::FileIOBase::GetInstance()->ResolvePath(TestAppRoot); + const AZ::IO::FixedMaxPath projectPath = (*testExeFolder) / EmptyDummyProjectName; auto configRoot = AZ::IO::FileIOBase::GetInstance()->ResolvePath("@exefolder@/testdata/config_regular"); ASSERT_TRUE(configRoot); UnitTestPlatformConfiguration config; m_absorber.Clear(); - ASSERT_TRUE(config.InitializeFromConfigFiles(configRoot->c_str(), testExeFolder->c_str(), EmptyDummyProjectName, false, false)); + ASSERT_TRUE(config.InitializeFromConfigFiles(configRoot->c_str(), testExeFolder->c_str(), projectPath.c_str(), false, false)); ASSERT_EQ(m_absorber.m_numErrorsAbsorbed, 0); // verify the data. @@ -322,12 +327,13 @@ TEST_F(PlatformConfigurationUnitTests, TestFailReadConfigFile_RegularScanfolder) using namespace AssetProcessor; const auto testExeFolder = AZ::IO::FileIOBase::GetInstance()->ResolvePath(TestAppRoot); + const AZ::IO::FixedMaxPath projectPath = (*testExeFolder) / EmptyDummyProjectName; auto configRoot = AZ::IO::FileIOBase::GetInstance()->ResolvePath("@exefolder@/testdata/config_regular"); ASSERT_TRUE(configRoot); UnitTestPlatformConfiguration config; m_absorber.Clear(); AssetUtilities::ComputeProjectName(EmptyDummyProjectName, true); - ASSERT_TRUE(config.InitializeFromConfigFiles(configRoot->c_str(), testExeFolder->c_str(), EmptyDummyProjectName, false, false)); + ASSERT_TRUE(config.InitializeFromConfigFiles(configRoot->c_str(), testExeFolder->c_str(), projectPath.c_str(), false, false)); ASSERT_EQ(m_absorber.m_numErrorsAbsorbed, 0); ASSERT_EQ(config.GetScanFolderCount(), 3); // the two, and then the one that has the same data as prior but different identifier. @@ -356,11 +362,12 @@ TEST_F(PlatformConfigurationUnitTests, TestFailReadConfigFile_RegularScanfolderP using namespace AssetProcessor; const auto testExeFolder = AZ::IO::FileIOBase::GetInstance()->ResolvePath(TestAppRoot); + const AZ::IO::FixedMaxPath projectPath = (*testExeFolder) / EmptyDummyProjectName; auto configRoot = AZ::IO::FileIOBase::GetInstance()->ResolvePath("@exefolder@/testdata/config_regular_platform_scanfolder"); ASSERT_TRUE(configRoot); UnitTestPlatformConfiguration config; m_absorber.Clear(); - ASSERT_TRUE(config.InitializeFromConfigFiles(configRoot->c_str(), testExeFolder->c_str(), EmptyDummyProjectName, false, false)); + ASSERT_TRUE(config.InitializeFromConfigFiles(configRoot->c_str(), testExeFolder->c_str(), projectPath.c_str(), false, false)); ASSERT_EQ(m_absorber.m_numErrorsAbsorbed, 0); ASSERT_EQ(config.GetScanFolderCount(), 5); @@ -402,11 +409,12 @@ TEST_F(PlatformConfigurationUnitTests, TestFailReadConfigFile_RegularExcludes) using namespace AssetProcessor; const auto testExeFolder = AZ::IO::FileIOBase::GetInstance()->ResolvePath(TestAppRoot); + const AZ::IO::FixedMaxPath projectPath = (*testExeFolder) / EmptyDummyProjectName; auto configRoot = AZ::IO::FileIOBase::GetInstance()->ResolvePath("@exefolder@/testdata/config_regular"); ASSERT_TRUE(configRoot); UnitTestPlatformConfiguration config; m_absorber.Clear(); - ASSERT_TRUE(config.InitializeFromConfigFiles(configRoot->c_str(), testExeFolder->c_str(), EmptyDummyProjectName, false, false)); + ASSERT_TRUE(config.InitializeFromConfigFiles(configRoot->c_str(), testExeFolder->c_str(), projectPath.c_str(), false, false)); ASSERT_EQ(m_absorber.m_numErrorsAbsorbed, 0); ASSERT_TRUE(config.IsFileExcluded("blahblah/$tmp_01.test")); @@ -427,11 +435,12 @@ TEST_F(PlatformConfigurationUnitTests, TestFailReadConfigFile_Recognizers) #endif const auto testExeFolder = AZ::IO::FileIOBase::GetInstance()->ResolvePath(TestAppRoot); + const AZ::IO::FixedMaxPath projectPath = (*testExeFolder) / EmptyDummyProjectName; auto configRoot = AZ::IO::FileIOBase::GetInstance()->ResolvePath("@exefolder@/testdata/config_regular"); ASSERT_TRUE(configRoot); UnitTestPlatformConfiguration config; m_absorber.Clear(); - ASSERT_TRUE(config.InitializeFromConfigFiles(configRoot->c_str(), testExeFolder->c_str(), EmptyDummyProjectName, false, false)); + ASSERT_TRUE(config.InitializeFromConfigFiles(configRoot->c_str(), testExeFolder->c_str(), projectPath.c_str(), false, false)); ASSERT_EQ(m_absorber.m_numErrorsAbsorbed, 0); const AssetProcessor::RecognizerContainer& recogs = config.GetAssetRecognizerContainer(); @@ -518,12 +527,13 @@ TEST_F(PlatformConfigurationUnitTests, TestFailReadConfigFile_Overrides) using namespace AzToolsFramework::AssetSystem; using namespace AssetProcessor; const auto testExeFolder = AZ::IO::FileIOBase::GetInstance()->ResolvePath(TestAppRoot); + const AZ::IO::FixedMaxPath projectPath = (*testExeFolder) / DummyProjectName; auto configRoot = AZ::IO::FileIOBase::GetInstance()->ResolvePath("@exefolder@/testdata/config_regular"); ASSERT_TRUE(configRoot); UnitTestPlatformConfiguration config; m_absorber.Clear(); - ASSERT_TRUE(config.InitializeFromConfigFiles(configRoot->c_str(), testExeFolder->c_str(), DummyProjectName, false, false)); + ASSERT_TRUE(config.InitializeFromConfigFiles(configRoot->c_str(), testExeFolder->c_str(), projectPath.c_str(), false, false)); ASSERT_EQ(m_absorber.m_numErrorsAbsorbed, 0); const AssetProcessor::RecognizerContainer& recogs = config.GetAssetRecognizerContainer(); @@ -625,11 +635,12 @@ TEST_F(PlatformConfigurationUnitTests, ReadCheckServer_FromConfig_Valid) using namespace AssetProcessor; const auto testExeFolder = AZ::IO::FileIOBase::GetInstance()->ResolvePath(TestAppRoot); + const AZ::IO::FixedMaxPath projectPath = (*testExeFolder) / EmptyDummyProjectName; auto configRoot = AZ::IO::FileIOBase::GetInstance()->ResolvePath("@exefolder@/testdata/config_regular"); ASSERT_TRUE(configRoot); UnitTestPlatformConfiguration config; m_absorber.Clear(); - ASSERT_TRUE(config.InitializeFromConfigFiles(configRoot->c_str(), testExeFolder->c_str(), EmptyDummyProjectName, false, false)); + ASSERT_TRUE(config.InitializeFromConfigFiles(configRoot->c_str(), testExeFolder->c_str(), projectPath.c_str(), false, false)); ASSERT_EQ(m_absorber.m_numErrorsAbsorbed, 0); const AssetProcessor::RecognizerContainer& recogs = config.GetAssetRecognizerContainer(); @@ -674,11 +685,12 @@ TEST_F(PlatformConfigurationUnitTests, Test_MetaFileTypes_AssetImporterExtension using namespace AssetProcessor; const auto testExeFolder = AZ::IO::FileIOBase::GetInstance()->ResolvePath(TestAppRoot); + const AZ::IO::FixedMaxPath projectPath = (*testExeFolder) / EmptyDummyProjectName; auto configRoot = AZ::IO::FileIOBase::GetInstance()->ResolvePath("@exefolder@/testdata/config_metadata"); ASSERT_TRUE(configRoot); UnitTestPlatformConfiguration config; m_absorber.Clear(); - ASSERT_FALSE(config.InitializeFromConfigFiles(configRoot->c_str(), testExeFolder->c_str(), EmptyDummyProjectName, false, false)); + ASSERT_FALSE(config.InitializeFromConfigFiles(configRoot->c_str(), testExeFolder->c_str(), projectPath.c_str(), false, false)); ASSERT_GT(m_absorber.m_numErrorsAbsorbed, 0); ASSERT_TRUE(config.MetaDataFileTypesCount() == 2); diff --git a/Code/Tools/AssetProcessor/native/utilities/PlatformConfiguration.cpp b/Code/Tools/AssetProcessor/native/utilities/PlatformConfiguration.cpp index 9a60bf3110..483d5a46aa 100644 --- a/Code/Tools/AssetProcessor/native/utilities/PlatformConfiguration.cpp +++ b/Code/Tools/AssetProcessor/native/utilities/PlatformConfiguration.cpp @@ -749,7 +749,7 @@ namespace AssetProcessor } AZStd::vector configFiles = AzToolsFramework::AssetUtils::GetConfigFiles(absoluteSystemRoot.toUtf8().constData(), - absoluteAssetRoot.toUtf8().constData(), projectPath.toUtf8().constData(), + projectPath.toUtf8().constData(), addPlatformConfigs, addGemsConfigs && !noGemScanFolders, settingsRegistry); // First Merge all Engine, Gem and Project specific AssetProcessor*Config.setreg/.inifiles diff --git a/Code/Tools/PythonBindingsExample/source/Application.cpp b/Code/Tools/PythonBindingsExample/source/Application.cpp index ab1d1b5acf..cfb28d8e09 100644 --- a/Code/Tools/PythonBindingsExample/source/Application.cpp +++ b/Code/Tools/PythonBindingsExample/source/Application.cpp @@ -39,7 +39,6 @@ namespace PythonBindingsExample AzToolsFramework::EditorPythonConsoleNotificationBus::Handler::BusConnect(); // prepare the Python binding gem(s) - CalculateExecutablePath(); Start(Descriptor()); AZ::SerializeContext* context; diff --git a/Code/Tools/SceneAPI/SceneCore/Tests/Containers/SceneBehaviorTests.cpp b/Code/Tools/SceneAPI/SceneCore/Tests/Containers/SceneBehaviorTests.cpp index 3bf75e2d9b..0478e6cdb2 100644 --- a/Code/Tools/SceneAPI/SceneCore/Tests/Containers/SceneBehaviorTests.cpp +++ b/Code/Tools/SceneAPI/SceneCore/Tests/Containers/SceneBehaviorTests.cpp @@ -368,7 +368,6 @@ namespace AZ::SceneAPI::Containers MOCK_METHOD0(GetSerializeContext, AZ::SerializeContext* ()); MOCK_METHOD0(GetJsonRegistrationContext, AZ::JsonRegistrationContext* ()); MOCK_METHOD0(GetBehaviorContext, AZ::BehaviorContext* ()); - MOCK_CONST_METHOD0(GetAppRoot, const char*()); MOCK_CONST_METHOD0(GetEngineRoot, const char*()); MOCK_CONST_METHOD0(GetExecutableFolder, const char* ()); MOCK_CONST_METHOD1(QueryApplicationType, void(AZ::ApplicationTypeQuery&)); diff --git a/Code/Tools/SerializeContextTools/Converter.cpp b/Code/Tools/SerializeContextTools/Converter.cpp index 6a8bebdbfc..294bf941ac 100644 --- a/Code/Tools/SerializeContextTools/Converter.cpp +++ b/Code/Tools/SerializeContextTools/Converter.cpp @@ -202,8 +202,6 @@ namespace AZ bool skipSystem = commandLine->HasSwitch("skipsystem"); bool isDryRun = commandLine->HasSwitch("dryrun"); - const char* appRoot = const_cast(application).GetAppRoot(); - PathDocumentContainer documents; bool result = true; const AZStd::string& filePath = application.GetConfigFilePath(); @@ -230,7 +228,7 @@ namespace AZ } auto callback = - [&result, skipGems, skipSystem, &configurationName, sourceGameFolder, &appRoot, &documents, &convertSettings, &verifySettings] + [&result, skipGems, skipSystem, &configurationName, sourceGameFolder, &documents, &convertSettings, &verifySettings] (void* classPtr, const Uuid& classId, SerializeContext* context) { if (classId == azrtti_typeid()) @@ -238,7 +236,7 @@ namespace AZ if (!skipSystem) { result = ConvertSystemSettings(documents, *reinterpret_cast(classPtr), - configurationName, sourceGameFolder, appRoot) && result; + configurationName, sourceGameFolder) && result; } // Cleanup the Serialized Element to allow any classes within the element's hierarchy to delete @@ -443,7 +441,7 @@ namespace AZ } bool Converter::ConvertSystemSettings(PathDocumentContainer& documents, const ComponentApplication::Descriptor& descriptor, - const AZStd::string& configurationName, const AZ::IO::PathView& projectFolder, [[maybe_unused]] const AZStd::string& applicationRoot) + const AZStd::string& configurationName, const AZ::IO::PathView& projectFolder) { AZ::IO::FixedMaxPath memoryFilePath{ projectFolder }; memoryFilePath /= "Registry"; diff --git a/Code/Tools/SerializeContextTools/Converter.h b/Code/Tools/SerializeContextTools/Converter.h index 6c8f6c70fb..7d30ca2a3a 100644 --- a/Code/Tools/SerializeContextTools/Converter.h +++ b/Code/Tools/SerializeContextTools/Converter.h @@ -43,7 +43,7 @@ namespace AZ using PathDocumentContainer = AZStd::vector; static bool ConvertSystemSettings(PathDocumentContainer& documents, const ComponentApplication::Descriptor& descriptor, - const AZStd::string& configurationName, const AZ::IO::PathView& projectFolder, const AZStd::string& applicationRoot); + const AZStd::string& configurationName, const AZ::IO::PathView& projectFolder); static bool ConvertSystemComponents(PathDocumentContainer& documents, const Entity& entity, const AZStd::string& configurationName, const AZ::IO::PathView& projectFolder, const JsonSerializerSettings& convertSettings, const JsonDeserializerSettings& verifySettings); diff --git a/Gems/AWSClientAuth/Code/Tests/AWSClientAuthGemMock.h b/Gems/AWSClientAuth/Code/Tests/AWSClientAuthGemMock.h index 1d2e8bad42..19314035c4 100644 --- a/Gems/AWSClientAuth/Code/Tests/AWSClientAuthGemMock.h +++ b/Gems/AWSClientAuth/Code/Tests/AWSClientAuthGemMock.h @@ -608,7 +608,6 @@ namespace AWSClientAuthUnitTest AZ::Entity* FindEntity(const AZ::EntityId&) override { return nullptr; } AZ::BehaviorContext* GetBehaviorContext() override { return nullptr; } const char* GetExecutableFolder() const override { return nullptr; } - const char* GetAppRoot() const override { return nullptr; } const char* GetEngineRoot() const override { return nullptr; } void EnumerateEntities(const EntityCallback& /*callback*/) override {} void QueryApplicationType(AZ::ApplicationTypeQuery& /*appType*/) const override {} diff --git a/Gems/AssetValidation/Code/Source/AssetValidationSystemComponent.cpp b/Gems/AssetValidation/Code/Source/AssetValidationSystemComponent.cpp index 56f28856af..8f8fb48212 100644 --- a/Gems/AssetValidation/Code/Source/AssetValidationSystemComponent.cpp +++ b/Gems/AssetValidation/Code/Source/AssetValidationSystemComponent.cpp @@ -439,13 +439,6 @@ namespace AssetValidation bool GetDefaultSeedListFiles(AZStd::vector& defaultSeedListFiles) { - const char* engineRoot = nullptr; - AzFramework::ApplicationRequests::Bus::BroadcastResult(engineRoot, &AzFramework::ApplicationRequests::GetEngineRoot); - - const char* appRoot = nullptr; - AzFramework::ApplicationRequests::Bus::BroadcastResult(appRoot, &AzFramework::ApplicationRequests::GetAppRoot); - - auto settingsRegistry = AZ::SettingsRegistry::Get(); AZ::SettingsRegistryInterface::FixedValueString gameFolder; auto projectKey = AZ::SettingsRegistryInterface::FixedValueString::format("%s/project_path", AZ::SettingsRegistryMergeUtils::BootstrapSettingsRootKey); @@ -509,30 +502,28 @@ namespace AssetValidation AZ::Outcome AssetValidationSystemComponent::LoadSeedList(const char* seedPath, AZStd::string& seedListPath) { - AZStd::string absoluteSeedPath = seedPath; + AZ::IO::Path absoluteSeedPath = seedPath; if (AZ::StringFunc::Path::IsRelative(seedPath)) { - const char* appRoot = nullptr; - AzFramework::ApplicationRequests::Bus::BroadcastResult(appRoot, &AzFramework::ApplicationRequests::GetEngineRoot); + AZ::IO::FixedMaxPath engineRoot = AZ::Utils::GetEnginePath(); - if (!appRoot) + if (engineRoot.empty()) { return AZ::Failure(AZStd::string("Couldn't get engine root")); } - absoluteSeedPath = AZStd::string::format("%s/%s", appRoot, seedPath); + absoluteSeedPath = (engineRoot / seedPath).String(); } - AzFramework::StringFunc::Path::Normalize(absoluteSeedPath); AzFramework::AssetSeedList seedList; - if (!AZ::Utils::LoadObjectFromFileInPlace(absoluteSeedPath, seedList)) + if (!AZ::Utils::LoadObjectFromFileInPlace(absoluteSeedPath.Native(), seedList)) { return AZ::Failure(AZStd::string::format("Failed to load seed list %s", absoluteSeedPath.c_str())); } - seedListPath = absoluteSeedPath; + seedListPath = AZStd::move(absoluteSeedPath.Native()); return AZ::Success(seedList); } diff --git a/Gems/AssetValidation/Code/Tests/AssetValidationTestShared.h b/Gems/AssetValidation/Code/Tests/AssetValidationTestShared.h index c4872ab425..8da3ae1b34 100644 --- a/Gems/AssetValidation/Code/Tests/AssetValidationTestShared.h +++ b/Gems/AssetValidation/Code/Tests/AssetValidationTestShared.h @@ -150,13 +150,13 @@ struct AssetValidationTest auto projectPathKey = AZ::SettingsRegistryInterface::FixedValueString(AZ::SettingsRegistryMergeUtils::BootstrapSettingsRootKey) + "/project_path"; - m_registry.Set(projectPathKey, (AZ::IO::FixedMaxPath(GetEngineRoot()) / "AutomatedTesting").Native()); + m_registry.Set(projectPathKey, (AZ::IO::FixedMaxPath(m_tempDir.GetDirectory()) / "AutomatedTesting").Native()); AZ::SettingsRegistryMergeUtils::MergeSettingsToRegistry_AddRuntimeFilePaths(m_registry); // Set the engine root to the temporary directory and re-update the runtime file paths auto enginePathKey = AZ::SettingsRegistryInterface::FixedValueString(AZ::SettingsRegistryMergeUtils::BootstrapSettingsRootKey) + "/engine_path"; - m_registry.Set(enginePathKey, GetEngineRoot()); + m_registry.Set(enginePathKey, m_tempDir.GetDirectory()); AZ::SettingsRegistryMergeUtils::MergeSettingsToRegistry_AddRuntimeFilePaths(m_registry); } } @@ -176,11 +176,6 @@ struct AssetValidationTest AZ_Assert(false, "Not implemented"); } - const char* GetEngineRoot() const override - { - return m_tempDir.GetDirectory(); - } - void SetUp() override { using namespace ::testing; diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Code/Tests/ImageProcessing_Test.cpp b/Gems/Atom/Asset/ImageProcessingAtom/Code/Tests/ImageProcessing_Test.cpp index d5b795a1fa..d0029ffc86 100644 --- a/Gems/Atom/Asset/ImageProcessingAtom/Code/Tests/ImageProcessing_Test.cpp +++ b/Gems/Atom/Asset/ImageProcessingAtom/Code/Tests/ImageProcessing_Test.cpp @@ -111,7 +111,6 @@ namespace UnitTest AZ::SerializeContext* GetSerializeContext() override { return m_context.get(); } AZ::BehaviorContext* GetBehaviorContext() override { return nullptr; } AZ::JsonRegistrationContext* GetJsonRegistrationContext() override { return m_jsonRegistrationContext.get(); } - const char* GetAppRoot() const override { return nullptr; } const char* GetEngineRoot() const override { return nullptr; } const char* GetExecutableFolder() const override { return nullptr; } void EnumerateEntities(const AZ::ComponentApplicationRequests::EntityCallback& /*callback*/) override {} diff --git a/Gems/Atom/Feature/Common/Code/Source/LuxCore/LuxCoreRenderer.cpp b/Gems/Atom/Feature/Common/Code/Source/LuxCore/LuxCoreRenderer.cpp index c753079d5b..ef3f33d1c3 100644 --- a/Gems/Atom/Feature/Common/Code/Source/LuxCore/LuxCoreRenderer.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/LuxCore/LuxCoreRenderer.cpp @@ -13,6 +13,7 @@ #include #include #include +#include #include #include @@ -295,14 +296,12 @@ namespace AZ } // Run luxcoreui.exe - AZStd::string luxCoreExeFullPath; - AzFramework::ApplicationRequests::Bus::BroadcastResult(luxCoreExeFullPath, &AzFramework::ApplicationRequests::GetAppRoot); - luxCoreExeFullPath = luxCoreExeFullPath + AZ_TRAIT_LUXCORE_EXEPATH; - AzFramework::StringFunc::Path::Normalize(luxCoreExeFullPath); + AZ::IO::FixedMaxPath luxCoreExeFullPath = AZ::Utils::GetEnginePath(); + luxCoreExeFullPath /= AZ_TRAIT_LUXCORE_EXEPATH; AZStd::string commandLine = "-o " + AZStd::string(resolvedPath) + "/render.cfg"; - LuxCoreUI::LaunchLuxCoreUI(luxCoreExeFullPath, commandLine); + LuxCoreUI::LaunchLuxCoreUI(luxCoreExeFullPath.String(), commandLine); } } } diff --git a/Gems/Atom/RPI/Code/Tests.Builders/BuilderTestFixture.h b/Gems/Atom/RPI/Code/Tests.Builders/BuilderTestFixture.h index 31c1bc6715..02e69e732c 100644 --- a/Gems/Atom/RPI/Code/Tests.Builders/BuilderTestFixture.h +++ b/Gems/Atom/RPI/Code/Tests.Builders/BuilderTestFixture.h @@ -46,7 +46,6 @@ namespace UnitTest bool DeleteEntity(const AZ::EntityId&) override { return false; } AZ::Entity* FindEntity(const AZ::EntityId&) override { return nullptr; } AZ::BehaviorContext* GetBehaviorContext() override { return nullptr; } - const char* GetAppRoot() const override { return nullptr; } const char* GetEngineRoot() const override { return nullptr; } const char* GetExecutableFolder() const override { return nullptr; } void EnumerateEntities(const EntityCallback& /*callback*/) override {} diff --git a/Gems/Atom/RPI/Code/Tests/Common/AssetManagerTestFixture.h b/Gems/Atom/RPI/Code/Tests/Common/AssetManagerTestFixture.h index ee3ad94d4f..fb88e62617 100644 --- a/Gems/Atom/RPI/Code/Tests/Common/AssetManagerTestFixture.h +++ b/Gems/Atom/RPI/Code/Tests/Common/AssetManagerTestFixture.h @@ -44,7 +44,6 @@ namespace UnitTest AZ::Entity* FindEntity(const AZ::EntityId&) override { return nullptr; } AZ::BehaviorContext* GetBehaviorContext() override { return nullptr; } AZ::JsonRegistrationContext* GetJsonRegistrationContext() override { return nullptr; } - const char* GetAppRoot() const override { return nullptr; } const char* GetEngineRoot() const override { return nullptr; } const char* GetExecutableFolder() const override { return nullptr; } void EnumerateEntities(const EntityCallback& /*callback*/) override {} diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Util/Util.cpp b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Util/Util.cpp index be112345a9..d3bce34af3 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Util/Util.cpp +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Util/Util.cpp @@ -133,29 +133,12 @@ namespace AtomToolsFramework bool LaunchTool(const QString& baseName, const QString& extension, const QStringList& arguments) { - const char* engineRoot = nullptr; - AzFramework::ApplicationRequests::Bus::BroadcastResult(engineRoot, &AzFramework::ApplicationRequests::GetEngineRoot); - AZ_Assert(engineRoot != nullptr, "AzFramework::ApplicationRequests::GetEngineRoot failed"); + AZ::IO::FixedMaxPath engineRoot = AZ::Utils::GetEnginePath(); + AZ_Assert(!engineRoot.empty(), "Cannot query Engine Path"); - char binFolderName[AZ_MAX_PATH_LEN] = {}; - AZ::Utils::GetExecutablePathReturnType ret = AZ::Utils::GetExecutablePath(binFolderName, AZ_MAX_PATH_LEN); + AZ::IO::FixedMaxPath launchPath = AZ::IO::FixedMaxPath(AZ::Utils::GetExecutableDirectory()) + / (baseName + extension).toUtf8().constData(); - // If it contains the filename, zero out the last path separator character... - if (ret.m_pathIncludesFilename) - { - char* lastSlash = strrchr(binFolderName, AZ_CORRECT_FILESYSTEM_SEPARATOR); - if (lastSlash) - { - *lastSlash = '\0'; - } - } - - const QString path = QString("%1%2%3%4") - .arg(binFolderName) - .arg(AZ_CORRECT_FILESYSTEM_SEPARATOR_STRING) - .arg(baseName) - .arg(extension); - - return QProcess::startDetached(path, arguments, engineRoot); + return QProcess::startDetached(launchPath.c_str(), arguments, engineRoot.c_str()); } } diff --git a/Gems/Atom/Utils/Code/Include/Atom/Utils/ImGuiPassTree.inl b/Gems/Atom/Utils/Code/Include/Atom/Utils/ImGuiPassTree.inl index 55e457926a..5a8aaf7ded 100644 --- a/Gems/Atom/Utils/Code/Include/Atom/Utils/ImGuiPassTree.inl +++ b/Gems/Atom/Utils/Code/Include/Atom/Utils/ImGuiPassTree.inl @@ -19,11 +19,11 @@ #include -#include #include #include #include +#include #ifndef SCRIPTABLE_IMGUI #define Scriptable_ImGui ImGui @@ -334,11 +334,10 @@ namespace AZ::Render if (m_engineRoot.empty()) { - const char* engineRoot = nullptr; - AzFramework::ApplicationRequests::Bus::BroadcastResult(engineRoot, &AzFramework::ApplicationRequests::GetEngineRoot); - if (engineRoot) + AZ::IO::FixedMaxPathString engineRoot = AZ::Utils::GetEnginePath(); + if (!engineRoot.empty()) { - m_engineRoot = AZStd::string(engineRoot); + m_engineRoot = AZStd::string_view(engineRoot); } } diff --git a/Gems/AudioSystem/Code/Source/Editor/ImplementationManager.cpp b/Gems/AudioSystem/Code/Source/Editor/ImplementationManager.cpp index bee5c1dd51..f339ff8bb3 100644 --- a/Gems/AudioSystem/Code/Source/Editor/ImplementationManager.cpp +++ b/Gems/AudioSystem/Code/Source/Editor/ImplementationManager.cpp @@ -9,8 +9,6 @@ #include -#include - #include #include #include @@ -32,10 +30,6 @@ bool CImplementationManager::LoadImplementation() // release the loaded implementation (if any) Release(); - const char* engineRoot = nullptr; - AzFramework::ApplicationRequests::Bus::BroadcastResult(engineRoot, &AzFramework::ApplicationRequests::GetEngineRoot); - AZ_Assert(engineRoot != nullptr, "Unable to communicate with AzFramework::ApplicationRequests::Bus"); - AudioControlsEditor::EditorImplPluginEventBus::Broadcast(&AudioControlsEditor::EditorImplPluginEventBus::Events::InitializeEditorImplPlugin); } else diff --git a/Gems/EditorPythonBindings/Code/Source/PythonSystemComponent.cpp b/Gems/EditorPythonBindings/Code/Source/PythonSystemComponent.cpp index 876ef19803..fe9156013f 100644 --- a/Gems/EditorPythonBindings/Code/Source/PythonSystemComponent.cpp +++ b/Gems/EditorPythonBindings/Code/Source/PythonSystemComponent.cpp @@ -597,11 +597,10 @@ namespace EditorPythonBindings { AZStd::unordered_set pyPackageSites(pythonPathStack.begin(), pythonPathStack.end()); - const char* engineRoot = nullptr; - AzFramework::ApplicationRequests::Bus::BroadcastResult(engineRoot, &AzFramework::ApplicationRequests::GetEngineRoot); + AZ::IO::FixedMaxPath engineRoot = AZ::Utils::GetEnginePath(); // set PYTHON_HOME - AZStd::string pyBasePath = Platform::GetPythonHomePath(PY_PACKAGE, engineRoot); + AZStd::string pyBasePath = Platform::GetPythonHomePath(PY_PACKAGE, engineRoot.c_str()); if (!AZ::IO::SystemFile::Exists(pyBasePath.c_str())) { AZ_Warning("python", false, "Python home path must exist! path:%s", pyBasePath.c_str()); diff --git a/Gems/EditorPythonBindings/Code/Tests/PythonTestingUtility.h b/Gems/EditorPythonBindings/Code/Tests/PythonTestingUtility.h index 143863b4c8..e2b3d1eadd 100644 --- a/Gems/EditorPythonBindings/Code/Tests/PythonTestingUtility.h +++ b/Gems/EditorPythonBindings/Code/Tests/PythonTestingUtility.h @@ -135,10 +135,6 @@ namespace UnitTest void NormalizePath(AZStd::string& ) override {} void NormalizePathKeepCase(AZStd::string& ) override {} void CalculateBranchTokenForEngineRoot(AZStd::string& ) const override {} - // Gets the engine root path for testing - const char* GetEngineRoot() const override { return m_engineRoot.c_str(); } - // Retrieves the app root path for testing - const char* GetAppRoot() const override { return m_engineRoot.c_str(); } AZ::ComponentApplication m_app; AZStd::unique_ptr m_fileIOHelper; diff --git a/Gems/LmbrCentral/Code/Tests/Builders/SliceBuilderTests.cpp b/Gems/LmbrCentral/Code/Tests/Builders/SliceBuilderTests.cpp index 73ef7143c8..0965991dfa 100644 --- a/Gems/LmbrCentral/Code/Tests/Builders/SliceBuilderTests.cpp +++ b/Gems/LmbrCentral/Code/Tests/Builders/SliceBuilderTests.cpp @@ -311,7 +311,6 @@ namespace UnitTest SerializeContext* GetSerializeContext() override { return m_serializeContext; } BehaviorContext* GetBehaviorContext() override { return nullptr; } JsonRegistrationContext* GetJsonRegistrationContext() override { return nullptr; } - const char* GetAppRoot() const override { return nullptr; } const char* GetEngineRoot() const override { return nullptr; } const char* GetExecutableFolder() const override { return nullptr; } void EnumerateEntities(const EntityCallback& /*callback*/) override {} diff --git a/Gems/Multiplayer/Code/Tests/CommonBenchmarkSetup.h b/Gems/Multiplayer/Code/Tests/CommonBenchmarkSetup.h index 3c3d77e011..238e652b52 100644 --- a/Gems/Multiplayer/Code/Tests/CommonBenchmarkSetup.h +++ b/Gems/Multiplayer/Code/Tests/CommonBenchmarkSetup.h @@ -41,7 +41,6 @@ namespace Multiplayer AZ::SerializeContext* GetSerializeContext() override { return {}; } AZ::BehaviorContext* GetBehaviorContext() override { return {}; } AZ::JsonRegistrationContext* GetJsonRegistrationContext() override { return {}; } - const char* GetAppRoot() const override { return {}; } const char* GetEngineRoot() const override { return {}; } const char* GetExecutableFolder() const override { return {}; } void QueryApplicationType([[maybe_unused]] AZ::ApplicationTypeQuery& appType) const override {} diff --git a/Gems/Multiplayer/Code/Tests/MockInterfaces.h b/Gems/Multiplayer/Code/Tests/MockInterfaces.h index 8cebf280b9..8fd32bd79b 100644 --- a/Gems/Multiplayer/Code/Tests/MockInterfaces.h +++ b/Gems/Multiplayer/Code/Tests/MockInterfaces.h @@ -146,7 +146,6 @@ namespace UnitTest MOCK_METHOD0(GetSerializeContext, AZ::SerializeContext* ()); MOCK_METHOD0(GetBehaviorContext, AZ::BehaviorContext* ()); MOCK_METHOD0(GetJsonRegistrationContext, AZ::JsonRegistrationContext* ()); - MOCK_CONST_METHOD0(GetAppRoot, const char* ()); MOCK_CONST_METHOD0(GetEngineRoot, const char* ()); MOCK_CONST_METHOD0(GetExecutableFolder, const char* ()); MOCK_METHOD0(GetDrillerManager, AZ::Debug::DrillerManager* ()); diff --git a/Gems/PhysX/Code/Source/Debug/PhysXDebug.cpp b/Gems/PhysX/Code/Source/Debug/PhysXDebug.cpp index bc9265a92a..fb8e61289d 100644 --- a/Gems/PhysX/Code/Source/Debug/PhysXDebug.cpp +++ b/Gems/PhysX/Code/Source/Debug/PhysXDebug.cpp @@ -13,7 +13,7 @@ #include #include #include -#include +#include namespace PhysX { @@ -108,8 +108,7 @@ namespace PhysX AzFramework::StringFunc::Append(filename, m_config.m_pvdConfigurationData.m_fileName.c_str()); AzFramework::StringFunc::Append(filename, ".pxd2"); - AZStd::string rootDirectory; - AZ::ComponentApplicationBus::BroadcastResult(rootDirectory, &AZ::ComponentApplicationRequests::GetAppRoot); + AZStd::string rootDirectory{ AZStd::string_view(AZ::Utils::GetEnginePath()) }; // Create the full filepath. AZStd::string safeFilePath; diff --git a/Gems/ScriptCanvas/Code/Tests/ScriptCanvasBuilderTests.cpp b/Gems/ScriptCanvas/Code/Tests/ScriptCanvasBuilderTests.cpp index cba14feac6..33982bbcd7 100644 --- a/Gems/ScriptCanvas/Code/Tests/ScriptCanvasBuilderTests.cpp +++ b/Gems/ScriptCanvas/Code/Tests/ScriptCanvasBuilderTests.cpp @@ -89,7 +89,6 @@ protected: AZ::SerializeContext* GetSerializeContext() override { return m_serializeContext; } AZ::BehaviorContext* GetBehaviorContext() override { return nullptr; } AZ::JsonRegistrationContext* GetJsonRegistrationContext() override { return nullptr; } - const char* GetAppRoot() const override { return nullptr; } const char* GetEngineRoot() const override { return nullptr; } const char* GetExecutableFolder() const override { return nullptr; } void EnumerateEntities(const AZ::ComponentApplicationRequests::EntityCallback& /*callback*/) override {} diff --git a/Gems/ScriptCanvasTesting/Code/Source/Framework/ScriptCanvasTestFixture.h b/Gems/ScriptCanvasTesting/Code/Source/Framework/ScriptCanvasTestFixture.h index f45b74d4f1..6e38f71eec 100644 --- a/Gems/ScriptCanvasTesting/Code/Source/Framework/ScriptCanvasTestFixture.h +++ b/Gems/ScriptCanvasTesting/Code/Source/Framework/ScriptCanvasTestFixture.h @@ -91,14 +91,6 @@ namespace ScriptCanvasTests AZ::IO::FileIOBase* fileIO = AZ::IO::FileIOBase::GetInstance(); AZ_Assert(fileIO, "SC unit tests require filehandling"); - if (!fileIO->GetAlias("@engroot@")) - { - const char* engineRoot = nullptr; - AzFramework::ApplicationRequests::Bus::BroadcastResult(engineRoot, &AzFramework::ApplicationRequests::GetEngineRoot); - AZ_Assert(engineRoot, "null engine root"); - fileIO->SetAlias("@engroot@", engineRoot); - } - s_setupSucceeded = fileIO->GetAlias("@engroot@") != nullptr; AZ::TickBus::AllowFunctionQueuing(true); diff --git a/cmake/Projects.cmake b/cmake/Projects.cmake index 2c42533e35..13161c9e0f 100644 --- a/cmake/Projects.cmake +++ b/cmake/Projects.cmake @@ -183,7 +183,9 @@ if("${CMAKE_INSTALL_CONFIG_NAME}" MATCHES "^([Rr][Ee][Ll][Ee][Aa][Ss][Ee])$") cmake_path(GET gem_source_path_setreg FILENAME setreg_filename) list(APPEND artifacts_to_remove "${cache_product_path}/registry/${setreg_filename}") endforeach() - file(REMOVE ${artifacts_to_remove}) + if (artifacts_to_remove) + file(REMOVE ${artifacts_to_remove}) + endif() endif() ]=])