From 99ef2735b74196d62921563f430beee6a055032e Mon Sep 17 00:00:00 2001 From: AMZN-Phil Date: Tue, 2 Nov 2021 16:16:37 -0700 Subject: [PATCH 01/71] Create download UI once and update existing UI with progress Signed-off-by: AMZN-Phil --- .../Source/DownloadController.cpp | 8 +- .../Source/DownloadController.h | 6 +- .../GemCatalog/GemCatalogHeaderWidget.cpp | 199 +++++++++++------- .../GemCatalog/GemCatalogHeaderWidget.h | 10 + .../Source/GemCatalog/GemCatalogScreen.cpp | 5 +- 5 files changed, 148 insertions(+), 80 deletions(-) diff --git a/Code/Tools/ProjectManager/Source/DownloadController.cpp b/Code/Tools/ProjectManager/Source/DownloadController.cpp index 224b90299c..00a7db5318 100644 --- a/Code/Tools/ProjectManager/Source/DownloadController.cpp +++ b/Code/Tools/ProjectManager/Source/DownloadController.cpp @@ -41,6 +41,8 @@ namespace O3DE::ProjectManager void DownloadController::AddGemDownload(const QString& gemName) { m_gemNames.push_back(gemName); + emit GemDownloadAdded(gemName); + if (m_gemNames.size() == 1) { m_worker->SetGemToDownload(m_gemNames[0], false); @@ -62,6 +64,7 @@ namespace O3DE::ProjectManager else { m_gemNames.erase(findResult); + emit GemDownloadRemoved(gemName); } } } @@ -69,7 +72,7 @@ namespace O3DE::ProjectManager void DownloadController::UpdateUIProgress(int progress) { m_lastProgress = progress; - emit GemDownloadProgress(progress); + emit GemDownloadProgress(*m_gemNames.begin(), progress); } void DownloadController::HandleResults(const QString& result) @@ -82,8 +85,9 @@ namespace O3DE::ProjectManager succeeded = false; } + QString gemName = *m_gemNames.begin(); m_gemNames.erase(m_gemNames.begin()); - emit Done(succeeded); + emit Done(gemName, succeeded); if (!m_gemNames.empty()) { diff --git a/Code/Tools/ProjectManager/Source/DownloadController.h b/Code/Tools/ProjectManager/Source/DownloadController.h index 11ceaacddb..0bf0ae473c 100644 --- a/Code/Tools/ProjectManager/Source/DownloadController.h +++ b/Code/Tools/ProjectManager/Source/DownloadController.h @@ -58,8 +58,10 @@ namespace O3DE::ProjectManager signals: void StartGemDownload(const QString& gemName); - void Done(bool success = true); - void GemDownloadProgress(int percentage); + void Done(const QString& gemName, bool success = true); + void GemDownloadAdded(const QString& gemName); + void GemDownloadRemoved(const QString& gemName); + void GemDownloadProgress(const QString& gemName, int percentage); private: DownloadWorker* m_worker; diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogHeaderWidget.cpp b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogHeaderWidget.cpp index 5d65c740af..cfe69283ff 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogHeaderWidget.cpp +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogHeaderWidget.cpp @@ -30,6 +30,7 @@ namespace O3DE::ProjectManager m_layout->setMargin(5); m_layout->setAlignment(Qt::AlignTop); setLayout(m_layout); + setMinimumHeight(400); QHBoxLayout* hLayout = new QHBoxLayout(); @@ -119,6 +120,12 @@ namespace O3DE::ProjectManager setWindowFlags(Qt::FramelessWindowHint | Qt::Dialog); } + CartOverlayWidget::~CartOverlayWidget() + { + // disconnect from all download controller signals + disconnect(m_downloadController, nullptr, this, nullptr); + } + void CartOverlayWidget::CreateGemSection(const QString& singularTitle, const QString& pluralTitle, GetTagIndicesCallback getTagIndices) { QWidget* widget = new QWidget(); @@ -162,13 +169,13 @@ namespace O3DE::ProjectManager void CartOverlayWidget::CreateDownloadSection() { - QWidget* widget = new QWidget(); - widget->setFixedWidth(s_width); - m_layout->addWidget(widget); + m_downloadSectionWidget = new QWidget(); + m_downloadSectionWidget->setFixedWidth(s_width); + m_layout->addWidget(m_downloadSectionWidget); QVBoxLayout* layout = new QVBoxLayout(); layout->setAlignment(Qt::AlignTop); - widget->setLayout(layout); + m_downloadSectionWidget->setLayout(layout); QLabel* titleLabel = new QLabel(); titleLabel->setObjectName("GemCatalogCartOverlaySectionLabel"); @@ -187,82 +194,126 @@ namespace O3DE::ProjectManager QLabel* processingQueueLabel = new QLabel("Processing Queue"); gemDownloadLayout->addWidget(processingQueueLabel); - QWidget* downloadingItemWidget = new QWidget(); - downloadingItemWidget->setObjectName("GemCatalogCartOverlayGemDownloadBG"); - gemDownloadLayout->addWidget(downloadingItemWidget); + m_downloadingListWidget = new QWidget(); + m_downloadingListWidget->setObjectName("GemCatalogCartOverlayGemDownloadBG"); + gemDownloadLayout->addWidget(m_downloadingListWidget); QVBoxLayout* downloadingItemLayout = new QVBoxLayout(); downloadingItemLayout->setAlignment(Qt::AlignTop); - downloadingItemWidget->setLayout(downloadingItemLayout); + m_downloadingListWidget->setLayout(downloadingItemLayout); - auto update = [=](int downloadProgress) + QLabel* downloadsInProgessLabel = new QLabel(""); + downloadsInProgessLabel->setObjectName("NumDownloadsInProgressLabel"); + downloadingItemLayout->addWidget(downloadsInProgessLabel); + + if (m_downloadController->IsDownloadQueueEmpty()) { - if (m_downloadController->IsDownloadQueueEmpty()) - { - widget->hide(); - } - else - { - widget->setUpdatesEnabled(false); - // remove items - QLayoutItem* layoutItem = nullptr; - while ((layoutItem = downloadingItemLayout->takeAt(0)) != nullptr) - { - if (layoutItem->layout()) - { - // Gem info row - QLayoutItem* rowLayoutItem = nullptr; - while ((rowLayoutItem = layoutItem->layout()->takeAt(0)) != nullptr) - { - rowLayoutItem->widget()->deleteLater(); - } - layoutItem->layout()->deleteLater(); - } - if (layoutItem->widget()) - { - layoutItem->widget()->deleteLater(); - } - } - - // Setup gem download rows - const AZStd::vector& downloadQueue = m_downloadController->GetDownloadQueue(); - - QLabel* downloadsInProgessLabel = new QLabel(""); - downloadsInProgessLabel->setText( - QString("%1 %2").arg(downloadQueue.size()).arg(downloadQueue.size() == 1 ? tr("download in progress...") : tr("downloads in progress..."))); - downloadingItemLayout->addWidget(downloadsInProgessLabel); - - for (int downloadingGemNumber = 0; downloadingGemNumber < downloadQueue.size(); ++downloadingGemNumber) - { - QHBoxLayout* nameProgressLayout = new QHBoxLayout(); - TagWidget* newTag = new TagWidget(downloadQueue[downloadingGemNumber]); - 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])); - 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); - } - - widget->setUpdatesEnabled(true); - widget->show(); - } - }; - - auto downloadEnded = [=](bool /*success*/) + m_downloadSectionWidget->hide(); + } + else { - update(0); // update the list to remove the gem that has finished - }; + // Setup gem download rows for gems that are already in the queue + const AZStd::vector& downloadQueue = m_downloadController->GetDownloadQueue(); + + for (int downloadingGemNumber = 0; downloadingGemNumber < downloadQueue.size(); ++downloadingGemNumber) + { + GemDownloadAdded(downloadQueue[downloadingGemNumber]); + } + } + // connect to download controller data changed - connect(m_downloadController, &DownloadController::GemDownloadProgress, this, update); - connect(m_downloadController, &DownloadController::Done, this, downloadEnded); - update(0); + connect(m_downloadController, &DownloadController::GemDownloadAdded, this, &CartOverlayWidget::GemDownloadAdded); + connect(m_downloadController, &DownloadController::GemDownloadRemoved, this, &CartOverlayWidget::GemDownloadRemoved); + connect(m_downloadController, &DownloadController::GemDownloadProgress, this, &CartOverlayWidget::GemDownloadProgress); + connect(m_downloadController, &DownloadController::Done, this, &CartOverlayWidget::GemDownloadComplete); + } + + void CartOverlayWidget::GemDownloadAdded(const QString& gemName) + { + QWidget* newGemDownloadWidget = new QWidget(); + newGemDownloadWidget->setObjectName(gemName); + QVBoxLayout* downloadingGemLayout = new QVBoxLayout(); + newGemDownloadWidget->setLayout(downloadingGemLayout); + QHBoxLayout* nameProgressLayout = new QHBoxLayout(); + TagWidget* newTag = new TagWidget(gemName); + nameProgressLayout->addWidget(newTag); + QLabel* progress = new QLabel(tr("Queued")); + progress->setObjectName("DownloadProgressLabel"); + nameProgressLayout->addWidget(progress); + QSpacerItem* spacer = new QSpacerItem(0, 0, QSizePolicy::Expanding, QSizePolicy::Minimum); + nameProgressLayout->addSpacerItem(spacer); + QLabel* cancelText = new QLabel(QString("Cancel").arg(gemName)); + cancelText->setTextInteractionFlags(Qt::LinksAccessibleByMouse); + connect(cancelText, &QLabel::linkActivated, this, &CartOverlayWidget::OnCancelDownloadActivated); + nameProgressLayout->addWidget(cancelText); + downloadingGemLayout->addLayout(nameProgressLayout); + QProgressBar* downloadProgessBar = new QProgressBar(); + downloadProgessBar->setObjectName("DownloadProgressBar"); + downloadingGemLayout->addWidget(downloadProgessBar); + downloadProgessBar->setValue(0); + + m_downloadingListWidget->layout()->addWidget(newGemDownloadWidget); + + const AZStd::vector& downloadQueue = m_downloadController->GetDownloadQueue(); + QLabel* numDownloads = m_downloadingListWidget->findChild("NumDownloadsInProgressLabel"); + numDownloads->setText(QString("%1 %2") + .arg(downloadQueue.size()) + .arg(downloadQueue.size() == 1 ? tr("download in progress...") : tr("downloads in progress..."))); + + m_downloadingListWidget->show(); + } + + void CartOverlayWidget::GemDownloadRemoved(const QString& gemName) + { + QWidget* gemToRemove = m_downloadingListWidget->findChild(gemName); + QLayout* gemToRemoveLayout = gemToRemove ? gemToRemove->layout() : nullptr; + + if (gemToRemoveLayout) + { + QLayoutItem* rowLayoutItem = nullptr; + while ((rowLayoutItem = gemToRemoveLayout->layout()->takeAt(0)) != nullptr) + { + rowLayoutItem->widget()->deleteLater(); + } + gemToRemoveLayout->layout()->deleteLater(); + gemToRemove->deleteLater(); + } + + const AZStd::vector& downloadQueue = m_downloadController->GetDownloadQueue(); + + if (m_downloadController->IsDownloadQueueEmpty()) + { + m_downloadSectionWidget->hide(); + } + else + { + QLabel* numDownloads = m_downloadingListWidget->findChild("NumDownloadsInProgressLabel"); + numDownloads->setText(QString("%1 %2") + .arg(downloadQueue.size()) + .arg(downloadQueue.size() == 1 ? tr("download in progress...") : tr("downloads in progress..."))); + } + } + + void CartOverlayWidget::GemDownloadProgress(const QString& gemName, int percentage) + { + QWidget* gemToUpdate = m_downloadingListWidget->findChild(gemName); + if (gemToUpdate) + { + QLabel* progressLabel = gemToUpdate->findChild("DownloadProgressLabel"); + if (progressLabel) + { + progressLabel->setText(QString("%1%").arg(percentage)); + } + QProgressBar* progressBar = gemToUpdate->findChild("DownloadProgressBar"); + if (progressBar) + { + progressBar->setValue(percentage); + } + } + } + + void CartOverlayWidget::GemDownloadComplete(const QString& gemName, bool /*success*/) + { + GemDownloadRemoved(gemName); // update the list to remove the gem that has finished } QStringList CartOverlayWidget::ConvertFromModelIndices(const QVector& gems) const diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogHeaderWidget.h b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogHeaderWidget.h index 4d17259840..a8f50a5338 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogHeaderWidget.h +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogHeaderWidget.h @@ -34,6 +34,13 @@ namespace O3DE::ProjectManager public: CartOverlayWidget(GemModel* gemModel, DownloadController* downloadController, QWidget* parent = nullptr); + ~CartOverlayWidget(); + + public slots: + void GemDownloadAdded(const QString& gemName); + void GemDownloadRemoved(const QString& gemName); + void GemDownloadProgress(const QString& gemName, int percentage); + void GemDownloadComplete(const QString& gemName, bool success); private: QStringList ConvertFromModelIndices(const QVector& gems) const; @@ -47,6 +54,9 @@ namespace O3DE::ProjectManager GemModel* m_gemModel = nullptr; DownloadController* m_downloadController = nullptr; + QWidget* m_downloadSectionWidget = nullptr; + QWidget* m_downloadingListWidget = nullptr; + inline constexpr static int s_width = 240; }; diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp index a22f41d054..32cf35c04d 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp @@ -145,7 +145,7 @@ namespace O3DE::ProjectManager } } - void GemCatalogScreen::OnGemStatusChanged(const QModelIndex& modelIndex, uint32_t numChangedDependencies) + void GemCatalogScreen::OnGemStatusChanged(const QModelIndex& modelIndex, uint32_t numChangedDependencies) { if (m_notificationsEnabled) { @@ -170,6 +170,7 @@ namespace O3DE::ProjectManager if (added && GemModel::GetDownloadStatus(modelIndex) == GemInfo::DownloadStatus::NotDownloaded) { m_downloadController->AddGemDownload(GemModel::GetName(modelIndex)); + GemModel::SetDownloadStatus(*m_proxModel, modelIndex, GemInfo::DownloadStatus::Downloading); } } @@ -187,7 +188,7 @@ namespace O3DE::ProjectManager toastConfiguration.m_customIconImage = ":/gem.svg"; toastConfiguration.m_borderRadius = 4; toastConfiguration.m_duration = AZStd::chrono::milliseconds(3000); - m_notificationsView->ShowToastNotification(toastConfiguration); + //m_notificationsView->ShowToastNotification(toastConfiguration); } } From c9fb41d0e5abf036210563395a36f5cc48517aa6 Mon Sep 17 00:00:00 2001 From: nvsickle Date: Wed, 3 Nov 2021 19:57:51 -0700 Subject: [PATCH 02/71] 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 52604d79f6d2de34f9b94b30daf08e518bfa6429 Mon Sep 17 00:00:00 2001 From: nvsickle Date: Thu, 4 Nov 2021 12:05:46 -0700 Subject: [PATCH 03/71] 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 047c5f2231dbba742363a2d9396170c23b572374 Mon Sep 17 00:00:00 2001 From: AMZN-Phil Date: Thu, 4 Nov 2021 15:09:11 -0700 Subject: [PATCH 04/71] 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 9d977e81da0b9d4c3135ad6f0d8e5aa9aec2298e Mon Sep 17 00:00:00 2001 From: AMZN-Phil Date: Thu, 4 Nov 2021 15:20:35 -0700 Subject: [PATCH 05/71] Uncomment temporary disabling of toast notifications Signed-off-by: AMZN-Phil --- .../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 32cf35c04d..db34375db5 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp @@ -188,7 +188,7 @@ namespace O3DE::ProjectManager toastConfiguration.m_customIconImage = ":/gem.svg"; toastConfiguration.m_borderRadius = 4; toastConfiguration.m_duration = AZStd::chrono::milliseconds(3000); - //m_notificationsView->ShowToastNotification(toastConfiguration); + m_notificationsView->ShowToastNotification(toastConfiguration); } } From 31382d080e94548b5d71702e44de5e9951191dd8 Mon Sep 17 00:00:00 2001 From: AMZN-Phil Date: Thu, 4 Nov 2021 17:07:02 -0700 Subject: [PATCH 06/71] 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 07/71] 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 c6e77f8e32c35d33fa639a00c6aea819b360ffbc Mon Sep 17 00:00:00 2001 From: AMZN-Phil Date: Fri, 5 Nov 2021 14:21:10 -0700 Subject: [PATCH 08/71] Code readability improvements Signed-off-by: AMZN-Phil --- .../Source/DownloadController.cpp | 8 ++-- .../GemCatalog/GemCatalogHeaderWidget.cpp | 41 ++++++++----------- .../Source/GemCatalog/GemCatalogScreen.cpp | 2 +- 3 files changed, 23 insertions(+), 28 deletions(-) diff --git a/Code/Tools/ProjectManager/Source/DownloadController.cpp b/Code/Tools/ProjectManager/Source/DownloadController.cpp index 00a7db5318..6326b2fc11 100644 --- a/Code/Tools/ProjectManager/Source/DownloadController.cpp +++ b/Code/Tools/ProjectManager/Source/DownloadController.cpp @@ -45,7 +45,7 @@ namespace O3DE::ProjectManager if (m_gemNames.size() == 1) { - m_worker->SetGemToDownload(m_gemNames[0], false); + m_worker->SetGemToDownload(m_gemNames.front(), false); m_workerThread.start(); } } @@ -72,7 +72,7 @@ namespace O3DE::ProjectManager void DownloadController::UpdateUIProgress(int progress) { m_lastProgress = progress; - emit GemDownloadProgress(*m_gemNames.begin(), progress); + emit GemDownloadProgress(m_gemNames.front(), progress); } void DownloadController::HandleResults(const QString& result) @@ -85,13 +85,13 @@ namespace O3DE::ProjectManager succeeded = false; } - QString gemName = *m_gemNames.begin(); + QString gemName = m_gemNames.front(); m_gemNames.erase(m_gemNames.begin()); 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/GemCatalog/GemCatalogHeaderWidget.cpp b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogHeaderWidget.cpp index cfe69283ff..b0729c0047 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogHeaderWidget.cpp +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogHeaderWidget.cpp @@ -214,9 +214,9 @@ namespace O3DE::ProjectManager // Setup gem download rows for gems that are already in the queue const AZStd::vector& downloadQueue = m_downloadController->GetDownloadQueue(); - for (int downloadingGemNumber = 0; downloadingGemNumber < downloadQueue.size(); ++downloadingGemNumber) + for (const QString& gemName : downloadQueue) { - GemDownloadAdded(downloadQueue[downloadingGemNumber]); + GemDownloadAdded(gemName); } } @@ -229,24 +229,28 @@ namespace O3DE::ProjectManager void CartOverlayWidget::GemDownloadAdded(const QString& gemName) { + // Containing widget for the current download item QWidget* newGemDownloadWidget = new QWidget(); newGemDownloadWidget->setObjectName(gemName); - QVBoxLayout* downloadingGemLayout = new QVBoxLayout(); + QVBoxLayout* downloadingGemLayout = new QVBoxLayout(newGemDownloadWidget); newGemDownloadWidget->setLayout(downloadingGemLayout); - QHBoxLayout* nameProgressLayout = new QHBoxLayout(); - TagWidget* newTag = new TagWidget(gemName); + + // Gem name, progress string, cancel + QHBoxLayout* nameProgressLayout = new QHBoxLayout(newGemDownloadWidget); + TagWidget* newTag = new TagWidget(gemName, newGemDownloadWidget); nameProgressLayout->addWidget(newTag); - QLabel* progress = new QLabel(tr("Queued")); + QLabel* progress = new QLabel(tr("Queued"), newGemDownloadWidget); progress->setObjectName("DownloadProgressLabel"); nameProgressLayout->addWidget(progress); - QSpacerItem* spacer = new QSpacerItem(0, 0, QSizePolicy::Expanding, QSizePolicy::Minimum); - nameProgressLayout->addSpacerItem(spacer); - QLabel* cancelText = new QLabel(QString("Cancel").arg(gemName)); + nameProgressLayout->addStretch(); + QLabel* cancelText = new QLabel(tr("Cancel").arg(gemName), newGemDownloadWidget); cancelText->setTextInteractionFlags(Qt::LinksAccessibleByMouse); connect(cancelText, &QLabel::linkActivated, this, &CartOverlayWidget::OnCancelDownloadActivated); nameProgressLayout->addWidget(cancelText); downloadingGemLayout->addLayout(nameProgressLayout); - QProgressBar* downloadProgessBar = new QProgressBar(); + + // Progress bar + QProgressBar* downloadProgessBar = new QProgressBar(newGemDownloadWidget); downloadProgessBar->setObjectName("DownloadProgressBar"); downloadingGemLayout->addWidget(downloadProgessBar); downloadProgessBar->setValue(0); @@ -265,31 +269,22 @@ namespace O3DE::ProjectManager void CartOverlayWidget::GemDownloadRemoved(const QString& gemName) { QWidget* gemToRemove = m_downloadingListWidget->findChild(gemName); - QLayout* gemToRemoveLayout = gemToRemove ? gemToRemove->layout() : nullptr; - - if (gemToRemoveLayout) + if (gemToRemove) { - QLayoutItem* rowLayoutItem = nullptr; - while ((rowLayoutItem = gemToRemoveLayout->layout()->takeAt(0)) != nullptr) - { - rowLayoutItem->widget()->deleteLater(); - } - gemToRemoveLayout->layout()->deleteLater(); gemToRemove->deleteLater(); } - const AZStd::vector& downloadQueue = m_downloadController->GetDownloadQueue(); - if (m_downloadController->IsDownloadQueueEmpty()) { m_downloadSectionWidget->hide(); } else { + size_t downloadQueueSize = m_downloadController->GetDownloadQueue().size(); QLabel* numDownloads = m_downloadingListWidget->findChild("NumDownloadsInProgressLabel"); numDownloads->setText(QString("%1 %2") - .arg(downloadQueue.size()) - .arg(downloadQueue.size() == 1 ? tr("download in progress...") : tr("downloads in progress..."))); + .arg(downloadQueueSize) + .arg(downloadQueueSize == 1 ? tr("download in progress...") : tr("downloads in progress..."))); } } diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp index 9f5d4a70f2..f3e1da011a 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp @@ -175,7 +175,7 @@ namespace O3DE::ProjectManager if (added && GemModel::GetDownloadStatus(modelIndex) == GemInfo::DownloadStatus::NotDownloaded) { m_downloadController->AddGemDownload(GemModel::GetName(modelIndex)); - GemModel::SetDownloadStatus(*m_proxyModel, modelIndex, GemInfo::DownloadStatus::Downloading); + GemModel::SetDownloadStatus(*m_proxyModel, m_proxyModel->mapFromSource(modelIndex), GemInfo::DownloadStatus::Downloading); } } From 9481f8a488ec26196ae7a04f4ba2b5b114e6e857 Mon Sep 17 00:00:00 2001 From: santorac <55155825+santorac@users.noreply.github.com> Date: Fri, 5 Nov 2021 23:39:34 -0700 Subject: [PATCH 09/71] Updated 002_wrinkle_regression_test.material to avoid subsurface scattering artifacts. Having subsurface scattering into a completely back area is an unrealistic scenario and caused colored artifacts. I changed the material to mask out the black areas from applying SS. Corresponding changes will be made to the expceted screenshot in AtomSampleViewer as well. Note these artifacts were originally introduced at commit 19638c4697a2e95bcb9b12badd82980e92b4c5ac Fri Jul 2 01:18:09 where SS was fixed to work again where it bad previously been broken and didn't show up in this test case. Signed-off-by: santorac <55155825+santorac@users.noreply.github.com> --- .../SkinTestCases/002_wrinkle_regression_test.material | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/Gems/Atom/TestData/TestData/Materials/SkinTestCases/002_wrinkle_regression_test.material b/Gems/Atom/TestData/TestData/Materials/SkinTestCases/002_wrinkle_regression_test.material index 400044d29f..78f597b14f 100644 --- a/Gems/Atom/TestData/TestData/Materials/SkinTestCases/002_wrinkle_regression_test.material +++ b/Gems/Atom/TestData/TestData/Materials/SkinTestCases/002_wrinkle_regression_test.material @@ -33,7 +33,7 @@ }, "subsurfaceScattering": { "enableSubsurfaceScattering": true, - "influenceMap": "Objects/Lucy/Lucy_thickness.tif", + "influenceMap": "TestData/Textures/checker8x8_gray_512.png", "scatterDistance": 15.0, "subsurfaceScatterFactor": 0.4300000071525574, "thicknessMap": "Objects/Lucy/Lucy_thickness.tif", @@ -47,8 +47,7 @@ 0.3182879388332367, 0.16388189792633058, 1.0 - ], - "useInfluenceMap": false + ] }, "wrinkleLayers": { "baseColorMap1": "TestData/Textures/cc0/Lava004_1K_Color.jpg", @@ -61,4 +60,4 @@ "normalMap2": "TestData/Textures/TextureHaven/4k_castle_brick_02_red/4k_castle_brick_02_red_normal.png" } } -} +} \ No newline at end of file From fe005c9c5050cd2e87ecf14719b0f03216ea2e9f Mon Sep 17 00:00:00 2001 From: dmcdiar Date: Mon, 8 Nov 2021 16:11:30 -0700 Subject: [PATCH 10/71] Added exposure controls to the ReflectionProbe component Signed-off-by: dmcdiar --- .../Atom/Features/PBR/DefaultObjectSrg.azsli | 1 + .../Atom/Features/PBR/Lights/Ibl.azsli | 6 +++--- .../Atom/Features/Skin/SkinObjectSrg.azsli | 1 + .../ReflectionProbeRenderInner.azsl | 2 +- .../ReflectionProbeRenderObjectSrg.azsli | 1 + .../ReflectionProbeRenderOuter.azsl | 2 +- .../ReflectionProbeFeatureProcessor.h | 2 ++ ...ReflectionProbeFeatureProcessorInterface.h | 2 ++ .../Code/Source/Mesh/MeshFeatureProcessor.cpp | 4 ++++ .../ReflectionProbe/ReflectionProbe.cpp | 17 ++++++++++++++-- .../Source/ReflectionProbe/ReflectionProbe.h | 11 ++++++++++ .../ReflectionProbeFeatureProcessor.cpp | 12 +++++++++++ .../EditorReflectionProbeComponent.cpp | 20 +++++++++++++++++++ .../EditorReflectionProbeComponent.h | 2 ++ .../ReflectionProbeComponentController.cpp | 19 ++++++++++++++++-- .../ReflectionProbeComponentController.h | 6 ++++++ 16 files changed, 99 insertions(+), 9 deletions(-) diff --git a/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/PBR/DefaultObjectSrg.azsli b/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/PBR/DefaultObjectSrg.azsli index 10526597cb..9f40e7ab8f 100644 --- a/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/PBR/DefaultObjectSrg.azsli +++ b/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/PBR/DefaultObjectSrg.azsli @@ -37,6 +37,7 @@ ShaderResourceGroup ObjectSrg : SRG_PerObject float m_padding; bool m_useReflectionProbe; bool m_useParallaxCorrection; + float m_exposure; }; ReflectionProbeData m_reflectionProbeData; diff --git a/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/PBR/Lights/Ibl.azsli b/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/PBR/Lights/Ibl.azsli index d33a307dfe..31439de144 100644 --- a/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/PBR/Lights/Ibl.azsli +++ b/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/PBR/Lights/Ibl.azsli @@ -85,12 +85,12 @@ void ApplyIBL(Surface surface, inout LightingData lightingData) if(useIbl) { - float iblExposureFactor = pow(2.0, SceneSrg::m_iblExposure); + float exposure = pow(2.0, ObjectSrg::m_reflectionProbeData.m_exposure); if(useDiffuseIbl) { float3 iblDiffuse = GetIblDiffuse(surface.normal, surface.albedo, lightingData.diffuseResponse); - lightingData.diffuseLighting += (iblDiffuse * iblExposureFactor * lightingData.diffuseAmbientOcclusion); + lightingData.diffuseLighting += (iblDiffuse * exposure * lightingData.diffuseAmbientOcclusion); } if(useSpecularIbl) @@ -116,7 +116,7 @@ void ApplyIBL(Surface surface, inout LightingData lightingData) iblSpecular = iblSpecular * (1.0 - clearCoatResponse) * (1.0 - clearCoatResponse) + clearCoatIblSpecular; } - lightingData.specularLighting += (iblSpecular * iblExposureFactor); + lightingData.specularLighting += (iblSpecular * exposure); } } } diff --git a/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/Skin/SkinObjectSrg.azsli b/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/Skin/SkinObjectSrg.azsli index d0766c295d..99a32629ef 100644 --- a/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/Skin/SkinObjectSrg.azsli +++ b/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/Skin/SkinObjectSrg.azsli @@ -46,6 +46,7 @@ ShaderResourceGroup ObjectSrg : SRG_PerObject float m_padding; bool m_useReflectionProbe; bool m_useParallaxCorrection; + float m_exposure; }; ReflectionProbeData m_reflectionProbeData; diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/Reflections/ReflectionProbeRenderInner.azsl b/Gems/Atom/Feature/Common/Assets/Shaders/Reflections/ReflectionProbeRenderInner.azsl index a0734caf02..e9333a4694 100644 --- a/Gems/Atom/Feature/Common/Assets/Shaders/Reflections/ReflectionProbeRenderInner.azsl +++ b/Gems/Atom/Feature/Common/Assets/Shaders/Reflections/ReflectionProbeRenderInner.azsl @@ -81,7 +81,7 @@ PSOutput MainPS(VSOutput IN, in uint sampleIndex : SV_SampleIndex) } // apply exposure setting - specular *= pow(2.0, SceneSrg::m_iblExposure); + specular *= pow(2.0, ObjectSrg::m_exposure); PSOutput OUT; OUT.m_color = float4(specular, 1.0f); diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/Reflections/ReflectionProbeRenderObjectSrg.azsli b/Gems/Atom/Feature/Common/Assets/Shaders/Reflections/ReflectionProbeRenderObjectSrg.azsli index 8151ed2fd5..366dc691ed 100644 --- a/Gems/Atom/Feature/Common/Assets/Shaders/Reflections/ReflectionProbeRenderObjectSrg.azsli +++ b/Gems/Atom/Feature/Common/Assets/Shaders/Reflections/ReflectionProbeRenderObjectSrg.azsli @@ -17,6 +17,7 @@ ShaderResourceGroup ObjectSrg : SRG_PerObject float3 m_outerObbHalfLengths; float3 m_innerObbHalfLengths; bool m_useParallaxCorrection; + float m_exposure; TextureCube m_reflectionCubeMap; float4x4 GetWorldMatrix() diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/Reflections/ReflectionProbeRenderOuter.azsl b/Gems/Atom/Feature/Common/Assets/Shaders/Reflections/ReflectionProbeRenderOuter.azsl index ac97172f1f..138d29398e 100644 --- a/Gems/Atom/Feature/Common/Assets/Shaders/Reflections/ReflectionProbeRenderOuter.azsl +++ b/Gems/Atom/Feature/Common/Assets/Shaders/Reflections/ReflectionProbeRenderOuter.azsl @@ -104,7 +104,7 @@ PSOutput MainPS(VSOutput IN, in uint sampleIndex : SV_SampleIndex) blendWeight /= max(1.0f, blendWeightAllProbes); // apply exposure setting - specular *= pow(2.0, SceneSrg::m_iblExposure); + specular *= pow(2.0, ObjectSrg::m_exposure); // apply blend weight for additive blending specular *= blendWeight; diff --git a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/ReflectionProbe/ReflectionProbeFeatureProcessor.h b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/ReflectionProbe/ReflectionProbeFeatureProcessor.h index 5efd235a67..ded36f5496 100644 --- a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/ReflectionProbe/ReflectionProbeFeatureProcessor.h +++ b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/ReflectionProbe/ReflectionProbeFeatureProcessor.h @@ -39,6 +39,8 @@ namespace AZ bool IsCubeMapReferenced(const AZStd::string& relativePath) override; bool IsValidProbeHandle(const ReflectionProbeHandle& probe) const override { return (probe.get() != nullptr); } void ShowProbeVisualization(const ReflectionProbeHandle& probe, bool showVisualization) override; + void SetRenderExposure(const ReflectionProbeHandle& probe, float renderExposure) override; + void SetBakeExposure(const ReflectionProbeHandle& probe, float bakeExposure) override; // FeatureProcessor overrides void Activate() override; diff --git a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/ReflectionProbe/ReflectionProbeFeatureProcessorInterface.h b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/ReflectionProbe/ReflectionProbeFeatureProcessorInterface.h index 4eb2130b1b..80c92281ea 100644 --- a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/ReflectionProbe/ReflectionProbeFeatureProcessorInterface.h +++ b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/ReflectionProbe/ReflectionProbeFeatureProcessorInterface.h @@ -50,6 +50,8 @@ namespace AZ virtual bool IsCubeMapReferenced(const AZStd::string& relativePath) = 0; virtual bool IsValidProbeHandle(const ReflectionProbeHandle& probe) const = 0; virtual void ShowProbeVisualization(const ReflectionProbeHandle& probe, bool showVisualization) = 0; + virtual void SetRenderExposure(const ReflectionProbeHandle& probe, float renderExposure) = 0; + virtual void SetBakeExposure(const ReflectionProbeHandle& probe, float bakeExposure) = 0; }; } // namespace Render } // namespace AZ diff --git a/Gems/Atom/Feature/Common/Code/Source/Mesh/MeshFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/Mesh/MeshFeatureProcessor.cpp index c7fb19bc5d..99f01ea630 100644 --- a/Gems/Atom/Feature/Common/Code/Source/Mesh/MeshFeatureProcessor.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/Mesh/MeshFeatureProcessor.cpp @@ -1178,6 +1178,9 @@ namespace AZ AZ::RHI::ShaderInputConstantIndex useParallaxCorrectionConstantIndex = m_shaderResourceGroup->FindShaderInputConstantIndex(Name("m_reflectionProbeData.m_useParallaxCorrection")); AZ_Error("MeshDataInstance", useParallaxCorrectionConstantIndex.IsValid(), "Failed to find ReflectionProbe constant index"); + AZ::RHI::ShaderInputConstantIndex exposureConstantIndex = m_shaderResourceGroup->FindShaderInputConstantIndex(Name("m_reflectionProbeData.m_exposure")); + AZ_Error("MeshDataInstance", exposureConstantIndex.IsValid(), "Failed to find ReflectionProbe constant index"); + // retrieve probe cubemap index Name reflectionCubeMapImageName = Name("m_reflectionProbeCubeMap"); RHI::ShaderInputImageIndex reflectionCubeMapImageIndex = m_shaderResourceGroup->FindShaderInputImageIndex(reflectionCubeMapImageName); @@ -1198,6 +1201,7 @@ namespace AZ m_shaderResourceGroup->SetConstant(innerObbHalfLengthsConstantIndex, reflectionProbes[0]->GetInnerObbWs().GetHalfLengths()); m_shaderResourceGroup->SetConstant(useReflectionProbeConstantIndex, true); m_shaderResourceGroup->SetConstant(useParallaxCorrectionConstantIndex, reflectionProbes[0]->GetUseParallaxCorrection()); + m_shaderResourceGroup->SetConstant(exposureConstantIndex, reflectionProbes[0]->GetRenderExposure()); m_shaderResourceGroup->SetImage(reflectionCubeMapImageIndex, reflectionProbes[0]->GetCubeMapImage()); } diff --git a/Gems/Atom/Feature/Common/Code/Source/ReflectionProbe/ReflectionProbe.cpp b/Gems/Atom/Feature/Common/Code/Source/ReflectionProbe/ReflectionProbe.cpp index e86d91d387..c4ea3249d5 100644 --- a/Gems/Atom/Feature/Common/Code/Source/ReflectionProbe/ReflectionProbe.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/ReflectionProbe/ReflectionProbe.cpp @@ -127,8 +127,8 @@ namespace AZ } else { - // set exposure to 0.0 while baking the cubemap - sceneSrg->SetConstant(m_iblExposureConstantIndex, 0.0f); + // set exposure to the user specified value while baking the cubemap + sceneSrg->SetConstant(m_iblExposureConstantIndex, m_bakeExposure); } } @@ -162,6 +162,7 @@ namespace AZ m_renderOuterSrg->SetConstant(m_reflectionRenderData->m_outerObbHalfLengthsRenderConstantIndex, m_outerObbWs.GetHalfLengths()); m_renderOuterSrg->SetConstant(m_reflectionRenderData->m_innerObbHalfLengthsRenderConstantIndex, m_innerObbWs.GetHalfLengths()); m_renderOuterSrg->SetConstant(m_reflectionRenderData->m_useParallaxCorrectionRenderConstantIndex, m_useParallaxCorrection); + m_renderOuterSrg->SetConstant(m_reflectionRenderData->m_exposureConstantIndex, m_renderExposure); m_renderOuterSrg->SetImage(m_reflectionRenderData->m_reflectionCubeMapRenderImageIndex, m_cubeMapImage); m_renderOuterSrg->Compile(); @@ -172,6 +173,7 @@ namespace AZ m_renderInnerSrg->SetConstant(m_reflectionRenderData->m_outerObbHalfLengthsRenderConstantIndex, m_outerObbWs.GetHalfLengths()); m_renderInnerSrg->SetConstant(m_reflectionRenderData->m_innerObbHalfLengthsRenderConstantIndex, m_innerObbWs.GetHalfLengths()); m_renderInnerSrg->SetConstant(m_reflectionRenderData->m_useParallaxCorrectionRenderConstantIndex, m_useParallaxCorrection); + m_renderInnerSrg->SetConstant(m_reflectionRenderData->m_exposureConstantIndex, m_renderExposure); m_renderInnerSrg->SetImage(m_reflectionRenderData->m_reflectionCubeMapRenderImageIndex, m_cubeMapImage); m_renderInnerSrg->Compile(); @@ -326,6 +328,17 @@ namespace AZ m_meshFeatureProcessor->SetVisible(m_visualizationMeshHandle, showVisualization); } + void ReflectionProbe::SetRenderExposure(float renderExposure) + { + m_renderExposure = renderExposure; + m_updateSrg = true; + } + + void ReflectionProbe::SetBakeExposure(float bakeExposure) + { + m_bakeExposure = bakeExposure; + } + const RHI::DrawPacket* ReflectionProbe::BuildDrawPacket( const Data::Instance& srg, const RPI::Ptr& pipelineState, diff --git a/Gems/Atom/Feature/Common/Code/Source/ReflectionProbe/ReflectionProbe.h b/Gems/Atom/Feature/Common/Code/Source/ReflectionProbe/ReflectionProbe.h index bee304c5b9..485f380463 100644 --- a/Gems/Atom/Feature/Common/Code/Source/ReflectionProbe/ReflectionProbe.h +++ b/Gems/Atom/Feature/Common/Code/Source/ReflectionProbe/ReflectionProbe.h @@ -61,6 +61,7 @@ namespace AZ RHI::ShaderInputNameIndex m_outerObbHalfLengthsRenderConstantIndex = "m_outerObbHalfLengths"; RHI::ShaderInputNameIndex m_innerObbHalfLengthsRenderConstantIndex = "m_innerObbHalfLengths"; RHI::ShaderInputNameIndex m_useParallaxCorrectionRenderConstantIndex = "m_useParallaxCorrection"; + RHI::ShaderInputNameIndex m_exposureConstantIndex = "m_exposure"; RHI::ShaderInputNameIndex m_reflectionCubeMapRenderImageIndex = "m_reflectionCubeMap"; }; @@ -106,6 +107,14 @@ namespace AZ // enables or disables rendering of the visualization sphere void ShowVisualization(bool showVisualization); + // the exposure to use when rendering meshes with this probe's cubemap + void SetRenderExposure(float renderExposure); + float GetRenderExposure() const { return m_renderExposure; } + + // the exposure to use when baking the probe cubemap + void SetBakeExposure(float bakeExposure); + float GetBakeExposure() const { return m_bakeExposure; } + private: AZ_DISABLE_COPY_MOVE(ReflectionProbe); @@ -157,6 +166,8 @@ namespace AZ RHI::ConstPtr m_blendWeightDrawPacket; RHI::ConstPtr m_renderOuterDrawPacket; RHI::ConstPtr m_renderInnerDrawPacket; + float m_renderExposure = 0.0f; + float m_bakeExposure = 0.0f; bool m_updateSrg = false; const RHI::DrawItemSortKey InvalidSortKey = static_cast(-1); diff --git a/Gems/Atom/Feature/Common/Code/Source/ReflectionProbe/ReflectionProbeFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/ReflectionProbe/ReflectionProbeFeatureProcessor.cpp index 52d089ae0d..b1484ac8a8 100644 --- a/Gems/Atom/Feature/Common/Code/Source/ReflectionProbe/ReflectionProbeFeatureProcessor.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/ReflectionProbe/ReflectionProbeFeatureProcessor.cpp @@ -283,6 +283,18 @@ namespace AZ probe->ShowVisualization(showVisualization); } + void ReflectionProbeFeatureProcessor::SetRenderExposure(const ReflectionProbeHandle& probe, float renderExposure) + { + AZ_Assert(probe.get(), "SetRenderExposure called with an invalid handle"); + probe->SetRenderExposure(renderExposure); + } + + void ReflectionProbeFeatureProcessor::SetBakeExposure(const ReflectionProbeHandle& probe, float bakeExposure) + { + AZ_Assert(probe.get(), "SetBakeExposure called with an invalid handle"); + probe->SetBakeExposure(bakeExposure); + } + void ReflectionProbeFeatureProcessor::FindReflectionProbes(const Vector3& position, ReflectionProbeVector& reflectionProbes) { reflectionProbes.clear(); diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/ReflectionProbe/EditorReflectionProbeComponent.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/ReflectionProbe/EditorReflectionProbeComponent.cpp index 99e99abf4a..c14d2c320a 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/ReflectionProbe/EditorReflectionProbeComponent.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/ReflectionProbe/EditorReflectionProbeComponent.cpp @@ -40,6 +40,7 @@ namespace AZ ->Field("bakedCubeMapQualityLevel", &EditorReflectionProbeComponent::m_bakedCubeMapQualityLevel) ->Field("bakedCubeMapRelativePath", &EditorReflectionProbeComponent::m_bakedCubeMapRelativePath) ->Field("authoredCubeMapAsset", &EditorReflectionProbeComponent::m_authoredCubeMapAsset) + ->Field("bakeExposure", &EditorReflectionProbeComponent::m_bakeExposure) ; if (AZ::EditContext* editContext = serializeContext->GetEditContext()) @@ -62,6 +63,13 @@ namespace AZ ->Attribute(AZ::Edit::Attributes::ButtonText, "Bake Reflection Probe") ->Attribute(AZ::Edit::Attributes::ChangeNotify, &EditorReflectionProbeComponent::BakeReflectionProbe) ->Attribute(AZ::Edit::Attributes::Visibility, &EditorReflectionProbeComponent::GetBakedCubemapVisibilitySetting) + ->DataElement(AZ::Edit::UIHandlers::Slider, &EditorReflectionProbeComponent::m_bakeExposure, "Bake Exposure", "Exposure to use when baking the cubemap") + ->Attribute(AZ::Edit::Attributes::SoftMin, -5.0f) + ->Attribute(AZ::Edit::Attributes::SoftMax, 5.0f) + ->Attribute(AZ::Edit::Attributes::Min, -20.0f) + ->Attribute(AZ::Edit::Attributes::Max, 20.0f) + ->Attribute(AZ::Edit::Attributes::ChangeNotify, &EditorReflectionProbeComponent::OnBakeExposureChanged) + ->Attribute(AZ::Edit::Attributes::Visibility, &EditorReflectionProbeComponent::GetBakedCubemapVisibilitySetting) ->ClassElement(AZ::Edit::ClassElements::Group, "Cubemap") ->Attribute(AZ::Edit::Attributes::AutoExpand, true) ->DataElement(AZ::Edit::UIHandlers::Default, &EditorReflectionProbeComponent::m_useBakedCubemap, "Use Baked Cubemap", "Selects between a cubemap that captures the environment at location in the scene or a preauthored cubemap") @@ -111,6 +119,11 @@ namespace AZ ->Attribute(AZ::Edit::Attributes::ChangeNotify, Edit::PropertyRefreshLevels::ValuesOnly) ->DataElement(AZ::Edit::UIHandlers::CheckBox, &ReflectionProbeComponentConfig::m_showVisualization, "Show Visualization", "Show the reflection probe visualization sphere") ->Attribute(AZ::Edit::Attributes::ChangeNotify, Edit::PropertyRefreshLevels::ValuesOnly) + ->DataElement(AZ::Edit::UIHandlers::Slider, &ReflectionProbeComponentConfig::m_renderExposure, "Exposure", "Exposure to use when rendering meshes with the cubemap") + ->Attribute(AZ::Edit::Attributes::SoftMin, -5.0f) + ->Attribute(AZ::Edit::Attributes::SoftMax, 5.0f) + ->Attribute(AZ::Edit::Attributes::Min, -20.0f) + ->Attribute(AZ::Edit::Attributes::Max, 20.0f) ; } } @@ -275,6 +288,13 @@ namespace AZ return AZ::Edit::PropertyRefreshLevels::None; } + AZ::u32 EditorReflectionProbeComponent::OnBakeExposureChanged() + { + m_controller.SetBakeExposure(m_bakeExposure); + + return AZ::Edit::PropertyRefreshLevels::None; + } + AZ::u32 EditorReflectionProbeComponent::GetBakedCubemapVisibilitySetting() { // controls specific to baked cubemaps call this to determine their visibility diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/ReflectionProbe/EditorReflectionProbeComponent.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/ReflectionProbe/EditorReflectionProbeComponent.h index 441da19e78..3cd017fd18 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/ReflectionProbe/EditorReflectionProbeComponent.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/ReflectionProbe/EditorReflectionProbeComponent.h @@ -55,6 +55,7 @@ namespace AZ // change notifications AZ::u32 OnUseBakedCubemapChanged(); AZ::u32 OnAuthoredCubemapChanged(); + AZ::u32 OnBakeExposureChanged(); // retrieves visibility for baked or authored cubemap controls AZ::u32 GetBakedCubemapVisibilitySetting(); @@ -77,6 +78,7 @@ namespace AZ AZStd::string m_bakedCubeMapRelativePath; Data::Asset m_bakedCubeMapAsset; Data::Asset m_authoredCubeMapAsset; + float m_bakeExposure = 0.0f; // flag indicating if a cubemap bake is currently in progress AZStd::atomic_bool m_bakeInProgress = false; diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/ReflectionProbe/ReflectionProbeComponentController.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/ReflectionProbe/ReflectionProbeComponentController.cpp index 4022dfda9b..017f6c9cdf 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/ReflectionProbe/ReflectionProbeComponentController.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/ReflectionProbe/ReflectionProbeComponentController.cpp @@ -35,7 +35,7 @@ namespace AZ if (auto* serializeContext = azrtti_cast(context)) { serializeContext->Class() - ->Version(0) + ->Version(1) ->Field("OuterHeight", &ReflectionProbeComponentConfig::m_outerHeight) ->Field("OuterLength", &ReflectionProbeComponentConfig::m_outerLength) ->Field("OuterWidth", &ReflectionProbeComponentConfig::m_outerWidth) @@ -49,7 +49,9 @@ namespace AZ ->Field("AuthoredCubeMapAsset", &ReflectionProbeComponentConfig::m_authoredCubeMapAsset) ->Field("EntityId", &ReflectionProbeComponentConfig::m_entityId) ->Field("UseParallaxCorrection", &ReflectionProbeComponentConfig::m_useParallaxCorrection) - ->Field("ShowVisualization", &ReflectionProbeComponentConfig::m_showVisualization); + ->Field("ShowVisualization", &ReflectionProbeComponentConfig::m_showVisualization) + ->Field("RenderExposure", &ReflectionProbeComponentConfig::m_renderExposure) + ->Field("BakeExposure", &ReflectionProbeComponentConfig::m_bakeExposure); } } @@ -157,6 +159,9 @@ namespace AZ cubeMapAsset.QueueLoad(); Data::AssetBus::MultiHandler::BusConnect(cubeMapAsset.GetId()); } + + // set cubemap render exposure + m_featureProcessor->SetRenderExposure(m_handle, m_configuration.m_renderExposure); } void ReflectionProbeComponentController::Deactivate() @@ -284,6 +289,16 @@ namespace AZ m_configuration.m_innerHeight = AZStd::min(m_configuration.m_innerHeight, m_configuration.m_outerHeight); } + void ReflectionProbeComponentController::SetBakeExposure(float bakeExposure) + { + if (!m_featureProcessor) + { + return; + } + + m_featureProcessor->SetBakeExposure(m_handle, bakeExposure); + } + void ReflectionProbeComponentController::BakeReflectionProbe(BuildCubeMapCallback callback, const AZStd::string& relativePath) { if (!m_featureProcessor) diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/ReflectionProbe/ReflectionProbeComponentController.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/ReflectionProbe/ReflectionProbeComponentController.h index 18e13f023b..ad7d9f7f53 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/ReflectionProbe/ReflectionProbeComponentController.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/ReflectionProbe/ReflectionProbeComponentController.h @@ -68,6 +68,9 @@ namespace AZ Data::Asset m_bakedCubeMapAsset; Data::Asset m_authoredCubeMapAsset; AZ::u64 m_entityId{ EntityId::InvalidEntityId }; + + float m_renderExposure = 0.0f; + float m_bakeExposure = 0.0f; }; class ReflectionProbeComponentController final @@ -99,6 +102,9 @@ namespace AZ // returns the outer extent Aabb for this reflection AZ::Aabb GetAabb() const; + // set the exposure to use when baking the cubemap + void SetBakeExposure(float bakeExposure); + // initiate the reflection probe bake, invokes callback when complete void BakeReflectionProbe(BuildCubeMapCallback callback, const AZStd::string& relativePath); From 898b1811e0be97b50e9b7845803765fda0635d5f Mon Sep 17 00:00:00 2001 From: Guthrie Adams Date: Thu, 21 Oct 2021 16:04:38 -0500 Subject: [PATCH 11/71] material editor loads source data Signed-off-by: Guthrie Adams --- .../RPI.Edit/Material/MaterialSourceData.h | 25 ++- .../RPI.Edit/Material/MaterialSourceData.cpp | 209 +++++++++++++----- .../Material/MaterialTypeAssetCreator.cpp | 1 + .../Code/Source/Document/MaterialDocument.cpp | 2 +- 4 files changed, 172 insertions(+), 65 deletions(-) diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Edit/Material/MaterialSourceData.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Edit/Material/MaterialSourceData.h index a67477f061..739c4341a9 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Edit/Material/MaterialSourceData.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Edit/Material/MaterialSourceData.h @@ -31,6 +31,7 @@ namespace AZ static constexpr const char UvGroupName[] = "uvSets"; class MaterialAsset; + class MaterialAssetCreator; //! This is a simple data structure for serializing in/out material source files. class MaterialSourceData final @@ -78,15 +79,33 @@ namespace AZ //! Creates a MaterialAsset from the MaterialSourceData content. //! @param assetId ID for the MaterialAsset - //! @param materialSourceFilePath Indicates the path of the .material file that the MaterialSourceData represents. Used for resolving file-relative paths. + //! @param materialSourceFilePath Indicates the path of the .material file that the MaterialSourceData represents. Used for + //! resolving file-relative paths. //! @param elevateWarnings Indicates whether to treat warnings as errors //! @param includeMaterialPropertyNames Indicates whether to save material property names into the material asset file Outcome> CreateMaterialAsset( Data::AssetId assetId, AZStd::string_view materialSourceFilePath = "", bool elevateWarnings = true, - bool includeMaterialPropertyNames = true - ) const; + bool includeMaterialPropertyNames = true) const; + + //! Creates a MaterialAsset from the MaterialSourceData content. + //! @param assetId ID for the MaterialAsset + //! @param materialSourceFilePath Indicates the path of the .material file that the MaterialSourceData represents. Used for + //! resolving file-relative paths. + //! @param elevateWarnings Indicates whether to treat warnings as errors + //! @param includeMaterialPropertyNames Indicates whether to save material property names into the material asset file + Outcome> CreateMaterialAssetFromSourceData( + Data::AssetId assetId, + AZStd::string_view materialSourceFilePath = "", + bool elevateWarnings = true, + bool includeMaterialPropertyNames = true) const; + + private: + static void ApplyMaterialSourceDataPropertiesToAssetCreator( + AZ::RPI::MaterialAssetCreator& materialAssetCreator, + const AZStd::string_view& materialSourceFilePath, + const MaterialSourceData& materialSourceData); }; } // namespace RPI } // namespace AZ diff --git a/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialSourceData.cpp b/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialSourceData.cpp index 1467b017d5..2a76befdf4 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialSourceData.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialSourceData.cpp @@ -17,6 +17,7 @@ #include #include #include +#include #include #include @@ -126,7 +127,8 @@ namespace AZ return changesWereApplied ? ApplyVersionUpdatesResult::UpdatesApplied : ApplyVersionUpdatesResult::NoUpdates; } - Outcome > MaterialSourceData::CreateMaterialAsset(Data::AssetId assetId, AZStd::string_view materialSourceFilePath, bool elevateWarnings, bool includeMaterialPropertyNames) const + Outcome> MaterialSourceData::CreateMaterialAsset( + Data::AssetId assetId, AZStd::string_view materialSourceFilePath, bool elevateWarnings, bool includeMaterialPropertyNames) const { MaterialAssetCreator materialAssetCreator; materialAssetCreator.SetElevateWarnings(elevateWarnings); @@ -172,66 +174,7 @@ namespace AZ materialAssetCreator.Begin(assetId, *parentMaterialAsset.GetValue().Get(), includeMaterialPropertyNames); } - for (auto& group : m_properties) - { - for (auto& property : group.second) - { - MaterialPropertyId propertyId{ group.first, property.first }; - if (!property.second.m_value.IsValid()) - { - AZ_Warning("Material source data", false, "Source data for material property value is invalid."); - } - else - { - MaterialPropertyIndex propertyIndex = materialAssetCreator.m_materialPropertiesLayout->FindPropertyIndex(propertyId.GetFullName()); - if (propertyIndex.IsValid()) - { - const MaterialPropertyDescriptor* propertyDescriptor = materialAssetCreator.m_materialPropertiesLayout->GetPropertyDescriptor(propertyIndex); - switch (propertyDescriptor->GetDataType()) - { - case MaterialPropertyDataType::Image: - { - Outcome> imageAssetResult = MaterialUtils::GetImageAssetReference(materialSourceFilePath, property.second.m_value.GetValue()); - - if (imageAssetResult.IsSuccess()) - { - auto& imageAsset = imageAssetResult.GetValue(); - // Load referenced images when load material - imageAsset.SetAutoLoadBehavior(Data::AssetLoadBehavior::PreLoad); - materialAssetCreator.SetPropertyValue(propertyId.GetFullName(), imageAsset); - } - else - { - materialAssetCreator.ReportError("Material property '%s': Could not find the image '%s'", propertyId.GetFullName().GetCStr(), property.second.m_value.GetValue().data()); - } - } - break; - case MaterialPropertyDataType::Enum: - { - AZ::Name enumName = AZ::Name(property.second.m_value.GetValue()); - uint32_t enumValue = propertyDescriptor->GetEnumValue(enumName); - if (enumValue == MaterialPropertyDescriptor::InvalidEnumValue) - { - materialAssetCreator.ReportError("Enum value '%s' couldn't be found in the 'enumValues' list", enumName.GetCStr()); - } - else - { - materialAssetCreator.SetPropertyValue(propertyId.GetFullName(), enumValue); - } - } - break; - default: - materialAssetCreator.SetPropertyValue(propertyId.GetFullName(), property.second.m_value); - break; - } - } - else - { - materialAssetCreator.ReportWarning("Can not find property id '%s' in MaterialPropertyLayout", propertyId.GetFullName().GetStringView().data()); - } - } - } - } + ApplyMaterialSourceDataPropertiesToAssetCreator(materialAssetCreator, materialSourceFilePath, *this); Data::Asset material; if (materialAssetCreator.End(material)) @@ -244,5 +187,149 @@ namespace AZ } } + Outcome> MaterialSourceData::CreateMaterialAssetFromSourceData( + Data::AssetId assetId, AZStd::string_view materialSourceFilePath, bool elevateWarnings, bool includeMaterialPropertyNames) const + { + MaterialAssetCreator materialAssetCreator; + materialAssetCreator.SetElevateWarnings(elevateWarnings); + + MaterialTypeSourceData materialTypeSourceData; + AZStd::string materialTypeSourcePath = AssetUtils::ResolvePathReference(materialSourceFilePath, m_materialType); + if (!AZ::RPI::JsonUtils::LoadObjectFromFile(materialTypeSourcePath, materialTypeSourceData)) + { + return Failure(); + } + + materialTypeSourceData.ResolveUvEnums(); + + auto materialTypeAsset = + materialTypeSourceData.CreateMaterialTypeAsset(AZ::Uuid::CreateRandom(), materialTypeSourcePath, elevateWarnings); + if (!materialTypeAsset.IsSuccess()) + { + return Failure(); + } + + materialAssetCreator.Begin(assetId, *materialTypeAsset.GetValue().Get(), includeMaterialPropertyNames); + + AZStd::vector parentMaterialSourceDataVec; + + AZStd::string parentMaterialPath = m_parentMaterial; + AZStd::string parentMaterialSourcePath = AssetUtils::ResolvePathReference(materialSourceFilePath, parentMaterialPath); + while (!parentMaterialPath.empty()) + { + MaterialSourceData parentMaterialSourceData; + if (!AZ::RPI::JsonUtils::LoadObjectFromFile(parentMaterialSourcePath, parentMaterialSourceData)) + { + return Failure(); + } + + // Make sure the parent material has the same material type + auto materialTypeIdOutcome1 = AssetUtils::MakeAssetId(materialSourceFilePath, m_materialType, 0); + auto materialTypeIdOutcome2 = AssetUtils::MakeAssetId(parentMaterialSourcePath, parentMaterialSourceData.m_materialType, 0); + if (!materialTypeIdOutcome1.IsSuccess() || !materialTypeIdOutcome2.IsSuccess() || + materialTypeIdOutcome1.GetValue() != materialTypeIdOutcome2.GetValue()) + { + AZ_Error("MaterialSourceData", false, "This material and its parent material do not share the same material type."); + return Failure(); + } + + parentMaterialPath = parentMaterialSourceData.m_parentMaterial; + parentMaterialSourcePath = AssetUtils::ResolvePathReference(parentMaterialSourcePath, parentMaterialPath); + parentMaterialSourceDataVec.push_back(parentMaterialSourceData); + } + + AZStd::reverse(parentMaterialSourceDataVec.begin(), parentMaterialSourceDataVec.end()); + for (const auto& parentMaterialSourceData : parentMaterialSourceDataVec) + { + ApplyMaterialSourceDataPropertiesToAssetCreator(materialAssetCreator, materialSourceFilePath, parentMaterialSourceData); + } + + ApplyMaterialSourceDataPropertiesToAssetCreator(materialAssetCreator, materialSourceFilePath, *this); + + Data::Asset material; + if (materialAssetCreator.End(material)) + { + return Success(material); + } + else + { + return Failure(); + } + } + + void MaterialSourceData::ApplyMaterialSourceDataPropertiesToAssetCreator( + AZ::RPI::MaterialAssetCreator& materialAssetCreator, + const AZStd::string_view& materialSourceFilePath, + const MaterialSourceData& materialSourceData) + { + for (auto& group : materialSourceData.m_properties) + { + for (auto& property : group.second) + { + MaterialPropertyId propertyId{ group.first, property.first }; + if (!property.second.m_value.IsValid()) + { + AZ_Warning("Material source data", false, "Source data for material property value is invalid."); + } + else + { + MaterialPropertyIndex propertyIndex = + materialAssetCreator.m_materialPropertiesLayout->FindPropertyIndex(propertyId.GetFullName()); + if (propertyIndex.IsValid()) + { + const MaterialPropertyDescriptor* propertyDescriptor = + materialAssetCreator.m_materialPropertiesLayout->GetPropertyDescriptor(propertyIndex); + switch (propertyDescriptor->GetDataType()) + { + case MaterialPropertyDataType::Image: + { + Outcome> imageAssetResult = MaterialUtils::GetImageAssetReference( + materialSourceFilePath, property.second.m_value.GetValue()); + + if (imageAssetResult.IsSuccess()) + { + auto& imageAsset = imageAssetResult.GetValue(); + // Load referenced images when load material + imageAsset.SetAutoLoadBehavior(Data::AssetLoadBehavior::PreLoad); + materialAssetCreator.SetPropertyValue(propertyId.GetFullName(), imageAsset); + } + else + { + materialAssetCreator.ReportError( + "Material property '%s': Could not find the image '%s'", propertyId.GetFullName().GetCStr(), + property.second.m_value.GetValue().data()); + } + } + break; + case MaterialPropertyDataType::Enum: + { + AZ::Name enumName = AZ::Name(property.second.m_value.GetValue()); + uint32_t enumValue = propertyDescriptor->GetEnumValue(enumName); + if (enumValue == MaterialPropertyDescriptor::InvalidEnumValue) + { + materialAssetCreator.ReportError( + "Enum value '%s' couldn't be found in the 'enumValues' list", enumName.GetCStr()); + } + else + { + materialAssetCreator.SetPropertyValue(propertyId.GetFullName(), enumValue); + } + } + break; + default: + materialAssetCreator.SetPropertyValue(propertyId.GetFullName(), property.second.m_value); + break; + } + } + else + { + materialAssetCreator.ReportWarning( + "Can not find property id '%s' in MaterialPropertyLayout", propertyId.GetFullName().GetStringView().data()); + } + } + } + } + } + } // namespace RPI } // namespace AZ diff --git a/Gems/Atom/RPI/Code/Source/RPI.Reflect/Material/MaterialTypeAssetCreator.cpp b/Gems/Atom/RPI/Code/Source/RPI.Reflect/Material/MaterialTypeAssetCreator.cpp index 46086dfecc..c81cf31d09 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Reflect/Material/MaterialTypeAssetCreator.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Reflect/Material/MaterialTypeAssetCreator.cpp @@ -43,6 +43,7 @@ namespace AZ return false; } + m_asset->PostLoadInit(); m_asset->SetReady(); m_materialShaderResourceGroupLayout = nullptr; diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/Document/MaterialDocument.cpp b/Gems/Atom/Tools/MaterialEditor/Code/Source/Document/MaterialDocument.cpp index 98af749261..1dcef43577 100644 --- a/Gems/Atom/Tools/MaterialEditor/Code/Source/Document/MaterialDocument.cpp +++ b/Gems/Atom/Tools/MaterialEditor/Code/Source/Document/MaterialDocument.cpp @@ -722,7 +722,7 @@ namespace MaterialEditor // we can create the asset dynamically from the source data. // Long term, the material document should not be concerned with assets at all. The viewport window should be the // only thing concerned with assets or instances. - auto createResult = m_materialSourceData.CreateMaterialAsset(Uuid::CreateRandom(), m_absolutePath, true); + auto createResult = m_materialSourceData.CreateMaterialAssetFromSourceData(Uuid::CreateRandom(), m_absolutePath, true); if (!createResult) { AZ_Error("MaterialDocument", false, "Material asset could not be created from source data: '%s'.", m_absolutePath.c_str()); From 30120b962607bba2698400d73b27036f3e5bfc63 Mon Sep 17 00:00:00 2001 From: Guthrie Adams Date: Fri, 22 Oct 2021 01:30:12 -0500 Subject: [PATCH 12/71] cleanup and setting asset preload flags Signed-off-by: Guthrie Adams --- .../RPI.Edit/Material/MaterialSourceData.h | 6 +-- .../RPI.Edit/Material/MaterialSourceData.cpp | 38 +++++++++---------- .../Material/MaterialTypeSourceData.cpp | 29 ++++++++------ 3 files changed, 38 insertions(+), 35 deletions(-) diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Edit/Material/MaterialSourceData.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Edit/Material/MaterialSourceData.h index 739c4341a9..17dc4556fb 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Edit/Material/MaterialSourceData.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Edit/Material/MaterialSourceData.h @@ -102,10 +102,8 @@ namespace AZ bool includeMaterialPropertyNames = true) const; private: - static void ApplyMaterialSourceDataPropertiesToAssetCreator( - AZ::RPI::MaterialAssetCreator& materialAssetCreator, - const AZStd::string_view& materialSourceFilePath, - const MaterialSourceData& materialSourceData); + void ApplyPropertiesToAssetCreator( + AZ::RPI::MaterialAssetCreator& materialAssetCreator, const AZStd::string_view& materialSourceFilePath) const; }; } // namespace RPI } // namespace AZ diff --git a/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialSourceData.cpp b/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialSourceData.cpp index 2a76befdf4..877e12ab2e 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialSourceData.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialSourceData.cpp @@ -174,7 +174,7 @@ namespace AZ materialAssetCreator.Begin(assetId, *parentMaterialAsset.GetValue().Get(), includeMaterialPropertyNames); } - ApplyMaterialSourceDataPropertiesToAssetCreator(materialAssetCreator, materialSourceFilePath, *this); + ApplyPropertiesToAssetCreator(materialAssetCreator, materialSourceFilePath); Data::Asset material; if (materialAssetCreator.End(material)) @@ -211,21 +211,21 @@ namespace AZ materialAssetCreator.Begin(assetId, *materialTypeAsset.GetValue().Get(), includeMaterialPropertyNames); - AZStd::vector parentMaterialSourceDataVec; + AZStd::vector parentSourceDataStack; - AZStd::string parentMaterialPath = m_parentMaterial; - AZStd::string parentMaterialSourcePath = AssetUtils::ResolvePathReference(materialSourceFilePath, parentMaterialPath); - while (!parentMaterialPath.empty()) + AZStd::string parentSourceRelPath = m_parentMaterial; + AZStd::string parentSourceAbsPath = AssetUtils::ResolvePathReference(materialSourceFilePath, parentSourceRelPath); + while (!parentSourceRelPath.empty()) { - MaterialSourceData parentMaterialSourceData; - if (!AZ::RPI::JsonUtils::LoadObjectFromFile(parentMaterialSourcePath, parentMaterialSourceData)) + MaterialSourceData parentSourceData; + if (!AZ::RPI::JsonUtils::LoadObjectFromFile(parentSourceAbsPath, parentSourceData)) { return Failure(); } // Make sure the parent material has the same material type auto materialTypeIdOutcome1 = AssetUtils::MakeAssetId(materialSourceFilePath, m_materialType, 0); - auto materialTypeIdOutcome2 = AssetUtils::MakeAssetId(parentMaterialSourcePath, parentMaterialSourceData.m_materialType, 0); + auto materialTypeIdOutcome2 = AssetUtils::MakeAssetId(parentSourceAbsPath, parentSourceData.m_materialType, 0); if (!materialTypeIdOutcome1.IsSuccess() || !materialTypeIdOutcome2.IsSuccess() || materialTypeIdOutcome1.GetValue() != materialTypeIdOutcome2.GetValue()) { @@ -233,18 +233,18 @@ namespace AZ return Failure(); } - parentMaterialPath = parentMaterialSourceData.m_parentMaterial; - parentMaterialSourcePath = AssetUtils::ResolvePathReference(parentMaterialSourcePath, parentMaterialPath); - parentMaterialSourceDataVec.push_back(parentMaterialSourceData); + parentSourceDataStack.push_back(parentSourceData); + parentSourceRelPath = parentSourceData.m_parentMaterial; + parentSourceAbsPath = AssetUtils::ResolvePathReference(parentSourceAbsPath, parentSourceRelPath); } - AZStd::reverse(parentMaterialSourceDataVec.begin(), parentMaterialSourceDataVec.end()); - for (const auto& parentMaterialSourceData : parentMaterialSourceDataVec) + while (!parentSourceDataStack.empty()) { - ApplyMaterialSourceDataPropertiesToAssetCreator(materialAssetCreator, materialSourceFilePath, parentMaterialSourceData); + parentSourceDataStack.back().ApplyPropertiesToAssetCreator(materialAssetCreator, materialSourceFilePath); + parentSourceDataStack.pop_back(); } - ApplyMaterialSourceDataPropertiesToAssetCreator(materialAssetCreator, materialSourceFilePath, *this); + ApplyPropertiesToAssetCreator(materialAssetCreator, materialSourceFilePath); Data::Asset material; if (materialAssetCreator.End(material)) @@ -257,12 +257,10 @@ namespace AZ } } - void MaterialSourceData::ApplyMaterialSourceDataPropertiesToAssetCreator( - AZ::RPI::MaterialAssetCreator& materialAssetCreator, - const AZStd::string_view& materialSourceFilePath, - const MaterialSourceData& materialSourceData) + void MaterialSourceData::ApplyPropertiesToAssetCreator( + AZ::RPI::MaterialAssetCreator& materialAssetCreator, const AZStd::string_view& materialSourceFilePath) const { - for (auto& group : materialSourceData.m_properties) + for (auto& group : m_properties) { for (auto& property : group.second) { diff --git a/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialTypeSourceData.cpp b/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialTypeSourceData.cpp index 08f57c7cd3..b20873141b 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialTypeSourceData.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialTypeSourceData.cpp @@ -393,11 +393,14 @@ namespace AZ for (const ShaderVariantReferenceData& shaderRef : m_shaderCollection) { const auto& shaderFile = shaderRef.m_shaderFilePath; - const auto& shaderAsset = AssetUtils::LoadAsset(materialTypeSourceFilePath, shaderFile, 0); + auto shaderAssetResult = AssetUtils::LoadAsset(materialTypeSourceFilePath, shaderFile, 0); - if (shaderAsset) + if (shaderAssetResult) { - auto optionsLayout = shaderAsset.GetValue()->GetShaderOptionGroupLayout(); + auto shaderAsset = shaderAssetResult.GetValue(); + shaderAsset.SetAutoLoadBehavior(Data::AssetLoadBehavior::PreLoad); + + auto optionsLayout = shaderAsset->GetShaderOptionGroupLayout(); ShaderOptionGroup options{ optionsLayout }; for (auto& iter : shaderRef.m_shaderOptionValues) { @@ -408,12 +411,11 @@ namespace AZ } materialTypeAssetCreator.AddShader( - shaderAsset.GetValue(), options.GetShaderVariantId(), - shaderRef.m_shaderTag.IsEmpty() ? Uuid::CreateRandom().ToString() : shaderRef.m_shaderTag - ); + shaderAsset, options.GetShaderVariantId(), + shaderRef.m_shaderTag.IsEmpty() ? Uuid::CreateRandom().ToString() : shaderRef.m_shaderTag); // Gather UV names - const ShaderInputContract& shaderInputContract = shaderAsset.GetValue()->GetInputContract(); + const ShaderInputContract& shaderInputContract = shaderAsset->GetInputContract(); for (const ShaderInputContract::StreamChannelInfo& channel : shaderInputContract.m_streamChannels) { const RHI::ShaderSemantic& semantic = channel.m_semantic; @@ -493,15 +495,20 @@ namespace AZ { case MaterialPropertyDataType::Image: { - Outcome> imageAssetResult = MaterialUtils::GetImageAssetReference(materialTypeSourceFilePath, property.m_value.GetValue()); + auto imageAssetResult = MaterialUtils::GetImageAssetReference( + materialTypeSourceFilePath, property.m_value.GetValue()); - if (imageAssetResult.IsSuccess()) + if (imageAssetResult) { - materialTypeAssetCreator.SetPropertyValue(propertyId.GetFullName(), imageAssetResult.GetValue()); + auto imageAsset = imageAssetResult.GetValue(); + imageAsset.SetAutoLoadBehavior(Data::AssetLoadBehavior::PreLoad); + materialTypeAssetCreator.SetPropertyValue(propertyId.GetFullName(), imageAsset); } else { - materialTypeAssetCreator.ReportError("Material property '%s': Could not find the image '%s'", propertyId.GetFullName().GetCStr(), property.m_value.GetValue().data()); + materialTypeAssetCreator.ReportError( + "Material property '%s': Could not find the image '%s'", propertyId.GetFullName().GetCStr(), + property.m_value.GetValue().data()); } } break; From 0724403f9014708c9e34fa7382cc4fcf10c82e76 Mon Sep 17 00:00:00 2001 From: Guthrie Adams Date: Mon, 25 Oct 2021 12:35:19 -0500 Subject: [PATCH 13/71] adding ifdef to compare loading vs creating material type assets Signed-off-by: Guthrie Adams --- .../Code/Source/RPI.Edit/Material/MaterialSourceData.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialSourceData.cpp b/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialSourceData.cpp index 877e12ab2e..f1a41d0548 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialSourceData.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialSourceData.cpp @@ -193,6 +193,7 @@ namespace AZ MaterialAssetCreator materialAssetCreator; materialAssetCreator.SetElevateWarnings(elevateWarnings); +#if 0 MaterialTypeSourceData materialTypeSourceData; AZStd::string materialTypeSourcePath = AssetUtils::ResolvePathReference(materialSourceFilePath, m_materialType); if (!AZ::RPI::JsonUtils::LoadObjectFromFile(materialTypeSourcePath, materialTypeSourceData)) @@ -208,6 +209,13 @@ namespace AZ { return Failure(); } +#else + auto materialTypeAsset = AssetUtils::LoadAsset(materialSourceFilePath, m_materialType); + if (!materialTypeAsset.IsSuccess()) + { + return Failure(); + } +#endif materialAssetCreator.Begin(assetId, *materialTypeAsset.GetValue().Get(), includeMaterialPropertyNames); From e632dc3b3982900770bd120cfa1238e1543489dd Mon Sep 17 00:00:00 2001 From: Guthrie Adams Date: Tue, 26 Oct 2021 12:24:37 -0500 Subject: [PATCH 14/71] Moving material type asset PostInit call to be consistent with material asset Signed-off-by: Guthrie Adams --- .../Code/Source/RPI.Reflect/Material/MaterialTypeAsset.cpp | 4 ++++ .../Source/RPI.Reflect/Material/MaterialTypeAssetCreator.cpp | 1 - 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/Gems/Atom/RPI/Code/Source/RPI.Reflect/Material/MaterialTypeAsset.cpp b/Gems/Atom/RPI/Code/Source/RPI.Reflect/Material/MaterialTypeAsset.cpp index 76634201eb..48654d7769 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Reflect/Material/MaterialTypeAsset.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Reflect/Material/MaterialTypeAsset.cpp @@ -188,6 +188,10 @@ namespace AZ void MaterialTypeAsset::SetReady() { m_status = AssetStatus::Ready; + + // If this was created dynamically using MaterialTypeAssetCreator (which is what calls SetReady()), + // we need to connect to the AssetBus for reloads. + PostLoadInit(); } bool MaterialTypeAsset::PostLoadInit() diff --git a/Gems/Atom/RPI/Code/Source/RPI.Reflect/Material/MaterialTypeAssetCreator.cpp b/Gems/Atom/RPI/Code/Source/RPI.Reflect/Material/MaterialTypeAssetCreator.cpp index c81cf31d09..46086dfecc 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Reflect/Material/MaterialTypeAssetCreator.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Reflect/Material/MaterialTypeAssetCreator.cpp @@ -43,7 +43,6 @@ namespace AZ return false; } - m_asset->PostLoadInit(); m_asset->SetReady(); m_materialShaderResourceGroupLayout = nullptr; From a5e11efda12c0d50df754b8999feac61ecaae516 Mon Sep 17 00:00:00 2001 From: nvsickle Date: Mon, 8 Nov 2021 16:21:35 -0800 Subject: [PATCH 15/71] 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 48f3bb7d7a354c9b7340c69d7698e85fd9ada063 Mon Sep 17 00:00:00 2001 From: santorac <55155825+santorac@users.noreply.github.com> Date: Wed, 3 Nov 2021 23:56:59 -0700 Subject: [PATCH 16/71] Fixed missing initialization of ShaderCollection::Item::m_renderStatesOverlay. This RenderStates is used to override the values in the final draw packet, if the values are valid; it's supposed to be initialized to invalid values, but it wasn't. So the depth compare function was getting set to Less instead of GreaterEqual. This wasn't a problem when using serialized assets from disk, because the deserialization uses the default constructor which did initialize m_renderStatesOverlay. No all Item constructors initialize m_renderStatesOverlay. Signed-off-by: santorac <55155825+santorac@users.noreply.github.com> Signed-off-by: Guthrie Adams --- .../Code/Source/RPI.Edit/Material/MaterialSourceData.cpp | 2 +- .../Code/Source/RPI.Reflect/Material/ShaderCollection.cpp | 8 +++++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialSourceData.cpp b/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialSourceData.cpp index f1a41d0548..7ff33b2d04 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialSourceData.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialSourceData.cpp @@ -193,7 +193,7 @@ namespace AZ MaterialAssetCreator materialAssetCreator; materialAssetCreator.SetElevateWarnings(elevateWarnings); -#if 0 +#if 1 MaterialTypeSourceData materialTypeSourceData; AZStd::string materialTypeSourcePath = AssetUtils::ResolvePathReference(materialSourceFilePath, m_materialType); if (!AZ::RPI::JsonUtils::LoadObjectFromFile(materialTypeSourcePath, materialTypeSourceData)) diff --git a/Gems/Atom/RPI/Code/Source/RPI.Reflect/Material/ShaderCollection.cpp b/Gems/Atom/RPI/Code/Source/RPI.Reflect/Material/ShaderCollection.cpp index 87076891dd..16813cb6b7 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Reflect/Material/ShaderCollection.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Reflect/Material/ShaderCollection.cpp @@ -126,8 +126,8 @@ namespace AZ } ShaderCollection::Item::Item() + : m_renderStatesOverlay(RHI::GetInvalidRenderStates()) { - m_renderStatesOverlay = RHI::GetInvalidRenderStates(); } ShaderCollection::Item& ShaderCollection::operator[](size_t i) @@ -156,7 +156,8 @@ namespace AZ } ShaderCollection::Item::Item(const Data::Asset& shaderAsset, const AZ::Name& shaderTag, ShaderVariantId variantId) - : m_shaderAsset(shaderAsset) + : m_renderStatesOverlay(RHI::GetInvalidRenderStates()) + , m_shaderAsset(shaderAsset) , m_shaderVariantId(variantId) , m_shaderTag(shaderTag) , m_shaderOptionGroup(shaderAsset->GetShaderOptionGroupLayout(), variantId) @@ -164,7 +165,8 @@ namespace AZ } ShaderCollection::Item::Item(Data::Asset&& shaderAsset, const AZ::Name& shaderTag, ShaderVariantId variantId) - : m_shaderAsset(AZStd::move(shaderAsset)) + : m_renderStatesOverlay(RHI::GetInvalidRenderStates()) + , m_shaderAsset(AZStd::move(shaderAsset)) , m_shaderVariantId(variantId) , m_shaderTag(shaderTag) , m_shaderOptionGroup(shaderAsset->GetShaderOptionGroupLayout(), variantId) From c0acbe7bd4cc17f1519efa9dee5a117c091d6be1 Mon Sep 17 00:00:00 2001 From: Guthrie Adams Date: Thu, 4 Nov 2021 12:27:18 -0500 Subject: [PATCH 17/71] =?UTF-8?q?Changed=20how=20asset=20creator=20generat?= =?UTF-8?q?es=20the=20asset=20instance.=20Instead=20of=20finding=20or=20cr?= =?UTF-8?q?eating=20the=20asset=20in=20the=20asset=20manager,=20one=20is?= =?UTF-8?q?=20directly=20instantiated=20and=20only=20added=20to=20the=20as?= =?UTF-8?q?set=20manager=20after=20creation=20is=20complete.=20This=20allo?= =?UTF-8?q?ws=20for=20reuse=20of=20previously=20loaded=20asset=20ids=20and?= =?UTF-8?q?=20will=20replace=20or=20=E2=80=9Creload=E2=80=9D=20a=20pre-exi?= =?UTF-8?q?sting=20asset=20with=20the=20newly=20created=20one.=20This=20al?= =?UTF-8?q?so=20sends=20although=20correct=20notifications.=20Changed=20ma?= =?UTF-8?q?terial=20document=20to=20load=20a=20source=20data=20are=20for?= =?UTF-8?q?=20the=20parent=20material=20as=20well.=20=20It=20was=20also=20?= =?UTF-8?q?a=20previously=20loading=20the=20parent=20material=20products?= =?UTF-8?q?=20asset=20which=20would=20be=20out=20of=20date=20compared=20to?= =?UTF-8?q?=20the=20source=20data.=20Changed=20material=20document=20to=20?= =?UTF-8?q?track=20source=20file=20dependency=20changes=20instead=20of=20p?= =?UTF-8?q?roduct=20asset=20changes.=20Fixed=20a=20bug=20or=20copy=20paste?= =?UTF-8?q?=20error=20in=20the=20document=20manager=20that=20was=20using?= =?UTF-8?q?=20the=20same=20container=20to=20track=20documents=20the=20modi?= =?UTF-8?q?fied=20externally=20and=20from=20other=20dependency=20changes.?= =?UTF-8?q?=20Returning=20source=20data=20dependencies=20when=20creating?= =?UTF-8?q?=20a=20material=20asset=20from=20source.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Guthrie Adams --- .../RPI.Edit/Material/MaterialSourceData.h | 3 +- .../Include/Atom/RPI.Reflect/AssetCreator.h | 3 +- .../RPI.Edit/Material/MaterialSourceData.cpp | 61 +++++++++++------- .../Material/MaterialTypeSourceData.cpp | 3 - .../AtomToolsDocumentSystemComponent.cpp | 14 +++-- .../AtomToolsDocumentSystemComponent.h | 4 +- .../Code/Source/Document/MaterialDocument.cpp | 63 ++++++++++--------- .../Code/Source/Document/MaterialDocument.h | 11 +--- 8 files changed, 86 insertions(+), 76 deletions(-) diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Edit/Material/MaterialSourceData.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Edit/Material/MaterialSourceData.h index 17dc4556fb..77bf45023d 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Edit/Material/MaterialSourceData.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Edit/Material/MaterialSourceData.h @@ -99,7 +99,8 @@ namespace AZ Data::AssetId assetId, AZStd::string_view materialSourceFilePath = "", bool elevateWarnings = true, - bool includeMaterialPropertyNames = true) const; + bool includeMaterialPropertyNames = true, + AZStd::unordered_set* sourceDependencies = nullptr) const; private: void ApplyPropertiesToAssetCreator( diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/AssetCreator.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/AssetCreator.h index abdbe9cdce..79d43d0b8d 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/AssetCreator.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/AssetCreator.h @@ -118,7 +118,7 @@ namespace AZ ResetIssueCounts(); // Because the asset creator can be used multiple times - m_asset = Data::AssetManager::Instance().CreateAsset(assetId, AZ::Data::AssetLoadBehavior::PreLoad); + m_asset = Data::Asset(assetId, aznew AssetDataT, AZ::Data::AssetLoadBehavior::PreLoad); m_beginCalled = true; if (!m_asset) @@ -138,6 +138,7 @@ namespace AZ } else { + Data::AssetManager::Instance().AssignAssetData(m_asset); result = AZStd::move(m_asset); success = true; } diff --git a/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialSourceData.cpp b/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialSourceData.cpp index 7ff33b2d04..c912826026 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialSourceData.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialSourceData.cpp @@ -188,14 +188,20 @@ namespace AZ } Outcome> MaterialSourceData::CreateMaterialAssetFromSourceData( - Data::AssetId assetId, AZStd::string_view materialSourceFilePath, bool elevateWarnings, bool includeMaterialPropertyNames) const + Data::AssetId assetId, + AZStd::string_view materialSourceFilePath, + bool elevateWarnings, + bool includeMaterialPropertyNames, + AZStd::unordered_set* sourceDependencies) const { - MaterialAssetCreator materialAssetCreator; - materialAssetCreator.SetElevateWarnings(elevateWarnings); + const auto materialTypeSourcePath = AssetUtils::ResolvePathReference(materialSourceFilePath, m_materialType); + const auto materialTypeAssetId = AssetUtils::MakeAssetId(materialTypeSourcePath, 0); + if (!materialTypeAssetId.IsSuccess()) + { + return Failure(); + } -#if 1 MaterialTypeSourceData materialTypeSourceData; - AZStd::string materialTypeSourcePath = AssetUtils::ResolvePathReference(materialSourceFilePath, m_materialType); if (!AZ::RPI::JsonUtils::LoadObjectFromFile(materialTypeSourcePath, materialTypeSourceData)) { return Failure(); @@ -203,21 +209,16 @@ namespace AZ materialTypeSourceData.ResolveUvEnums(); - auto materialTypeAsset = - materialTypeSourceData.CreateMaterialTypeAsset(AZ::Uuid::CreateRandom(), materialTypeSourcePath, elevateWarnings); + const auto materialTypeAsset = + materialTypeSourceData.CreateMaterialTypeAsset(materialTypeAssetId.GetValue(), materialTypeSourcePath, elevateWarnings); if (!materialTypeAsset.IsSuccess()) { return Failure(); } -#else - auto materialTypeAsset = AssetUtils::LoadAsset(materialSourceFilePath, m_materialType); - if (!materialTypeAsset.IsSuccess()) - { - return Failure(); - } -#endif - materialAssetCreator.Begin(assetId, *materialTypeAsset.GetValue().Get(), includeMaterialPropertyNames); + AZStd::unordered_set dependencies; + dependencies.insert(materialSourceFilePath); + dependencies.insert(materialTypeSourcePath); AZStd::vector parentSourceDataStack; @@ -225,6 +226,13 @@ namespace AZ AZStd::string parentSourceAbsPath = AssetUtils::ResolvePathReference(materialSourceFilePath, parentSourceRelPath); while (!parentSourceRelPath.empty()) { + if (dependencies.find(parentSourceAbsPath) != dependencies.end()) + { + return Failure(); + } + + dependencies.insert(parentSourceAbsPath); + MaterialSourceData parentSourceData; if (!AZ::RPI::JsonUtils::LoadObjectFromFile(parentSourceAbsPath, parentSourceData)) { @@ -232,20 +240,22 @@ namespace AZ } // Make sure the parent material has the same material type - auto materialTypeIdOutcome1 = AssetUtils::MakeAssetId(materialSourceFilePath, m_materialType, 0); - auto materialTypeIdOutcome2 = AssetUtils::MakeAssetId(parentSourceAbsPath, parentSourceData.m_materialType, 0); - if (!materialTypeIdOutcome1.IsSuccess() || !materialTypeIdOutcome2.IsSuccess() || - materialTypeIdOutcome1.GetValue() != materialTypeIdOutcome2.GetValue()) + const auto parentTypeAssetId = AssetUtils::MakeAssetId(parentSourceAbsPath, parentSourceData.m_materialType, 0); + if (!parentTypeAssetId || parentTypeAssetId.GetValue() != materialTypeAssetId.GetValue()) { AZ_Error("MaterialSourceData", false, "This material and its parent material do not share the same material type."); return Failure(); } - parentSourceDataStack.push_back(parentSourceData); parentSourceRelPath = parentSourceData.m_parentMaterial; parentSourceAbsPath = AssetUtils::ResolvePathReference(parentSourceAbsPath, parentSourceRelPath); + parentSourceDataStack.emplace_back(AZStd::move(parentSourceData)); } + MaterialAssetCreator materialAssetCreator; + materialAssetCreator.SetElevateWarnings(elevateWarnings); + materialAssetCreator.Begin(assetId, *materialTypeAsset.GetValue().Get(), includeMaterialPropertyNames); + while (!parentSourceDataStack.empty()) { parentSourceDataStack.back().ApplyPropertiesToAssetCreator(materialAssetCreator, materialSourceFilePath); @@ -257,12 +267,15 @@ namespace AZ Data::Asset material; if (materialAssetCreator.End(material)) { + if (sourceDependencies) + { + sourceDependencies->insert(dependencies.begin(), dependencies.end()); + } + return Success(material); } - else - { - return Failure(); - } + + return Failure(); } void MaterialSourceData::ApplyPropertiesToAssetCreator( diff --git a/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialTypeSourceData.cpp b/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialTypeSourceData.cpp index b20873141b..396ba71e14 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialTypeSourceData.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialTypeSourceData.cpp @@ -398,8 +398,6 @@ namespace AZ if (shaderAssetResult) { auto shaderAsset = shaderAssetResult.GetValue(); - shaderAsset.SetAutoLoadBehavior(Data::AssetLoadBehavior::PreLoad); - auto optionsLayout = shaderAsset->GetShaderOptionGroupLayout(); ShaderOptionGroup options{ optionsLayout }; for (auto& iter : shaderRef.m_shaderOptionValues) @@ -501,7 +499,6 @@ namespace AZ if (imageAssetResult) { auto imageAsset = imageAssetResult.GetValue(); - imageAsset.SetAutoLoadBehavior(Data::AssetLoadBehavior::PreLoad); materialTypeAssetCreator.SetPropertyValue(propertyId.GetFullName(), imageAsset); } else diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Document/AtomToolsDocumentSystemComponent.cpp b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Document/AtomToolsDocumentSystemComponent.cpp index 5652e9fe23..00de2a7c4c 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Document/AtomToolsDocumentSystemComponent.cpp +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Document/AtomToolsDocumentSystemComponent.cpp @@ -159,7 +159,7 @@ namespace AtomToolsFramework void AtomToolsDocumentSystemComponent::OnDocumentExternallyModified(const AZ::Uuid& documentId) { - m_documentIdsToReopen.insert(documentId); + m_documentIdsWithExternalChanges.insert(documentId); if (!AZ::TickBus::Handler::BusIsConnected()) { AZ::TickBus::Handler::BusConnect(); @@ -168,7 +168,7 @@ namespace AtomToolsFramework void AtomToolsDocumentSystemComponent::OnDocumentDependencyModified(const AZ::Uuid& documentId) { - m_documentIdsToReopen.insert(documentId); + m_documentIdsWithDependencyChanges.insert(documentId); if (!AZ::TickBus::Handler::BusIsConnected()) { AZ::TickBus::Handler::BusConnect(); @@ -177,7 +177,7 @@ namespace AtomToolsFramework void AtomToolsDocumentSystemComponent::OnTick([[maybe_unused]] float deltaTime, [[maybe_unused]] AZ::ScriptTimePoint time) { - for (const AZ::Uuid& documentId : m_documentIdsToReopen) + for (const AZ::Uuid& documentId : m_documentIdsWithExternalChanges) { AZStd::string documentPath; AtomToolsDocumentRequestBus::EventResult(documentPath, documentId, &AtomToolsDocumentRequestBus::Events::GetAbsolutePath); @@ -191,6 +191,8 @@ namespace AtomToolsFramework continue; } + m_documentIdsWithDependencyChanges.erase(documentId); + AtomToolsFramework::TraceRecorder traceRecorder(m_maxMessageBoxLineCount); bool openResult = false; @@ -204,7 +206,7 @@ namespace AtomToolsFramework } } - for (const AZ::Uuid& documentId : m_documentIdsToReopen) + for (const AZ::Uuid& documentId : m_documentIdsWithDependencyChanges) { AZStd::string documentPath; AtomToolsDocumentRequestBus::EventResult(documentPath, documentId, &AtomToolsDocumentRequestBus::Events::GetAbsolutePath); @@ -231,8 +233,8 @@ namespace AtomToolsFramework } } - m_documentIdsToReopen.clear(); - m_documentIdsToReopen.clear(); + m_documentIdsWithDependencyChanges.clear(); + m_documentIdsWithExternalChanges.clear(); AZ::TickBus::Handler::BusDisconnect(); } diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Document/AtomToolsDocumentSystemComponent.h b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Document/AtomToolsDocumentSystemComponent.h index 9c556a07e7..a0f5eb085d 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Document/AtomToolsDocumentSystemComponent.h +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Document/AtomToolsDocumentSystemComponent.h @@ -85,8 +85,8 @@ namespace AtomToolsFramework AZStd::intrusive_ptr m_settings; AZStd::function m_documentCreator; AZStd::unordered_map> m_documentMap; - AZStd::unordered_set m_documentIdsToRebuild; - AZStd::unordered_set m_documentIdsToReopen; + AZStd::unordered_set m_documentIdsWithExternalChanges; + AZStd::unordered_set m_documentIdsWithDependencyChanges; const size_t m_maxMessageBoxLineCount = 15; }; } // namespace AtomToolsFramework diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/Document/MaterialDocument.cpp b/Gems/Atom/Tools/MaterialEditor/Code/Source/Document/MaterialDocument.cpp index 1dcef43577..049d4c47ff 100644 --- a/Gems/Atom/Tools/MaterialEditor/Code/Source/Document/MaterialDocument.cpp +++ b/Gems/Atom/Tools/MaterialEditor/Code/Source/Document/MaterialDocument.cpp @@ -567,26 +567,26 @@ namespace MaterialEditor } } - void MaterialDocument::SourceFileChanged(AZStd::string relativePath, AZStd::string scanFolder, AZ::Uuid sourceUUID) + void MaterialDocument::SourceFileChanged(AZStd::string relativePath, AZStd::string scanFolder, [[maybe_unused]] AZ::Uuid sourceUUID) { - if (m_sourceAssetId.m_guid == sourceUUID) + auto sourcePath = AZ::RPI::AssetUtils::ResolvePathReference(scanFolder, relativePath); + + if (m_absolutePath == sourcePath) { // ignore notifications caused by saving the open document if (!m_saveTriggeredInternally) { AZ_TracePrintf("MaterialDocument", "Material document changed externally: '%s'.\n", m_absolutePath.c_str()); - AtomToolsFramework::AtomToolsDocumentNotificationBus::Broadcast(&AtomToolsFramework::AtomToolsDocumentNotificationBus::Events::OnDocumentExternallyModified, m_id); + AtomToolsFramework::AtomToolsDocumentNotificationBus::Broadcast( + &AtomToolsFramework::AtomToolsDocumentNotificationBus::Events::OnDocumentExternallyModified, m_id); } m_saveTriggeredInternally = false; } - } - - void MaterialDocument::OnAssetReloaded(AZ::Data::Asset asset) - { - if (m_dependentAssetIds.find(asset->GetId()) != m_dependentAssetIds.end()) + else if (m_sourceDependencies.find(sourcePath) != m_sourceDependencies.end()) { AZ_TracePrintf("MaterialDocument", "Material document dependency changed: '%s'.\n", m_absolutePath.c_str()); - AtomToolsFramework::AtomToolsDocumentNotificationBus::Broadcast(&AtomToolsFramework::AtomToolsDocumentNotificationBus::Events::OnDocumentDependencyModified, m_id); + AtomToolsFramework::AtomToolsDocumentNotificationBus::Broadcast( + &AtomToolsFramework::AtomToolsDocumentNotificationBus::Events::OnDocumentDependencyModified, m_id); } } @@ -655,7 +655,6 @@ namespace MaterialEditor return false; } - m_sourceAssetId = sourceAssetInfo.m_assetId; m_relativePath = sourceAssetInfo.m_relativePath; if (!AzFramework::StringFunc::Path::Normalize(m_relativePath)) { @@ -722,14 +721,15 @@ namespace MaterialEditor // we can create the asset dynamically from the source data. // Long term, the material document should not be concerned with assets at all. The viewport window should be the // only thing concerned with assets or instances. - auto createResult = m_materialSourceData.CreateMaterialAssetFromSourceData(Uuid::CreateRandom(), m_absolutePath, true); - if (!createResult) + auto materialAssetResult = + m_materialSourceData.CreateMaterialAssetFromSourceData(Uuid::CreateRandom(), m_absolutePath, true, true, &m_sourceDependencies); + if (!materialAssetResult) { AZ_Error("MaterialDocument", false, "Material asset could not be created from source data: '%s'.", m_absolutePath.c_str()); return false; } - m_materialAsset = createResult.GetValue(); + m_materialAsset = materialAssetResult.GetValue(); if (!m_materialAsset.IsReady()) { AZ_Error("MaterialDocument", false, "Material asset is not ready: '%s'.", m_absolutePath.c_str()); @@ -743,28 +743,35 @@ namespace MaterialEditor return false; } - // track material type asset to notify when dependencies change - m_dependentAssetIds.insert(materialTypeAsset->GetId()); - AZ::Data::AssetBus::MultiHandler::BusConnect(materialTypeAsset->GetId()); - AZStd::array_view parentPropertyValues = materialTypeAsset->GetDefaultPropertyValues(); AZ::Data::Asset parentMaterialAsset; if (!m_materialSourceData.m_parentMaterial.empty()) { - // There is a parent for this material - auto parentMaterialResult = AssetUtils::LoadAsset(m_absolutePath, m_materialSourceData.m_parentMaterial); - if (!parentMaterialResult) + AZ::RPI::MaterialSourceData parentMaterialSourceData; + const auto parentMaterialFilePath = AssetUtils::ResolvePathReference(m_absolutePath, m_materialSourceData.m_parentMaterial); + if (!AZ::RPI::JsonUtils::LoadObjectFromFile(parentMaterialFilePath, parentMaterialSourceData)) { - AZ_Error("MaterialDocument", false, "Parent material asset could not be loaded: '%s'.", m_materialSourceData.m_parentMaterial.c_str()); + AZ_Error("MaterialDocument", false, "Material parent source data could not be loaded for: '%s'.", parentMaterialFilePath.c_str()); return false; } - parentMaterialAsset = parentMaterialResult.GetValue(); - parentPropertyValues = parentMaterialAsset->GetPropertyValues(); + const auto parentMaterialAssetIdResult = AssetUtils::MakeAssetId(parentMaterialFilePath, 0); + if (!parentMaterialAssetIdResult) + { + AZ_Error("MaterialDocument", false, "Material parent asset ID could not be created: '%s'.", parentMaterialFilePath.c_str()); + return false; + } - // track parent material asset to notify when dependencies change - m_dependentAssetIds.insert(parentMaterialAsset->GetId()); - AZ::Data::AssetBus::MultiHandler::BusConnect(parentMaterialAsset->GetId()); + auto parentMaterialAssetResult = m_materialSourceData.CreateMaterialAssetFromSourceData( + parentMaterialAssetIdResult.GetValue(), parentMaterialFilePath, true, true, &m_sourceDependencies); + if (!parentMaterialAssetResult) + { + AZ_Error("MaterialDocument", false, "Material parent asset could not be created from source data: '%s'.", parentMaterialFilePath.c_str()); + return false; + } + + parentMaterialAsset = parentMaterialAssetResult.GetValue(); + parentPropertyValues = parentMaterialAsset->GetPropertyValues(); } // Creating a material from a material asset will fail if a texture is referenced but not loaded @@ -913,15 +920,13 @@ namespace MaterialEditor void MaterialDocument::Clear() { AZ::TickBus::Handler::BusDisconnect(); - AZ::Data::AssetBus::MultiHandler::BusDisconnect(); AzToolsFramework::AssetSystemBus::Handler::BusDisconnect(); m_materialAsset = {}; m_materialInstance = {}; m_absolutePath.clear(); m_relativePath.clear(); - m_sourceAssetId = {}; - m_dependentAssetIds.clear(); + m_sourceDependencies.clear(); m_saveTriggeredInternally = {}; m_compilePending = {}; m_properties.clear(); diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/Document/MaterialDocument.h b/Gems/Atom/Tools/MaterialEditor/Code/Source/Document/MaterialDocument.h index 03997a2a91..452111f99a 100644 --- a/Gems/Atom/Tools/MaterialEditor/Code/Source/Document/MaterialDocument.h +++ b/Gems/Atom/Tools/MaterialEditor/Code/Source/Document/MaterialDocument.h @@ -29,7 +29,6 @@ namespace MaterialEditor : public AtomToolsFramework::AtomToolsDocument , public MaterialDocumentRequestBus::Handler , private AZ::TickBus::Handler - , private AZ::Data::AssetBus::MultiHandler , private AzToolsFramework::AssetSystemBus::Handler { public: @@ -105,11 +104,6 @@ namespace MaterialEditor void SourceFileChanged(AZStd::string relativePath, AZStd::string scanFolder, AZ::Uuid sourceUUID) override; ////////////////////////////////////////////////////////////////////////// - ////////////////////////////////////////////////////////////////////////// - // AZ::Data::AssetBus::Router overrides... - void OnAssetReloaded(AZ::Data::Asset asset) override; - ////////////////////////////////////////////////////////////////////////// - bool SavePropertiesToSourceData(AZ::RPI::MaterialSourceData& sourceData, PropertyFilterFunction propertyFilter) const; bool OpenInternal(AZStd::string_view loadPath); @@ -137,11 +131,8 @@ namespace MaterialEditor // Material instance being edited AZ::Data::Instance m_materialInstance; - // Asset used to open document - AZ::Data::AssetId m_sourceAssetId; - // Set of assets that can trigger a document reload - AZStd::unordered_set m_dependentAssetIds; + AZStd::unordered_set m_sourceDependencies; // Track if document saved itself last to skip external modification notification bool m_saveTriggeredInternally = false; From 5afd701e2389d244c3ea03c529a806b20dd95993 Mon Sep 17 00:00:00 2001 From: Guthrie Adams Date: Thu, 4 Nov 2021 18:20:27 -0500 Subject: [PATCH 18/71] updated comments and error messages Signed-off-by: Guthrie Adams --- .../RPI.Edit/Material/MaterialSourceData.h | 1 + .../RPI.Edit/Material/MaterialSourceData.cpp | 25 +++++++++++++++---- 2 files changed, 21 insertions(+), 5 deletions(-) diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Edit/Material/MaterialSourceData.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Edit/Material/MaterialSourceData.h index 77bf45023d..53d3072370 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Edit/Material/MaterialSourceData.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Edit/Material/MaterialSourceData.h @@ -95,6 +95,7 @@ namespace AZ //! resolving file-relative paths. //! @param elevateWarnings Indicates whether to treat warnings as errors //! @param includeMaterialPropertyNames Indicates whether to save material property names into the material asset file + //! @param sourceDependencies if not null, will be populated with a set of all of the loaded material and material type paths Outcome> CreateMaterialAssetFromSourceData( Data::AssetId assetId, AZStd::string_view materialSourceFilePath = "", diff --git a/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialSourceData.cpp b/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialSourceData.cpp index c912826026..7c37d894d4 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialSourceData.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialSourceData.cpp @@ -198,12 +198,14 @@ namespace AZ const auto materialTypeAssetId = AssetUtils::MakeAssetId(materialTypeSourcePath, 0); if (!materialTypeAssetId.IsSuccess()) { + AZ_Error("MaterialSourceData", false, "Failed to create material type asset ID: '%s'.", materialTypeSourcePath.c_str()); return Failure(); } MaterialTypeSourceData materialTypeSourceData; if (!AZ::RPI::JsonUtils::LoadObjectFromFile(materialTypeSourcePath, materialTypeSourceData)) { + AZ_Error("MaterialSourceData", false, "Failed to load MaterialTypeSourceData: '%s'.", materialTypeSourcePath.c_str()); return Failure(); } @@ -213,45 +215,58 @@ namespace AZ materialTypeSourceData.CreateMaterialTypeAsset(materialTypeAssetId.GetValue(), materialTypeSourcePath, elevateWarnings); if (!materialTypeAsset.IsSuccess()) { + AZ_Error("MaterialSourceData", false, "Failed to create material type asset from source data: '%s'.", materialTypeSourcePath.c_str()); return Failure(); } + // Track all of the material and material type assets loaded while trying to create a material asset from source data. This will + // be used for evaluating circular dependencies and returned for external monitoring or other use. AZStd::unordered_set dependencies; dependencies.insert(materialSourceFilePath); dependencies.insert(materialTypeSourcePath); + // Load and build a stack of MaterialSourceData from all of the parent materials in the hierarchy. Properties from the source + // data will be applied in reverse to the asset creator. AZStd::vector parentSourceDataStack; AZStd::string parentSourceRelPath = m_parentMaterial; AZStd::string parentSourceAbsPath = AssetUtils::ResolvePathReference(materialSourceFilePath, parentSourceRelPath); while (!parentSourceRelPath.empty()) { - if (dependencies.find(parentSourceAbsPath) != dependencies.end()) + if (!dependencies.insert(parentSourceAbsPath).second) { + AZ_Error("MaterialSourceData", false, "Detected circular dependency between materials: '%s' and '%s'.", materialSourceFilePath, parentSourceAbsPath.c_str()); return Failure(); } - dependencies.insert(parentSourceAbsPath); - MaterialSourceData parentSourceData; if (!AZ::RPI::JsonUtils::LoadObjectFromFile(parentSourceAbsPath, parentSourceData)) { + AZ_Error("MaterialSourceData", false, "Failed to load MaterialSourceData for parent material: '%s'.", parentSourceAbsPath.c_str()); return Failure(); } - // Make sure the parent material has the same material type + // Make sure that all materials in the hierarchy share the same material type const auto parentTypeAssetId = AssetUtils::MakeAssetId(parentSourceAbsPath, parentSourceData.m_materialType, 0); - if (!parentTypeAssetId || parentTypeAssetId.GetValue() != materialTypeAssetId.GetValue()) + if (!parentTypeAssetId) + { + AZ_Error("MaterialSourceData", false, "Parent material asset ID isn't valid: '%s'.", parentSourceAbsPath.c_str()); + return Failure(); + } + + if (parentTypeAssetId.GetValue() != materialTypeAssetId.GetValue()) { AZ_Error("MaterialSourceData", false, "This material and its parent material do not share the same material type."); return Failure(); } + // Get the location of the next parent material and push the source data onto the stack parentSourceRelPath = parentSourceData.m_parentMaterial; parentSourceAbsPath = AssetUtils::ResolvePathReference(parentSourceAbsPath, parentSourceRelPath); parentSourceDataStack.emplace_back(AZStd::move(parentSourceData)); } + // Create the material asset from all the previously loaded source data MaterialAssetCreator materialAssetCreator; materialAssetCreator.SetElevateWarnings(elevateWarnings); materialAssetCreator.Begin(assetId, *materialTypeAsset.GetValue().Get(), includeMaterialPropertyNames); From 791d11c8f96cd500164688e5df225148167ead93 Mon Sep 17 00:00:00 2001 From: Guthrie Adams Date: Fri, 5 Nov 2021 22:06:31 -0500 Subject: [PATCH 19/71] Fix parent material loading Signed-off-by: Guthrie Adams --- .../RPI/Code/Source/RPI.Edit/Material/MaterialSourceData.cpp | 2 +- .../MaterialEditor/Code/Source/Document/MaterialDocument.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialSourceData.cpp b/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialSourceData.cpp index 7c37d894d4..e5466a173f 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialSourceData.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialSourceData.cpp @@ -235,7 +235,7 @@ namespace AZ { if (!dependencies.insert(parentSourceAbsPath).second) { - AZ_Error("MaterialSourceData", false, "Detected circular dependency between materials: '%s' and '%s'.", materialSourceFilePath, parentSourceAbsPath.c_str()); + AZ_Error("MaterialSourceData", false, "Detected circular dependency between materials: '%s' and '%s'.", materialSourceFilePath.data(), parentSourceAbsPath.c_str()); return Failure(); } diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/Document/MaterialDocument.cpp b/Gems/Atom/Tools/MaterialEditor/Code/Source/Document/MaterialDocument.cpp index 049d4c47ff..ee58cbea3e 100644 --- a/Gems/Atom/Tools/MaterialEditor/Code/Source/Document/MaterialDocument.cpp +++ b/Gems/Atom/Tools/MaterialEditor/Code/Source/Document/MaterialDocument.cpp @@ -762,8 +762,8 @@ namespace MaterialEditor return false; } - auto parentMaterialAssetResult = m_materialSourceData.CreateMaterialAssetFromSourceData( - parentMaterialAssetIdResult.GetValue(), parentMaterialFilePath, true, true, &m_sourceDependencies); + auto parentMaterialAssetResult = parentMaterialSourceData.CreateMaterialAssetFromSourceData( + parentMaterialAssetIdResult.GetValue(), parentMaterialFilePath, true, true); if (!parentMaterialAssetResult) { AZ_Error("MaterialDocument", false, "Material parent asset could not be created from source data: '%s'.", parentMaterialFilePath.c_str()); From c372761f4e348bf63f7f7b6b0ee930f177bfd2da Mon Sep 17 00:00:00 2001 From: Guthrie Adams Date: Sun, 7 Nov 2021 15:04:46 -0600 Subject: [PATCH 20/71] Changing lua material functor script loading code to pass the correct sub ID for a compiled script asset Signed-off-by: Guthrie Adams --- .../Source/RPI.Edit/Material/LuaMaterialFunctorSourceData.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/LuaMaterialFunctorSourceData.cpp b/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/LuaMaterialFunctorSourceData.cpp index b230953f8c..37bd5a19f2 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/LuaMaterialFunctorSourceData.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/LuaMaterialFunctorSourceData.cpp @@ -137,7 +137,7 @@ namespace AZ } else if (!m_luaSourceFile.empty()) { - auto loadOutcome = RPI::AssetUtils::LoadAsset(materialTypeSourceFilePath, m_luaSourceFile); + auto loadOutcome = RPI::AssetUtils::LoadAsset(materialTypeSourceFilePath, m_luaSourceFile, ScriptAsset::CompiledAssetSubId); if (!loadOutcome) { AZ_Error("LuaMaterialFunctorSourceData", false, "Could not load script file '%s'", m_luaSourceFile.c_str()); From dcb3ac43375b15b1fde049e8c8b9d6a3907883cd Mon Sep 17 00:00:00 2001 From: dmcdiar Date: Mon, 8 Nov 2021 17:53:03 -0700 Subject: [PATCH 21/71] Set skybox exposure during ReflectionProbe bake Signed-off-by: dmcdiar --- .../Source/ReflectionProbe/ReflectionProbe.cpp | 15 +++++++++------ .../Code/Source/ReflectionProbe/ReflectionProbe.h | 6 ++++-- .../EditorReflectionProbeComponent.cpp | 4 ++-- 3 files changed, 15 insertions(+), 10 deletions(-) diff --git a/Gems/Atom/Feature/Common/Code/Source/ReflectionProbe/ReflectionProbe.cpp b/Gems/Atom/Feature/Common/Code/Source/ReflectionProbe/ReflectionProbe.cpp index c4ea3249d5..4ac5782b04 100644 --- a/Gems/Atom/Feature/Common/Code/Source/ReflectionProbe/ReflectionProbe.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/ReflectionProbe/ReflectionProbe.cpp @@ -120,15 +120,17 @@ namespace AZ m_scene->RemoveRenderPipeline(m_environmentCubeMapPipelineId); m_environmentCubeMapPass = nullptr; - // restore exposure - sceneSrg->SetConstant(m_iblExposureConstantIndex, m_previousExposure); + // restore exposures + sceneSrg->SetConstant(m_globalIblExposureConstantIndex, m_previousGlobalIblExposure); + sceneSrg->SetConstant(m_skyBoxExposureConstantIndex, m_previousSkyBoxExposure); m_buildingCubeMap = false; } else { - // set exposure to the user specified value while baking the cubemap - sceneSrg->SetConstant(m_iblExposureConstantIndex, m_bakeExposure); + // set exposures to the user specified value while baking the cubemap + sceneSrg->SetConstant(m_globalIblExposureConstantIndex, m_bakeExposure); + sceneSrg->SetConstant(m_skyBoxExposureConstantIndex, m_bakeExposure); } } @@ -305,9 +307,10 @@ namespace AZ const RPI::Ptr& rootPass = environmentCubeMapPipeline->GetRootPass(); rootPass->AddChild(m_environmentCubeMapPass); - // store the current IBL exposure value + // store the current IBL exposure values Data::Instance sceneSrg = m_scene->GetShaderResourceGroup(); - m_previousExposure = sceneSrg->GetConstant(m_iblExposureConstantIndex); + m_previousGlobalIblExposure = sceneSrg->GetConstant(m_globalIblExposureConstantIndex); + m_previousSkyBoxExposure = sceneSrg->GetConstant(m_skyBoxExposureConstantIndex); m_scene->AddRenderPipeline(environmentCubeMapPipeline); } diff --git a/Gems/Atom/Feature/Common/Code/Source/ReflectionProbe/ReflectionProbe.h b/Gems/Atom/Feature/Common/Code/Source/ReflectionProbe/ReflectionProbe.h index 485f380463..17ef54367b 100644 --- a/Gems/Atom/Feature/Common/Code/Source/ReflectionProbe/ReflectionProbe.h +++ b/Gems/Atom/Feature/Common/Code/Source/ReflectionProbe/ReflectionProbe.h @@ -180,8 +180,10 @@ namespace AZ RPI::Ptr m_environmentCubeMapPass = nullptr; RPI::RenderPipelineId m_environmentCubeMapPipelineId; BuildCubeMapCallback m_callback; - RHI::ShaderInputNameIndex m_iblExposureConstantIndex = "m_iblExposure"; - float m_previousExposure = 0.0f; + RHI::ShaderInputNameIndex m_globalIblExposureConstantIndex = "m_iblExposure"; + RHI::ShaderInputNameIndex m_skyBoxExposureConstantIndex = "m_cubemapExposure"; + float m_previousGlobalIblExposure = 0.0f; + float m_previousSkyBoxExposure = 0.0f; bool m_buildingCubeMap = false; }; diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/ReflectionProbe/EditorReflectionProbeComponent.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/ReflectionProbe/EditorReflectionProbeComponent.cpp index c7179587c0..578c6e9300 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/ReflectionProbe/EditorReflectionProbeComponent.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/ReflectionProbe/EditorReflectionProbeComponent.cpp @@ -64,8 +64,8 @@ namespace AZ ->Attribute(AZ::Edit::Attributes::ChangeNotify, &EditorReflectionProbeComponent::BakeReflectionProbe) ->Attribute(AZ::Edit::Attributes::Visibility, &EditorReflectionProbeComponent::GetBakedCubemapVisibilitySetting) ->DataElement(AZ::Edit::UIHandlers::Slider, &EditorReflectionProbeComponent::m_bakeExposure, "Bake Exposure", "Exposure to use when baking the cubemap") - ->Attribute(AZ::Edit::Attributes::SoftMin, -5.0f) - ->Attribute(AZ::Edit::Attributes::SoftMax, 5.0f) + ->Attribute(AZ::Edit::Attributes::SoftMin, -16.0f) + ->Attribute(AZ::Edit::Attributes::SoftMax, 16.0f) ->Attribute(AZ::Edit::Attributes::Min, -20.0f) ->Attribute(AZ::Edit::Attributes::Max, 20.0f) ->Attribute(AZ::Edit::Attributes::ChangeNotify, &EditorReflectionProbeComponent::OnBakeExposureChanged) From 487ac2b516fd27b39e5cd18d68e44990afe9a9dd Mon Sep 17 00:00:00 2001 From: nvsickle Date: Mon, 8 Nov 2021 17:37:32 -0800 Subject: [PATCH 22/71] 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 23/71] 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 af08cc5ab319c7275d367f6af9305d3107276099 Mon Sep 17 00:00:00 2001 From: sphrose <82213493+sphrose@users.noreply.github.com> Date: Tue, 9 Nov 2021 10:05:33 +0000 Subject: [PATCH 24/71] Various bug fixes. Signed-off-by: sphrose <82213493+sphrose@users.noreply.github.com> --- .../TerrainSurfaceMaterialsListComponent.cpp | 13 +++++++++---- .../TerrainSurfaceMaterialsListComponent.h | 4 ++-- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/Gems/Terrain/Code/Source/TerrainRenderer/Components/TerrainSurfaceMaterialsListComponent.cpp b/Gems/Terrain/Code/Source/TerrainRenderer/Components/TerrainSurfaceMaterialsListComponent.cpp index 271919070c..7da6130f7b 100644 --- a/Gems/Terrain/Code/Source/TerrainRenderer/Components/TerrainSurfaceMaterialsListComponent.cpp +++ b/Gems/Terrain/Code/Source/TerrainRenderer/Components/TerrainSurfaceMaterialsListComponent.cpp @@ -74,7 +74,7 @@ namespace Terrain ->DataElement( AZ::Edit::UIHandlers::Default, &TerrainSurfaceMaterialsListConfig::m_surfaceMaterials, - "Gradient to Material Mappings", "Maps surfaces to materials."); + "Material Mappings", "Maps surfaces to materials."); } } } @@ -112,6 +112,11 @@ namespace Terrain { } + TerrainSurfaceMaterialsListComponent ::~TerrainSurfaceMaterialsListComponent() + { + Deactivate(); + } + void TerrainSurfaceMaterialsListComponent::Activate() { m_cachedAabb = AZ::Aabb::CreateNull(); @@ -123,7 +128,7 @@ namespace Terrain { surfaceMaterialMapping.m_active = false; surfaceMaterialMapping.m_materialAsset.QueueLoad(); - AZ::Data::AssetBus::Handler::BusConnect(surfaceMaterialMapping.m_materialAsset.GetId()); + AZ::Data::AssetBus::MultiHandler::BusConnect(surfaceMaterialMapping.m_materialAsset.GetId()); } } } @@ -136,7 +141,7 @@ namespace Terrain { if (surfaceMaterialMapping.m_materialAsset.GetId().IsValid()) { - AZ::Data::AssetBus::Handler::BusDisconnect(surfaceMaterialMapping.m_materialAsset.GetId()); + AZ::Data::AssetBus::MultiHandler::BusDisconnect(surfaceMaterialMapping.m_materialAsset.GetId()); surfaceMaterialMapping.m_materialAsset.Release(); surfaceMaterialMapping.m_materialInstance.reset(); surfaceMaterialMapping.m_activeMaterialAssetId = AZ::Data::AssetId(); @@ -202,7 +207,7 @@ namespace Terrain // Don't disconnect from the AssetBus if this material is mapped more than once. if (CountMaterialIDInstances(surfaceMaterialMapping.m_activeMaterialAssetId) == 1) { - AZ::Data::AssetBus::Handler::BusDisconnect(surfaceMaterialMapping.m_activeMaterialAssetId); + AZ::Data::AssetBus::MultiHandler::BusDisconnect(surfaceMaterialMapping.m_activeMaterialAssetId); } surfaceMaterialMapping.m_activeMaterialAssetId = AZ::Data::AssetId(); diff --git a/Gems/Terrain/Code/Source/TerrainRenderer/Components/TerrainSurfaceMaterialsListComponent.h b/Gems/Terrain/Code/Source/TerrainRenderer/Components/TerrainSurfaceMaterialsListComponent.h index 7c36033c41..a6650bf035 100644 --- a/Gems/Terrain/Code/Source/TerrainRenderer/Components/TerrainSurfaceMaterialsListComponent.h +++ b/Gems/Terrain/Code/Source/TerrainRenderer/Components/TerrainSurfaceMaterialsListComponent.h @@ -53,7 +53,7 @@ namespace Terrain class TerrainSurfaceMaterialsListComponent : public AZ::Component , private TerrainAreaMaterialRequestBus::Handler - , private AZ::Data::AssetBus::Handler + , private AZ::Data::AssetBus::MultiHandler , private LmbrCentral::ShapeComponentNotificationsBus::Handler { public: @@ -67,7 +67,7 @@ namespace Terrain TerrainSurfaceMaterialsListComponent(const TerrainSurfaceMaterialsListConfig& configuration); TerrainSurfaceMaterialsListComponent() = default; - ~TerrainSurfaceMaterialsListComponent() = default; + ~TerrainSurfaceMaterialsListComponent(); ////////////////////////////////////////////////////////////////////////// // AZ::Component interface implementation 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 25/71] 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 26/71] 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 27/71] 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 bff8a2e147f66403b19f9658d556c5be9c6aaedc Mon Sep 17 00:00:00 2001 From: sphrose <82213493+sphrose@users.noreply.github.com> Date: Tue, 9 Nov 2021 16:00:26 +0000 Subject: [PATCH 28/71] improved fix Signed-off-by: sphrose <82213493+sphrose@users.noreply.github.com> --- .../Components/TerrainSurfaceMaterialsListComponent.cpp | 7 +------ .../Components/TerrainSurfaceMaterialsListComponent.h | 2 +- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/Gems/Terrain/Code/Source/TerrainRenderer/Components/TerrainSurfaceMaterialsListComponent.cpp b/Gems/Terrain/Code/Source/TerrainRenderer/Components/TerrainSurfaceMaterialsListComponent.cpp index 7da6130f7b..1dbcbd1120 100644 --- a/Gems/Terrain/Code/Source/TerrainRenderer/Components/TerrainSurfaceMaterialsListComponent.cpp +++ b/Gems/Terrain/Code/Source/TerrainRenderer/Components/TerrainSurfaceMaterialsListComponent.cpp @@ -112,11 +112,6 @@ namespace Terrain { } - TerrainSurfaceMaterialsListComponent ::~TerrainSurfaceMaterialsListComponent() - { - Deactivate(); - } - void TerrainSurfaceMaterialsListComponent::Activate() { m_cachedAabb = AZ::Aabb::CreateNull(); @@ -243,7 +238,7 @@ namespace Terrain // All materials have been deactivated, stop listening for requests and notifications. m_cachedAabb = AZ::Aabb::CreateNull(); LmbrCentral::ShapeComponentNotificationsBus::Handler::BusDisconnect(); - TerrainAreaMaterialRequestBus::Handler::BusConnect(GetEntityId()); + TerrainAreaMaterialRequestBus::Handler::BusDisconnect(); } } diff --git a/Gems/Terrain/Code/Source/TerrainRenderer/Components/TerrainSurfaceMaterialsListComponent.h b/Gems/Terrain/Code/Source/TerrainRenderer/Components/TerrainSurfaceMaterialsListComponent.h index a6650bf035..72eee5f68e 100644 --- a/Gems/Terrain/Code/Source/TerrainRenderer/Components/TerrainSurfaceMaterialsListComponent.h +++ b/Gems/Terrain/Code/Source/TerrainRenderer/Components/TerrainSurfaceMaterialsListComponent.h @@ -67,7 +67,7 @@ namespace Terrain TerrainSurfaceMaterialsListComponent(const TerrainSurfaceMaterialsListConfig& configuration); TerrainSurfaceMaterialsListComponent() = default; - ~TerrainSurfaceMaterialsListComponent(); + ~TerrainSurfaceMaterialsListComponent() = default; ////////////////////////////////////////////////////////////////////////// // AZ::Component interface implementation 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 29/71] 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 c182b213ad8a4f965fd2f6e786b05103b0ce4204 Mon Sep 17 00:00:00 2001 From: brianherrera Date: Tue, 9 Nov 2021 10:02:11 -0800 Subject: [PATCH 30/71] Remove timeout in the mount step We no longer need a timeout here. A timeout mechanism was added to the mount script to raise an exeception if the EBS volume is not mounted in the configured timeframe. This also causes a bug with the retry mechanism where Jenkins will hit this timeout in the event the node goes offline during the setup stage instead of raising an exception. Signed-off-by: brianherrera --- scripts/build/Jenkins/Jenkinsfile | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/scripts/build/Jenkins/Jenkinsfile b/scripts/build/Jenkins/Jenkinsfile index 1388366661..34732a5fad 100644 --- a/scripts/build/Jenkins/Jenkinsfile +++ b/scripts/build/Jenkins/Jenkinsfile @@ -277,9 +277,7 @@ def HandleDriveMount(String snapshot, String repositoryName, String projectName, if(recreateVolume) { palSh("${pythonCmd} ${INCREMENTAL_BUILD_SCRIPT_PATH} --action delete --repository_name ${repositoryName} --project ${projectName} --pipeline ${pipeline} --branch ${branchName} --platform ${platform} --build_type ${buildType}", 'Deleting volume', winSlashReplacement=false) } - timeout(5) { - palSh("${pythonCmd} ${INCREMENTAL_BUILD_SCRIPT_PATH} --action mount --snapshot ${snapshot} --repository_name ${repositoryName} --project ${projectName} --pipeline ${pipeline} --branch ${branchName} --platform ${platform} --build_type ${buildType}", 'Mounting volume', winSlashReplacement=false) - } + palSh("${pythonCmd} ${INCREMENTAL_BUILD_SCRIPT_PATH} --action mount --snapshot ${snapshot} --repository_name ${repositoryName} --project ${projectName} --pipeline ${pipeline} --branch ${branchName} --platform ${platform} --build_type ${buildType}", 'Mounting volume', winSlashReplacement=false) if(env.IS_UNIX) { sh label: 'Setting volume\'s ownership', 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 31/71] [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() ]=]) From eb60dd404b4ba9286981bc24d901ee4cfbc80786 Mon Sep 17 00:00:00 2001 From: dmcdiar Date: Tue, 9 Nov 2021 12:17:58 -0700 Subject: [PATCH 32/71] Moved probe exposure to specular only, since it's not used by the diffuse Signed-off-by: dmcdiar --- .../Assets/ShaderLib/Atom/Features/PBR/Lights/Ibl.azsli | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/PBR/Lights/Ibl.azsli b/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/PBR/Lights/Ibl.azsli index 31439de144..3254b8e4ed 100644 --- a/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/PBR/Lights/Ibl.azsli +++ b/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/PBR/Lights/Ibl.azsli @@ -85,12 +85,12 @@ void ApplyIBL(Surface surface, inout LightingData lightingData) if(useIbl) { - float exposure = pow(2.0, ObjectSrg::m_reflectionProbeData.m_exposure); + float globalIblExposure = pow(2.0, SceneSrg::m_iblExposure); if(useDiffuseIbl) { float3 iblDiffuse = GetIblDiffuse(surface.normal, surface.albedo, lightingData.diffuseResponse); - lightingData.diffuseLighting += (iblDiffuse * exposure * lightingData.diffuseAmbientOcclusion); + lightingData.diffuseLighting += (iblDiffuse * globalIblExposure * lightingData.diffuseAmbientOcclusion); } if(useSpecularIbl) @@ -116,6 +116,7 @@ void ApplyIBL(Surface surface, inout LightingData lightingData) iblSpecular = iblSpecular * (1.0 - clearCoatResponse) * (1.0 - clearCoatResponse) + clearCoatIblSpecular; } + float exposure = ObjectSrg::m_reflectionProbeData.m_useReflectionProbe ? pow(2.0, ObjectSrg::m_reflectionProbeData.m_exposure) : globalIblExposure; lightingData.specularLighting += (iblSpecular * exposure); } } From e3b1c4b7d09b63bea6503c66f9686b6f9fa4556e Mon Sep 17 00:00:00 2001 From: jiaweig <51759646+jiaweig-amzn@users.noreply.github.com> Date: Tue, 9 Nov 2021 11:27:32 -0800 Subject: [PATCH 33/71] Move swapchain and image recreation to the end of the frame (#5388) Signed-off-by: jiaweig --- .../RHI/Code/Include/Atom/RHI/SwapChain.h | 11 ++ .../RHI/FrameGraphAttachmentDatabase.cpp | 8 +- Gems/Atom/RHI/Code/Source/RHI/SwapChain.cpp | 145 ++++++++---------- .../RHI/Vulkan/Code/Source/RHI/SwapChain.cpp | 22 ++- .../RHI/Vulkan/Code/Source/RHI/SwapChain.h | 1 + 5 files changed, 101 insertions(+), 86 deletions(-) diff --git a/Gems/Atom/RHI/Code/Include/Atom/RHI/SwapChain.h b/Gems/Atom/RHI/Code/Include/Atom/RHI/SwapChain.h index 97ac3baa90..abad1fb263 100644 --- a/Gems/Atom/RHI/Code/Include/Atom/RHI/SwapChain.h +++ b/Gems/Atom/RHI/Code/Include/Atom/RHI/SwapChain.h @@ -75,6 +75,9 @@ namespace AZ //! Return True if the swap chain prefers exclusive full screen mode and a transition happened, false otherwise. virtual bool SetExclusiveFullScreenState([[maybe_unused]]bool fullScreenState) { return false; } + //! Recreate the swapchain if it becomes invalid during presenting. This should happen at the end of the frame + //! due to images being used as attachments in the frame graph. + virtual void ProcessRecreation() {}; protected: SwapChain(); @@ -98,6 +101,14 @@ namespace AZ ////////////////////////////////////////////////////////////////////////// + //! Shutdown and clear all the images. + void ShutdownImages(); + + //! Initialized all the images. + ResultCode InitImages(); + + //! Flag indicating if swapchain recreation is needed at the end of the frame. + bool m_pendingRecreation = false; private: bool ValidateDescriptor(const SwapChainDescriptor& descriptor) const; diff --git a/Gems/Atom/RHI/Code/Source/RHI/FrameGraphAttachmentDatabase.cpp b/Gems/Atom/RHI/Code/Source/RHI/FrameGraphAttachmentDatabase.cpp index 6bac2b8c7d..388277ff59 100644 --- a/Gems/Atom/RHI/Code/Source/RHI/FrameGraphAttachmentDatabase.cpp +++ b/Gems/Atom/RHI/Code/Source/RHI/FrameGraphAttachmentDatabase.cpp @@ -134,7 +134,6 @@ namespace AZ m_scopeAttachmentLookup.clear(); m_imageAttachments.clear(); m_bufferAttachments.clear(); - m_swapChainAttachments.clear(); m_importedImageAttachments.clear(); m_importedBufferAttachments.clear(); m_transientImageAttachments.clear(); @@ -153,6 +152,13 @@ namespace AZ delete attachment; } m_attachments.clear(); + + for (auto swapchainAttachment : m_swapChainAttachments) + { + swapchainAttachment->GetSwapChain()->ProcessRecreation(); + } + + m_swapChainAttachments.clear(); } ImageDescriptor FrameGraphAttachmentDatabase::GetImageDescriptor(const AttachmentId& attachmentId) const diff --git a/Gems/Atom/RHI/Code/Source/RHI/SwapChain.cpp b/Gems/Atom/RHI/Code/Source/RHI/SwapChain.cpp index ff1f0e69a6..074eedf1b6 100644 --- a/Gems/Atom/RHI/Code/Source/RHI/SwapChain.cpp +++ b/Gems/Atom/RHI/Code/Source/RHI/SwapChain.cpp @@ -58,43 +58,68 @@ namespace AZ // Overwrite descriptor dimensions with the native ones (the ones assigned by the platform) returned by InitInternal. m_descriptor.m_dimensions = nativeDimensions; - m_images.reserve(m_descriptor.m_dimensions.m_imageCount); + resultCode = InitImages(); + } - for (uint32_t imageIdx = 0; imageIdx < m_descriptor.m_dimensions.m_imageCount; ++imageIdx) - { - m_images.emplace_back(RHI::Factory::Get().CreateImage()); - } + return resultCode; + } - InitImageRequest request; + void SwapChain::ShutdownImages() + { + // Shutdown existing set of images. + uint32_t imageSize = aznumeric_cast(m_images.size()); + for (uint32_t imageIdx = 0; imageIdx < imageSize; ++imageIdx) + { + m_images[imageIdx]->Shutdown(); + } - RHI::ImageDescriptor& imageDescriptor = request.m_descriptor; - imageDescriptor.m_dimension = RHI::ImageDimension::Image2D; - imageDescriptor.m_bindFlags = RHI::ImageBindFlags::Color; - imageDescriptor.m_size.m_width = m_descriptor.m_dimensions.m_imageWidth; - imageDescriptor.m_size.m_height = m_descriptor.m_dimensions.m_imageHeight; - imageDescriptor.m_format = m_descriptor.m_dimensions.m_imageFormat; + m_images.clear(); + } - for (uint32_t imageIdx = 0; imageIdx < m_descriptor.m_dimensions.m_imageCount; ++imageIdx) - { - request.m_image = m_images[imageIdx].get(); - request.m_imageIndex = imageIdx; + ResultCode SwapChain::InitImages() + { + ResultCode resultCode = ResultCode::Success; - resultCode = ImagePoolBase::InitImage( - request.m_image, - imageDescriptor, - [this, &request]() + m_images.reserve(m_descriptor.m_dimensions.m_imageCount); + + // If the new display mode has more buffers, add them. + for (uint32_t i = 0; i < m_descriptor.m_dimensions.m_imageCount; ++i) + { + m_images.emplace_back(RHI::Factory::Get().CreateImage()); + } + + InitImageRequest request; + + RHI::ImageDescriptor& imageDescriptor = request.m_descriptor; + imageDescriptor.m_dimension = RHI::ImageDimension::Image2D; + imageDescriptor.m_bindFlags = RHI::ImageBindFlags::Color; + imageDescriptor.m_size.m_width = m_descriptor.m_dimensions.m_imageWidth; + imageDescriptor.m_size.m_height = m_descriptor.m_dimensions.m_imageHeight; + imageDescriptor.m_format = m_descriptor.m_dimensions.m_imageFormat; + + for (uint32_t imageIdx = 0; imageIdx < m_descriptor.m_dimensions.m_imageCount; ++imageIdx) + { + request.m_image = m_images[imageIdx].get(); + request.m_imageIndex = imageIdx; + + resultCode = ImagePoolBase::InitImage( + request.m_image, imageDescriptor, + [this, &request]() { return InitImageInternal(request); }); - if (resultCode != ResultCode::Success) - { - Shutdown(); - break; - } + if (resultCode != ResultCode::Success) + { + AZ_Error("Swapchain", false, "Failed to initialize images."); + Shutdown(); + break; } } + // Reset the current index back to 0 so we match the platform swap chain. + m_currentImageIndex = 0; + return resultCode; } @@ -105,63 +130,15 @@ namespace AZ } ResultCode SwapChain::Resize(const RHI::SwapChainDimensions& dimensions) - { - // Shutdown existing set of images. - for (uint32_t imageIdx = 0; imageIdx < GetImageCount(); ++imageIdx) - { - m_images[imageIdx]->Shutdown(); - } + { + ShutdownImages(); SwapChainDimensions nativeDimensions = dimensions; ResultCode resultCode = ResizeInternal(dimensions, &nativeDimensions); if (resultCode == ResultCode::Success) { m_descriptor.m_dimensions = nativeDimensions; - m_images.reserve(m_descriptor.m_dimensions.m_imageCount); - - // If the new display mode has more buffers, add them. - while (m_images.size() < static_cast(m_descriptor.m_dimensions.m_imageCount)) - { - m_images.emplace_back(RHI::Factory::Get().CreateImage()); - } - - // If it has fewer, trim down. - while (m_images.size() > static_cast(m_descriptor.m_dimensions.m_imageCount)) - { - m_images.pop_back(); - } - - InitImageRequest request; - - RHI::ImageDescriptor& imageDescriptor = request.m_descriptor; - imageDescriptor.m_dimension = RHI::ImageDimension::Image2D; - imageDescriptor.m_bindFlags = RHI::ImageBindFlags::Color; - imageDescriptor.m_size.m_width = m_descriptor.m_dimensions.m_imageWidth; - imageDescriptor.m_size.m_height = m_descriptor.m_dimensions.m_imageHeight; - imageDescriptor.m_format = m_descriptor.m_dimensions.m_imageFormat; - - for (uint32_t imageIdx = 0; imageIdx < GetImageCount(); ++imageIdx) - { - request.m_image = m_images[imageIdx].get(); - request.m_imageIndex = imageIdx; - - resultCode = ImagePoolBase::InitImage( - request.m_image, - imageDescriptor, - [this, &request]() - { - return InitImageInternal(request); - }); - - if (resultCode != ResultCode::Success) - { - Shutdown(); - break; - } - } - - // Reset the current index back to 0 so we match the platform swap chain. - m_currentImageIndex = 0; + resultCode = InitImages(); } return resultCode; @@ -188,7 +165,7 @@ namespace AZ uint32_t SwapChain::GetImageCount() const { - return static_cast(m_images.size()); + return aznumeric_cast(m_images.size()); } uint32_t SwapChain::GetCurrentImageIndex() const @@ -209,8 +186,18 @@ namespace AZ void SwapChain::Present() { AZ_TRACE_METHOD(); - m_currentImageIndex = PresentInternal(); - AZ_Assert(m_currentImageIndex < m_images.size(), "Invalid image index"); + // Due to swapchain recreation, the images are refreshed. + // There is no need to present swapchain for this frame. + const uint32_t imageCount = aznumeric_cast(m_images.size()); + if (imageCount == 0) + { + return; + } + else + { + m_currentImageIndex = PresentInternal(); + AZ_Assert(m_currentImageIndex < imageCount, "Invalid image index"); + } } } } diff --git a/Gems/Atom/RHI/Vulkan/Code/Source/RHI/SwapChain.cpp b/Gems/Atom/RHI/Vulkan/Code/Source/RHI/SwapChain.cpp index bef2b154e1..19c88ec34f 100644 --- a/Gems/Atom/RHI/Vulkan/Code/Source/RHI/SwapChain.cpp +++ b/Gems/Atom/RHI/Vulkan/Code/Source/RHI/SwapChain.cpp @@ -59,6 +59,19 @@ namespace AZ m_swapChainBarrier.m_isValid = true; } + void SwapChain::ProcessRecreation() + { + if (m_pendingRecreation) + { + ShutdownImages(); + InvalidateNativeSwapChain(); + CreateSwapchain(); + InitImages(); + + m_pendingRecreation = false; + } + } + void SwapChain::SetVerticalSyncIntervalInternal(uint32_t previousVsyncInterval) { if (GetDescriptor().m_verticalSyncInterval == 0 || previousVsyncInterval == 0) @@ -231,8 +244,7 @@ namespace AZ // VK_SUBOPTIMAL_KHR is treated as success, but we better update the surface info as well. if (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR) { - InvalidateNativeSwapChain(); - CreateSwapchain(); + m_pendingRecreation = true; } else { @@ -246,18 +258,16 @@ namespace AZ } }; - m_presentationQueue->QueueCommand(AZStd::move(presentCommand)); - uint32_t acquiredImageIndex = GetCurrentImageIndex(); RHI::ResultCode result = AcquireNewImage(&acquiredImageIndex); if (result == RHI::ResultCode::Fail) { - InvalidateNativeSwapChain(); - CreateSwapchain(); + m_pendingRecreation = true; return 0; } else { + m_presentationQueue->QueueCommand(AZStd::move(presentCommand)); return acquiredImageIndex; } } diff --git a/Gems/Atom/RHI/Vulkan/Code/Source/RHI/SwapChain.h b/Gems/Atom/RHI/Vulkan/Code/Source/RHI/SwapChain.h index ee2ff3c207..68abc97b2d 100644 --- a/Gems/Atom/RHI/Vulkan/Code/Source/RHI/SwapChain.h +++ b/Gems/Atom/RHI/Vulkan/Code/Source/RHI/SwapChain.h @@ -51,6 +51,7 @@ namespace AZ void QueueBarrier(const VkPipelineStageFlags src, const VkPipelineStageFlags dst, const VkImageMemoryBarrier& imageBarrier); + void ProcessRecreation() override; private: SwapChain() = default; From 7cc9c584b78a1c66e714a95d046a1123849f4f10 Mon Sep 17 00:00:00 2001 From: Chris Galvan Date: Tue, 9 Nov 2021 13:53:04 -0600 Subject: [PATCH 34/71] Ensure QtForPython is a proper dependency for the PythonToolGem. Signed-off-by: Chris Galvan --- Templates/PythonToolGem/Template/Code/CMakeLists.txt | 2 ++ Templates/PythonToolGem/Template/gem.json | 5 ++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/Templates/PythonToolGem/Template/Code/CMakeLists.txt b/Templates/PythonToolGem/Template/Code/CMakeLists.txt index a6044e717b..b90f2d7703 100644 --- a/Templates/PythonToolGem/Template/Code/CMakeLists.txt +++ b/Templates/PythonToolGem/Template/Code/CMakeLists.txt @@ -53,6 +53,8 @@ if(PAL_TRAIT_BUILD_HOST_TOOLS) BUILD_DEPENDENCIES PUBLIC Gem::${Name}.Editor.Static + RUNTIME_DEPENDENCIES + Gem::QtForPython.Editor ) # By default, we will specify that the above target ${Name} would be used by diff --git a/Templates/PythonToolGem/Template/gem.json b/Templates/PythonToolGem/Template/gem.json index d4ff637bee..84f5b65a3e 100644 --- a/Templates/PythonToolGem/Template/gem.json +++ b/Templates/PythonToolGem/Template/gem.json @@ -13,5 +13,8 @@ "${Name}" ], "icon_path": "preview.png", - "requirements": "" + "requirements": "", + "dependencies": [ + "QtForPython" + ] } From caf1c18fbe8bd84d6788615323ac6e9f23732738 Mon Sep 17 00:00:00 2001 From: chiyenteng <82238204+chiyenteng@users.noreply.github.com> Date: Tue, 9 Nov 2021 12:40:56 -0800 Subject: [PATCH 35/71] Prevent track editor view's default size to be zero (#5453) * Prevent track editor view's default size to be zero Signed-off-by: chiyteng * minor rewording Signed-off-by: chiyteng --- Gems/LyShine/Code/Editor/Animation/UiAnimViewDialog.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Gems/LyShine/Code/Editor/Animation/UiAnimViewDialog.cpp b/Gems/LyShine/Code/Editor/Animation/UiAnimViewDialog.cpp index e6c2dda74c..9ad9a50aa5 100644 --- a/Gems/LyShine/Code/Editor/Animation/UiAnimViewDialog.cpp +++ b/Gems/LyShine/Code/Editor/Animation/UiAnimViewDialog.cpp @@ -257,6 +257,7 @@ BOOL CUiAnimViewDialog::OnInitDialog() m_wndSplitter->addWidget(m_wndDopeSheet); m_wndSplitter->setStretchFactor(0, 1); m_wndSplitter->setStretchFactor(1, 10); + m_wndSplitter->setChildrenCollapsible(false); l->addWidget(m_wndSplitter); w->setLayout(l); setCentralWidget(w); @@ -283,6 +284,11 @@ BOOL CUiAnimViewDialog::OnInitDialog() m_wndCurveEditorDock->setVisible(false); m_wndCurveEditorDock->setEnabled(false); + // In order to prevent the track editor view from collapsing and becoming invisible, we use the + // minimum size of the curve editor for the track editor as well. Since both editors use the same + // view widget in the UI animation editor when not in 'Both' mode, the sizes can be identical. + m_wndDopeSheet->setMinimumSize(m_wndCurveEditor->minimumSizeHint()); + InitSequences(); m_lazyInitDone = false; From 461b63c61a4c4f8a45687ec1959ffe1a2401eb92 Mon Sep 17 00:00:00 2001 From: Alex Peterson <26804013+AMZN-alexpete@users.noreply.github.com> Date: Tue, 9 Nov 2021 14:14:13 -0800 Subject: [PATCH 36/71] Temporarily disable the platform filter (#5454) Signed-off-by: Alex Peterson <26804013+AMZN-alexpete@users.noreply.github.com> --- Code/Tools/ProjectManager/Source/GemCatalog/GemFilterWidget.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemFilterWidget.cpp b/Code/Tools/ProjectManager/Source/GemCatalog/GemFilterWidget.cpp index b608445d0f..acea6ce378 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemFilterWidget.cpp +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemFilterWidget.cpp @@ -221,7 +221,6 @@ namespace O3DE::ProjectManager ResetGemStatusFilter(); ResetGemOriginFilter(); ResetTypeFilter(); - ResetPlatformFilter(); ResetFeatureFilter(); } From c8b9f05079fd974d904504a63b77775b6e9d002c Mon Sep 17 00:00:00 2001 From: Gene Walters Date: Tue, 9 Nov 2021 15:35:17 -0800 Subject: [PATCH 37/71] Ensuring the 4 types of RPCs (1)Autonomous->Authority (2)Authority->Autonomous (3)Authority->Client and (4)Server->Authority all compile. Invoking anything that starts from Autonomous or Authority requires a controller (otherwise just requires a component), and anything handled by Authority or Autonomous requires a controller for Handle on OnEvent methods (otherwise OnEvent and Handle occurs on the component) Signed-off-by: Gene Walters --- .../AutoGen/AutoComponent_Header.jinja | 28 +++---- .../AutoGen/AutoComponent_Source.jinja | 78 ++++++++++--------- 2 files changed, 57 insertions(+), 49 deletions(-) diff --git a/Gems/Multiplayer/Code/Include/Multiplayer/AutoGen/AutoComponent_Header.jinja b/Gems/Multiplayer/Code/Include/Multiplayer/AutoGen/AutoComponent_Header.jinja index 5cfeb250fa..b78b7cffba 100644 --- a/Gems/Multiplayer/Code/Include/Multiplayer/AutoGen/AutoComponent_Header.jinja +++ b/Gems/Multiplayer/Code/Include/Multiplayer/AutoGen/AutoComponent_Header.jinja @@ -443,35 +443,31 @@ namespace {{ Component.attrib['Namespace'] }} {{ DeclareNetworkPropertyAccessors(Component, 'Autonomous', 'Authority', false)|indent(8) -}} {{ DeclareNetworkPropertyAccessors(Component, 'Autonomous', 'Authority', true)|indent(8) -}} {{ DeclareArchetypePropertyGetters(Component)|indent(8) -}} - {{ DeclareRpcInvocations(Component, 'Client', 'Authority', false)|indent(8) -}} - {{ DeclareRpcInvocations(Component, 'Client', 'Authority', true)|indent(8) -}} {{ DeclareRpcInvocations(Component, 'Autonomous', 'Authority', false)|indent(8) -}} {{ DeclareRpcInvocations(Component, 'Autonomous', 'Authority', true)|indent(8) -}} {{ DeclareRpcInvocations(Component, 'Authority', 'Autonomous', false)|indent(8) -}} {{ DeclareRpcInvocations(Component, 'Authority', 'Autonomous', true)|indent(8) -}} {{ DeclareRpcInvocations(Component, 'Authority', 'Client', false)|indent(8) -}} {{ DeclareRpcInvocations(Component, 'Authority', 'Client', true)|indent(8) -}} + + //! RPC Handlers: Override handlers in order ti implement what happens after receiving an RPC {{ AutoComponentMacros.DeclareRpcHandlers(Component, 'Server', 'Authority', false)|indent(8) -}} - {{ AutoComponentMacros.DeclareRpcHandlers(Component, 'Client', 'Authority', false)|indent(8) -}} {{ AutoComponentMacros.DeclareRpcHandlers(Component, 'Autonomous', 'Authority', false)|indent(8) -}} {{ AutoComponentMacros.DeclareRpcHandlers(Component, 'Authority', 'Autonomous', false)|indent(8) -}} - {{ AutoComponentMacros.DeclareRpcSignals(Component, 'Server', 'Authority')|indent(8) -}} - {{ AutoComponentMacros.DeclareRpcSignals(Component, 'Client', 'Authority')|indent(8) -}} - {{ AutoComponentMacros.DeclareRpcSignals(Component, 'Autonomous', 'Authority')|indent(8) -}} - {{ AutoComponentMacros.DeclareRpcSignals(Component, 'Authority', 'Autonomous')|indent(8) -}} + + //! RPC Event Getters: Subscribe to these events and get notified when an RPC is received {{ AutoComponentMacros.DeclareRpcEventGetters(Component, 'Server', 'Authority')|indent(8) -}} - {{ AutoComponentMacros.DeclareRpcEventGetters(Component, 'Client', 'Authority')|indent(8) -}} {{ AutoComponentMacros.DeclareRpcEventGetters(Component, 'Autonomous', 'Authority')|indent(8) -}} - {{ AutoComponentMacros.DeclareRpcEventGetters(Component, 'Authority', 'Autonomous')|indent(8) }} + {{ AutoComponentMacros.DeclareRpcEventGetters(Component, 'Authority', 'Autonomous')|indent(8) -}} + {% for Service in Component.iter('ComponentRelation') %} {% if (Service.attrib['HasController']|booleanTrue) and (Service.attrib['Constraint'] != 'Incompatible') %} {{ Service.attrib['Namespace'] }}::{{ Service.attrib['Name'] }}Controller* Get{{ Service.attrib['Name'] }}Controller(); {% endif %} {% endfor %} - + protected: {{ AutoComponentMacros.DeclareRpcEvents(Component, 'Server', 'Authority')|indent(8) -}} - {{ AutoComponentMacros.DeclareRpcEvents(Component, 'Client', 'Authority')|indent(8) -}} {{ AutoComponentMacros.DeclareRpcEvents(Component, 'Autonomous', 'Authority')|indent(8) -}} {{ AutoComponentMacros.DeclareRpcEvents(Component, 'Authority', 'Autonomous')|indent(8) }} }; @@ -517,6 +513,8 @@ namespace {{ Component.attrib['Namespace'] }} {{ DeclareNetworkPropertyGetters(Component, 'Autonomous', 'Authority', false)|indent(8) -}} {{ DeclareArchetypePropertyGetters(Component)|indent(8) -}} {{ DeclareRpcInvocations(Component, 'Server', 'Authority', false)|indent(8) -}} + + //! RPC Event Getters: Subscribe to these events and get notified when this component receives an RPC {{ AutoComponentMacros.DeclareRpcEventGetters(Component, 'Authority', 'Client')|indent(8) -}} //! MultiplayerComponent interface @@ -541,9 +539,13 @@ namespace {{ Component.attrib['Namespace'] }} {{ DeclareNetworkPropertyGetters(Component, 'Authority', 'Client', true)|indent(8) -}} {{ DeclareNetworkPropertyGetters(Component, 'Autonomous', 'Authority', true)|indent(8) -}} {{ DeclareRpcInvocations(Component, 'Server', 'Authority', true)|indent(8) -}} + + //! RPC Handlers: Override handlers in order to implement what happens after receiving an RPC {{ AutoComponentMacros.DeclareRpcHandlers(Component, 'Authority', 'Client', false)|indent(8) -}} - {{ AutoComponentMacros.DeclareRpcSignals(Component, 'Authority', 'Client')|indent(8) -}} - {{ AutoComponentMacros.DeclareRpcEvents(Component, 'Authority', 'Client')|indent(8) }} + + //! RPC Events: Subscribe to these events and get notified when an RPC is received + {{ AutoComponentMacros.DeclareRpcEvents(Component, 'Authority', 'Client')|indent(8) -}} + {% for Service in Component.iter('ComponentRelation') %} {% if Service.attrib['Constraint'] != 'Incompatible' %} const {{ Service.attrib['Namespace'] }}::{{ Service.attrib['Name'] }}* Get{{ Service.attrib['Name'] }}() const; diff --git a/Gems/Multiplayer/Code/Include/Multiplayer/AutoGen/AutoComponent_Source.jinja b/Gems/Multiplayer/Code/Include/Multiplayer/AutoGen/AutoComponent_Source.jinja index cf62f6f901..e9bc21875b 100644 --- a/Gems/Multiplayer/Code/Include/Multiplayer/AutoGen/AutoComponent_Source.jinja +++ b/Gems/Multiplayer/Code/Include/Multiplayer/AutoGen/AutoComponent_Source.jinja @@ -340,27 +340,11 @@ void {{ ClassName }}::{{ UpperFirst(Property.attrib['Name']) }}({{ ', '.join(par {% endmacro %} {# -#} -{% macro DefineRpcSignal(Component, ClassName, Property, InvokeFrom) %} -{% set paramNames = [] %} -{% set paramTypes = [] %} -{% set paramDefines = [] %} -{{ AutoComponentMacros.ParseRpcParams(Property, paramNames, paramTypes, paramDefines) }} -void {{ ClassName }}::Signal{{ UpperFirst(Property.attrib['Name']) }}({{ ', '.join(paramDefines) }}) -{ - m_{{ UpperFirst(Property.attrib['Name']) }}Event.Signal({{ ', '.join(paramNames) }}); -} -{% endmacro %} -{# - #} {% macro DefineRpcInvocations(Component, ClassName, InvokeFrom, HandleOn, IsProtected) %} {% call(Property) AutoComponentMacros.ParseRemoteProcedures(Component, InvokeFrom, HandleOn) %} {% if Property.attrib['IsPublic']|booleanTrue != IsProtected %} {{ DefineRpcInvocation(Component, ClassName, Property, InvokeFrom, HandleOn) -}} -{% if Property.attrib['GenerateEventBindings']|booleanTrue == true %} -{{ DefineRpcSignal(Component, ClassName, Property, InvokeFrom) -}} -{% endif %} {% endif %} {% endcall %} {% endmacro %} @@ -374,33 +358,46 @@ void {{ ClassName }}::Signal{{ UpperFirst(Property.attrib['Name']) }}({{ ', '.jo {% set paramTypes = [] %} {% set paramDefines = [] %} {{ AutoComponentMacros.ParseRpcParams(Property, paramNames, paramTypes, paramDefines) }} - ->Method("{{ UpperFirst(Property.attrib['Name']) }}", [](const {{ ClassName }}* self, {{ ', '.join(paramDefines) }}) { - self->m_controller->{{ UpperFirst(Property.attrib['Name']) }}({{ ', '.join(paramNames) }}); + ->Method("{{ UpperFirst(Property.attrib['Name']) }}", []({{ ClassName }}* self, {{ ', '.join(paramDefines) }}) { +{% if (InvokeFrom == 'Server') %} + self->{{ UpperFirst(Property.attrib['Name']) }}({{ ', '.join(paramNames) }}); +{% elif (InvokeFrom == 'Authority') or (InvokeFrom == 'Autonomous') %} + if (self->m_controller) + { + self->m_controller->{{ UpperFirst(Property.attrib['Name']) }}({{ ', '.join(paramNames) }}); + } + else + { + AZ_Warning("Network RPC", false, "{{ ClassName }} {{ UpperFirst(Property.attrib['Name']) }} method failed. Entity '%s' (id: %s) {{ ClassName }} is missing the network controller. This remote-procedure can only be invoked from {{InvokeFrom}} network entities, because this entity doesn't have a controller, it must not be a {{InvokeFrom}} entity. Please check your network context before attempting to call {{ UpperFirst(Property.attrib['Name']) }}.", self->GetEntity()->GetName().c_str(), self->GetEntityId().ToString().c_str()) + } +{% endif %} }) ->Method("{{ UpperFirst(Property.attrib['Name']) }}ByEntityId", [](AZ::EntityId id, {{ ', '.join(paramDefines) }}) { AZ::Entity* entity = AZ::Interface::Get()->FindEntity(id); if (!entity) { - AZ_Warning("Network Property", false, "{{ ClassName }} {{ UpperFirst(Property.attrib['Name']) }}ByEntityId failed. The entity with id %s doesn't exist, please provide a valid entity id.", id.ToString().c_str()) + AZ_Warning("Network RPC", false, "{{ ClassName }} {{ UpperFirst(Property.attrib['Name']) }}ByEntityId failed. The entity with id %s doesn't exist, please provide a valid entity id.", id.ToString().c_str()) return; } {{ ClassName }}* networkComponent = entity->FindComponent<{{ ClassName }}>(); if (!networkComponent) { - AZ_Warning("Network Property", false, "{{ ClassName }} {{ UpperFirst(Property.attrib['Name']) }}ByEntityId failed. Entity '%s' (id: %s) is missing {{ ClassName }}, be sure to add {{ ClassName }} to this entity.", entity->GetName().c_str(), id.ToString().c_str()) + AZ_Warning("Network RPC", false, "{{ ClassName }} {{ UpperFirst(Property.attrib['Name']) }}ByEntityId failed. Entity '%s' (id: %s) is missing {{ ClassName }}, be sure to add {{ ClassName }} to this entity.", entity->GetName().c_str(), id.ToString().c_str()) return; } - +{% if (InvokeFrom == 'Server') %} + networkComponent->{{ UpperFirst(Property.attrib['Name']) }}({{ ', '.join(paramNames) }}); +{% elif (InvokeFrom == 'Authority') or (InvokeFrom == 'Autonomous') %} {{ ClassName }}Controller* controller = static_cast<{{ ClassName }}Controller*>(networkComponent->GetController()); if (!controller) { - AZ_Warning("Network Property", false, "{{ ClassName }} {{ UpperFirst(Property.attrib['Name']) }}ByEntityId method failed. Entity '%s' (id: %s) {{ ClassName }} is missing the network controller. This RemoteProcedure can only be invoked from {{InvokeFrom}} network entities, because this entity doesn't have a controller, it must not be a {{InvokeFrom}} entity. Please check your network context before attempting to call {{ UpperFirst(Property.attrib['Name']) }}.", entity->GetName().c_str(), id.ToString().c_str()) + AZ_Warning("Network RPC", false, "{{ ClassName }} {{ UpperFirst(Property.attrib['Name']) }}ByEntityId method failed. Entity '%s' (id: %s) {{ ClassName }} is missing the network controller. This RemoteProcedure can only be invoked from {{InvokeFrom}} network entities, because this entity doesn't have a controller, it must not be a {{InvokeFrom}} entity. Please check your network context before attempting to call {{ UpperFirst(Property.attrib['Name']) }}.", entity->GetName().c_str(), id.ToString().c_str()) return; } - controller->{{ UpperFirst(Property.attrib['Name']) }}({{ ', '.join(paramNames) }}); +{% endif %} }, { { { "Source", "The Source containing the {{ ClassName }}Controller" }{% for paramName in paramNames %}, {"{{ paramName }}"}{% endfor %}}}) ->Attribute(AZ::Script::Attributes::ToolTip, "{{Property.attrib['Description']}}") {% endif %} @@ -436,9 +433,13 @@ void {{ ClassName }}::Signal{{ UpperFirst(Property.attrib['Name']) }}({{ ', '.jo {% set paramTypes = [] %} {% set paramDefines = [] %} {{ AutoComponentMacros.ParseRpcParams(Property, paramNames, paramTypes, paramDefines) }} - ->Method("Get{{ UpperFirst(Property.attrib['Name']) }}Event", [](const {{ ClassName }}* self) -> AZ::Event<{{ ', '.join(paramTypes) }}>& + ->Method("Get{{ UpperFirst(Property.attrib['Name']) }}Event", []({{ ClassName }}* self) -> AZ::Event<{{ ', '.join(paramTypes) }}>& { +{% if HandleOn == 'Client' %} + return self->Get{{ UpperFirst(Property.attrib['Name']) }}Event(); +{% elif (HandleOn == 'Authority') or (HandleOn == 'Autonomous') %} return self->m_controller->Get{{ UpperFirst(Property.attrib['Name']) }}Event(); +{% endif %} }) ->Attribute(AZ::Script::Attributes::AzEventDescription, {{ LowerFirst(Property.attrib['Name']) }}EventDesc) ->Method("Get{{ UpperFirst(Property.attrib['Name']) }}EventByEntityId", [](AZ::EntityId id) -> AZ::Event<{{ ', '.join(paramTypes) }}>* @@ -456,7 +457,9 @@ void {{ ClassName }}::Signal{{ UpperFirst(Property.attrib['Name']) }}({{ ', '.jo AZ_Warning("Network Property", false, "{{ ClassName }} Get{{ UpperFirst(Property.attrib['Name']) }}EventByEntityId failed. Entity '%s' (id: %s) is missing {{ ClassName }}, be sure to add {{ ClassName }} to this entity.", entity->GetName().c_str(), id.ToString().c_str()) return nullptr; } - +{% if HandleOn == 'Client' %} + return &networkComponent->Get{{ UpperFirst(Property.attrib['Name']) }}Event(); +{% elif (HandleOn == 'Authority') or (HandleOn == 'Autonomous') %} {{ ClassName }}Controller* controller = static_cast<{{ ClassName }}Controller*>(networkComponent->GetController()); if (!controller) { @@ -465,6 +468,7 @@ void {{ ClassName }}::Signal{{ UpperFirst(Property.attrib['Name']) }}({{ ', '.jo } return &controller->Get{{ UpperFirst(Property.attrib['Name']) }}Event(); +{% endif %} }) ->Attribute(AZ::Script::Attributes::AzEventDescription, AZStd::move({{ LowerFirst(Property.attrib['Name']) }}EventDesc)) {% endif %} @@ -494,29 +498,31 @@ case {{ UpperFirst(Component.attrib['Name']) }}Internal::RemoteProcedure::{{ Upp { AZ_Assert(GetNetBindComponent()->GetNetEntityRole() == Multiplayer::NetEntityRole::Authority, "Entity proxy does not have authority"); m_controller->Handle{{ UpperFirst(Property.attrib['Name']) }}(invokingConnection, {{ ', '.join(rpcParamList) }}); -{% if Property.attrib['GenerateEventBindings']|booleanTrue == true %} - m_controller->Signal{{ UpperFirst(Property.attrib['Name']) }}({{ ', '.join(rpcParamList) }}); -{% endif %} +{% if (Property.attrib['GenerateEventBindings']|booleanTrue == true) %} + m_controller->Get{{ UpperFirst(Property.attrib['Name']) }}Event().Signal({{ ', '.join(rpcParamList) }}); +{% endif %} } -{% if Property.attrib['IsReliable']|booleanTrue %} -{# if the rpc is not reliable we can simply drop it, also note message reliability type is default reliable in EntityRpcMessage #} else // Note that this rpc is marked reliable, trigger the appropriate rpc event so it can be forwarded { +{% if Property.attrib['IsReliable']|booleanTrue %} +{# if the rpc is not reliable we can simply drop it, also note message reliability type is default reliable in EntityRpcMessage #} m_netBindComponent->{{ "GetSend" + InvokeFrom + "To" + HandleOn + "RpcEvent" }}().Signal(message); +{% endif %} } - -{% endif %} {% elif HandleOn == 'Autonomous' %} if (m_controller) { AZ_Assert(GetNetBindComponent()->GetNetEntityRole() == Multiplayer::NetEntityRole::Autonomous, "Entity proxy does not have autonomy"); m_controller->Handle{{ UpperFirst(Property.attrib['Name']) }}(invokingConnection, {{ ', '.join(rpcParamList) }}); -{% if Property.attrib['GenerateEventBindings']|booleanTrue == true %} - m_controller->Signal{{ UpperFirst(Property.attrib['Name']) }}({{ ', '.join(rpcParamList) }}); -{% endif %} +{% if Property.attrib['GenerateEventBindings']|booleanTrue == true %} + m_controller->Get{{ UpperFirst(Property.attrib['Name']) }}Event().Signal({{ ', '.join(rpcParamList) }}); +{% endif %} } -{% else %} +{% elif HandleOn == 'Client' %} Handle{{ UpperFirst(Property.attrib['Name']) }}(invokingConnection, {{ ', '.join(rpcParamList) }}); +{% if Property.attrib['GenerateEventBindings']|booleanTrue == true %} + m_{{ UpperFirst(Property.attrib['Name']) }}Event.Signal({{ ', '.join(rpcParamList) }}); +{% endif %} {% endif %} } else if (paramsSerialized) From c99071533d2ff5acec2b576d3932c3635e5b6565 Mon Sep 17 00:00:00 2001 From: Gene Walters Date: Tue, 9 Nov 2021 15:39:43 -0800 Subject: [PATCH 38/71] Small: fix typo Signed-off-by: Gene Walters --- .../Code/Include/Multiplayer/AutoGen/AutoComponent_Header.jinja | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gems/Multiplayer/Code/Include/Multiplayer/AutoGen/AutoComponent_Header.jinja b/Gems/Multiplayer/Code/Include/Multiplayer/AutoGen/AutoComponent_Header.jinja index b78b7cffba..58a47b336f 100644 --- a/Gems/Multiplayer/Code/Include/Multiplayer/AutoGen/AutoComponent_Header.jinja +++ b/Gems/Multiplayer/Code/Include/Multiplayer/AutoGen/AutoComponent_Header.jinja @@ -450,7 +450,7 @@ namespace {{ Component.attrib['Namespace'] }} {{ DeclareRpcInvocations(Component, 'Authority', 'Client', false)|indent(8) -}} {{ DeclareRpcInvocations(Component, 'Authority', 'Client', true)|indent(8) -}} - //! RPC Handlers: Override handlers in order ti implement what happens after receiving an RPC + //! RPC Handlers: Override handlers in order to implement what happens after receiving an RPC {{ AutoComponentMacros.DeclareRpcHandlers(Component, 'Server', 'Authority', false)|indent(8) -}} {{ AutoComponentMacros.DeclareRpcHandlers(Component, 'Autonomous', 'Authority', false)|indent(8) -}} {{ AutoComponentMacros.DeclareRpcHandlers(Component, 'Authority', 'Autonomous', false)|indent(8) -}} From 15586ee53e0e8a627cee52bc54905e772ee4cbfc Mon Sep 17 00:00:00 2001 From: moraaar Date: Tue, 9 Nov 2021 23:42:01 +0000 Subject: [PATCH 39/71] Adding missing pragma once at XcbInputDeviceMouse.h (#5448) Signed-off-by: moraaar --- .../Platform/Common/Xcb/AzFramework/XcbInputDeviceMouse.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Code/Framework/AzFramework/Platform/Common/Xcb/AzFramework/XcbInputDeviceMouse.h b/Code/Framework/AzFramework/Platform/Common/Xcb/AzFramework/XcbInputDeviceMouse.h index a69a8a9ec5..f5b805a7a5 100644 --- a/Code/Framework/AzFramework/Platform/Common/Xcb/AzFramework/XcbInputDeviceMouse.h +++ b/Code/Framework/AzFramework/Platform/Common/Xcb/AzFramework/XcbInputDeviceMouse.h @@ -6,6 +6,8 @@ * */ +#pragma once + #include #include #include From 31439eb7c85c91d39835f43c79d904e3375f5afe Mon Sep 17 00:00:00 2001 From: Ken Pruiksma Date: Tue, 9 Nov 2021 17:52:26 -0600 Subject: [PATCH 40/71] Adding m_exposure field to terrain's object srg to sync it with the default object srg. (#5462) Signed-off-by: Ken Pruiksma --- Gems/Terrain/Assets/Shaders/Terrain/TerrainCommon.azsli | 1 + 1 file changed, 1 insertion(+) diff --git a/Gems/Terrain/Assets/Shaders/Terrain/TerrainCommon.azsli b/Gems/Terrain/Assets/Shaders/Terrain/TerrainCommon.azsli index cd680f721a..52d0e0a6cc 100644 --- a/Gems/Terrain/Assets/Shaders/Terrain/TerrainCommon.azsli +++ b/Gems/Terrain/Assets/Shaders/Terrain/TerrainCommon.azsli @@ -56,6 +56,7 @@ ShaderResourceGroup ObjectSrg : SRG_PerObject float m_padding; bool m_useReflectionProbe; bool m_useParallaxCorrection; + float m_exposure; }; ReflectionProbeData m_reflectionProbeData; From dadf06edda132c0d2c02a9668f16da770670d01f Mon Sep 17 00:00:00 2001 From: antonmic <56370189+antonmic@users.noreply.github.com> Date: Tue, 9 Nov 2021 19:03:26 -0800 Subject: [PATCH 41/71] Fixed issue where skin material wouldn't render if applied to a model with several submeshes and those submeshes had different material types applied to them. Signed-off-by: antonmic <56370189+antonmic@users.noreply.github.com> --- .../Atom/Feature/Mesh/MeshFeatureProcessor.h | 13 +- .../Mesh/MeshFeatureProcessorInterface.h | 6 +- .../Code/Mocks/MockMeshFeatureProcessor.h | 2 +- .../Code/Source/Mesh/MeshFeatureProcessor.cpp | 244 +++++++++--------- .../SkinnedMeshFeatureProcessor.cpp | 14 +- .../Code/Source/AtomActorInstance.cpp | 6 +- 6 files changed, 147 insertions(+), 138 deletions(-) diff --git a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Mesh/MeshFeatureProcessor.h b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Mesh/MeshFeatureProcessor.h index 2ac184e2e0..4aec78be51 100644 --- a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Mesh/MeshFeatureProcessor.h +++ b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Mesh/MeshFeatureProcessor.h @@ -30,7 +30,7 @@ namespace AZ class TransformServiceFeatureProcessor; class RayTracingFeatureProcessor; - class MeshDataInstance + class ModelDataInstance { friend class MeshFeatureProcessor; friend class MeshLoader; @@ -47,7 +47,7 @@ namespace AZ public: using ModelChangedEvent = MeshFeatureProcessorInterface::ModelChangedEvent; - MeshLoader(const Data::Asset& modelAsset, MeshDataInstance* parent); + MeshLoader(const Data::Asset& modelAsset, ModelDataInstance* parent); ~MeshLoader(); ModelChangedEvent& GetModelChangedEvent(); @@ -68,7 +68,7 @@ namespace AZ } }; MeshFeatureProcessorInterface::ModelChangedEvent m_modelChangedEvent; Data::Asset m_modelAsset; - MeshDataInstance* m_parent = nullptr; + ModelDataInstance* m_parent = nullptr; }; void DeInit(); @@ -99,7 +99,8 @@ namespace AZ //! A reference to the original model asset in case it got cloned before creating the model instance. Data::Asset m_originalModelAsset; - Data::Instance m_shaderResourceGroup; + //! List of object SRGs used by meshes in this model + AZStd::vector> m_objectSrgList; AZStd::unique_ptr m_meshLoader; RPI::Scene* m_scene = nullptr; RHI::DrawItemSortKey m_sortKey; @@ -152,7 +153,7 @@ namespace AZ Data::Instance GetModel(const MeshHandle& meshHandle) const override; Data::Asset GetModelAsset(const MeshHandle& meshHandle) const override; - Data::Instance GetObjectSrg(const MeshHandle& meshHandle) const override; + AZStd::vector>& GetObjectSrgs(const MeshHandle& meshHandle) const override; void QueueObjectSrgForCompile(const MeshHandle& meshHandle) const override; void SetMaterialAssignmentMap(const MeshHandle& meshHandle, const Data::Instance& material) override; void SetMaterialAssignmentMap(const MeshHandle& meshHandle, const MaterialAssignmentMap& materials) override; @@ -195,7 +196,7 @@ namespace AZ void OnRenderPipelineRemoved(RPI::RenderPipeline* pipeline) override; AZStd::concurrency_checker m_meshDataChecker; - StableDynamicArray m_meshData; + StableDynamicArray m_modelData; TransformServiceFeatureProcessor* m_transformService; RayTracingFeatureProcessor* m_rayTracingFeatureProcessor = nullptr; AZ::RPI::ShaderSystemInterface::GlobalShaderOptionUpdatedEvent::Handler m_handleGlobalShaderOptionUpdate; diff --git a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Mesh/MeshFeatureProcessorInterface.h b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Mesh/MeshFeatureProcessorInterface.h index cffbe5c3c5..3be5f3efd8 100644 --- a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Mesh/MeshFeatureProcessorInterface.h +++ b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Mesh/MeshFeatureProcessorInterface.h @@ -20,7 +20,7 @@ namespace AZ { namespace Render { - class MeshDataInstance; + class ModelDataInstance; //! Settings to apply to a mesh handle when acquiring it for the first time struct MeshHandleDescriptor @@ -40,7 +40,7 @@ namespace AZ public: AZ_RTTI(AZ::Render::MeshFeatureProcessorInterface, "{975D7F0C-2E7E-4819-94D0-D3C4E2024721}", FeatureProcessor); - using MeshHandle = StableDynamicArrayHandle; + using MeshHandle = StableDynamicArrayHandle; using ModelChangedEvent = Event>; //! Acquires a model with an optional collection of material assignments. @@ -66,7 +66,7 @@ namespace AZ //! instead of compiling the srg directly. This way, if the srg has already been queued for compile, //! it will not be queued twice in the same frame. The ObjectSrg should not be updated during //! Simulate, or it will create a race between updating the data and the call to Compile - virtual Data::Instance GetObjectSrg(const MeshHandle& meshHandle) const = 0; + virtual AZStd::vector>& GetObjectSrgs(const MeshHandle& meshHandle) const = 0; //! Queues the object srg for compile. virtual void QueueObjectSrgForCompile(const MeshHandle& meshHandle) const = 0; //! Sets the MaterialAssignmentMap for a meshHandle, using just a single material for the DefaultMaterialAssignmentId. diff --git a/Gems/Atom/Feature/Common/Code/Mocks/MockMeshFeatureProcessor.h b/Gems/Atom/Feature/Common/Code/Mocks/MockMeshFeatureProcessor.h index 35e399997f..05a3274657 100644 --- a/Gems/Atom/Feature/Common/Code/Mocks/MockMeshFeatureProcessor.h +++ b/Gems/Atom/Feature/Common/Code/Mocks/MockMeshFeatureProcessor.h @@ -19,7 +19,7 @@ namespace UnitTest MOCK_METHOD1(CloneMesh, MeshHandle(const MeshHandle&)); MOCK_CONST_METHOD1(GetModel, AZStd::intrusive_ptr(const MeshHandle&)); MOCK_CONST_METHOD1(GetModelAsset, AZ::Data::Asset(const MeshHandle&)); - MOCK_CONST_METHOD1(GetObjectSrg, AZStd::intrusive_ptr(const MeshHandle&)); + MOCK_CONST_METHOD1(GetObjectSrgs, AZStd::vector>&(const MeshHandle&)); MOCK_CONST_METHOD1(QueueObjectSrgForCompile, void(const MeshHandle&)); MOCK_CONST_METHOD1(GetMaterialAssignmentMap, const AZ::Render::MaterialAssignmentMap&(const MeshHandle&)); MOCK_METHOD2(ConnectModelChangeEventHandler, void(const MeshHandle&, ModelChangedEvent::Handler&)); diff --git a/Gems/Atom/Feature/Common/Code/Source/Mesh/MeshFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/Mesh/MeshFeatureProcessor.cpp index c7fb19bc5d..778c80e5e1 100644 --- a/Gems/Atom/Feature/Common/Code/Source/Mesh/MeshFeatureProcessor.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/Mesh/MeshFeatureProcessor.cpp @@ -67,7 +67,7 @@ namespace AZ m_handleGlobalShaderOptionUpdate.Disconnect(); DisableSceneNotification(); - AZ_Warning("MeshFeatureProcessor", m_meshData.size() == 0, + AZ_Warning("MeshFeatureProcessor", m_modelData.size() == 0, "Deactivaing the MeshFeatureProcessor, but there are still outstanding mesh handles.\n" ); m_transformService = nullptr; @@ -81,7 +81,7 @@ namespace AZ AZStd::concurrency_check_scope scopeCheck(m_meshDataChecker); - const auto iteratorRanges = m_meshData.GetParallelRanges(); + const auto iteratorRanges = m_modelData.GetParallelRanges(); AZ::JobCompletion jobCompletion; for (const auto& iteratorRange : iteratorRanges) { @@ -125,11 +125,11 @@ namespace AZ m_forceRebuildDrawPackets = false; // CullingSystem::RegisterOrUpdateCullable() is not threadsafe, so need to do those updates in a single thread - for (MeshDataInstance& meshDataInstance : m_meshData) + for (ModelDataInstance& modelDataInstance : m_modelData) { - if (meshDataInstance.m_model && meshDataInstance.m_cullBoundsNeedsUpdate) + if (modelDataInstance.m_model && modelDataInstance.m_cullBoundsNeedsUpdate) { - meshDataInstance.UpdateCullBounds(m_transformService); + modelDataInstance.UpdateCullBounds(m_transformService); } } } @@ -151,14 +151,14 @@ namespace AZ AZ_PROFILE_SCOPE(AzRender, "MeshFeatureProcessor: AcquireMesh"); // don't need to check the concurrency during emplace() because the StableDynamicArray won't move the other elements during insertion - MeshHandle meshDataHandle = m_meshData.emplace(); + MeshHandle meshDataHandle = m_modelData.emplace(); meshDataHandle->m_descriptor = descriptor; meshDataHandle->m_scene = GetParentScene(); meshDataHandle->m_materialAssignments = materials; meshDataHandle->m_objectId = m_transformService->ReserveObjectId(); meshDataHandle->m_originalModelAsset = descriptor.m_modelAsset; - meshDataHandle->m_meshLoader = AZStd::make_unique(descriptor.m_modelAsset, &*meshDataHandle); + meshDataHandle->m_meshLoader = AZStd::make_unique(descriptor.m_modelAsset, &*meshDataHandle); return meshDataHandle; } @@ -183,7 +183,7 @@ namespace AZ m_transformService->ReleaseObjectId(meshHandle->m_objectId); AZStd::concurrency_check_scope scopeCheck(m_meshDataChecker); - m_meshData.erase(meshHandle); + m_modelData.erase(meshHandle); return true; } @@ -215,9 +215,10 @@ namespace AZ return {}; } - Data::Instance MeshFeatureProcessor::GetObjectSrg(const MeshHandle& meshHandle) const + AZStd::vector>& MeshFeatureProcessor::GetObjectSrgs(const MeshHandle& meshHandle) const { - return meshHandle.IsValid() ? meshHandle->m_shaderResourceGroup : nullptr; + static AZStd::vector> staticEmptyList; + return meshHandle.IsValid() ? meshHandle->m_objectSrgList : staticEmptyList; } void MeshFeatureProcessor::QueueObjectSrgForCompile(const MeshHandle& meshHandle) const @@ -274,9 +275,9 @@ namespace AZ { if (meshHandle.IsValid()) { - MeshDataInstance& meshData = *meshHandle; - meshData.m_cullBoundsNeedsUpdate = true; - meshData.m_objectSrgNeedsUpdate = true; + ModelDataInstance& modelData = *meshHandle; + modelData.m_cullBoundsNeedsUpdate = true; + modelData.m_objectSrgNeedsUpdate = true; m_transformService->SetTransformForId(meshHandle->m_objectId, transform, nonUniformScale); @@ -292,10 +293,10 @@ namespace AZ { if (meshHandle.IsValid()) { - MeshDataInstance& meshData = *meshHandle; - meshData.m_aabb = localAabb; - meshData.m_cullBoundsNeedsUpdate = true; - meshData.m_objectSrgNeedsUpdate = true; + ModelDataInstance& modelData = *meshHandle; + modelData.m_aabb = localAabb; + modelData.m_cullBoundsNeedsUpdate = true; + modelData.m_objectSrgNeedsUpdate = true; } }; @@ -465,7 +466,7 @@ namespace AZ void MeshFeatureProcessor::UpdateMeshReflectionProbes() { // we need to rebuild the Srg for any meshes that are using the forward pass IBL specular option - for (auto& meshInstance : m_meshData) + for (auto& meshInstance : m_modelData) { if (meshInstance.m_descriptor.m_useForwardPassIblSpecular) { @@ -474,14 +475,14 @@ namespace AZ } } - // MeshDataInstance::MeshLoader... - MeshDataInstance::MeshLoader::MeshLoader(const Data::Asset& modelAsset, MeshDataInstance* parent) + // ModelDataInstance::MeshLoader... + ModelDataInstance::MeshLoader::MeshLoader(const Data::Asset& modelAsset, ModelDataInstance* parent) : m_modelAsset(modelAsset) , m_parent(parent) { if (!m_modelAsset.GetId().IsValid()) { - AZ_Error("MeshDataInstance::MeshLoader", false, "Invalid model asset Id."); + AZ_Error("ModelDataInstance::MeshLoader", false, "Invalid model asset Id."); return; } @@ -494,19 +495,19 @@ namespace AZ AzFramework::AssetCatalogEventBus::Handler::BusConnect(); } - MeshDataInstance::MeshLoader::~MeshLoader() + ModelDataInstance::MeshLoader::~MeshLoader() { AzFramework::AssetCatalogEventBus::Handler::BusDisconnect(); Data::AssetBus::Handler::BusDisconnect(); } - MeshFeatureProcessorInterface::ModelChangedEvent& MeshDataInstance::MeshLoader::GetModelChangedEvent() + MeshFeatureProcessorInterface::ModelChangedEvent& ModelDataInstance::MeshLoader::GetModelChangedEvent() { return m_modelChangedEvent; } //! AssetBus::Handler overrides... - void MeshDataInstance::MeshLoader::OnAssetReady(Data::Asset asset) + void ModelDataInstance::MeshLoader::OnAssetReady(Data::Asset asset) { Data::Asset modelAsset = asset; @@ -527,7 +528,7 @@ namespace AZ } else { - AZ_Error("MeshDataInstance", false, "Cannot clone model for '%s'. Cloth simulation results won't be individual per entity.", modelAsset->GetName().GetCStr()); + AZ_Error("ModelDataInstance", false, "Cannot clone model for '%s'. Cloth simulation results won't be individual per entity.", modelAsset->GetName().GetCStr()); model = RPI::Model::FindOrCreate(modelAsset); } } @@ -547,29 +548,29 @@ namespace AZ { //when running with null renderer, the RPI::Model::FindOrCreate(...) is expected to return nullptr, so suppress this error. AZ_Error( - "MeshDataInstance::OnAssetReady", RHI::IsNullRenderer(), "Failed to create model instance for '%s'", + "ModelDataInstance::OnAssetReady", RHI::IsNullRenderer(), "Failed to create model instance for '%s'", asset.GetHint().c_str()); } } - void MeshDataInstance::MeshLoader::OnModelReloaded(Data::Asset asset) + void ModelDataInstance::MeshLoader::OnModelReloaded(Data::Asset asset) { OnAssetReady(asset); } - void MeshDataInstance::MeshLoader::OnAssetError(Data::Asset asset) + void ModelDataInstance::MeshLoader::OnAssetError(Data::Asset asset) { // Note: m_modelAsset and asset represents same asset, but only m_modelAsset contains the file path in its hint from serialization AZ_Error( - "MeshDataInstance::MeshLoader", false, "Failed to load asset %s. It may be missing, or not be finished processing", + "ModelDataInstance::MeshLoader", false, "Failed to load asset %s. It may be missing, or not be finished processing", m_modelAsset.GetHint().c_str()); AzFramework::AssetSystemRequestBus::Broadcast( &AzFramework::AssetSystem::AssetSystemRequests::EscalateAssetByUuid, m_modelAsset.GetId().m_guid); } - void MeshDataInstance::MeshLoader::OnCatalogAssetChanged(const AZ::Data::AssetId& assetId) + void ModelDataInstance::MeshLoader::OnCatalogAssetChanged(const AZ::Data::AssetId& assetId) { if (assetId == m_modelAsset.GetId()) { @@ -584,7 +585,7 @@ namespace AZ } } - void MeshDataInstance::MeshLoader::OnCatalogAssetAdded(const AZ::Data::AssetId& assetId) + void ModelDataInstance::MeshLoader::OnCatalogAssetAdded(const AZ::Data::AssetId& assetId) { if (assetId == m_modelAsset.GetId()) { @@ -599,9 +600,9 @@ namespace AZ } } - // MeshDataInstance... + // ModelDataInstance... - void MeshDataInstance::DeInit() + void ModelDataInstance::DeInit() { m_scene->GetCullingScene()->UnregisterCullable(m_cullable); @@ -609,11 +610,11 @@ namespace AZ m_drawPacketListsByLod.clear(); m_materialAssignments.clear(); - m_shaderResourceGroup = {}; + m_objectSrgList = {}; m_model = {}; } - void MeshDataInstance::Init(Data::Instance model) + void ModelDataInstance::Init(Data::Instance model) { m_model = model; const size_t modelLodCount = m_model->GetLodCount(); @@ -623,11 +624,11 @@ namespace AZ BuildDrawPacketList(modelLodIndex); } - if (m_shaderResourceGroup) + for(auto& objectSrg : m_objectSrgList) { // Set object Id once since it never changes RHI::ShaderInputNameIndex objectIdIndex = "m_objectId"; - m_shaderResourceGroup->SetConstant(objectIdIndex, m_objectId.GetIndex()); + objectSrg->SetConstant(objectIdIndex, m_objectId.GetIndex()); objectIdIndex.AssertValid(); } @@ -643,12 +644,12 @@ namespace AZ m_objectSrgNeedsUpdate = true; } - void MeshDataInstance::BuildDrawPacketList(size_t modelLodIndex) + void ModelDataInstance::BuildDrawPacketList(size_t modelLodIndex) { RPI::ModelLod& modelLod = *m_model->GetLods()[modelLodIndex]; const size_t meshCount = modelLod.GetMeshes().size(); - MeshDataInstance::DrawPacketList& drawPacketListOut = m_drawPacketListsByLod[modelLodIndex]; + ModelDataInstance::DrawPacketList& drawPacketListOut = m_drawPacketListsByLod[modelLodIndex]; drawPacketListOut.clear(); drawPacketListOut.reserve(meshCount); @@ -682,27 +683,32 @@ namespace AZ continue; } - if (m_shaderResourceGroup && m_shaderResourceGroup->GetLayout()->GetHash() != objectSrgLayout->GetHash()) + Data::Instance meshObjectSrg; + + // See if the object SRG for this mesh is already in our list of object SRGs + for (auto& objectSrgIter : m_objectSrgList) { - AZ_Warning("MeshFeatureProcessor", false, "All materials on a model must use the same per-object ShaderResourceGroup. Skipping."); - continue; + if (objectSrgIter->GetLayout()->GetHash() == objectSrgLayout->GetHash()) + { + meshObjectSrg = objectSrgIter; + } } - // The first time we find the per-surface SRG asset we create an instance and store it - // in shaderResourceGroupInOut. All of the Model's draw packets will use this same instance. - if (!m_shaderResourceGroup) + // If the object SRG for this mesh was not already in the list, create it and add it to the list + if (!meshObjectSrg) { auto& shaderAsset = material->GetAsset()->GetMaterialTypeAsset()->GetShaderAssetForObjectSrg(); - m_shaderResourceGroup = RPI::ShaderResourceGroup::Create(shaderAsset, objectSrgLayout->GetName()); - if (!m_shaderResourceGroup) + meshObjectSrg = RPI::ShaderResourceGroup::Create(shaderAsset, objectSrgLayout->GetName()); + if (!meshObjectSrg) { AZ_Warning("MeshFeatureProcessor", false, "Failed to create a new shader resource group, skipping."); continue; } + m_objectSrgList.push_back(meshObjectSrg); } // setup the mesh draw packet - RPI::MeshDrawPacket drawPacket(modelLod, meshIndex, material, m_shaderResourceGroup, materialAssignment.m_matModUvOverrides); + RPI::MeshDrawPacket drawPacket(modelLod, meshIndex, material, meshObjectSrg, materialAssignment.m_matModUvOverrides); // set the shader option to select forward pass IBL specular if necessary if (!drawPacket.SetShaderOption(AZ::Name("o_meshUseForwardPassIBLSpecular"), AZ::RPI::ShaderOptionValue{ m_descriptor.m_useForwardPassIblSpecular })) @@ -726,7 +732,7 @@ namespace AZ } } - void MeshDataInstance::SetRayTracingData() + void ModelDataInstance::SetRayTracingData() { if (!m_model) { @@ -993,7 +999,7 @@ namespace AZ rayTracingFeatureProcessor->SetMesh(m_objectId, m_model->GetModelAsset()->GetId(), subMeshes); } - void MeshDataInstance::RemoveRayTracingData() + void ModelDataInstance::RemoveRayTracingData() { // remove from ray tracing RayTracingFeatureProcessor* rayTracingFeatureProcessor = m_scene->GetFeatureProcessor(); @@ -1003,7 +1009,7 @@ namespace AZ } } - void MeshDataInstance::SetSortKey(RHI::DrawItemSortKey sortKey) + void ModelDataInstance::SetSortKey(RHI::DrawItemSortKey sortKey) { m_sortKey = sortKey; for (auto& drawPacketList : m_drawPacketListsByLod) @@ -1015,24 +1021,24 @@ namespace AZ } } - RHI::DrawItemSortKey MeshDataInstance::GetSortKey() const + RHI::DrawItemSortKey ModelDataInstance::GetSortKey() const { return m_sortKey; } - void MeshDataInstance::SetMeshLodConfiguration(RPI::Cullable::LodConfiguration meshLodConfig) + void ModelDataInstance::SetMeshLodConfiguration(RPI::Cullable::LodConfiguration meshLodConfig) { m_cullable.m_lodData.m_lodConfiguration = meshLodConfig; } - RPI::Cullable::LodConfiguration MeshDataInstance::GetMeshLodConfiguration() const + RPI::Cullable::LodConfiguration ModelDataInstance::GetMeshLodConfiguration() const { return m_cullable.m_lodData.m_lodConfiguration; } - void MeshDataInstance::UpdateDrawPackets(bool forceUpdate /*= false*/) + void ModelDataInstance::UpdateDrawPackets(bool forceUpdate /*= false*/) { - AZ_PROFILE_SCOPE(AzRender, "MeshDataInstance:: UpdateDrawPackets"); + AZ_PROFILE_SCOPE(AzRender, "ModelDataInstance:: UpdateDrawPackets"); for (auto& drawPacketList : m_drawPacketListsByLod) { for (auto& drawPacket : drawPacketList) @@ -1045,9 +1051,9 @@ namespace AZ } } - void MeshDataInstance::BuildCullable() + void ModelDataInstance::BuildCullable() { - AZ_PROFILE_SCOPE(AzRender, "MeshDataInstance: BuildCullable"); + AZ_PROFILE_SCOPE(AzRender, "ModelDataInstance: BuildCullable"); AZ_Assert(m_cullableNeedsRebuild, "This function only needs to be called if the cullable to be rebuilt"); AZ_Assert(m_model, "The model has not finished loading yet"); @@ -1122,9 +1128,9 @@ namespace AZ m_cullBoundsNeedsUpdate = true; } - void MeshDataInstance::UpdateCullBounds(const TransformServiceFeatureProcessor* transformService) + void ModelDataInstance::UpdateCullBounds(const TransformServiceFeatureProcessor* transformService) { - AZ_PROFILE_SCOPE(AzRender, "MeshDataInstance: UpdateCullBounds"); + AZ_PROFILE_SCOPE(AzRender, "ModelDataInstance: UpdateCullBounds"); AZ_Assert(m_cullBoundsNeedsUpdate, "This function only needs to be called if the culling bounds need to be rebuilt"); AZ_Assert(m_model, "The model has not finished loading yet"); @@ -1148,70 +1154,70 @@ namespace AZ m_cullBoundsNeedsUpdate = false; } - void MeshDataInstance::UpdateObjectSrg() + void ModelDataInstance::UpdateObjectSrg() { - if (!m_shaderResourceGroup) + for (auto& objectSrg : m_objectSrgList) { - return; + ReflectionProbeFeatureProcessor* reflectionProbeFeatureProcessor = m_scene->GetFeatureProcessor(); + + if (reflectionProbeFeatureProcessor && (m_descriptor.m_useForwardPassIblSpecular || m_hasForwardPassIblSpecularMaterial)) + { + // retrieve probe constant indices + AZ::RHI::ShaderInputConstantIndex modelToWorldConstantIndex = objectSrg->FindShaderInputConstantIndex(Name("m_reflectionProbeData.m_modelToWorld")); + AZ_Error("ModelDataInstance", modelToWorldConstantIndex.IsValid(), "Failed to find ReflectionProbe constant index"); + + AZ::RHI::ShaderInputConstantIndex modelToWorldInverseConstantIndex = objectSrg->FindShaderInputConstantIndex(Name("m_reflectionProbeData.m_modelToWorldInverse")); + AZ_Error("ModelDataInstance", modelToWorldInverseConstantIndex.IsValid(), "Failed to find ReflectionProbe constant index"); + + AZ::RHI::ShaderInputConstantIndex outerObbHalfLengthsConstantIndex = objectSrg->FindShaderInputConstantIndex(Name("m_reflectionProbeData.m_outerObbHalfLengths")); + AZ_Error("ModelDataInstance", outerObbHalfLengthsConstantIndex.IsValid(), "Failed to find ReflectionProbe constant index"); + + AZ::RHI::ShaderInputConstantIndex innerObbHalfLengthsConstantIndex = objectSrg->FindShaderInputConstantIndex(Name("m_reflectionProbeData.m_innerObbHalfLengths")); + AZ_Error("ModelDataInstance", innerObbHalfLengthsConstantIndex.IsValid(), "Failed to find ReflectionProbe constant index"); + + AZ::RHI::ShaderInputConstantIndex useReflectionProbeConstantIndex = objectSrg->FindShaderInputConstantIndex(Name("m_reflectionProbeData.m_useReflectionProbe")); + AZ_Error("ModelDataInstance", useReflectionProbeConstantIndex.IsValid(), "Failed to find ReflectionProbe constant index"); + + AZ::RHI::ShaderInputConstantIndex useParallaxCorrectionConstantIndex = objectSrg->FindShaderInputConstantIndex(Name("m_reflectionProbeData.m_useParallaxCorrection")); + AZ_Error("ModelDataInstance", useParallaxCorrectionConstantIndex.IsValid(), "Failed to find ReflectionProbe constant index"); + + // retrieve probe cubemap index + Name reflectionCubeMapImageName = Name("m_reflectionProbeCubeMap"); + RHI::ShaderInputImageIndex reflectionCubeMapImageIndex = objectSrg->FindShaderInputImageIndex(reflectionCubeMapImageName); + AZ_Error("ModelDataInstance", reflectionCubeMapImageIndex.IsValid(), "Failed to find shader image index [%s]", reflectionCubeMapImageName.GetCStr()); + + // retrieve the list of probes that contain the centerpoint of the mesh + TransformServiceFeatureProcessor* transformServiceFeatureProcessor = m_scene->GetFeatureProcessor(); + Transform transform = transformServiceFeatureProcessor->GetTransformForId(m_objectId); + + ReflectionProbeFeatureProcessor::ReflectionProbeVector reflectionProbes; + reflectionProbeFeatureProcessor->FindReflectionProbes(transform.GetTranslation(), reflectionProbes); + + if (!reflectionProbes.empty() && reflectionProbes[0]) + { + objectSrg->SetConstant(modelToWorldConstantIndex, reflectionProbes[0]->GetTransform()); + objectSrg->SetConstant(modelToWorldInverseConstantIndex, Matrix3x4::CreateFromTransform(reflectionProbes[0]->GetTransform()).GetInverseFull()); + objectSrg->SetConstant(outerObbHalfLengthsConstantIndex, reflectionProbes[0]->GetOuterObbWs().GetHalfLengths()); + objectSrg->SetConstant(innerObbHalfLengthsConstantIndex, reflectionProbes[0]->GetInnerObbWs().GetHalfLengths()); + objectSrg->SetConstant(useReflectionProbeConstantIndex, true); + objectSrg->SetConstant(useParallaxCorrectionConstantIndex, reflectionProbes[0]->GetUseParallaxCorrection()); + + objectSrg->SetImage(reflectionCubeMapImageIndex, reflectionProbes[0]->GetCubeMapImage()); + } + else + { + objectSrg->SetConstant(useReflectionProbeConstantIndex, false); + } + } + + objectSrg->Compile(); } - ReflectionProbeFeatureProcessor* reflectionProbeFeatureProcessor = m_scene->GetFeatureProcessor(); - - if (reflectionProbeFeatureProcessor && (m_descriptor.m_useForwardPassIblSpecular || m_hasForwardPassIblSpecularMaterial)) - { - // retrieve probe constant indices - AZ::RHI::ShaderInputConstantIndex modelToWorldConstantIndex = m_shaderResourceGroup->FindShaderInputConstantIndex(Name("m_reflectionProbeData.m_modelToWorld")); - AZ_Error("MeshDataInstance", modelToWorldConstantIndex.IsValid(), "Failed to find ReflectionProbe constant index"); - - AZ::RHI::ShaderInputConstantIndex modelToWorldInverseConstantIndex = m_shaderResourceGroup->FindShaderInputConstantIndex(Name("m_reflectionProbeData.m_modelToWorldInverse")); - AZ_Error("MeshDataInstance", modelToWorldInverseConstantIndex.IsValid(), "Failed to find ReflectionProbe constant index"); - - AZ::RHI::ShaderInputConstantIndex outerObbHalfLengthsConstantIndex = m_shaderResourceGroup->FindShaderInputConstantIndex(Name("m_reflectionProbeData.m_outerObbHalfLengths")); - AZ_Error("MeshDataInstance", outerObbHalfLengthsConstantIndex.IsValid(), "Failed to find ReflectionProbe constant index"); - - AZ::RHI::ShaderInputConstantIndex innerObbHalfLengthsConstantIndex = m_shaderResourceGroup->FindShaderInputConstantIndex(Name("m_reflectionProbeData.m_innerObbHalfLengths")); - AZ_Error("MeshDataInstance", innerObbHalfLengthsConstantIndex.IsValid(), "Failed to find ReflectionProbe constant index"); - - AZ::RHI::ShaderInputConstantIndex useReflectionProbeConstantIndex = m_shaderResourceGroup->FindShaderInputConstantIndex(Name("m_reflectionProbeData.m_useReflectionProbe")); - AZ_Error("MeshDataInstance", useReflectionProbeConstantIndex.IsValid(), "Failed to find ReflectionProbe constant index"); - - AZ::RHI::ShaderInputConstantIndex useParallaxCorrectionConstantIndex = m_shaderResourceGroup->FindShaderInputConstantIndex(Name("m_reflectionProbeData.m_useParallaxCorrection")); - AZ_Error("MeshDataInstance", useParallaxCorrectionConstantIndex.IsValid(), "Failed to find ReflectionProbe constant index"); - - // retrieve probe cubemap index - Name reflectionCubeMapImageName = Name("m_reflectionProbeCubeMap"); - RHI::ShaderInputImageIndex reflectionCubeMapImageIndex = m_shaderResourceGroup->FindShaderInputImageIndex(reflectionCubeMapImageName); - AZ_Error("MeshDataInstance", reflectionCubeMapImageIndex.IsValid(), "Failed to find shader image index [%s]", reflectionCubeMapImageName.GetCStr()); - - // retrieve the list of probes that contain the centerpoint of the mesh - TransformServiceFeatureProcessor* transformServiceFeatureProcessor = m_scene->GetFeatureProcessor(); - Transform transform = transformServiceFeatureProcessor->GetTransformForId(m_objectId); - - ReflectionProbeFeatureProcessor::ReflectionProbeVector reflectionProbes; - reflectionProbeFeatureProcessor->FindReflectionProbes(transform.GetTranslation(), reflectionProbes); - - if (!reflectionProbes.empty() && reflectionProbes[0]) - { - m_shaderResourceGroup->SetConstant(modelToWorldConstantIndex, reflectionProbes[0]->GetTransform()); - m_shaderResourceGroup->SetConstant(modelToWorldInverseConstantIndex, Matrix3x4::CreateFromTransform(reflectionProbes[0]->GetTransform()).GetInverseFull()); - m_shaderResourceGroup->SetConstant(outerObbHalfLengthsConstantIndex, reflectionProbes[0]->GetOuterObbWs().GetHalfLengths()); - m_shaderResourceGroup->SetConstant(innerObbHalfLengthsConstantIndex, reflectionProbes[0]->GetInnerObbWs().GetHalfLengths()); - m_shaderResourceGroup->SetConstant(useReflectionProbeConstantIndex, true); - m_shaderResourceGroup->SetConstant(useParallaxCorrectionConstantIndex, reflectionProbes[0]->GetUseParallaxCorrection()); - - m_shaderResourceGroup->SetImage(reflectionCubeMapImageIndex, reflectionProbes[0]->GetCubeMapImage()); - } - else - { - m_shaderResourceGroup->SetConstant(useReflectionProbeConstantIndex, false); - } - } - - m_shaderResourceGroup->Compile(); - m_objectSrgNeedsUpdate = false; + // Set m_objectSrgNeedsUpdate to false if there are object SRGs in the list + m_objectSrgNeedsUpdate = m_objectSrgNeedsUpdate && (m_objectSrgList.size() == 0); } - bool MeshDataInstance::MaterialRequiresForwardPassIblSpecular(Data::Instance material) const + bool ModelDataInstance::MaterialRequiresForwardPassIblSpecular(Data::Instance material) const { // look for a shader that has the o_materialUseForwardPassIBLSpecular option set // Note: this should be changed to have the material automatically set the forwardPassIBLSpecular @@ -1237,7 +1243,7 @@ namespace AZ return false; } - void MeshDataInstance::SetVisible(bool isVisible) + void ModelDataInstance::SetVisible(bool isVisible) { m_visible = isVisible; m_cullable.m_isHidden = !isVisible; diff --git a/Gems/Atom/Feature/Common/Code/Source/SkinnedMesh/SkinnedMeshFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/SkinnedMesh/SkinnedMeshFeatureProcessor.cpp index 4c379c4239..c135b017fa 100644 --- a/Gems/Atom/Feature/Common/Code/Source/SkinnedMesh/SkinnedMeshFeatureProcessor.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/SkinnedMesh/SkinnedMeshFeatureProcessor.cpp @@ -95,13 +95,13 @@ namespace AZ renderProxy.m_instance->m_model->WaitForUpload(); } - //Note: we are creating pointers to the meshDataInstance cullpacket and lod packet here, + //Note: we are creating pointers to the modelDataInstance cullpacket and lod packet here, //and holding them until the skinnedMeshDispatchItems are dispatched. There is an assumption that the underlying //data will not move during this phase. - MeshDataInstance& meshDataInstance = **renderProxy.m_meshHandle; - m_workgroup.m_cullPackets.push_back(&meshDataInstance.GetCullPacket()); - m_workgroup.m_drawListMask |= meshDataInstance.GetCullPacket().m_drawListMask; - m_lodPackets.push_back(&meshDataInstance.GetLodPacket()); + ModelDataInstance& modelDataInstance = **renderProxy.m_meshHandle; + m_workgroup.m_cullPackets.push_back(&modelDataInstance.GetCullPacket()); + m_workgroup.m_drawListMask |= modelDataInstance.GetCullPacket().m_drawListMask; + m_lodPackets.push_back(&modelDataInstance.GetLodPacket()); m_potentiallyVisibleProxies.push_back(&renderProxy); } } @@ -187,8 +187,8 @@ namespace AZ renderProxy.m_instance->m_model->WaitForUpload(); } - MeshDataInstance& meshDataInstance = **renderProxy.m_meshHandle; - const RPI::Cullable& cullable = meshDataInstance.GetCullable(); + ModelDataInstance& modelDataInstance = **renderProxy.m_meshHandle; + const RPI::Cullable& cullable = modelDataInstance.GetCullable(); for (const RPI::ViewPtr& viewPtr : packet.m_views) { diff --git a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/AtomActorInstance.cpp b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/AtomActorInstance.cpp index a3161002a0..7cd4fc073b 100644 --- a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/AtomActorInstance.cpp +++ b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/AtomActorInstance.cpp @@ -880,12 +880,14 @@ namespace AZ { if (m_meshHandle) { - Data::Instance wrinkleMaskObjectSrg = m_meshFeatureProcessor->GetObjectSrg(*m_meshHandle); - if (wrinkleMaskObjectSrg) + AZStd::vector>& wrinkleMaskObjectSrgs = m_meshFeatureProcessor->GetObjectSrgs(*m_meshHandle); + + for (auto& wrinkleMaskObjectSrg : wrinkleMaskObjectSrgs) { RHI::ShaderInputImageIndex wrinkleMasksIndex = wrinkleMaskObjectSrg->FindShaderInputImageIndex(Name{ "m_wrinkle_masks" }); RHI::ShaderInputConstantIndex wrinkleMaskWeightsIndex = wrinkleMaskObjectSrg->FindShaderInputConstantIndex(Name{ "m_wrinkle_mask_weights" }); RHI::ShaderInputConstantIndex wrinkleMaskCountIndex = wrinkleMaskObjectSrg->FindShaderInputConstantIndex(Name{ "m_wrinkle_mask_count" }); + if (wrinkleMasksIndex.IsValid() || wrinkleMaskWeightsIndex.IsValid() || wrinkleMaskCountIndex.IsValid()) { AZ_Error("AtomActorInstance", wrinkleMasksIndex.IsValid(), "m_wrinkle_masks not found on the ObjectSrg, but m_wrinkle_mask_weights and/or m_wrinkle_mask_count are being used."); From 1f72001cdb2bc03967e4680c3c9671018f98f09f Mon Sep 17 00:00:00 2001 From: antonmic <56370189+antonmic@users.noreply.github.com> Date: Wed, 10 Nov 2021 00:56:25 -0800 Subject: [PATCH 42/71] Added two missing MeshDataInstance to ModelDataInstance renames in error message Signed-off-by: antonmic <56370189+antonmic@users.noreply.github.com> --- .../Feature/Common/Code/Source/Mesh/MeshFeatureProcessor.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Gems/Atom/Feature/Common/Code/Source/Mesh/MeshFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/Mesh/MeshFeatureProcessor.cpp index 49fe4cf093..7227311915 100644 --- a/Gems/Atom/Feature/Common/Code/Source/Mesh/MeshFeatureProcessor.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/Mesh/MeshFeatureProcessor.cpp @@ -1182,12 +1182,12 @@ namespace AZ AZ_Error("ModelDataInstance", useParallaxCorrectionConstantIndex.IsValid(), "Failed to find ReflectionProbe constant index"); AZ::RHI::ShaderInputConstantIndex exposureConstantIndex = objectSrg->FindShaderInputConstantIndex(Name("m_reflectionProbeData.m_exposure")); - AZ_Error("MeshDataInstance", exposureConstantIndex.IsValid(), "Failed to find ReflectionProbe constant index"); + AZ_Error("ModelDataInstance", exposureConstantIndex.IsValid(), "Failed to find ReflectionProbe constant index"); // retrieve probe cubemap index Name reflectionCubeMapImageName = Name("m_reflectionProbeCubeMap"); RHI::ShaderInputImageIndex reflectionCubeMapImageIndex = objectSrg->FindShaderInputImageIndex(reflectionCubeMapImageName); - AZ_Error("MeshDataInstance", reflectionCubeMapImageIndex.IsValid(), "Failed to find shader image index [%s]", reflectionCubeMapImageName.GetCStr()); + AZ_Error("ModelDataInstance", reflectionCubeMapImageIndex.IsValid(), "Failed to find shader image index [%s]", reflectionCubeMapImageName.GetCStr()); // retrieve the list of probes that contain the centerpoint of the mesh TransformServiceFeatureProcessor* transformServiceFeatureProcessor = m_scene->GetFeatureProcessor(); From 0e3df14ea2f1b2e36c3d64cf6ff72b52eb2d2f5a Mon Sep 17 00:00:00 2001 From: John Date: Wed, 10 Nov 2021 11:59:28 +0000 Subject: [PATCH 43/71] Add missing bus connection/disconnection. Signed-off-by: John --- .../UI/PropertyEditor/EntityPropertyEditor.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/EntityPropertyEditor.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/EntityPropertyEditor.cpp index 9ffe8021e3..a449fa0055 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/EntityPropertyEditor.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/EntityPropertyEditor.cpp @@ -606,6 +606,7 @@ namespace AzToolsFramework AzToolsFramework::ComponentModeFramework::EditorComponentModeNotificationBus::Handler::BusConnect( AzToolsFramework::GetEntityContextId()); + ViewportEditorModeNotificationsBus::Handler::BusConnect(GetEntityContextId()); } EntityPropertyEditor::~EntityPropertyEditor() @@ -618,7 +619,8 @@ namespace AzToolsFramework AZ::EntitySystemBus::Handler::BusDisconnect(); EditorEntityContextNotificationBus::Handler::BusDisconnect(); AzToolsFramework::ComponentModeFramework::EditorComponentModeNotificationBus::Handler::BusDisconnect(); - + ViewportEditorModeNotificationsBus::Handler::BusDisconnect(); + for (auto& entityId : m_overrideSelectedEntityIds) { DisconnectFromEntityBuses(entityId); From 027b0f86ae5bac33ae04967eb66bf5927df1face Mon Sep 17 00:00:00 2001 From: AMZN-Igarri <82394219+AMZN-Igarri@users.noreply.github.com> Date: Wed, 10 Nov 2021 14:41:59 +0100 Subject: [PATCH 44/71] Activate AssetBrowserTableView feature (#5367) Signed-off-by: igarri --- .../AzToolsFramework/AssetBrowser/AssetBrowserFilterModel.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/AssetBrowserFilterModel.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/AssetBrowserFilterModel.cpp index acf935e6dc..c6772ea2d7 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/AssetBrowserFilterModel.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/AssetBrowserFilterModel.cpp @@ -20,7 +20,7 @@ AZ_PUSH_DISABLE_WARNING(4251, "-Wunknown-warning-option") AZ_POP_DISABLE_WARNING AZ_CVAR( - bool, ed_useNewAssetBrowserTableView, false, nullptr, AZ::ConsoleFunctorFlags::Null, + bool, ed_useNewAssetBrowserTableView, true, nullptr, AZ::ConsoleFunctorFlags::Null, "Use the new AssetBrowser TableView for searching assets."); namespace AzToolsFramework { From 847e13154f2b95947561b07ad00b8420764916de Mon Sep 17 00:00:00 2001 From: Chris Galvan Date: Wed, 10 Nov 2021 09:55:49 -0600 Subject: [PATCH 45/71] Updated some Script Canvas node slot names to EntityID for consistency. Signed-off-by: Chris Galvan --- Assets/Editor/Translation/scriptcanvas_en_us.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Assets/Editor/Translation/scriptcanvas_en_us.ts b/Assets/Editor/Translation/scriptcanvas_en_us.ts index 7b8361c879..6d436b7caf 100644 --- a/Assets/Editor/Translation/scriptcanvas_en_us.ts +++ b/Assets/Editor/Translation/scriptcanvas_en_us.ts @@ -62164,7 +62164,7 @@ An Entity can be selected by using the pick button, or by dragging an Entity fro HANDLER_TAGGLOBALNOTIFICATIONBUS_ONENTITYTAGADDED_OUTPUT0_NAME Simple Type: EntityID C++ Type: const EntityId& - Entity + EntityID HANDLER_TAGGLOBALNOTIFICATIONBUS_ONENTITYTAGADDED_OUTPUT0_TOOLTIP @@ -62202,7 +62202,7 @@ An Entity can be selected by using the pick button, or by dragging an Entity fro HANDLER_TAGGLOBALNOTIFICATIONBUS_ONENTITYTAGREMOVED_OUTPUT0_NAME Simple Type: EntityID C++ Type: const EntityId& - Entity + EntityId HANDLER_TAGGLOBALNOTIFICATIONBUS_ONENTITYTAGREMOVED_OUTPUT0_TOOLTIP @@ -81852,7 +81852,7 @@ The element is removed from its current parent and added as a child of the new p HANDLER_SPAWNERCOMPONENTNOTIFICATIONBUS_ONENTITYSPAWNED_OUTPUT1_NAME Simple Type: EntityID C++ Type: const EntityId& - Entity + EntityID HANDLER_SPAWNERCOMPONENTNOTIFICATIONBUS_ONENTITYSPAWNED_OUTPUT1_TOOLTIP @@ -89198,7 +89198,7 @@ The element is removed from its current parent and added as a child of the new p HANDLER_ENTITYBUS_ONENTITYACTIVATED_OUTPUT0_NAME Simple Type: EntityID C++ Type: const EntityId& - Entity + EntityID HANDLER_ENTITYBUS_ONENTITYACTIVATED_OUTPUT0_TOOLTIP @@ -89236,7 +89236,7 @@ The element is removed from its current parent and added as a child of the new p HANDLER_ENTITYBUS_ONENTITYDEACTIVATED_OUTPUT0_NAME Simple Type: EntityID C++ Type: const EntityId& - Entity + EntityID HANDLER_ENTITYBUS_ONENTITYDEACTIVATED_OUTPUT0_TOOLTIP From f0b4eb17127534ca0919cb9eb372439e2739f5de Mon Sep 17 00:00:00 2001 From: Guthrie Adams Date: Wed, 10 Nov 2021 10:54:53 -0600 Subject: [PATCH 46/71] update comment and error message Signed-off-by: Guthrie Adams --- .../RPI.Edit/Material/LuaMaterialFunctorSourceData.cpp | 5 ++++- .../RPI/Code/Source/RPI.Edit/Material/MaterialSourceData.cpp | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/LuaMaterialFunctorSourceData.cpp b/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/LuaMaterialFunctorSourceData.cpp index 37bd5a19f2..14ef3bb17d 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/LuaMaterialFunctorSourceData.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/LuaMaterialFunctorSourceData.cpp @@ -137,7 +137,10 @@ namespace AZ } else if (!m_luaSourceFile.empty()) { - auto loadOutcome = RPI::AssetUtils::LoadAsset(materialTypeSourceFilePath, m_luaSourceFile, ScriptAsset::CompiledAssetSubId); + // The sub ID for script assets must be explicit. + // LUA source files output a compiled as well as an uncompiled asset, sub Ids of 1 and 2. + auto loadOutcome = + RPI::AssetUtils::LoadAsset(materialTypeSourceFilePath, m_luaSourceFile, ScriptAsset::CompiledAssetSubId); if (!loadOutcome) { AZ_Error("LuaMaterialFunctorSourceData", false, "Could not load script file '%s'", m_luaSourceFile.c_str()); diff --git a/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialSourceData.cpp b/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialSourceData.cpp index e5466a173f..d6308ec655 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialSourceData.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialSourceData.cpp @@ -250,7 +250,7 @@ namespace AZ const auto parentTypeAssetId = AssetUtils::MakeAssetId(parentSourceAbsPath, parentSourceData.m_materialType, 0); if (!parentTypeAssetId) { - AZ_Error("MaterialSourceData", false, "Parent material asset ID isn't valid: '%s'.", parentSourceAbsPath.c_str()); + AZ_Error("MaterialSourceData", false, "Parent material asset ID wasn't found: '%s'.", parentSourceAbsPath.c_str()); return Failure(); } From 7159e3fe575378254983e09dabe44a9ef52e53c7 Mon Sep 17 00:00:00 2001 From: sphrose <82213493+sphrose@users.noreply.github.com> Date: Wed, 10 Nov 2021 17:22:55 +0000 Subject: [PATCH 47/71] Moving to stabilization Signed-off-by: sphrose <82213493+sphrose@users.noreply.github.com> --- Gems/Terrain/Code/Tests/LayerSpawnerTests.cpp | 162 +++++++++--------- 1 file changed, 82 insertions(+), 80 deletions(-) diff --git a/Gems/Terrain/Code/Tests/LayerSpawnerTests.cpp b/Gems/Terrain/Code/Tests/LayerSpawnerTests.cpp index 3778ba860f..9de441eecf 100644 --- a/Gems/Terrain/Code/Tests/LayerSpawnerTests.cpp +++ b/Gems/Terrain/Code/Tests/LayerSpawnerTests.cpp @@ -6,15 +6,13 @@ * */ +#include + #include #include #include -#include - #include -#include -#include #include #include @@ -23,21 +21,12 @@ using ::testing::NiceMock; using ::testing::AtLeast; using ::testing::_; -using ::testing::NiceMock; -using ::testing::AtLeast; -using ::testing::_; - class LayerSpawnerComponentTest : public ::testing::Test { protected: AZ::ComponentApplication m_app; - AZStd::unique_ptr m_entity; - Terrain::TerrainLayerSpawnerComponent* m_layerSpawnerComponent; - UnitTest::MockAxisAlignedBoxShapeComponent* m_shapeComponent; - AZStd::unique_ptr> m_terrainSystem; - void SetUp() override { AZ::ComponentApplication::Descriptor appDesc; @@ -50,78 +39,86 @@ protected: void TearDown() override { - m_entity.reset(); - m_terrainSystem.reset(); m_app.Destroy(); } - void CreateEntity() + AZStd::unique_ptr CreateEntity() { - m_entity = AZStd::make_unique(); - m_entity->Init(); + auto entity = AZStd::make_unique(); + entity->Init(); - ASSERT_TRUE(m_entity); + return entity; } - void AddLayerSpawnerAndShapeComponentToEntity() + Terrain::TerrainLayerSpawnerComponent* AddLayerSpawnerToEntity(AZ::Entity* entity, const Terrain::TerrainLayerSpawnerConfig& config) { - AddLayerSpawnerAndShapeComponentToEntity(Terrain::TerrainLayerSpawnerConfig()); + auto layerSpawnerComponent = entity->CreateComponent(config); + m_app.RegisterComponentDescriptor(layerSpawnerComponent->CreateDescriptor()); + + return layerSpawnerComponent; } - void AddLayerSpawnerAndShapeComponentToEntity(const Terrain::TerrainLayerSpawnerConfig& config) + UnitTest::MockAxisAlignedBoxShapeComponent* AddShapeComponentToEntity(AZ::Entity* entity) { - m_layerSpawnerComponent = m_entity->CreateComponent(config); - m_app.RegisterComponentDescriptor(m_layerSpawnerComponent->CreateDescriptor()); + UnitTest::MockAxisAlignedBoxShapeComponent* shapeComponent = entity->CreateComponent(); + m_app.RegisterComponentDescriptor(shapeComponent->CreateDescriptor()); - m_shapeComponent = m_entity->CreateComponent(); - m_app.RegisterComponentDescriptor(m_shapeComponent->CreateDescriptor()); - - ASSERT_TRUE(m_layerSpawnerComponent); - ASSERT_TRUE(m_shapeComponent); - } - - void CreateMockTerrainSystem() - { - m_terrainSystem = AZStd::make_unique>(); + return shapeComponent; } }; -TEST_F(LayerSpawnerComponentTest, ActivatEntityActivateSuccess) +TEST_F(LayerSpawnerComponentTest, ActivateEntityWithoutShapeFails) { - CreateEntity(); - AddLayerSpawnerAndShapeComponentToEntity(); + auto entity = CreateEntity(); - m_entity->Activate(); - EXPECT_EQ(m_entity->GetState(), AZ::Entity::State::Active); - - m_entity->Deactivate(); + AddLayerSpawnerToEntity(entity.get(), Terrain::TerrainLayerSpawnerConfig()); + + const AZ::Entity::DependencySortOutcome sortOutcome = entity->EvaluateDependenciesGetDetails(); + EXPECT_FALSE(sortOutcome.IsSuccess()); + + entity.reset(); +} + +TEST_F(LayerSpawnerComponentTest, ActivateEntityActivateSuccess) +{ + auto entity = CreateEntity(); + + AddLayerSpawnerToEntity(entity.get(), Terrain::TerrainLayerSpawnerConfig()); + AddShapeComponentToEntity(entity.get()); + + entity->Activate(); + EXPECT_EQ(entity->GetState(), AZ::Entity::State::Active); + + entity.reset(); } TEST_F(LayerSpawnerComponentTest, LayerSpawnerDefaultValuesCorrect) { - CreateEntity(); - AddLayerSpawnerAndShapeComponentToEntity(); + auto entity = CreateEntity(); + AddLayerSpawnerToEntity(entity.get(), Terrain::TerrainLayerSpawnerConfig()); + AddShapeComponentToEntity(entity.get()); - m_entity->Activate(); + entity->Activate(); AZ::u32 priority = 999, layer = 999; - Terrain::TerrainSpawnerRequestBus::Event(m_entity->GetId(), &Terrain::TerrainSpawnerRequestBus::Events::GetPriority, layer, priority); + Terrain::TerrainSpawnerRequestBus::Event(entity->GetId(), &Terrain::TerrainSpawnerRequestBus::Events::GetPriority, layer, priority); EXPECT_EQ(0, priority); EXPECT_EQ(1, layer); bool useGroundPlane = false; - Terrain::TerrainSpawnerRequestBus::EventResult(useGroundPlane, m_entity->GetId(), &Terrain::TerrainSpawnerRequestBus::Events::GetUseGroundPlane); + Terrain::TerrainSpawnerRequestBus::EventResult( + useGroundPlane, entity->GetId(), &Terrain::TerrainSpawnerRequestBus::Events::GetUseGroundPlane); EXPECT_TRUE(useGroundPlane); - m_entity->Deactivate(); + entity.reset(); } TEST_F(LayerSpawnerComponentTest, LayerSpawnerConfigValuesCorrect) { - CreateEntity(); + auto entity = CreateEntity(); constexpr static AZ::u32 testPriority = 15; constexpr static AZ::u32 testLayer = 0; @@ -131,12 +128,13 @@ TEST_F(LayerSpawnerComponentTest, LayerSpawnerConfigValuesCorrect) config.m_priority = testPriority; config.m_useGroundPlane = false; - AddLayerSpawnerAndShapeComponentToEntity(config); + AddLayerSpawnerToEntity(entity.get(), config); + AddShapeComponentToEntity(entity.get()); - m_entity->Activate(); + entity->Activate(); AZ::u32 priority = 999, layer = 999; - Terrain::TerrainSpawnerRequestBus::Event(m_entity->GetId(), &Terrain::TerrainSpawnerRequestBus::Events::GetPriority, layer, priority); + Terrain::TerrainSpawnerRequestBus::Event(entity->GetId(), &Terrain::TerrainSpawnerRequestBus::Events::GetPriority, layer, priority); EXPECT_EQ(testPriority, priority); EXPECT_EQ(testLayer, layer); @@ -144,82 +142,86 @@ TEST_F(LayerSpawnerComponentTest, LayerSpawnerConfigValuesCorrect) bool useGroundPlane = true; Terrain::TerrainSpawnerRequestBus::EventResult( - useGroundPlane, m_entity->GetId(), &Terrain::TerrainSpawnerRequestBus::Events::GetUseGroundPlane); + useGroundPlane, entity->GetId(), &Terrain::TerrainSpawnerRequestBus::Events::GetUseGroundPlane); EXPECT_FALSE(useGroundPlane); - m_entity->Deactivate(); + entity.reset(); } TEST_F(LayerSpawnerComponentTest, LayerSpawnerRegisterAreaUpdatesTerrainSystem) { - CreateEntity(); + auto entity = CreateEntity(); - CreateMockTerrainSystem(); + NiceMock terrainSystem; // The Activate call should register the area. - EXPECT_CALL(*m_terrainSystem, RegisterArea(_)).Times(1); + EXPECT_CALL(terrainSystem, RegisterArea(_)).Times(1); - AddLayerSpawnerAndShapeComponentToEntity(); + AddLayerSpawnerToEntity(entity.get(), Terrain::TerrainLayerSpawnerConfig()); + AddShapeComponentToEntity(entity.get()); - m_entity->Activate(); + entity->Activate(); - m_entity->Deactivate(); + entity.reset(); } TEST_F(LayerSpawnerComponentTest, LayerSpawnerUnregisterAreaUpdatesTerrainSystem) { - CreateEntity(); + auto entity = CreateEntity(); - CreateMockTerrainSystem(); + NiceMock terrainSystem; // The Deactivate call should unregister the area. - EXPECT_CALL(*m_terrainSystem, UnregisterArea(_)).Times(1); + EXPECT_CALL(terrainSystem, UnregisterArea(_)).Times(1); - AddLayerSpawnerAndShapeComponentToEntity(); + AddLayerSpawnerToEntity(entity.get(), Terrain::TerrainLayerSpawnerConfig()); + AddShapeComponentToEntity(entity.get()); - m_entity->Activate(); + entity->Activate(); - m_entity->Deactivate(); + entity.reset(); } TEST_F(LayerSpawnerComponentTest, LayerSpawnerTransformChangedUpdatesTerrainSystem) { - CreateEntity(); + auto entity = CreateEntity(); - CreateMockTerrainSystem(); + NiceMock terrainSystem; // The TransformChanged call should refresh the area. - EXPECT_CALL(*m_terrainSystem, RefreshArea(_, _)).Times(1); + EXPECT_CALL(terrainSystem, RefreshArea(_, _)).Times(1); - AddLayerSpawnerAndShapeComponentToEntity(); + AddLayerSpawnerToEntity(entity.get(), Terrain::TerrainLayerSpawnerConfig()); + AddShapeComponentToEntity(entity.get()); - m_entity->Activate(); + entity->Activate(); // The component gets transform change notifications via the shape bus. LmbrCentral::ShapeComponentNotificationsBus::Event( - m_entity->GetId(), &LmbrCentral::ShapeComponentNotificationsBus::Events::OnShapeChanged, + entity->GetId(), &LmbrCentral::ShapeComponentNotificationsBus::Events::OnShapeChanged, LmbrCentral::ShapeComponentNotifications::ShapeChangeReasons::TransformChanged); - m_entity->Deactivate(); + entity.reset(); } TEST_F(LayerSpawnerComponentTest, LayerSpawnerShapeChangedUpdatesTerrainSystem) { - CreateEntity(); + auto entity = CreateEntity(); - CreateMockTerrainSystem(); + NiceMock terrainSystem; // The ShapeChanged call should refresh the area. - EXPECT_CALL(*m_terrainSystem, RefreshArea(_, _)).Times(1); + EXPECT_CALL(terrainSystem, RefreshArea(_, _)).Times(1); - AddLayerSpawnerAndShapeComponentToEntity(); + AddLayerSpawnerToEntity(entity.get(), Terrain::TerrainLayerSpawnerConfig()); + AddShapeComponentToEntity(entity.get()); - m_entity->Activate(); + entity->Activate(); - LmbrCentral::ShapeComponentNotificationsBus::Event( - m_entity->GetId(), &LmbrCentral::ShapeComponentNotificationsBus::Events::OnShapeChanged, + LmbrCentral::ShapeComponentNotificationsBus::Event( + entity->GetId(), &LmbrCentral::ShapeComponentNotificationsBus::Events::OnShapeChanged, LmbrCentral::ShapeComponentNotifications::ShapeChangeReasons::ShapeChanged); - m_entity->Deactivate(); + entity.reset(); } From 0c546828d642b5a71e2762a8dbe419acbf3a3400 Mon Sep 17 00:00:00 2001 From: SJ Date: Wed, 10 Nov 2021 09:31:59 -0800 Subject: [PATCH 48/71] 1. Add nullptr checks to prevent crashes when non-critical shaders fail to compile. (#5451) 2. Add a higher "launch_ap_timeout" for Mac because launching a newly built/downloaded AP can take a while. Signed-off-by: amzn-sj --- .../PostProcessing/BlendColorGradingLutsPass.cpp | 6 +++++- .../ReflectionProbeFeatureProcessor.cpp | 7 ++++++- .../RPI.Public/Pass/FullscreenTrianglePass.cpp | 6 ++++++ Registry/Platform/Mac/bootstrap_overrides.setreg | 12 ++++++++++++ 4 files changed, 29 insertions(+), 2 deletions(-) create mode 100644 Registry/Platform/Mac/bootstrap_overrides.setreg diff --git a/Gems/Atom/Feature/Common/Code/Source/PostProcessing/BlendColorGradingLutsPass.cpp b/Gems/Atom/Feature/Common/Code/Source/PostProcessing/BlendColorGradingLutsPass.cpp index f74837bd9a..ca93898d5e 100644 --- a/Gems/Atom/Feature/Common/Code/Source/PostProcessing/BlendColorGradingLutsPass.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/PostProcessing/BlendColorGradingLutsPass.cpp @@ -46,7 +46,11 @@ namespace AZ void BlendColorGradingLutsPass::InitializeShaderVariant() { - AZ_Assert(m_shader != nullptr, "BlendColorGradingLutsPass %s has a null shader when calling InitializeShaderVariant.", GetPathName().GetCStr()); + if (m_shader == nullptr) + { + AZ_Assert(false, "BlendColorGradingLutsPass %s has a null shader when calling InitializeShaderVariant.", GetPathName().GetCStr()); + return; + } // Total variations is MaxBlendLuts plus one for the fallback case that none of the LUTs are found, // and hence zero LUTs are blended resulting in an identity LUT. diff --git a/Gems/Atom/Feature/Common/Code/Source/ReflectionProbe/ReflectionProbeFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/ReflectionProbe/ReflectionProbeFeatureProcessor.cpp index b1484ac8a8..e9038858ad 100644 --- a/Gems/Atom/Feature/Common/Code/Source/ReflectionProbe/ReflectionProbeFeatureProcessor.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/ReflectionProbe/ReflectionProbeFeatureProcessor.cpp @@ -443,7 +443,12 @@ namespace AZ { // load shader shader = RPI::LoadCriticalShader(filePath); - AZ_Error("ReflectionProbeFeatureProcessor", shader, "Failed to find asset for shader [%s]", filePath); + + if (shader == nullptr) + { + AZ_Error("ReflectionProbeFeatureProcessor", false, "Failed to find asset for shader [%s]", filePath); + return; + } // store drawlist tag drawListTag = shader->GetDrawListTag(); diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/FullscreenTrianglePass.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/FullscreenTrianglePass.cpp index 40dce7d138..828966f377 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/FullscreenTrianglePass.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/FullscreenTrianglePass.cpp @@ -136,6 +136,12 @@ namespace AZ RHI::DrawLinear draw = RHI::DrawLinear(); draw.m_vertexCount = 3; + if (m_shader == nullptr) + { + AZ_Error("PassSystem", false, "[FullscreenTrianglePass]: Shader not loaded!"); + return; + } + RHI::PipelineStateDescriptorForDraw pipelineStateDescriptor; // [GFX TODO][ATOM-872] The pass should be able to drive the shader variant diff --git a/Registry/Platform/Mac/bootstrap_overrides.setreg b/Registry/Platform/Mac/bootstrap_overrides.setreg new file mode 100644 index 0000000000..4e1ca76724 --- /dev/null +++ b/Registry/Platform/Mac/bootstrap_overrides.setreg @@ -0,0 +1,12 @@ +{ + "Amazon": { + "AzCore": { + "Bootstrap": { + // The first time an application is launched on MacOS, each + // dynamic library is inspected by the OS before being loaded. + // This can take a while on some Macs. + "launch_ap_timeout": 300 + } + } + } +} From 3ced915f8ede3c1e0eb13688aaa9516abfd6e2b9 Mon Sep 17 00:00:00 2001 From: John Date: Wed, 10 Nov 2021 17:36:21 +0000 Subject: [PATCH 49/71] Fix attempted rendering of invalid Entity selection boxes. Signed-off-by: John --- .../ViewportSelection/EditorTransformComponentSelection.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorTransformComponentSelection.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorTransformComponentSelection.cpp index 39c882b766..f40e354ca2 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorTransformComponentSelection.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorTransformComponentSelection.cpp @@ -1177,8 +1177,10 @@ namespace AzToolsFramework continue; } - const AZ::Aabb bound = CalculateEditorEntitySelectionBounds(entityId, viewportInfo); - debugDisplay.DrawSolidBox(bound.GetMin(), bound.GetMax()); + if (const AZ::Aabb bound = CalculateEditorEntitySelectionBounds(entityId, viewportInfo); bound.IsValid()) + { + debugDisplay.DrawSolidBox(bound.GetMin(), bound.GetMax()); + } } debugDisplay.DepthTestOn(); From 576248a870fb7aab37949822a54a9b3969a6a6b1 Mon Sep 17 00:00:00 2001 From: Shirang Jia Date: Wed, 10 Nov 2021 10:26:44 -0800 Subject: [PATCH 50/71] Merge Jenkinsfile from development to stabilization (#5391) Signed-off-by: shiranj --- scripts/build/Jenkins/Jenkinsfile | 45 ++++++++++++++++++++++++++++--- 1 file changed, 42 insertions(+), 3 deletions(-) diff --git a/scripts/build/Jenkins/Jenkinsfile b/scripts/build/Jenkins/Jenkinsfile index 34732a5fad..beb4a21620 100644 --- a/scripts/build/Jenkins/Jenkinsfile +++ b/scripts/build/Jenkins/Jenkinsfile @@ -16,7 +16,7 @@ EMPTY_JSON = readJSON text: '{}' ENGINE_REPOSITORY_NAME = 'o3de' // Branches with build snapshots -BUILD_SNAPSHOTS = ['development', 'stabilization/2106'] +BUILD_SNAPSHOTS = ['development', 'stabilization/2110'] // Build snapshots with empty snapshot (for use with 'SNAPSHOT' pipeline paramater) BUILD_SNAPSHOTS_WITH_EMPTY = BUILD_SNAPSHOTS + '' @@ -102,6 +102,10 @@ def IsJobEnabled(branchName, buildTypeMap, pipelineName, platformName) { } } +def IsAPLogUpload(branchName, jobName) { + return !IsPullRequest(branchName) && jobName.toLowerCase().contains('asset') && env.AP_LOGS_S3_BUCKET +} + def GetRunningPipelineName(JENKINS_JOB_NAME) { // If the job name has an underscore def job_parts = JENKINS_JOB_NAME.tokenize('/')[0].tokenize('_') @@ -267,7 +271,7 @@ def CheckoutRepo(boolean disableSubmodules = false) { palRm('commitdate') } -def HandleDriveMount(String snapshot, String repositoryName, String projectName, String pipeline, String branchName, String platform, String buildType, String workspace, boolean recreateVolume = false) { +def HandleDriveMount(String snapshot, String repositoryName, String projectName, String pipeline, String branchName, String platform, String buildType, String workspace, boolean recreateVolume = false) { unstash name: 'incremental_build_script' def pythonCmd = '' @@ -429,6 +433,27 @@ def ExportTestScreenshots(Map options, String branchName, String platformName, S } } +def UploadAPLogs(Map options, String branchName, String platformName, String jobName, String workspace, Map params) { + dir("${workspace}/${ENGINE_REPOSITORY_NAME}") { + projects = params.CMAKE_LY_PROJECTS.split(",") + projects.each{ project -> + def apLogsPath = "${project}/user/log" + def s3UploadScriptPath = "scripts/build/tools/upload_to_s3.py" + if(env.IS_UNIX) { + pythonPath = "${options.PYTHON_DIR}/python.sh" + } + else { + pythonPath = "${options.PYTHON_DIR}/python.cmd" + } + def command = "${pythonPath} -u ${s3UploadScriptPath} --base_dir ${apLogsPath} " + + "--file_regex \".*\" --bucket ${env.AP_LOGS_S3_BUCKET} " + + "--search_subdirectories True --key_prefix ${env.JENKINS_JOB_NAME}/${branchName}/${env.BUILD_NUMBER}/${platformName}/${jobName} " + + '--extra_args {\\"ACL\\":\\"bucket-owner-full-control\\"}' + palSh(command, "Uploading AP logs for job ${jobName} for branch ${branchName}", false) + } + } + } + def PostBuildCommonSteps(String workspace, boolean mount = true) { echo 'Starting post-build common steps...' @@ -492,6 +517,14 @@ def CreateExportTestScreenshotsStage(Map pipelineConfig, String branchName, Stri } } +def CreateUploadAPLogsStage(Map pipelineConfig, String branchName, String platformName, String jobName, String workspace, Map params) { + return { + stage("${jobName}_upload_ap_logs") { + UploadAPLogs(pipelineConfig, branchName, platformName, jobName, workspace, params) + } + } +} + def CreateTeardownStage(Map environmentVars) { return { stage('Teardown') { @@ -516,9 +549,11 @@ def CreateSingleNode(Map pipelineConfig, def platform, def build_job, Map envVar CreateSetupStage(pipelineConfig, snapshot, repositoryName, projectName, pipelineName, branchName, platform.key, build_job.key, envVars, onlyMountEBSVolume).call() if(build_job.value.steps) { //this is a pipe with many steps so create all the build stages + pipelineEnvVars = GetBuildEnvVars(platform.value.PIPELINE_ENV ?: EMPTY_JSON, build_job.value.PIPELINE_ENV ?: EMPTY_JSON, pipelineName) build_job.value.steps.each { build_step -> build_job_name = build_step - envVars = GetBuildEnvVars(platform.value.PIPELINE_ENV ?: EMPTY_JSON, platform.value.build_types[build_step].PIPELINE_ENV ?: EMPTY_JSON, pipelineName) + // This addition of maps makes it that the right operand will override entries if they overlap with the left operand + envVars = pipelineEnvVars + GetBuildEnvVars(platform.value.PIPELINE_ENV ?: EMPTY_JSON, platform.value.build_types[build_step].PIPELINE_ENV ?: EMPTY_JSON, pipelineName) try { CreateBuildStage(pipelineConfig, platform.key, build_step, envVars).call() } @@ -541,6 +576,9 @@ def CreateSingleNode(Map pipelineConfig, def platform, def build_job, Map envVar error "Node disconnected during build: ${e}" // Error raised to retry stage on a new node } } + if (IsAPLogUpload(branchName, build_job_name)) { + CreateUploadAPLogsStage(pipelineConfig, branchName, platform.key, build_job_name, envVars['WORKSPACE'], platform.value.build_types[build_job_name].PARAMETERS).call() + } // All other errors will be raised outside the retry block currentResult = envVars['ON_FAILURE_MARK'] ?: 'FAILURE' currentException = e.toString() @@ -768,6 +806,7 @@ try { platform.value.build_types.each { build_job -> if (IsJobEnabled(branchName, build_job, pipelineName, platform.key)) { // User can filter jobs, jobs are tagged by pipeline def envVars = GetBuildEnvVars(platform.value.PIPELINE_ENV ?: EMPTY_JSON, build_job.value.PIPELINE_ENV ?: EMPTY_JSON, pipelineName) + envVars['JENKINS_JOB_NAME'] = env.JOB_NAME // Save original Jenkins job name to JENKINS_JOB_NAME envVars['JOB_NAME'] = "${branchName}_${platform.key}_${build_job.key}" // backwards compatibility, some scripts rely on this someBuildHappened = true From f2e191ea77c64232fb1fabf8f02ac235c3704518 Mon Sep 17 00:00:00 2001 From: AMZN-Phil Date: Wed, 10 Nov 2021 10:28:32 -0800 Subject: [PATCH 51/71] Fix trying to remove a cache file Signed-off-by: AMZN-Phil --- scripts/o3de/o3de/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/o3de/o3de/utils.py b/scripts/o3de/o3de/utils.py index 56f9ae4bcd..9872c0779b 100755 --- a/scripts/o3de/o3de/utils.py +++ b/scripts/o3de/o3de/utils.py @@ -128,7 +128,7 @@ def download_file(parsed_uri, download_path: pathlib.Path, force_overwrite, down logger.warn(f'File already downloaded to {download_path}.') else: try: - shutil.rmtree(download_path) + os.unlink(download_path) except OSError: logger.error(f'Could not remove existing download path {download_path}.') return 1 From e0cc86e8985b93e836a72772910ae304ef26cc3c Mon Sep 17 00:00:00 2001 From: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Date: Wed, 10 Nov 2021 13:21:42 -0600 Subject: [PATCH 52/71] Remove AssetProcessorManagerTest AssertAbsorber and update test to use the one from the base class instead (#5216) (#5381) Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> (cherry picked from commit b3301414ad1f76161fa88eaf8650f42bfb94617c) # Conflicts: # Code/Tools/AssetProcessor/native/tests/assetmanager/AssetProcessorManagerTest.cpp --- .../AssetProcessorManagerTest.cpp | 32 +++++++++---------- .../assetmanager/AssetProcessorManagerTest.h | 1 - 2 files changed, 16 insertions(+), 17 deletions(-) diff --git a/Code/Tools/AssetProcessor/native/tests/assetmanager/AssetProcessorManagerTest.cpp b/Code/Tools/AssetProcessor/native/tests/assetmanager/AssetProcessorManagerTest.cpp index f8d758e092..1a6063cff0 100644 --- a/Code/Tools/AssetProcessor/native/tests/assetmanager/AssetProcessorManagerTest.cpp +++ b/Code/Tools/AssetProcessor/native/tests/assetmanager/AssetProcessorManagerTest.cpp @@ -243,7 +243,7 @@ void AssetProcessorManagerTest::SetUp() m_mockApplicationManager->BusConnect(); m_assetProcessorManager.reset(new AssetProcessorManager_Test(m_config.get())); - m_assertAbsorber.Clear(); + m_errorAbsorber->Clear(); m_isIdling = false; @@ -334,9 +334,9 @@ TEST_F(AssetProcessorManagerTest, UnitTestForGettingJobInfoBySourceUUIDSuccess) EXPECT_STRCASEEQ(relFileName.toUtf8().data(), response.m_jobList[0].m_sourceFile.c_str()); EXPECT_STRCASEEQ(tempPath.filePath("subfolder1").toUtf8().data(), response.m_jobList[0].m_watchFolder.c_str()); - ASSERT_EQ(m_assertAbsorber.m_numWarningsAbsorbed, 0); - ASSERT_EQ(m_assertAbsorber.m_numErrorsAbsorbed, 0); - ASSERT_EQ(m_assertAbsorber.m_numAssertsAbsorbed, 0); + ASSERT_EQ(m_errorAbsorber->m_numWarningsAbsorbed, 0); + ASSERT_EQ(m_errorAbsorber->m_numErrorsAbsorbed, 0); + ASSERT_EQ(m_errorAbsorber->m_numAssertsAbsorbed, 0); } TEST_F(AssetProcessorManagerTest, WarningsAndErrorsReported_SuccessfullySavedToDatabase) @@ -388,9 +388,9 @@ TEST_F(AssetProcessorManagerTest, WarningsAndErrorsReported_SuccessfullySavedToD ASSERT_EQ(response.m_jobList[0].m_warningCount, 11); ASSERT_EQ(response.m_jobList[0].m_errorCount, 22); - ASSERT_EQ(m_assertAbsorber.m_numWarningsAbsorbed, 0); - ASSERT_EQ(m_assertAbsorber.m_numErrorsAbsorbed, 0); - ASSERT_EQ(m_assertAbsorber.m_numAssertsAbsorbed, 0); + ASSERT_EQ(m_errorAbsorber->m_numWarningsAbsorbed, 0); + ASSERT_EQ(m_errorAbsorber->m_numErrorsAbsorbed, 0); + ASSERT_EQ(m_errorAbsorber->m_numAssertsAbsorbed, 0); } @@ -1312,8 +1312,8 @@ void PathDependencyTest::SetUp() void PathDependencyTest::TearDown() { - ASSERT_EQ(m_assertAbsorber.m_numAssertsAbsorbed, 0); - ASSERT_EQ(m_assertAbsorber.m_numErrorsAbsorbed, 0); + ASSERT_EQ(m_errorAbsorber->m_numAssertsAbsorbed, 0); + ASSERT_EQ(m_errorAbsorber->m_numErrorsAbsorbed, 0); AssetProcessorManagerTest::TearDown(); } @@ -1617,7 +1617,7 @@ TEST_F(PathDependencyTest, AssetProcessed_Impl_SelfReferrentialProductDependency mainFile.m_products.push_back(productAssetId); // tell the APM that the asset has been processed and allow it to bubble through its event queue: - m_assertAbsorber.Clear(); + m_errorAbsorber->Clear(); m_assetProcessorManager->AssetProcessed(jobDetails.m_jobEntry, processJobResponse); ASSERT_TRUE(BlockUntilIdle(5000)); @@ -1627,8 +1627,8 @@ TEST_F(PathDependencyTest, AssetProcessed_Impl_SelfReferrentialProductDependency ASSERT_TRUE(dependencyContainer.empty()); // We are testing 2 different dependencies, so we should get 2 warnings - ASSERT_EQ(m_assertAbsorber.m_numWarningsAbsorbed, 2); - m_assertAbsorber.Clear(); + ASSERT_EQ(m_errorAbsorber->m_numWarningsAbsorbed, 2); + m_errorAbsorber->Clear(); } // This test shows the process of deferring resolution of a path dependency works. @@ -1945,8 +1945,8 @@ TEST_F(PathDependencyTest, WildcardDependencies_ExcludePathsExisting_ResolveCorr ); // Test asset PrimaryFile1 has 4 conflict dependencies - ASSERT_EQ(m_assertAbsorber.m_numErrorsAbsorbed, 4); - m_assertAbsorber.Clear(); + ASSERT_EQ(m_errorAbsorber->m_numErrorsAbsorbed, 4); + m_errorAbsorber->Clear(); } TEST_F(PathDependencyTest, WildcardDependencies_Deferred_ResolveCorrectly) @@ -2093,8 +2093,8 @@ TEST_F(PathDependencyTest, WildcardDependencies_ExcludedPathDeferred_ResolveCorr // Test asset PrimaryFile1 has 4 conflict dependencies // After test assets dep2 and dep3 are processed, // another 2 errors will be raised because of the confliction - ASSERT_EQ(m_assertAbsorber.m_numErrorsAbsorbed, 6); - m_assertAbsorber.Clear(); + ASSERT_EQ(m_errorAbsorber->m_numErrorsAbsorbed, 6); + m_errorAbsorber->Clear(); } void PathDependencyTest::RunWildcardTest(bool useCorrectDatabaseSeparator, AssetBuilderSDK::ProductPathDependencyType pathDependencyType, bool buildDependenciesFirst) diff --git a/Code/Tools/AssetProcessor/native/tests/assetmanager/AssetProcessorManagerTest.h b/Code/Tools/AssetProcessor/native/tests/assetmanager/AssetProcessorManagerTest.h index 3443a4c519..2f0121485e 100644 --- a/Code/Tools/AssetProcessor/native/tests/assetmanager/AssetProcessorManagerTest.h +++ b/Code/Tools/AssetProcessor/native/tests/assetmanager/AssetProcessorManagerTest.h @@ -58,7 +58,6 @@ protected: AZStd::unique_ptr m_assetProcessorManager; AZStd::unique_ptr m_mockApplicationManager; AZStd::unique_ptr m_config; - UnitTestUtils::AssertAbsorber m_assertAbsorber; // absorb asserts/warnings/errors so that the unit test output is not cluttered QString m_gameName; QDir m_normalizedCacheRootDir; AZStd::atomic_bool m_isIdling; From d945a031c1b97fd7fd7a9d11ae8e75a2a9ceb83c Mon Sep 17 00:00:00 2001 From: greerdv Date: Wed, 10 Nov 2021 19:30:12 +0000 Subject: [PATCH 53/71] prevent twist limits being created with equal lower and upper limits Signed-off-by: greerdv --- .../Code/Source/Joint/PhysXJointUtils.cpp | 18 ++++++++++++++++-- Gems/PhysX/Code/Source/Joint/PhysXJointUtils.h | 4 +++- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/Gems/PhysX/Code/Source/Joint/PhysXJointUtils.cpp b/Gems/PhysX/Code/Source/Joint/PhysXJointUtils.cpp index 3558c9fb56..e69fb70fb2 100644 --- a/Gems/PhysX/Code/Source/Joint/PhysXJointUtils.cpp +++ b/Gems/PhysX/Code/Source/Joint/PhysXJointUtils.cpp @@ -224,8 +224,22 @@ namespace PhysX { physx::PxJointLimitCone limitCone(swingLimitY, swingLimitZ); joint->setSwingLimit(limitCone); - const float twistLower = AZ::DegToRad(AZStd::GetMin(configuration.m_twistLimitLower, configuration.m_twistLimitUpper)); - const float twistUpper = AZ::DegToRad(AZStd::GetMax(configuration.m_twistLimitLower, configuration.m_twistLimitUpper)); + float twistLower = AZ::DegToRad(AZStd::GetMin(configuration.m_twistLimitLower, configuration.m_twistLimitUpper)); + float twistUpper = AZ::DegToRad(AZStd::GetMax(configuration.m_twistLimitLower, configuration.m_twistLimitUpper)); + // make sure there is at least a small difference between the lower and upper limits to avoid problems in PhysX + const float minSwingLimitRangeRadians = AZ::DegToRad(JointConstants::MinTwistLimitRangeDegrees); + if (const float twistLimitRange = twistUpper - twistLower; + twistLimitRange < minSwingLimitRangeRadians) + { + if (twistUpper > 0.0f) + { + twistLower -= (minSwingLimitRangeRadians - twistLimitRange); + } + else + { + twistUpper += (minSwingLimitRangeRadians - twistLimitRange); + } + } physx::PxJointAngularLimitPair twistLimitPair(twistLower, twistUpper); joint->setTwistLimit(twistLimitPair); diff --git a/Gems/PhysX/Code/Source/Joint/PhysXJointUtils.h b/Gems/PhysX/Code/Source/Joint/PhysXJointUtils.h index 7a30473dac..a99eb7aacb 100644 --- a/Gems/PhysX/Code/Source/Joint/PhysXJointUtils.h +++ b/Gems/PhysX/Code/Source/Joint/PhysXJointUtils.h @@ -18,9 +18,11 @@ namespace PhysX { namespace JointConstants { - // Setting swing limits to very small values can cause extreme stability problems, so clamp above a small + // Setting joint limits to very small values can cause extreme stability problems, so clamp above a small // threshold. static const float MinSwingLimitDegrees = 1.0f; + // Minimum range between lower and upper twist limits. + static const float MinTwistLimitRangeDegrees = 1.0f; } // namespace JointConstants namespace Utils From 3fd03479de46c75509d730164973f60e04f8371b Mon Sep 17 00:00:00 2001 From: antonmic <56370189+antonmic@users.noreply.github.com> Date: Wed, 10 Nov 2021 11:56:45 -0800 Subject: [PATCH 54/71] Addressed PR feedback Signed-off-by: antonmic <56370189+antonmic@users.noreply.github.com> --- .../Atom/Feature/Mesh/MeshFeatureProcessor.h | 2 +- .../Feature/Mesh/MeshFeatureProcessorInterface.h | 13 ++++++++----- .../Common/Code/Mocks/MockMeshFeatureProcessor.h | 2 +- .../Code/Source/Mesh/MeshFeatureProcessor.cpp | 2 +- .../EMotionFXAtom/Code/Source/AtomActorInstance.cpp | 2 +- 5 files changed, 12 insertions(+), 9 deletions(-) diff --git a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Mesh/MeshFeatureProcessor.h b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Mesh/MeshFeatureProcessor.h index 4aec78be51..23cd76ca20 100644 --- a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Mesh/MeshFeatureProcessor.h +++ b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Mesh/MeshFeatureProcessor.h @@ -153,7 +153,7 @@ namespace AZ Data::Instance GetModel(const MeshHandle& meshHandle) const override; Data::Asset GetModelAsset(const MeshHandle& meshHandle) const override; - AZStd::vector>& GetObjectSrgs(const MeshHandle& meshHandle) const override; + const AZStd::vector>& GetObjectSrgs(const MeshHandle& meshHandle) const override; void QueueObjectSrgForCompile(const MeshHandle& meshHandle) const override; void SetMaterialAssignmentMap(const MeshHandle& meshHandle, const Data::Instance& material) override; void SetMaterialAssignmentMap(const MeshHandle& meshHandle, const MaterialAssignmentMap& materials) override; diff --git a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Mesh/MeshFeatureProcessorInterface.h b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Mesh/MeshFeatureProcessorInterface.h index 3be5f3efd8..356b1936ca 100644 --- a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Mesh/MeshFeatureProcessorInterface.h +++ b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Mesh/MeshFeatureProcessorInterface.h @@ -61,12 +61,15 @@ namespace AZ virtual Data::Instance GetModel(const MeshHandle& meshHandle) const = 0; //! Gets the underlying RPI::ModelAsset for a meshHandle. virtual Data::Asset GetModelAsset(const MeshHandle& meshHandle) const = 0; - //! Gets the ObjectSrg for a meshHandle. - //! Updating the ObjectSrg should be followed by a call to QueueObjectSrgForCompile, - //! instead of compiling the srg directly. This way, if the srg has already been queued for compile, - //! it will not be queued twice in the same frame. The ObjectSrg should not be updated during + + //! Gets the ObjectSrgs for a meshHandle. + //! Updating the ObjectSrgs should be followed by a call to QueueObjectSrgForCompile, + //! instead of compiling the srgs directly. This way, if the srgs have already been queued for compile, + //! they will not be queued twice in the same frame. The ObjectSrgs should not be updated during //! Simulate, or it will create a race between updating the data and the call to Compile - virtual AZStd::vector>& GetObjectSrgs(const MeshHandle& meshHandle) const = 0; + //! Cases where there may be multiple ObjectSrgs: if a model has multiple submeshes and those submeshes use different + //! materials with different object SRGs. + virtual const AZStd::vector>& GetObjectSrgs(const MeshHandle& meshHandle) const = 0; //! Queues the object srg for compile. virtual void QueueObjectSrgForCompile(const MeshHandle& meshHandle) const = 0; //! Sets the MaterialAssignmentMap for a meshHandle, using just a single material for the DefaultMaterialAssignmentId. diff --git a/Gems/Atom/Feature/Common/Code/Mocks/MockMeshFeatureProcessor.h b/Gems/Atom/Feature/Common/Code/Mocks/MockMeshFeatureProcessor.h index 05a3274657..2c818d3c9b 100644 --- a/Gems/Atom/Feature/Common/Code/Mocks/MockMeshFeatureProcessor.h +++ b/Gems/Atom/Feature/Common/Code/Mocks/MockMeshFeatureProcessor.h @@ -19,7 +19,7 @@ namespace UnitTest MOCK_METHOD1(CloneMesh, MeshHandle(const MeshHandle&)); MOCK_CONST_METHOD1(GetModel, AZStd::intrusive_ptr(const MeshHandle&)); MOCK_CONST_METHOD1(GetModelAsset, AZ::Data::Asset(const MeshHandle&)); - MOCK_CONST_METHOD1(GetObjectSrgs, AZStd::vector>&(const MeshHandle&)); + MOCK_CONST_METHOD1(GetObjectSrgs, const AZStd::vector>&(const MeshHandle&)); MOCK_CONST_METHOD1(QueueObjectSrgForCompile, void(const MeshHandle&)); MOCK_CONST_METHOD1(GetMaterialAssignmentMap, const AZ::Render::MaterialAssignmentMap&(const MeshHandle&)); MOCK_METHOD2(ConnectModelChangeEventHandler, void(const MeshHandle&, ModelChangedEvent::Handler&)); diff --git a/Gems/Atom/Feature/Common/Code/Source/Mesh/MeshFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/Mesh/MeshFeatureProcessor.cpp index 7227311915..112eff64a8 100644 --- a/Gems/Atom/Feature/Common/Code/Source/Mesh/MeshFeatureProcessor.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/Mesh/MeshFeatureProcessor.cpp @@ -215,7 +215,7 @@ namespace AZ return {}; } - AZStd::vector>& MeshFeatureProcessor::GetObjectSrgs(const MeshHandle& meshHandle) const + const AZStd::vector>& MeshFeatureProcessor::GetObjectSrgs(const MeshHandle& meshHandle) const { static AZStd::vector> staticEmptyList; return meshHandle.IsValid() ? meshHandle->m_objectSrgList : staticEmptyList; diff --git a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/AtomActorInstance.cpp b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/AtomActorInstance.cpp index 7cd4fc073b..a3978c2d03 100644 --- a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/AtomActorInstance.cpp +++ b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/AtomActorInstance.cpp @@ -880,7 +880,7 @@ namespace AZ { if (m_meshHandle) { - AZStd::vector>& wrinkleMaskObjectSrgs = m_meshFeatureProcessor->GetObjectSrgs(*m_meshHandle); + const AZStd::vector>& wrinkleMaskObjectSrgs = m_meshFeatureProcessor->GetObjectSrgs(*m_meshHandle); for (auto& wrinkleMaskObjectSrg : wrinkleMaskObjectSrgs) { From cf58398c6c31e10bfea1c134328e585efcaab05b Mon Sep 17 00:00:00 2001 From: Junbo Liang <68558268+junbo75@users.noreply.github.com> Date: Wed, 10 Nov 2021 13:05:32 -0800 Subject: [PATCH 55/71] [AWSMetrics] Fail to build the project when include AWSMetricsBus header in the project C++ code (#5468) --- .../Code/Include/{Private => Public}/MetricsAttribute.h | 0 Gems/AWSMetrics/Code/awsmetrics_files.cmake | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename Gems/AWSMetrics/Code/Include/{Private => Public}/MetricsAttribute.h (100%) diff --git a/Gems/AWSMetrics/Code/Include/Private/MetricsAttribute.h b/Gems/AWSMetrics/Code/Include/Public/MetricsAttribute.h similarity index 100% rename from Gems/AWSMetrics/Code/Include/Private/MetricsAttribute.h rename to Gems/AWSMetrics/Code/Include/Public/MetricsAttribute.h diff --git a/Gems/AWSMetrics/Code/awsmetrics_files.cmake b/Gems/AWSMetrics/Code/awsmetrics_files.cmake index b51235c957..b1a3a647df 100644 --- a/Gems/AWSMetrics/Code/awsmetrics_files.cmake +++ b/Gems/AWSMetrics/Code/awsmetrics_files.cmake @@ -8,6 +8,7 @@ set(FILES Include/Public/AWSMetricsBus.h + Include/Public/MetricsAttribute.h Include/Private/AWSMetricsConstant.h Include/Private/AWSMetricsServiceApi.h Include/Private/AWSMetricsSystemComponent.h @@ -15,7 +16,6 @@ set(FILES Include/Private/DefaultClientIdProvider.h Include/Private/GlobalStatistics.h Include/Private/IdentityProvider.h - Include/Private/MetricsAttribute.h Include/Private/MetricsEvent.h Include/Private/MetricsEventBuilder.h Include/Private/MetricsManager.h From 21a254e9dca5262dcde7a1cebd41ef7dcf8df09c Mon Sep 17 00:00:00 2001 From: Qing Tao <55564570+VickyAtAZ@users.noreply.github.com> Date: Wed, 10 Nov 2021 13:15:04 -0800 Subject: [PATCH 56/71] Fixed a type with pass filter (#5506) Signed-off-by: Qing Tao <55564570+VickyAtAZ@users.noreply.github.com> --- .../Source/CoreLights/DirectionalLightFeatureProcessor.cpp | 2 +- Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/PassFilter.h | 4 ++-- Gems/Atom/RPI/Code/Source/RPI.Public/Pass/PassFilter.cpp | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Gems/Atom/Feature/Common/Code/Source/CoreLights/DirectionalLightFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/CoreLights/DirectionalLightFeatureProcessor.cpp index b6c6910fd3..410c80dbdc 100644 --- a/Gems/Atom/Feature/Common/Code/Source/CoreLights/DirectionalLightFeatureProcessor.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/CoreLights/DirectionalLightFeatureProcessor.cpp @@ -1056,7 +1056,7 @@ namespace AZ // if the shadow is rendering in an EnvironmentCubeMapPass it also needs to be a ReflectiveCubeMap view, // to filter out shadows from objects that are excluded from the cubemap RPI::PassFilter passFilter = RPI::PassFilter::CreateWithPassClass(); - passFilter.SetOwenrScene(GetParentScene()); // only handles passes for this scene + passFilter.SetOwnerScene(GetParentScene()); // only handles passes for this scene RPI::PassSystemInterface::Get()->ForEachPass(passFilter, [&usageFlags]([[maybe_unused]] RPI::Pass* pass) -> RPI::PassFilterExecutionFlow { usageFlags |= RPI::View::UsageReflectiveCubeMap; diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/PassFilter.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/PassFilter.h index c42991725e..b93458113b 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/PassFilter.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/PassFilter.h @@ -56,8 +56,8 @@ namespace AZ OwnerRenderPipeline = AZ_BIT(5) }; - void SetOwenrScene(const Scene* scene); - void SetOwenrRenderPipeline(const RenderPipeline* renderPipeline); + void SetOwnerScene(const Scene* scene); + void SetOwnerRenderPipeline(const RenderPipeline* renderPipeline); void SetPassName(Name passName); void SetTemplateName(Name passTemplateName); void SetPassClass(TypeId passClassTypeId); diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/PassFilter.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/PassFilter.cpp index d9e458c615..d172abd81f 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/PassFilter.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/PassFilter.cpp @@ -90,13 +90,13 @@ namespace AZ return filter; } - void PassFilter::SetOwenrScene(const Scene* scene) + void PassFilter::SetOwnerScene(const Scene* scene) { m_ownerScene = scene; UpdateFilterOptions(); } - void PassFilter::SetOwenrRenderPipeline(const RenderPipeline* renderPipeline) + void PassFilter::SetOwnerRenderPipeline(const RenderPipeline* renderPipeline) { m_ownerRenderPipeline = renderPipeline; UpdateFilterOptions(); From d5081a47db1bb8ec4c7a154f2a61b9bad1450034 Mon Sep 17 00:00:00 2001 From: jiaweig <51759646+jiaweig-amzn@users.noreply.github.com> Date: Wed, 10 Nov 2021 13:32:23 -0800 Subject: [PATCH 57/71] Fix/update swapchain recreation on vsync interval changes (#5502) Signed-off-by: jiaweig <51759646+jiaweig-amzn@users.noreply.github.com> --- Gems/Atom/RHI/Vulkan/Code/Source/RHI/SwapChain.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Gems/Atom/RHI/Vulkan/Code/Source/RHI/SwapChain.cpp b/Gems/Atom/RHI/Vulkan/Code/Source/RHI/SwapChain.cpp index 19c88ec34f..47c92d97fb 100644 --- a/Gems/Atom/RHI/Vulkan/Code/Source/RHI/SwapChain.cpp +++ b/Gems/Atom/RHI/Vulkan/Code/Source/RHI/SwapChain.cpp @@ -78,8 +78,7 @@ namespace AZ { // The presentation mode may change when transitioning to or from a vsynced presentation mode // In this case, the swapchain must be recreated. - InvalidateNativeSwapChain(); - CreateSwapchain(); + m_pendingRecreation = true; } } From 5054cfe9b550baf29750118c6b7b387a8ed5a8fc Mon Sep 17 00:00:00 2001 From: greerdv Date: Wed, 10 Nov 2021 22:04:40 +0000 Subject: [PATCH 58/71] fix typo Signed-off-by: greerdv --- Gems/PhysX/Code/Source/Joint/PhysXJointUtils.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Gems/PhysX/Code/Source/Joint/PhysXJointUtils.cpp b/Gems/PhysX/Code/Source/Joint/PhysXJointUtils.cpp index e69fb70fb2..107bced7f2 100644 --- a/Gems/PhysX/Code/Source/Joint/PhysXJointUtils.cpp +++ b/Gems/PhysX/Code/Source/Joint/PhysXJointUtils.cpp @@ -227,17 +227,17 @@ namespace PhysX { float twistLower = AZ::DegToRad(AZStd::GetMin(configuration.m_twistLimitLower, configuration.m_twistLimitUpper)); float twistUpper = AZ::DegToRad(AZStd::GetMax(configuration.m_twistLimitLower, configuration.m_twistLimitUpper)); // make sure there is at least a small difference between the lower and upper limits to avoid problems in PhysX - const float minSwingLimitRangeRadians = AZ::DegToRad(JointConstants::MinTwistLimitRangeDegrees); + const float minTwistLimitRangeRadians = AZ::DegToRad(JointConstants::MinTwistLimitRangeDegrees); if (const float twistLimitRange = twistUpper - twistLower; - twistLimitRange < minSwingLimitRangeRadians) + twistLimitRange < minTwistLimitRangeRadians) { if (twistUpper > 0.0f) { - twistLower -= (minSwingLimitRangeRadians - twistLimitRange); + twistLower -= (minTwistLimitRangeRadians - twistLimitRange); } else { - twistUpper += (minSwingLimitRangeRadians - twistLimitRange); + twistUpper += (minTwistLimitRangeRadians - twistLimitRange); } } physx::PxJointAngularLimitPair twistLimitPair(twistLower, twistUpper); From 7a2eb349ca04051e281fcbfe0adca25e7850a3f9 Mon Sep 17 00:00:00 2001 From: Chris Galvan Date: Wed, 10 Nov 2021 16:20:12 -0600 Subject: [PATCH 59/71] Fixed LC crash by preventing graphs from staying open after they are no longer in prefab focus. Signed-off-by: Chris Galvan --- .../Code/Source/Editor/MainWindow.cpp | 24 +++++++++++++++++++ .../Code/Source/Editor/MainWindow.h | 15 ++++++++++++ 2 files changed, 39 insertions(+) diff --git a/Gems/LandscapeCanvas/Code/Source/Editor/MainWindow.cpp b/Gems/LandscapeCanvas/Code/Source/Editor/MainWindow.cpp index 4574b938f6..f6f0d8b655 100644 --- a/Gems/LandscapeCanvas/Code/Source/Editor/MainWindow.cpp +++ b/Gems/LandscapeCanvas/Code/Source/Editor/MainWindow.cpp @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -448,6 +449,9 @@ namespace LandscapeCanvasEditor AZ::ComponentApplicationBus::BroadcastResult(m_serializeContext, &AZ::ComponentApplicationRequests::GetSerializeContext); AZ_Assert(m_serializeContext, "Failed to acquire application serialize context."); + m_prefabFocusPublicInterface = AZ::Interface::Get(); + AZ_Assert(m_prefabFocusPublicInterface, "LandscapeCanvas - could not get PrefabFocusPublicInterface on construction."); + const GraphCanvas::EditorId& editorId = GetEditorId(); // Register unique color palettes for our connections (data types) @@ -459,6 +463,7 @@ namespace LandscapeCanvasEditor AzToolsFramework::EditorPickModeNotificationBus::Handler::BusConnect(AzToolsFramework::GetEntityContextId()); AzToolsFramework::EntityCompositionNotificationBus::Handler::BusConnect(); AzToolsFramework::ToolsApplicationNotificationBus::Handler::BusConnect(); + AzToolsFramework::Prefab::PrefabFocusNotificationBus::Handler::BusConnect(AzToolsFramework::GetEntityContextId()); AzToolsFramework::Prefab::PrefabPublicNotificationBus::Handler::BusConnect(); CrySystemEventBus::Handler::BusConnect(); AZ::EntitySystemBus::Handler::BusConnect(); @@ -484,6 +489,7 @@ namespace LandscapeCanvasEditor AZ::EntitySystemBus::Handler::BusDisconnect(); CrySystemEventBus::Handler::BusDisconnect(); AzToolsFramework::Prefab::PrefabPublicNotificationBus::Handler::BusDisconnect(); + AzToolsFramework::Prefab::PrefabFocusNotificationBus::Handler::BusDisconnect(); AzToolsFramework::ToolsApplicationNotificationBus::Handler::BusDisconnect(); AzToolsFramework::EditorPickModeNotificationBus::Handler::BusDisconnect(); AzToolsFramework::EditorEntityContextNotificationBus::Handler::BusDisconnect(); @@ -2500,6 +2506,24 @@ namespace LandscapeCanvasEditor } } + void MainWindow::OnPrefabFocusChanged() + { + // Make sure to close any open graphs that aren't currently in p refab focus + // to prevent the user from making modifications outside of the allowed focus scope + AZStd::vector dockWidgetsToClose; + for (auto [entityId, dockWidgetId] : m_dockWidgetsByEntity) + { + if (!m_prefabFocusPublicInterface->IsOwningPrefabBeingFocused(entityId)) + { + dockWidgetsToClose.push_back(dockWidgetId); + } + } + for (auto dockWidgetId : dockWidgetsToClose) + { + CloseEditor(dockWidgetId); + } + } + void MainWindow::OnPrefabInstancePropagationBegin() { // Ignore graph updates during prefab propagation because the entities will be diff --git a/Gems/LandscapeCanvas/Code/Source/Editor/MainWindow.h b/Gems/LandscapeCanvas/Code/Source/Editor/MainWindow.h index e0fb2d8e10..de6b10529d 100644 --- a/Gems/LandscapeCanvas/Code/Source/Editor/MainWindow.h +++ b/Gems/LandscapeCanvas/Code/Source/Editor/MainWindow.h @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -31,6 +32,14 @@ #include #endif +namespace AzToolsFramework +{ + namespace Prefab + { + class PrefabFocusPublicInterface; + } +} + namespace LandscapeCanvasEditor { //////////////////////////////////////////////////////////////////////// @@ -81,6 +90,7 @@ namespace LandscapeCanvasEditor , private AzToolsFramework::EntityCompositionNotificationBus::Handler , private AzToolsFramework::PropertyEditorEntityChangeNotificationBus::MultiHandler , private AzToolsFramework::ToolsApplicationNotificationBus::Handler + , private AzToolsFramework::Prefab::PrefabFocusNotificationBus::Handler , private AzToolsFramework::Prefab::PrefabPublicNotificationBus::Handler , private CrySystemEventBus::Handler { @@ -181,6 +191,9 @@ namespace LandscapeCanvasEditor void EntityParentChanged(AZ::EntityId entityId, AZ::EntityId newParentId, AZ::EntityId oldParentId) override; //////////////////////////////////////////////////////////////////////// + //! PrefabFocusNotificationBus overrides + void OnPrefabFocusChanged() override; + //! PrefabPublicNotificationBus overrides void OnPrefabInstancePropagationBegin() override; void OnPrefabInstancePropagationEnd() override; @@ -248,6 +261,8 @@ namespace LandscapeCanvasEditor AZ::SerializeContext* m_serializeContext = nullptr; + AzToolsFramework::Prefab::PrefabFocusPublicInterface* m_prefabFocusPublicInterface = nullptr; + bool m_ignoreGraphUpdates = false; bool m_prefabPropagationInProgress = false; bool m_inObjectPickMode = false; From 27f0aa7f137babf9097bf90d8fcbdf42a692ac06 Mon Sep 17 00:00:00 2001 From: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> Date: Wed, 10 Nov 2021 14:43:32 -0800 Subject: [PATCH 60/71] LYN-7468 | Viewport manipulators for the container of the focused prefab should be hidden (#5432) * Extend the level entity behavior to open prefab containers in focus mode. Disable manipulators for these entities too. Signed-off-by: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> * Minor adjustments Signed-off-by: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> * Fix enum casing in Entity Inspector. Signed-off-by: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> * Split views between for Level and FocusedContainer entities. Signed-off-by: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> * Slightly different fix to support components on focused containers. Signed-off-by: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> * Minor fixesto RefreshSelectedEntityIds. Signed-off-by: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> --- .../Prefab/PrefabFocusHandler.cpp | 16 ++--- .../PropertyEditor/EntityPropertyEditor.cpp | 68 +++++++++++++++---- .../PropertyEditor/EntityPropertyEditor.hxx | 12 ++-- .../EditorTransformComponentSelection.cpp | 11 +++ 4 files changed, 77 insertions(+), 30 deletions(-) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusHandler.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusHandler.cpp index 8098727177..5b51944a75 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusHandler.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusHandler.cpp @@ -175,20 +175,14 @@ namespace AzToolsFramework::Prefab m_focusedInstance = focusedInstance; m_focusedTemplateId = focusedInstance->get().GetTemplateId(); - AZ::EntityId containerEntityId; - - if (focusedInstance->get().GetParentInstance() != AZStd::nullopt) - { - containerEntityId = focusedInstance->get().GetContainerEntityId(); - } - else - { - containerEntityId = AZ::EntityId(); - } - // Focus on the descendants of the container entity in the Editor, if the interface is initialized. if (m_focusModeInterface) { + const AZ::EntityId containerEntityId = + (focusedInstance->get().GetParentInstance() != AZStd::nullopt) + ? focusedInstance->get().GetContainerEntityId() + : AZ::EntityId(); + m_focusModeInterface->SetFocusRoot(containerEntityId); } diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/EntityPropertyEditor.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/EntityPropertyEditor.cpp index a449fa0055..29bc106eed 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/EntityPropertyEditor.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/EntityPropertyEditor.cpp @@ -45,6 +45,7 @@ AZ_POP_DISABLE_WARNING #include #include #include +#include #include #include #include @@ -894,25 +895,51 @@ namespace AzToolsFramework { if (!m_prefabsAreEnabled) { - return m_isLevelEntityEditor ? InspectorLayout::LEVEL : InspectorLayout::ENTITY; + return m_isLevelEntityEditor ? InspectorLayout::Level : InspectorLayout::Entity; } + // Prefabs layout logic + + // If this is the container entity for the root instance, treat it like a level entity. AZ::EntityId levelContainerEntityId = m_prefabPublicInterface->GetLevelInstanceContainerEntityId(); if (AZStd::find(m_selectedEntityIds.begin(), m_selectedEntityIds.end(), levelContainerEntityId) != m_selectedEntityIds.end()) { if (m_selectedEntityIds.size() > 1) { - return InspectorLayout::INVALID; + return InspectorLayout::Invalid; } else { - return InspectorLayout::LEVEL; + return InspectorLayout::Level; } } else { - return InspectorLayout::ENTITY; + // If this is the container entity for the currently focused prefab, utilize a separate layout. + if (auto prefabFocusPublicInterface = AZ::Interface::Get()) + { + AzFramework::EntityContextId editorEntityContextId = AzFramework::EntityContextId::CreateNull(); + EditorEntityContextRequestBus::BroadcastResult( + editorEntityContextId, &EditorEntityContextRequests::GetEditorEntityContextId); + + AZ::EntityId focusedPrefabContainerEntityId = + prefabFocusPublicInterface->GetFocusedPrefabContainerEntityId(editorEntityContextId); + if (AZStd::find(m_selectedEntityIds.begin(), m_selectedEntityIds.end(), focusedPrefabContainerEntityId) != + m_selectedEntityIds.end()) + { + if (m_selectedEntityIds.size() > 1) + { + return InspectorLayout::Invalid; + } + else + { + return InspectorLayout::ContainerEntityOfFocusedPrefab; + } + } + } } + + return InspectorLayout::Entity; } void EntityPropertyEditor::UpdateEntityDisplay() @@ -921,7 +948,7 @@ namespace AzToolsFramework InspectorLayout layout = GetCurrentInspectorLayout(); - if (layout == InspectorLayout::LEVEL) + if (!m_prefabsAreEnabled && layout == InspectorLayout::Level) { AZStd::string levelName; AzToolsFramework::EditorRequestBus::BroadcastResult(levelName, &AzToolsFramework::EditorRequests::GetLevelName); @@ -963,14 +990,19 @@ namespace AzToolsFramework InspectorLayout layout = GetCurrentInspectorLayout(); - if (layout == InspectorLayout::LEVEL) + if (layout == InspectorLayout::Level) { // The Level Inspector should only have a list of selectable components after the // level entity itself is valid (i.e. "selected"). return selection.empty() ? SelectionEntityTypeInfo::None : SelectionEntityTypeInfo::LevelEntity; } - if (layout == InspectorLayout::INVALID) + if (layout == InspectorLayout::ContainerEntityOfFocusedPrefab) + { + return selection.empty() ? SelectionEntityTypeInfo::None : SelectionEntityTypeInfo::ContainerEntityOfFocusedPrefab; + } + + if (layout == InspectorLayout::Invalid) { return SelectionEntityTypeInfo::Mixed; } @@ -1140,7 +1172,8 @@ namespace AzToolsFramework } } - bool isLevelLayout = GetCurrentInspectorLayout() == InspectorLayout::LEVEL; + bool isLevelLayout = GetCurrentInspectorLayout() == InspectorLayout::Level; + bool isContainerOfFocusedPrefabLayout = GetCurrentInspectorLayout() == InspectorLayout::ContainerEntityOfFocusedPrefab; m_gui->m_entityDetailsLabel->setText(entityDetailsLabelText); m_gui->m_entityDetailsLabel->setVisible(entityDetailsVisible); @@ -1148,10 +1181,14 @@ namespace AzToolsFramework m_gui->m_entityNameLabel->setVisible(hasEntitiesDisplayed); m_gui->m_entityIcon->setVisible(hasEntitiesDisplayed); m_gui->m_pinButton->setVisible(m_overrideSelectedEntityIds.empty() && hasEntitiesDisplayed && !m_isSystemEntityEditor); - m_gui->m_statusLabel->setVisible(hasEntitiesDisplayed && !m_isSystemEntityEditor && !isLevelLayout); - m_gui->m_statusComboBox->setVisible(hasEntitiesDisplayed && !m_isSystemEntityEditor && !isLevelLayout); - m_gui->m_entityIdLabel->setVisible(hasEntitiesDisplayed && !m_isSystemEntityEditor && !isLevelLayout); - m_gui->m_entityIdText->setVisible(hasEntitiesDisplayed && !m_isSystemEntityEditor && !isLevelLayout); + m_gui->m_statusLabel->setVisible( + hasEntitiesDisplayed && !m_isSystemEntityEditor && !isLevelLayout); + m_gui->m_statusComboBox->setVisible( + hasEntitiesDisplayed && !m_isSystemEntityEditor && !isLevelLayout); + m_gui->m_entityIdLabel->setVisible( + hasEntitiesDisplayed && !m_isSystemEntityEditor && !isLevelLayout); + m_gui->m_entityIdText->setVisible( + hasEntitiesDisplayed && !m_isSystemEntityEditor && !isLevelLayout); bool displayComponentSearchBox = hasEntitiesDisplayed; if (hasEntitiesDisplayed) @@ -1159,7 +1196,9 @@ namespace AzToolsFramework // Build up components to display SharedComponentArray sharedComponentArray; BuildSharedComponentArray(sharedComponentArray, - !(selectionEntityTypeInfo == SelectionEntityTypeInfo::OnlyStandardEntities || selectionEntityTypeInfo == SelectionEntityTypeInfo::OnlyPrefabEntities)); + !(selectionEntityTypeInfo == SelectionEntityTypeInfo::OnlyStandardEntities || + selectionEntityTypeInfo == SelectionEntityTypeInfo::OnlyPrefabEntities) || + selectionEntityTypeInfo == SelectionEntityTypeInfo::ContainerEntityOfFocusedPrefab); if (sharedComponentArray.size() == 0) { @@ -1175,7 +1214,8 @@ namespace AzToolsFramework UpdateEntityDisplay(); } - m_gui->m_darkBox->setVisible(displayComponentSearchBox && !m_isSystemEntityEditor && !isLevelLayout); + m_gui->m_darkBox->setVisible( + displayComponentSearchBox && !m_isSystemEntityEditor && !isLevelLayout && !isContainerOfFocusedPrefabLayout); m_gui->m_entitySearchBox->setVisible(displayComponentSearchBox); bool displayAddComponentMenu = CanAddComponentsToSelection(selectionEntityTypeInfo); diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/EntityPropertyEditor.hxx b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/EntityPropertyEditor.hxx index 5279cefa9f..8dd0ffc4ee 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/EntityPropertyEditor.hxx +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/EntityPropertyEditor.hxx @@ -354,7 +354,8 @@ namespace AzToolsFramework OnlyLayerEntities, OnlyPrefabEntities, Mixed, - LevelEntity + LevelEntity, + ContainerEntityOfFocusedPrefab }; /** * Returns what kinds of entities are in the current selection. This is used because mixed selection @@ -364,7 +365,7 @@ namespace AzToolsFramework SelectionEntityTypeInfo GetSelectionEntityTypeInfo(const EntityIdList& selection) const; /** - * Returns true if a selection matching the passed in selection informatation allows components to be added. + * Returns true if a selection matching the passed in selection information allows components to be added. */ bool CanAddComponentsToSelection(const SelectionEntityTypeInfo& selectionEntityTypeInfo) const; @@ -581,9 +582,10 @@ namespace AzToolsFramework enum class InspectorLayout { - ENTITY = 0, // All selected entities are regular entities - LEVEL, // The selected entity is the level prefab container entity - INVALID // Other entities are selected alongside the level prefab container entity + Entity = 0, // All selected entities are regular entities. + Level, // The selected entity is the prefab container entity for the level prefab, or the slice level entity. + ContainerEntityOfFocusedPrefab, // The selected entity is the prefab container entity for the focused prefab. + Invalid // Other entities are selected alongside the level prefab container entity. }; InspectorLayout GetCurrentInspectorLayout() const; diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorTransformComponentSelection.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorTransformComponentSelection.cpp index 39c882b766..084b489aa1 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorTransformComponentSelection.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorTransformComponentSelection.cpp @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -3604,6 +3605,16 @@ namespace AzToolsFramework m_selectedEntityIds.clear(); m_selectedEntityIds.reserve(selectedEntityIds.size()); AZStd::copy(selectedEntityIds.begin(), selectedEntityIds.end(), AZStd::inserter(m_selectedEntityIds, m_selectedEntityIds.end())); + + // Do not create manipulators for the container entity of the focused prefab. + if (auto prefabFocusPublicInterface = AZ::Interface::Get()) + { + AzFramework::EntityContextId editorEntityContextId = GetEntityContextId(); + if (AZ::EntityId focusRoot = prefabFocusPublicInterface->GetFocusedPrefabContainerEntityId(editorEntityContextId); focusRoot.IsValid()) + { + m_selectedEntityIds.erase(focusRoot); + } + } } void EditorTransformComponentSelection::OnTransformChanged( From e7035c5af6a71be30e1ac7cd1cf00bd7b099a633 Mon Sep 17 00:00:00 2001 From: Chris Galvan Date: Wed, 10 Nov 2021 16:56:29 -0600 Subject: [PATCH 61/71] Fixed typo. Signed-off-by: Chris Galvan --- Gems/LandscapeCanvas/Code/Source/Editor/MainWindow.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gems/LandscapeCanvas/Code/Source/Editor/MainWindow.cpp b/Gems/LandscapeCanvas/Code/Source/Editor/MainWindow.cpp index f6f0d8b655..ce9eab5f7e 100644 --- a/Gems/LandscapeCanvas/Code/Source/Editor/MainWindow.cpp +++ b/Gems/LandscapeCanvas/Code/Source/Editor/MainWindow.cpp @@ -2508,7 +2508,7 @@ namespace LandscapeCanvasEditor void MainWindow::OnPrefabFocusChanged() { - // Make sure to close any open graphs that aren't currently in p refab focus + // Make sure to close any open graphs that aren't currently in prefab focus // to prevent the user from making modifications outside of the allowed focus scope AZStd::vector dockWidgetsToClose; for (auto [entityId, dockWidgetId] : m_dockWidgetsByEntity) From 9c57c9e64fb67cc78bad3834f279f4e71e4f07fa Mon Sep 17 00:00:00 2001 From: hershey5045 <43485729+hershey5045@users.noreply.github.com> Date: Wed, 10 Nov 2021 16:03:50 -0800 Subject: [PATCH 62/71] Fix track view bug where postfxs do not render correctly. (#5465) * Fix track view bug where postfxs do not render correctly. Signed-off-by: hershey5045 <43485729+hershey5045@users.noreply.github.com> * Reduce scope and add comments. Signed-off-by: hershey5045 <43485729+hershey5045@users.noreply.github.com> --- .../TrackView/AtomOutputFrameCapture.cpp | 27 ++++++++++++++++++- .../Editor/TrackView/AtomOutputFrameCapture.h | 3 ++- .../TrackView/SequenceBatchRenderDialog.cpp | 6 ++++- .../PostProcessFeatureProcessor.cpp | 21 ++++++++++++++- .../PostProcess/PostProcessFeatureProcessor.h | 6 +++++ .../PostProcessing/EyeAdaptationPass.cpp | 4 +-- 6 files changed, 61 insertions(+), 6 deletions(-) diff --git a/Code/Editor/TrackView/AtomOutputFrameCapture.cpp b/Code/Editor/TrackView/AtomOutputFrameCapture.cpp index 94451e6914..5943e3c2d7 100644 --- a/Code/Editor/TrackView/AtomOutputFrameCapture.cpp +++ b/Code/Editor/TrackView/AtomOutputFrameCapture.cpp @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -47,18 +48,42 @@ namespace TrackView AZ::Name viewName = AZ::Name("MainCamera"); m_view = AZ::RPI::View::CreateView(viewName, AZ::RPI::View::UsageCamera); m_renderPipeline->SetDefaultView(m_view); + m_targetView = scene.GetDefaultRenderPipeline()->GetDefaultView(); + if (AZ::Render::PostProcessFeatureProcessor* fp = scene.GetFeatureProcessor()) + { + // This will be set again to mimic the active camera in UpdateView + fp->SetViewAlias(m_view, m_targetView); + } } void AtomOutputFrameCapture::DestroyPipeline(AZ::RPI::Scene& scene) { + if (AZ::Render::PostProcessFeatureProcessor* fp = scene.GetFeatureProcessor()) + { + // Remove view alias introduced in CreatePipeline and UpdateView + fp->RemoveViewAlias(m_view); + } scene.RemoveRenderPipeline(m_renderPipeline->GetId()); m_passHierarchy.clear(); m_renderPipeline.reset(); m_view.reset(); + m_targetView.reset(); } - void AtomOutputFrameCapture::UpdateView(const AZ::Matrix3x4& cameraTransform, const AZ::Matrix4x4& cameraProjection) + void AtomOutputFrameCapture::UpdateView(const AZ::Matrix3x4& cameraTransform, const AZ::Matrix4x4& cameraProjection, const AZ::RPI::ViewPtr targetView) { + if (targetView && targetView != m_targetView) + { + if (AZ::RPI::Scene* scene = SceneFromGameEntityContext()) + { + if (AZ::Render::PostProcessFeatureProcessor* fp = scene->GetFeatureProcessor()) + { + fp->SetViewAlias(m_view, targetView); + m_targetView = targetView; + } + } + } + m_view->SetCameraTransform(cameraTransform); m_view->SetViewToClipMatrix(cameraProjection); } diff --git a/Code/Editor/TrackView/AtomOutputFrameCapture.h b/Code/Editor/TrackView/AtomOutputFrameCapture.h index 2686a81c99..4719ab08e5 100644 --- a/Code/Editor/TrackView/AtomOutputFrameCapture.h +++ b/Code/Editor/TrackView/AtomOutputFrameCapture.h @@ -39,11 +39,12 @@ namespace TrackView CaptureFinishedCallback captureFinishedCallback); //! Update the internal view that is associated with the created pipeline. - void UpdateView(const AZ::Matrix3x4& cameraTransform, const AZ::Matrix4x4& cameraProjection); + void UpdateView(const AZ::Matrix3x4& cameraTransform, const AZ::Matrix4x4& cameraProjection, const AZ::RPI::ViewPtr targetView = nullptr); private: AZ::RPI::RenderPipelinePtr m_renderPipeline; //!< The internal render pipeline. AZ::RPI::ViewPtr m_view; //!< The view associated with the render pipeline. + AZ::RPI::ViewPtr m_targetView; //!< The view that this render pipeline will mimic. AZStd::vector m_passHierarchy; //!< Pass hierarchy (includes pipelineName and CopyToSwapChain). CaptureFinishedCallback m_captureFinishedCallback; //!< Stored callback called from OnCaptureFinished. diff --git a/Code/Editor/TrackView/SequenceBatchRenderDialog.cpp b/Code/Editor/TrackView/SequenceBatchRenderDialog.cpp index d7901e338a..a796a8ce37 100644 --- a/Code/Editor/TrackView/SequenceBatchRenderDialog.cpp +++ b/Code/Editor/TrackView/SequenceBatchRenderDialog.cpp @@ -16,6 +16,7 @@ #include #include +#include // Qt #include @@ -91,9 +92,12 @@ namespace static void UpdateAtomOutputFrameCaptureView(TrackView::AtomOutputFrameCapture& atomOutputFrameCapture, const int width, const int height) { const AZ::EntityId activeCameraEntityId = TrackView::ActiveCameraEntityId(); + AZ::RPI::ViewPtr view = nullptr; + AZ::RPI::ViewProviderBus::EventResult(view, activeCameraEntityId, &AZ::RPI::ViewProvider::GetView); atomOutputFrameCapture.UpdateView( TrackView::TransformFromEntityId(activeCameraEntityId), - TrackView::ProjectionFromCameraEntityId(activeCameraEntityId, static_cast(width), static_cast(height))); + TrackView::ProjectionFromCameraEntityId(activeCameraEntityId, aznumeric_cast(width), aznumeric_cast(height)), + view); } CSequenceBatchRenderDialog::CSequenceBatchRenderDialog(float fps, QWidget* pParent /* = nullptr */) diff --git a/Gems/Atom/Feature/Common/Code/Source/PostProcess/PostProcessFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/PostProcess/PostProcessFeatureProcessor.cpp index a9d8d5105f..c8e683e1d1 100644 --- a/Gems/Atom/Feature/Common/Code/Source/PostProcess/PostProcessFeatureProcessor.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/PostProcess/PostProcessFeatureProcessor.cpp @@ -37,6 +37,11 @@ namespace AZ m_currentTime = AZStd::chrono::system_clock::now(); } + void PostProcessFeatureProcessor::Deactivate() + { + m_viewAliasMap.clear(); + } + void PostProcessFeatureProcessor::UpdateTime() { AZStd::chrono::system_clock::time_point now = AZStd::chrono::system_clock::now(); @@ -45,6 +50,16 @@ namespace AZ m_deltaTime = deltaTime.count(); } + void PostProcessFeatureProcessor::SetViewAlias(const AZ::RPI::ViewPtr sourceView, const AZ::RPI::ViewPtr targetView) + { + m_viewAliasMap[sourceView.get()] = targetView.get(); + } + + void PostProcessFeatureProcessor::RemoveViewAlias(const AZ::RPI::ViewPtr sourceView) + { + m_viewAliasMap.erase(sourceView.get()); + } + void PostProcessFeatureProcessor::Simulate(const FeatureProcessor::SimulatePacket& packet) { AZ_PROFILE_SCOPE(RPI, "PostProcessFeatureProcessor: Simulate"); @@ -200,8 +215,12 @@ namespace AZ AZ::Render::PostProcessSettings* PostProcessFeatureProcessor::GetLevelSettingsFromView(AZ::RPI::ViewPtr view) { + // check for view aliases first + auto viewAliasiterator = m_viewAliasMap.find(view.get()); + + // Use the view alias if it exists + auto settingsIterator = m_blendedPerViewSettings.find(viewAliasiterator != m_viewAliasMap.end() ? viewAliasiterator->second : view.get()); // If no settings for the view is found, the global settings is returned. - auto settingsIterator = m_blendedPerViewSettings.find(view.get()); return settingsIterator != m_blendedPerViewSettings.end() ? &settingsIterator->second : m_globalAggregateLevelSettings.get(); diff --git a/Gems/Atom/Feature/Common/Code/Source/PostProcess/PostProcessFeatureProcessor.h b/Gems/Atom/Feature/Common/Code/Source/PostProcess/PostProcessFeatureProcessor.h index 2c1cc98449..10af993d9d 100644 --- a/Gems/Atom/Feature/Common/Code/Source/PostProcess/PostProcessFeatureProcessor.h +++ b/Gems/Atom/Feature/Common/Code/Source/PostProcess/PostProcessFeatureProcessor.h @@ -34,6 +34,7 @@ namespace AZ //! FeatureProcessor overrides... void Activate() override; + void Deactivate() override; void Simulate(const FeatureProcessor::SimulatePacket& packet) override; //! PostProcessFeatureProcessorInterface... @@ -43,6 +44,9 @@ namespace AZ void OnPostProcessSettingsChanged() override; PostProcessSettings* GetLevelSettingsFromView(AZ::RPI::ViewPtr view); + void SetViewAlias(const AZ::RPI::ViewPtr sourceView, const AZ::RPI::ViewPtr targetView); + void RemoveViewAlias(const AZ::RPI::ViewPtr sourceView); + private: PostProcessFeatureProcessor(const PostProcessFeatureProcessor&) = delete; @@ -83,6 +87,8 @@ namespace AZ // Each camera/view will have its own PostProcessSettings AZStd::unordered_map m_blendedPerViewSettings; + // This is used for mimicking a postfx setting of a different view + AZStd::unordered_map m_viewAliasMap; }; } // namespace Render } // namespace AZ diff --git a/Gems/Atom/Feature/Common/Code/Source/PostProcessing/EyeAdaptationPass.cpp b/Gems/Atom/Feature/Common/Code/Source/PostProcessing/EyeAdaptationPass.cpp index 862892ad1b..5683241693 100644 --- a/Gems/Atom/Feature/Common/Code/Source/PostProcessing/EyeAdaptationPass.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/PostProcessing/EyeAdaptationPass.cpp @@ -81,7 +81,7 @@ namespace AZ if (scene) { PostProcessFeatureProcessor* fp = scene->GetFeatureProcessor(); - AZ::RPI::ViewPtr view = GetView(); + AZ::RPI::ViewPtr view = GetRenderPipeline()->GetDefaultView(); if (fp) { PostProcessSettings* postProcessSettings = fp->GetLevelSettingsFromView(view); @@ -110,7 +110,7 @@ namespace AZ PostProcessFeatureProcessor* fp = scene->GetFeatureProcessor(); if (fp) { - AZ::RPI::ViewPtr view = GetView(); + AZ::RPI::ViewPtr view = GetRenderPipeline()->GetDefaultView(); PostProcessSettings* postProcessSettings = fp->GetLevelSettingsFromView(view); if (postProcessSettings) { From e98a65a7351da2e36cddfc8abad0cff906fa87c9 Mon Sep 17 00:00:00 2001 From: moraaar Date: Thu, 11 Nov 2021 09:31:28 +0000 Subject: [PATCH 63/71] Fixed casing of all .fbx.assetinfo files to match their .fbx (#5490) Signed-off-by: moraaar --- .../{r0-b_body.fbx.assetinfo => R0-B_Body.fbx.assetinfo} | 0 .../{r0-b_body.fbx.assetinfo => R0-B_Body.fbx.assetinfo} | 0 ...dev_sedan_r0-b.fbx.assetinfo => _dev_Sedan_r0-b.fbx.assetinfo} | 0 ...dev_sedan_r0-b.fbx.assetinfo => _dev_Sedan_r0-b.fbx.assetinfo} | 0 ...opy.fbx.assetinfo => rin_skeleton_newgeo - Copy.fbx.assetinfo} | 0 ...dev_sedan_r0-b.fbx.assetinfo => _dev_Sedan_r0-b.fbx.assetinfo} | 0 ...dev_sedan_r0-b.fbx.assetinfo => _dev_Sedan_r0-b.fbx.assetinfo} | 0 7 files changed, 0 insertions(+), 0 deletions(-) rename AutomatedTesting/Assets/Physics/Collider_PxMeshAutoAssigned/SphereBot/{r0-b_body.fbx.assetinfo => R0-B_Body.fbx.assetinfo} (100%) rename AutomatedTesting/Assets/Physics/Collider_PxMeshConvexMeshCollides/SphereBot/{r0-b_body.fbx.assetinfo => R0-B_Body.fbx.assetinfo} (100%) rename AutomatedTesting/Levels/Physics/ForceRegion_ImpulsesPxMeshShapedRigidBody/PhysXSedan/{_dev_sedan_r0-b.fbx.assetinfo => _dev_Sedan_r0-b.fbx.assetinfo} (100%) rename AutomatedTesting/Levels/Physics/ForceRegion_PxMeshShapedForce/PhysXSedan/{_dev_sedan_r0-b.fbx.assetinfo => _dev_Sedan_r0-b.fbx.assetinfo} (100%) rename AutomatedTesting/Levels/Physics/Material_DefaultMaterialLibraryChangesWork/{rin_skeleton_newgeo - copy.fbx.assetinfo => rin_skeleton_newgeo - Copy.fbx.assetinfo} (100%) rename AutomatedTesting/Levels/Physics/Physics_WorldBodyBusWorksOnEditorComponents/PhysXSedan/{_dev_sedan_r0-b.fbx.assetinfo => _dev_Sedan_r0-b.fbx.assetinfo} (100%) rename AutomatedTesting/Levels/Physics/RigidBody_COM_ComputingWorks/PhysXSedan/{_dev_sedan_r0-b.fbx.assetinfo => _dev_Sedan_r0-b.fbx.assetinfo} (100%) diff --git a/AutomatedTesting/Assets/Physics/Collider_PxMeshAutoAssigned/SphereBot/r0-b_body.fbx.assetinfo b/AutomatedTesting/Assets/Physics/Collider_PxMeshAutoAssigned/SphereBot/R0-B_Body.fbx.assetinfo similarity index 100% rename from AutomatedTesting/Assets/Physics/Collider_PxMeshAutoAssigned/SphereBot/r0-b_body.fbx.assetinfo rename to AutomatedTesting/Assets/Physics/Collider_PxMeshAutoAssigned/SphereBot/R0-B_Body.fbx.assetinfo diff --git a/AutomatedTesting/Assets/Physics/Collider_PxMeshConvexMeshCollides/SphereBot/r0-b_body.fbx.assetinfo b/AutomatedTesting/Assets/Physics/Collider_PxMeshConvexMeshCollides/SphereBot/R0-B_Body.fbx.assetinfo similarity index 100% rename from AutomatedTesting/Assets/Physics/Collider_PxMeshConvexMeshCollides/SphereBot/r0-b_body.fbx.assetinfo rename to AutomatedTesting/Assets/Physics/Collider_PxMeshConvexMeshCollides/SphereBot/R0-B_Body.fbx.assetinfo diff --git a/AutomatedTesting/Levels/Physics/ForceRegion_ImpulsesPxMeshShapedRigidBody/PhysXSedan/_dev_sedan_r0-b.fbx.assetinfo b/AutomatedTesting/Levels/Physics/ForceRegion_ImpulsesPxMeshShapedRigidBody/PhysXSedan/_dev_Sedan_r0-b.fbx.assetinfo similarity index 100% rename from AutomatedTesting/Levels/Physics/ForceRegion_ImpulsesPxMeshShapedRigidBody/PhysXSedan/_dev_sedan_r0-b.fbx.assetinfo rename to AutomatedTesting/Levels/Physics/ForceRegion_ImpulsesPxMeshShapedRigidBody/PhysXSedan/_dev_Sedan_r0-b.fbx.assetinfo diff --git a/AutomatedTesting/Levels/Physics/ForceRegion_PxMeshShapedForce/PhysXSedan/_dev_sedan_r0-b.fbx.assetinfo b/AutomatedTesting/Levels/Physics/ForceRegion_PxMeshShapedForce/PhysXSedan/_dev_Sedan_r0-b.fbx.assetinfo similarity index 100% rename from AutomatedTesting/Levels/Physics/ForceRegion_PxMeshShapedForce/PhysXSedan/_dev_sedan_r0-b.fbx.assetinfo rename to AutomatedTesting/Levels/Physics/ForceRegion_PxMeshShapedForce/PhysXSedan/_dev_Sedan_r0-b.fbx.assetinfo diff --git a/AutomatedTesting/Levels/Physics/Material_DefaultMaterialLibraryChangesWork/rin_skeleton_newgeo - copy.fbx.assetinfo b/AutomatedTesting/Levels/Physics/Material_DefaultMaterialLibraryChangesWork/rin_skeleton_newgeo - Copy.fbx.assetinfo similarity index 100% rename from AutomatedTesting/Levels/Physics/Material_DefaultMaterialLibraryChangesWork/rin_skeleton_newgeo - copy.fbx.assetinfo rename to AutomatedTesting/Levels/Physics/Material_DefaultMaterialLibraryChangesWork/rin_skeleton_newgeo - Copy.fbx.assetinfo diff --git a/AutomatedTesting/Levels/Physics/Physics_WorldBodyBusWorksOnEditorComponents/PhysXSedan/_dev_sedan_r0-b.fbx.assetinfo b/AutomatedTesting/Levels/Physics/Physics_WorldBodyBusWorksOnEditorComponents/PhysXSedan/_dev_Sedan_r0-b.fbx.assetinfo similarity index 100% rename from AutomatedTesting/Levels/Physics/Physics_WorldBodyBusWorksOnEditorComponents/PhysXSedan/_dev_sedan_r0-b.fbx.assetinfo rename to AutomatedTesting/Levels/Physics/Physics_WorldBodyBusWorksOnEditorComponents/PhysXSedan/_dev_Sedan_r0-b.fbx.assetinfo diff --git a/AutomatedTesting/Levels/Physics/RigidBody_COM_ComputingWorks/PhysXSedan/_dev_sedan_r0-b.fbx.assetinfo b/AutomatedTesting/Levels/Physics/RigidBody_COM_ComputingWorks/PhysXSedan/_dev_Sedan_r0-b.fbx.assetinfo similarity index 100% rename from AutomatedTesting/Levels/Physics/RigidBody_COM_ComputingWorks/PhysXSedan/_dev_sedan_r0-b.fbx.assetinfo rename to AutomatedTesting/Levels/Physics/RigidBody_COM_ComputingWorks/PhysXSedan/_dev_Sedan_r0-b.fbx.assetinfo From f24c3d3457e1b773b2615d0864820783a8acb5ba Mon Sep 17 00:00:00 2001 From: galibzon <66021303+galibzon@users.noreply.github.com> Date: Thu, 11 Nov 2021 05:24:33 -0600 Subject: [PATCH 64/71] ASV Trace::Assert Environment.h(438) You are using an invalid variable, (#5521) the owner has removed it! This fixes the issue by forcing NameDictionary to not transfer ownership. This means ComponentApplication()::Destroy will fully destroy the NameDictionary before the OS::Allocator is destroyed. In Windows the bug was not happening when running AssetProcessorBatch because for Windows, _exit() is called before the application shutsdown forcing all module to properly decrease the reference count of EnvironmentVaqriableHolderBase::m_useCount for NameDictionary. In MacOS, there's no _exit() so when the NameDictionary destructor was being called before existing the application the reference count wouldn't be 0, and would eventually try to destry the NameDictionary BUT the OS::Allocator was already destroyed. Signed-off-by: galibzon <66021303+galibzon@users.noreply.github.com> --- Code/Framework/AzCore/AzCore/Name/NameDictionary.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Code/Framework/AzCore/AzCore/Name/NameDictionary.cpp b/Code/Framework/AzCore/AzCore/Name/NameDictionary.cpp index 3047a2894e..6cba54a17f 100644 --- a/Code/Framework/AzCore/AzCore/Name/NameDictionary.cpp +++ b/Code/Framework/AzCore/AzCore/Name/NameDictionary.cpp @@ -50,7 +50,12 @@ namespace AZ if (!s_instance) { - s_instance = Environment::FindVariable(NameDictionaryInstanceName); + // Because the NameDictionary allocates memory using the AZ::Allocator and it is created + // in the executable memory space, it's ownership cannot be transferred to other module memory spaces + // Otherwise this could cause the the NameDictionary to be destroyed in static de-init + // after the AZ::Allocators have been destroyed + // Therefore we supply the isTransferOwnership value of false using CreateVariableEx + s_instance = AZ::Environment::CreateVariableEx(NameDictionaryInstanceName, true, false); } return s_instance.IsConstructed(); From c3093edffeaada3e1eb5aabfe301bf3b139fc986 Mon Sep 17 00:00:00 2001 From: sphrose <82213493+sphrose@users.noreply.github.com> Date: Thu, 11 Nov 2021 12:12:18 +0000 Subject: [PATCH 65/71] Redoing tests that got lost when TerrainPhysicsManager was merged. Signed-off-by: sphrose <82213493+sphrose@users.noreply.github.com> --- .../Tests/TerrainHeightGradientListTests.cpp | 93 ++++++++++++------ .../Tests/TerrainSurfaceGradientListTests.cpp | 97 +++++++++---------- 2 files changed, 106 insertions(+), 84 deletions(-) diff --git a/Gems/Terrain/Code/Tests/TerrainHeightGradientListTests.cpp b/Gems/Terrain/Code/Tests/TerrainHeightGradientListTests.cpp index ec500d6ada..535aacb8c8 100644 --- a/Gems/Terrain/Code/Tests/TerrainHeightGradientListTests.cpp +++ b/Gems/Terrain/Code/Tests/TerrainHeightGradientListTests.cpp @@ -19,7 +19,6 @@ #include using ::testing::_; -using ::testing::AtLeast; using ::testing::Mock; using ::testing::NiceMock; using ::testing::Return; @@ -29,8 +28,6 @@ class TerrainHeightGradientListComponentTest : public ::testing::Test protected: AZ::ComponentApplication m_app; - AZStd::unique_ptr m_entity; - void SetUp() override { AZ::ComponentApplication::Descriptor appDesc; @@ -46,47 +43,74 @@ protected: m_app.Destroy(); } - void CreateEntity() + AZStd::unique_ptr CreateEntity() { - m_entity = AZStd::make_unique(); - ASSERT_TRUE(m_entity); - - // Create the required box component. - UnitTest::MockAxisAlignedBoxShapeComponent* boxComponent = m_entity->CreateComponent(); - m_app.RegisterComponentDescriptor(boxComponent->CreateDescriptor()); + auto entity = AZStd::make_unique(); + entity->Init(); + return entity; + } + Terrain::TerrainHeightGradientListComponent* AddHeightGradientListToEntity(AZ::Entity* entity) + { // Create the TerrainHeightGradientListComponent with an entity in its configuration. Terrain::TerrainHeightGradientListConfig config; - config.m_gradientEntities.push_back(m_entity->GetId()); + config.m_gradientEntities.push_back(entity->GetId()); - Terrain::TerrainHeightGradientListComponent* heightGradientListComponent = m_entity->CreateComponent(config); + auto heightGradientListComponent = entity->CreateComponent(config); m_app.RegisterComponentDescriptor(heightGradientListComponent->CreateDescriptor()); - // Create a MockTerrainLayerSpawnerComponent to provide the required TerrainAreaService. - UnitTest::MockTerrainLayerSpawnerComponent* layerSpawner = m_entity->CreateComponent(); - m_app.RegisterComponentDescriptor(layerSpawner->CreateDescriptor()); + return heightGradientListComponent; + } - m_entity->Init(); + void AddRequiredComponetsToEntity(AZ::Entity* entity) + { + // Create the required box component. + UnitTest::MockAxisAlignedBoxShapeComponent* boxComponent = entity->CreateComponent(); + m_app.RegisterComponentDescriptor(boxComponent->CreateDescriptor()); + + // Create a MockTerrainLayerSpawnerComponent to provide the required TerrainAreaService. + UnitTest::MockTerrainLayerSpawnerComponent* layerSpawner = entity->CreateComponent(); + m_app.RegisterComponentDescriptor(layerSpawner->CreateDescriptor()); } }; +TEST_F(TerrainHeightGradientListComponentTest, MissingRequiredComponentsActivateFailure) +{ + auto entity = CreateEntity(); + + AddHeightGradientListToEntity(entity.get()); + + const AZ::Entity::DependencySortOutcome sortOutcome = entity->EvaluateDependenciesGetDetails(); + EXPECT_FALSE(sortOutcome.IsSuccess()); + + entity.reset(); +} + TEST_F(TerrainHeightGradientListComponentTest, ActivateEntityActivateSuccess) { // Check that the entity activates. - CreateEntity(); + auto entity = CreateEntity(); - m_entity->Activate(); - EXPECT_EQ(m_entity->GetState(), AZ::Entity::State::Active); + AddHeightGradientListToEntity(entity.get()); - m_entity.reset(); + AddRequiredComponetsToEntity(entity.get()); + + entity->Activate(); + EXPECT_EQ(entity->GetState(), AZ::Entity::State::Active); + + entity.reset(); } TEST_F(TerrainHeightGradientListComponentTest, TerrainHeightGradientRefreshesTerrainSystem) { // Check that the HeightGradientListComponent informs the TerrainSystem when the composition changes. - CreateEntity(); + auto entity = CreateEntity(); - m_entity->Activate(); + AddHeightGradientListToEntity(entity.get()); + + AddRequiredComponetsToEntity(entity.get()); + + entity->Activate(); NiceMock terrainSystem; @@ -95,32 +119,36 @@ TEST_F(TerrainHeightGradientListComponentTest, TerrainHeightGradientRefreshesTer // and once when the HeightGradientListComponent gets the OnCompositionChanged directly through the DependencyNotificationBus. EXPECT_CALL(terrainSystem, RefreshArea(_, _)).Times(2); - LmbrCentral::DependencyNotificationBus::Event(m_entity->GetId(), &LmbrCentral::DependencyNotificationBus::Events::OnCompositionChanged); + LmbrCentral::DependencyNotificationBus::Event(entity->GetId(), &LmbrCentral::DependencyNotificationBus::Events::OnCompositionChanged); // Stop the EXPECT_CALL check now, as OnCompositionChanged will get called twice again during the reset. Mock::VerifyAndClearExpectations(&terrainSystem); - m_entity.reset(); + entity.reset(); } TEST_F(TerrainHeightGradientListComponentTest, TerrainHeightGradientListReturnsHeights) { // Check that the HeightGradientListComponent returns expected height values. - CreateEntity(); + auto entity = CreateEntity(); - NiceMock heightfieldRequestBus(m_entity->GetId()); + AddHeightGradientListToEntity(entity.get()); - m_entity->Activate(); + AddRequiredComponetsToEntity(entity.get()); + + NiceMock heightfieldRequestBus(entity->GetId()); + + entity->Activate(); const float mockGradientValue = 0.25f; - NiceMock gradientRequests(m_entity->GetId()); + NiceMock gradientRequests(entity->GetId()); ON_CALL(gradientRequests, GetValue).WillByDefault(Return(mockGradientValue)); // Setup a mock to provide the encompassing Aabb to the HeightGradientListComponent. const float min = 0.0f; const float max = 1000.0f; const AZ::Aabb aabb = AZ::Aabb::CreateFromMinMax(AZ::Vector3(min), AZ::Vector3(max)); - NiceMock mockShapeRequests(m_entity->GetId()); + NiceMock mockShapeRequests(entity->GetId()); ON_CALL(mockShapeRequests, GetEncompassingAabb).WillByDefault(Return(aabb)); const float worldMax = 10000.0f; @@ -130,17 +158,18 @@ TEST_F(TerrainHeightGradientListComponentTest, TerrainHeightGradientListReturnsH ON_CALL(mockterrainDataRequests, GetTerrainAabb).WillByDefault(Return(worldAabb)); // Ensure the cached values in the HeightGradientListComponent are up to date. - LmbrCentral::DependencyNotificationBus::Event(m_entity->GetId(), &LmbrCentral::DependencyNotificationBus::Events::OnCompositionChanged); + LmbrCentral::DependencyNotificationBus::Event(entity->GetId(), &LmbrCentral::DependencyNotificationBus::Events::OnCompositionChanged); const AZ::Vector3 inPosition = AZ::Vector3::CreateZero(); AZ::Vector3 outPosition = AZ::Vector3::CreateZero(); bool terrainExists = false; - Terrain::TerrainAreaHeightRequestBus::Event(m_entity->GetId(), &Terrain::TerrainAreaHeightRequestBus::Events::GetHeight, inPosition, outPosition, terrainExists); + Terrain::TerrainAreaHeightRequestBus::Event( + entity->GetId(), &Terrain::TerrainAreaHeightRequestBus::Events::GetHeight, inPosition, outPosition, terrainExists); const float height = outPosition.GetZ(); EXPECT_NEAR(height, mockGradientValue * max, 0.01f); - m_entity.reset(); + entity.reset(); } diff --git a/Gems/Terrain/Code/Tests/TerrainSurfaceGradientListTests.cpp b/Gems/Terrain/Code/Tests/TerrainSurfaceGradientListTests.cpp index dea861bda5..fb94d2320d 100644 --- a/Gems/Terrain/Code/Tests/TerrainSurfaceGradientListTests.cpp +++ b/Gems/Terrain/Code/Tests/TerrainSurfaceGradientListTests.cpp @@ -11,8 +11,6 @@ #include using ::testing::NiceMock; -using ::testing::AtLeast; -using ::testing::_; using ::testing::Return; namespace UnitTest @@ -22,10 +20,6 @@ namespace UnitTest protected: AZ::ComponentApplication m_app; - AZStd::unique_ptr m_entity; - UnitTest::MockTerrainLayerSpawnerComponent* m_layerSpawnerComponent = nullptr; - AZStd::unique_ptr m_gradientEntity1, m_gradientEntity2; - const AZStd::string surfaceTag1 = "testtag1"; const AZStd::string surfaceTag2 = "testtag2"; @@ -37,81 +31,80 @@ namespace UnitTest appDesc.m_stackRecordLevels = 20; m_app.Create(appDesc); - - CreateEntities(); } void TearDown() override { - m_gradientEntity2.reset(); - m_gradientEntity1.reset(); - m_entity.reset(); - m_app.Destroy(); } - void CreateEntities() + AZStd::unique_ptr CreateEntity() { - m_entity = AZStd::make_unique(); - ASSERT_TRUE(m_entity); - - m_entity->Init(); - - m_gradientEntity1 = AZStd::make_unique(); - ASSERT_TRUE(m_gradientEntity1); - - m_gradientEntity1->Init(); - - m_gradientEntity2 = AZStd::make_unique(); - ASSERT_TRUE(m_gradientEntity2); - - m_gradientEntity2->Init(); + auto entity = AZStd::make_unique(); + entity->Init(); + return entity; } - void AddSurfaceGradientListToEntities() + UnitTest::MockTerrainLayerSpawnerComponent* AddRequiredComponentsToEntity(AZ::Entity* entity) { - m_layerSpawnerComponent = m_entity->CreateComponent(); - m_app.RegisterComponentDescriptor(m_layerSpawnerComponent->CreateDescriptor()); + auto layerSpawnerComponent = entity->CreateComponent(); + m_app.RegisterComponentDescriptor(layerSpawnerComponent->CreateDescriptor()); - Terrain::TerrainSurfaceGradientListConfig config; - - Terrain::TerrainSurfaceGradientMapping mapping1; - mapping1.m_gradientEntityId = m_gradientEntity1->GetId(); - mapping1.m_surfaceTag = SurfaceData::SurfaceTag(surfaceTag1); - config.m_gradientSurfaceMappings.emplace_back(mapping1); - - Terrain::TerrainSurfaceGradientMapping mapping2; - mapping2.m_gradientEntityId = m_gradientEntity2->GetId(); - mapping2.m_surfaceTag = SurfaceData::SurfaceTag(surfaceTag2); - config.m_gradientSurfaceMappings.emplace_back(mapping2); - - Terrain::TerrainSurfaceGradientListComponent* terrainSurfaceGradientListComponent = - m_entity->CreateComponent(config); - m_app.RegisterComponentDescriptor(terrainSurfaceGradientListComponent->CreateDescriptor()); + return layerSpawnerComponent; } }; + TEST_F(TerrainSurfaceGradientListTest, SurfaceGradientMissingRequirementsActivateFails) + { + auto entity = CreateEntity(); + + auto terrainSurfaceGradientListComponent = entity->CreateComponent(); + m_app.RegisterComponentDescriptor(terrainSurfaceGradientListComponent->CreateDescriptor()); + + const AZ::Entity::DependencySortOutcome sortOutcome = entity->EvaluateDependenciesGetDetails(); + EXPECT_FALSE(sortOutcome.IsSuccess()); + + entity.reset(); + } + + TEST_F(TerrainSurfaceGradientListTest, SurfaceGradientActivateSuccess) + { + auto entity = CreateEntity(); + + AddRequiredComponentsToEntity(entity.get()); + + auto terrainSurfaceGradientListComponent = entity->CreateComponent(); + m_app.RegisterComponentDescriptor(terrainSurfaceGradientListComponent->CreateDescriptor()); + + entity->Activate(); + + + + entity.reset(); + } + TEST_F(TerrainSurfaceGradientListTest, SurfaceGradientReturnsSurfaceWeights) { // When there is more than one surface/weight defined and added to the component, they should all // be returned. The component isn't required to return them in descending order. - AddSurfaceGradientListToEntities(); + auto entity = CreateEntity(); - m_entity->Activate(); - m_gradientEntity1->Activate(); - m_gradientEntity2->Activate(); + AddRequiredComponentsToEntity(entity.get()); + + auto gradientEntity1 = CreateEntity(); + auto gradientEntity2 = CreateEntity(); const float gradient1Value = 0.3f; - NiceMock mockGradientRequests1(m_gradientEntity1->GetId()); + NiceMock mockGradientRequests1(gradientEntity1->GetId()); ON_CALL(mockGradientRequests1, GetValue).WillByDefault(Return(gradient1Value)); const float gradient2Value = 1.0f; - NiceMock mockGradientRequests2(m_gradientEntity2->GetId()); + NiceMock mockGradientRequests2(gradientEntity2->GetId()); ON_CALL(mockGradientRequests2, GetValue).WillByDefault(Return(gradient2Value)); AzFramework::SurfaceData::SurfaceTagWeightList weightList; Terrain::TerrainAreaSurfaceRequestBus::Event( - m_entity->GetId(), &Terrain::TerrainAreaSurfaceRequestBus::Events::GetSurfaceWeights, AZ::Vector3::CreateZero(), weightList); + entity->GetId(), &Terrain::TerrainAreaSurfaceRequestBus::Events::GetSurfaceWeights, AZ::Vector3::CreateZero(), weightList); AZ::Crc32 expectedCrcList[] = { AZ::Crc32(surfaceTag1), AZ::Crc32(surfaceTag2) }; const float expectedWeightList[] = { gradient1Value, gradient2Value }; From 039d2fc0c4b82ba97acb3d41a87c858e2da7649f Mon Sep 17 00:00:00 2001 From: John Date: Thu, 11 Nov 2021 12:13:55 +0000 Subject: [PATCH 66/71] Remove SurfaceManipulator. Signed-off-by: John --- .../EditorTransformComponentSelection.cpp | 33 ------------------- 1 file changed, 33 deletions(-) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorTransformComponentSelection.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorTransformComponentSelection.cpp index 39c882b766..e9af69dc36 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorTransformComponentSelection.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorTransformComponentSelection.cpp @@ -1334,39 +1334,6 @@ namespace AzToolsFramework EndRecordManipulatorCommand(); }); - // surface - translationManipulators->InstallSurfaceManipulatorMouseDownCallback( - [this, manipulatorEntityIds]([[maybe_unused]] const SurfaceManipulator::Action& action) - { - BuildSortedEntityIdVectorFromEntityIdMap(m_entityIdManipulators.m_lookups, manipulatorEntityIds->m_entityIds); - - InitializeTranslationLookup(m_entityIdManipulators); - - m_axisPreview.m_translation = m_entityIdManipulators.m_manipulators->GetLocalTransform().GetTranslation(); - m_axisPreview.m_orientation = QuaternionFromTransformNoScaling(m_entityIdManipulators.m_manipulators->GetLocalTransform()); - - // [ref 1.] - BeginRecordManipulatorCommand(); - }); - - translationManipulators->InstallSurfaceManipulatorMouseMoveCallback( - [this, prevModifiers, manipulatorEntityIds](const SurfaceManipulator::Action& action) mutable - { - UpdateTranslationManipulator( - action, manipulatorEntityIds->m_entityIds, m_entityIdManipulators, m_pivotOverrideFrame, prevModifiers, - m_transformChangedInternally, m_spaceCluster.m_spaceLock); - }); - - translationManipulators->InstallSurfaceManipulatorMouseUpCallback( - [this, manipulatorEntityIds]([[maybe_unused]] const SurfaceManipulator::Action& action) - { - AzToolsFramework::EditorTransformChangeNotificationBus::Broadcast( - &AzToolsFramework::EditorTransformChangeNotificationBus::Events::OnEntityTransformChanged, - manipulatorEntityIds->m_entityIds); - - EndRecordManipulatorCommand(); - }); - // transfer ownership m_entityIdManipulators.m_manipulators = AZStd::move(translationManipulators); } From 4e0e3c7904bed001a8e7f0403d923ffdb2d0b48b Mon Sep 17 00:00:00 2001 From: AMZN-Igarri <82394219+AMZN-Igarri@users.noreply.github.com> Date: Thu, 11 Nov 2021 13:16:11 +0100 Subject: [PATCH 67/71] Entering the Game Mode when the SlideAlongAxisBasedOnAngle in the Camera Rig is set results in an assert (#5410) * Fixed assert and added None behavior. Signed-off-by: AMZN-Igarri <82394219+AMZN-Igarri@users.noreply.github.com> * cleaned up file Signed-off-by: AMZN-Igarri <82394219+AMZN-Igarri@users.noreply.github.com> * Switched over to checkboxes Signed-off-by: AMZN-Igarri <82394219+AMZN-Igarri@users.noreply.github.com> * Fixed naming. Signed-off-by: AMZN-Igarri <82394219+AMZN-Igarri@users.noreply.github.com> * Fixed naming Signed-off-by: AMZN-Igarri <82394219+AMZN-Igarri@users.noreply.github.com> * Fixed serialize version and zero vector normalization Signed-off-by: AMZN-Igarri <82394219+AMZN-Igarri@users.noreply.github.com> * Cleaned up format. Signed-off-by: AMZN-Igarri <82394219+AMZN-Igarri@users.noreply.github.com> * Fixed Warnings Signed-off-by: AMZN-Igarri <82394219+AMZN-Igarri@users.noreply.github.com> --- .../StartingPointCameraConstants.h | 11 ----- .../StartingPointCameraUtilities.h | 18 +++------ .../SlideAlongAxisBasedOnAngle.cpp | 21 +++++----- .../SlideAlongAxisBasedOnAngle.h | 4 +- .../StartingPointCameraUtilities.cpp | 40 +++++++------------ 5 files changed, 34 insertions(+), 60 deletions(-) diff --git a/Gems/StartingPointCamera/Code/Include/StartingPointCamera/StartingPointCameraConstants.h b/Gems/StartingPointCamera/Code/Include/StartingPointCamera/StartingPointCameraConstants.h index 849a462ab2..9a36cf5222 100644 --- a/Gems/StartingPointCamera/Code/Include/StartingPointCamera/StartingPointCameraConstants.h +++ b/Gems/StartingPointCamera/Code/Include/StartingPointCamera/StartingPointCameraConstants.h @@ -24,17 +24,6 @@ namespace Camera Z_Axis = 2 }; - ////////////////////////////////////////////////////////////////////////// - /// These are intended to be used as an index and needs to be implicitly - /// convertible to int. See StartingPointCameraUtilities.h for examples - enum VectorComponentType : int - { - X_Component = 0, - Y_Component = 1, - Z_Component = 2, - None = 3, - }; - ////////////////////////////////////////////////////////////////////////// /// These are intended to be used as an index and needs to be implicitly /// convertible to int. See StartingPointCameraUtilities.h for examples diff --git a/Gems/StartingPointCamera/Code/Include/StartingPointCamera/StartingPointCameraUtilities.h b/Gems/StartingPointCamera/Code/Include/StartingPointCamera/StartingPointCameraUtilities.h index eec86059c5..c565bf9379 100644 --- a/Gems/StartingPointCamera/Code/Include/StartingPointCamera/StartingPointCameraUtilities.h +++ b/Gems/StartingPointCamera/Code/Include/StartingPointCamera/StartingPointCameraUtilities.h @@ -16,24 +16,16 @@ namespace Camera { const char* GetNameFromUuid(const AZ::Uuid& uuid); - ////////////////////////////////////////////////////////////////////////// - /// This methods will 0 out a vector component and re-normalize it - ////////////////////////////////////////////////////////////////////////// - void MaskComponentFromNormalizedVector(AZ::Vector3& v, VectorComponentType vectorComponentType); + //! This methods will 0 out specified vector components and re-normalize it + void MaskComponentFromNormalizedVector(AZ::Vector3& v, bool ignoreX, bool ignoreY, bool ignoreZ); - ////////////////////////////////////////////////////////////////////////// - /// This will calculate the requested Euler angle from a given AZ::Quaternion - ////////////////////////////////////////////////////////////////////////// + //! This will calculate the requested Euler angle from a given AZ::Quaternion float GetEulerAngleFromTransform(const AZ::Transform& rotation, EulerAngleType eulerAngleType); - ////////////////////////////////////////////////////////////////////////// - /// This will calculate an AZ::Transform based on an Euler angle - ////////////////////////////////////////////////////////////////////////// + //! This will calculate an AZ::Transform based on an Euler angle AZ::Transform CreateRotationFromEulerAngle(EulerAngleType rotationType, float radians); - ////////////////////////////////////////////////////////////////////////// - /// Creates the Quaternion representing the rotation looking down the vector - ////////////////////////////////////////////////////////////////////////// + //! Creates the Quaternion representing the rotation looking down the vector AZ::Quaternion CreateQuaternionFromViewVector(const AZ::Vector3 lookVector); } //namespace Camera diff --git a/Gems/StartingPointCamera/Code/Source/CameraLookAtBehaviors/SlideAlongAxisBasedOnAngle.cpp b/Gems/StartingPointCamera/Code/Source/CameraLookAtBehaviors/SlideAlongAxisBasedOnAngle.cpp index d7fcc771f4..5031f149b8 100644 --- a/Gems/StartingPointCamera/Code/Source/CameraLookAtBehaviors/SlideAlongAxisBasedOnAngle.cpp +++ b/Gems/StartingPointCamera/Code/Source/CameraLookAtBehaviors/SlideAlongAxisBasedOnAngle.cpp @@ -20,10 +20,12 @@ namespace Camera if (serializeContext) { serializeContext->Class() - ->Version(1) + ->Version(2) ->Field("Axis to slide along", &SlideAlongAxisBasedOnAngle::m_axisToSlideAlong) ->Field("Angle Type", &SlideAlongAxisBasedOnAngle::m_angleTypeToChangeFor) - ->Field("Vector Component To Ignore", &SlideAlongAxisBasedOnAngle::m_vectorComponentToIgnore) + ->Field("Ignore X Component", &SlideAlongAxisBasedOnAngle::m_ignoreX) + ->Field("Ignore Y Component", &SlideAlongAxisBasedOnAngle::m_ignoreY) + ->Field("Ignore Z Component", &SlideAlongAxisBasedOnAngle::m_ignoreZ) ->Field("Max Positive Slide Distance", &SlideAlongAxisBasedOnAngle::m_maximumPositiveSlideDistance) ->Field("Max Negative Slide Distance", &SlideAlongAxisBasedOnAngle::m_maximumNegativeSlideDistance); @@ -40,15 +42,16 @@ namespace Camera ->EnumAttribute(EulerAngleType::Pitch, "Pitch") ->EnumAttribute(EulerAngleType::Roll, "Roll") ->EnumAttribute(EulerAngleType::Yaw, "Yaw") - ->DataElement(AZ::Edit::UIHandlers::ComboBox, &SlideAlongAxisBasedOnAngle::m_vectorComponentToIgnore, "Vector Component To Ignore", "The Vector Component To Ignore") - ->EnumAttribute(VectorComponentType::None, "None") - ->EnumAttribute(VectorComponentType::X_Component, "X") - ->EnumAttribute(VectorComponentType::Y_Component, "Y") - ->EnumAttribute(VectorComponentType::Z_Component, "Z") ->DataElement(0, &SlideAlongAxisBasedOnAngle::m_maximumPositiveSlideDistance, "Max Positive Slide Distance", "The maximum distance to slide in the positive") ->Attribute(AZ::Edit::Attributes::Suffix, "m") ->DataElement(0, &SlideAlongAxisBasedOnAngle::m_maximumNegativeSlideDistance, "Max Negative Slide Distance", "The maximum distance to slide in the negative") - ->Attribute(AZ::Edit::Attributes::Suffix, "m"); + ->Attribute(AZ::Edit::Attributes::Suffix, "m") + ->ClassElement(AZ::Edit::ClassElements::Group, "Vector Components To Ignore") + ->Attribute(AZ::Edit::Attributes::AutoExpand, true) + ->DataElement(0, &SlideAlongAxisBasedOnAngle::m_ignoreX, "X", "When active, the X Component will be ignored.") + ->DataElement(0, &SlideAlongAxisBasedOnAngle::m_ignoreY, "Y", "When active, the Y Component will be ignored.") + ->DataElement(0, &SlideAlongAxisBasedOnAngle::m_ignoreZ, "Z", "When active, the Z Component will be ignored.") + ; } } } @@ -60,7 +63,7 @@ namespace Camera float slideScale = currentPositionOnRange > 0.0f ? m_maximumPositiveSlideDistance : m_maximumNegativeSlideDistance; AZ::Vector3 basis = outLookAtTargetTransform.GetBasis(m_axisToSlideAlong); - MaskComponentFromNormalizedVector(basis, m_vectorComponentToIgnore); + MaskComponentFromNormalizedVector(basis, m_ignoreX, m_ignoreY, m_ignoreZ); outLookAtTargetTransform.SetTranslation(outLookAtTargetTransform.GetTranslation() + basis * currentPositionOnRange * slideScale); } diff --git a/Gems/StartingPointCamera/Code/Source/CameraLookAtBehaviors/SlideAlongAxisBasedOnAngle.h b/Gems/StartingPointCamera/Code/Source/CameraLookAtBehaviors/SlideAlongAxisBasedOnAngle.h index 3558fd7272..2c756d1ac7 100644 --- a/Gems/StartingPointCamera/Code/Source/CameraLookAtBehaviors/SlideAlongAxisBasedOnAngle.h +++ b/Gems/StartingPointCamera/Code/Source/CameraLookAtBehaviors/SlideAlongAxisBasedOnAngle.h @@ -43,8 +43,10 @@ namespace Camera // Reflected data RelativeAxisType m_axisToSlideAlong = ForwardBackward; EulerAngleType m_angleTypeToChangeFor = Pitch; - VectorComponentType m_vectorComponentToIgnore = None; float m_maximumPositiveSlideDistance = 0.0f; float m_maximumNegativeSlideDistance = 0.0f; + bool m_ignoreX = false; + bool m_ignoreY = false; + bool m_ignoreZ = false; }; } // namespace Camera diff --git a/Gems/StartingPointCamera/Code/Source/StartingPointCamera/StartingPointCameraUtilities.cpp b/Gems/StartingPointCamera/Code/Source/StartingPointCamera/StartingPointCameraUtilities.cpp index b8f0945c55..0831ef26e0 100644 --- a/Gems/StartingPointCamera/Code/Source/StartingPointCamera/StartingPointCameraUtilities.cpp +++ b/Gems/StartingPointCamera/Code/Source/StartingPointCamera/StartingPointCameraUtilities.cpp @@ -26,38 +26,32 @@ namespace Camera return ""; } - ////////////////////////////////////////////////////////////////////////// - /// This methods will 0 out a vector component and re-normalize it - ////////////////////////////////////////////////////////////////////////// - void MaskComponentFromNormalizedVector(AZ::Vector3& v, VectorComponentType vectorComponentType) + void MaskComponentFromNormalizedVector(AZ::Vector3& v, bool ignoreX, bool ignoreY, bool ignoreZ) { - switch (vectorComponentType) - { - case X_Component: + + if (ignoreX) { v.SetX(0.f); - break; } - case Y_Component: + + if (ignoreY) { v.SetY(0.f); - break; } - case Z_Component: + + if (ignoreZ) { v.SetZ(0.f); - break; } - default: - AZ_Assert(false, "MaskComponentFromNormalizedVector: VectorComponentType - unexpected value"); - break; + + if (v.IsZero()) + { + AZ_Warning("StartingPointCameraUtilities", false, "MaskComponentFromNormalizedVector: trying to normalize zero vector.") + return; } v.Normalize(); } - ////////////////////////////////////////////////////////////////////////// - /// This will calculate the requested Euler angle from a given AZ::Quaternion - ////////////////////////////////////////////////////////////////////////// float GetEulerAngleFromTransform(const AZ::Transform& rotation, EulerAngleType eulerAngleType) { AZ::Vector3 angles = rotation.GetEulerDegrees(); @@ -70,14 +64,11 @@ namespace Camera case Yaw: return angles.GetZ(); default: - AZ_Warning("", false, "GetEulerAngleFromRotation: eulerAngleType - value not supported"); + AZ_Warning("StartingPointCameraUtilities", false, "GetEulerAngleFromRotation: eulerAngleType - value not supported"); return 0.f; } } - ////////////////////////////////////////////////////////////////////////// - /// This will calculate an AZ::Transform based on an Euler angle - ////////////////////////////////////////////////////////////////////////// AZ::Transform CreateRotationFromEulerAngle(EulerAngleType rotationType, float radians) { switch (rotationType) @@ -89,14 +80,11 @@ namespace Camera case Yaw: return AZ::Transform::CreateRotationZ(radians); default: - AZ_Warning("", false, "CreateRotationFromEulerAngle: rotationType - value not supported"); + AZ_Warning("StartingPointCameraUtilities", false, "CreateRotationFromEulerAngle: rotationType - value not supported"); return AZ::Transform::Identity(); } } - ////////////////////////////////////////////////////////////////////////// - /// Creates the Quaternion representing the rotation looking down the vector - ////////////////////////////////////////////////////////////////////////// AZ::Quaternion CreateQuaternionFromViewVector(const AZ::Vector3 lookVector) { float twoDimensionLength = AZ::Vector2(lookVector.GetX(), lookVector.GetY()).GetLength(); From 398decd06eff4fb718abb7e8da22bcd52d33e8a9 Mon Sep 17 00:00:00 2001 From: sphrose <82213493+sphrose@users.noreply.github.com> Date: Thu, 11 Nov 2021 12:57:48 +0000 Subject: [PATCH 68/71] review changes Signed-off-by: sphrose <82213493+sphrose@users.noreply.github.com> --- .../Terrain/Code/Tests/TerrainHeightGradientListTests.cpp | 8 -------- .../Code/Tests/TerrainSurfaceGradientListTests.cpp | 6 +----- 2 files changed, 1 insertion(+), 13 deletions(-) diff --git a/Gems/Terrain/Code/Tests/TerrainHeightGradientListTests.cpp b/Gems/Terrain/Code/Tests/TerrainHeightGradientListTests.cpp index 535aacb8c8..89fc714c3c 100644 --- a/Gems/Terrain/Code/Tests/TerrainHeightGradientListTests.cpp +++ b/Gems/Terrain/Code/Tests/TerrainHeightGradientListTests.cpp @@ -82,8 +82,6 @@ TEST_F(TerrainHeightGradientListComponentTest, MissingRequiredComponentsActivate const AZ::Entity::DependencySortOutcome sortOutcome = entity->EvaluateDependenciesGetDetails(); EXPECT_FALSE(sortOutcome.IsSuccess()); - - entity.reset(); } TEST_F(TerrainHeightGradientListComponentTest, ActivateEntityActivateSuccess) @@ -97,8 +95,6 @@ TEST_F(TerrainHeightGradientListComponentTest, ActivateEntityActivateSuccess) entity->Activate(); EXPECT_EQ(entity->GetState(), AZ::Entity::State::Active); - - entity.reset(); } TEST_F(TerrainHeightGradientListComponentTest, TerrainHeightGradientRefreshesTerrainSystem) @@ -123,8 +119,6 @@ TEST_F(TerrainHeightGradientListComponentTest, TerrainHeightGradientRefreshesTer // Stop the EXPECT_CALL check now, as OnCompositionChanged will get called twice again during the reset. Mock::VerifyAndClearExpectations(&terrainSystem); - - entity.reset(); } TEST_F(TerrainHeightGradientListComponentTest, TerrainHeightGradientListReturnsHeights) @@ -169,7 +163,5 @@ TEST_F(TerrainHeightGradientListComponentTest, TerrainHeightGradientListReturnsH const float height = outPosition.GetZ(); EXPECT_NEAR(height, mockGradientValue * max, 0.01f); - - entity.reset(); } diff --git a/Gems/Terrain/Code/Tests/TerrainSurfaceGradientListTests.cpp b/Gems/Terrain/Code/Tests/TerrainSurfaceGradientListTests.cpp index fb94d2320d..71f5d64fa8 100644 --- a/Gems/Terrain/Code/Tests/TerrainSurfaceGradientListTests.cpp +++ b/Gems/Terrain/Code/Tests/TerrainSurfaceGradientListTests.cpp @@ -63,8 +63,6 @@ namespace UnitTest const AZ::Entity::DependencySortOutcome sortOutcome = entity->EvaluateDependenciesGetDetails(); EXPECT_FALSE(sortOutcome.IsSuccess()); - - entity.reset(); } TEST_F(TerrainSurfaceGradientListTest, SurfaceGradientActivateSuccess) @@ -78,9 +76,7 @@ namespace UnitTest entity->Activate(); - - - entity.reset(); + EXPECT_EQ(entity->GetState(), AZ::Entity::State::Active); } TEST_F(TerrainSurfaceGradientListTest, SurfaceGradientReturnsSurfaceWeights) From 2df8d5b620efef3d5022db65d0a5fd5c93fcf9d4 Mon Sep 17 00:00:00 2001 From: AMZN-stankowi <4838196+AMZN-stankowi@users.noreply.github.com> Date: Thu, 11 Nov 2021 07:50:16 -0800 Subject: [PATCH 69/71] Fixed crash if you save a bundle outside the default bundle folder (#4974) (#5255) Signed-off-by: stankowi <4838196+AMZN-stankowi@users.noreply.github.com> --- .../source/models/AssetBundlerAbstractFileTableModel.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/Code/Tools/AssetBundler/source/models/AssetBundlerAbstractFileTableModel.cpp b/Code/Tools/AssetBundler/source/models/AssetBundlerAbstractFileTableModel.cpp index 45d01b9b5b..8def0a698c 100644 --- a/Code/Tools/AssetBundler/source/models/AssetBundlerAbstractFileTableModel.cpp +++ b/Code/Tools/AssetBundler/source/models/AssetBundlerAbstractFileTableModel.cpp @@ -61,8 +61,12 @@ namespace AssetBundler { AZStd::string absolutePath = filePath.toUtf8().data(); if (AZ::IO::FileIOBase::GetInstance()->Exists(absolutePath.c_str())) - { - AZStd::string projectName = pathToProjectNameMap.at(absolutePath); + { + AZStd::string projectName; + if (pathToProjectNameMap.contains(absolutePath)) + { + projectName = pathToProjectNameMap.at(absolutePath); + } // If a project name is already specified, then the associated file is a default file LoadFile(absolutePath, projectName, !projectName.empty()); From 6e70097ad712a02171cd6cc27908c737a6566b65 Mon Sep 17 00:00:00 2001 From: AMZN-stankowi <4838196+AMZN-stankowi@users.noreply.github.com> Date: Thu, 11 Nov 2021 07:50:25 -0800 Subject: [PATCH 70/71] Fixed all errors with default seeds (#5489) * Cleaning up errors with default assets, used in bundled release builds Signed-off-by: AMZN-stankowi <4838196+AMZN-stankowi@users.noreply.github.com> * Updated simple asset references to be to the product, not source assets Signed-off-by: AMZN-stankowi <4838196+AMZN-stankowi@users.noreply.github.com> --- .../Slices/DefaultLevelSetup.slice | 2 +- Assets/Engine/Entities/GeomCache.ent | 3 - .../Scripts/Entities/Render/GeomCache.lua | 178 ------------------ Code/Editor/CryEdit.cpp | 10 - Code/Editor/Include/IFileUtil.h | 1 - Code/Editor/Objects/EntityObject.cpp | 18 +- Code/Editor/Objects/EntityObject.h | 1 - Code/Editor/Objects/ObjectManager.cpp | 2 +- Code/Editor/Util/FileUtil.cpp | 4 +- Code/LauncherUnified/Launcher.cpp | 19 -- .../AssetBuilderSDK/AssetBuilderSDK.cpp | 7 - .../Canvases/DefaultMainMenuScreen.uicanvas | 4 +- Gems/LmbrCentral/Assets/seedList.seed | 37 ---- Gems/LyShine/Assets/seedList.seed | 4 +- Gems/LyShine/Code/Source/Sprite.cpp | 3 +- .../Comp/Button/Styles.uicanvas | 28 +-- .../Comp/Image/ImageTypes.uicanvas | 12 +- .../Comp/Mask/MaskingInteractables.uicanvas | 36 ++-- .../Comp/Text/ImageMarkup.uicanvas | 4 +- .../Performance/DrawCallsControl.uicanvas | 2 +- .../ChildDropTargets_Draggable.slice | 6 +- .../ChildDropTargets_EndDropTarget.slice | 2 +- .../DragAndDrop/DraggableElement.slice | 4 +- .../Slices/LyShineExamples/NextButton.slice | 4 +- Gems/LyShineExamples/Assets/seedList.seed | 32 ++-- .../Assets/UI/Slices/Library/Button.slice | 4 +- .../Assets/UI/Slices/Library/Checkbox.slice | 10 +- .../Assets/UI/Slices/Library/Dropdown.slice | 6 +- .../Assets/UI/Slices/Library/Textinput.slice | 4 +- .../UI/Slices/Library/TooltipDisplay.slice | 2 +- 30 files changed, 91 insertions(+), 358 deletions(-) delete mode 100644 Assets/Engine/Entities/GeomCache.ent delete mode 100644 Assets/Engine/Scripts/Entities/Render/GeomCache.lua delete mode 100644 Gems/LmbrCentral/Assets/seedList.seed diff --git a/Assets/Engine/EngineAssets/Slices/DefaultLevelSetup.slice b/Assets/Engine/EngineAssets/Slices/DefaultLevelSetup.slice index 1b7dfdf40d..b82c482c4f 100644 --- a/Assets/Engine/EngineAssets/Slices/DefaultLevelSetup.slice +++ b/Assets/Engine/EngineAssets/Slices/DefaultLevelSetup.slice @@ -145,7 +145,7 @@ - + diff --git a/Assets/Engine/Entities/GeomCache.ent b/Assets/Engine/Entities/GeomCache.ent deleted file mode 100644 index e7a63190c3..0000000000 --- a/Assets/Engine/Entities/GeomCache.ent +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:cf441215a769562f88aa20711aee68dadcbf02597d1e2270547055e8e6aec6a3 -size 77 diff --git a/Assets/Engine/Scripts/Entities/Render/GeomCache.lua b/Assets/Engine/Scripts/Entities/Render/GeomCache.lua deleted file mode 100644 index b496aecd8d..0000000000 --- a/Assets/Engine/Scripts/Entities/Render/GeomCache.lua +++ /dev/null @@ -1,178 +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 --- --- --- ----------------------------------------------------------------------------------------------------- -Script.ReloadScript("scripts/Utils/EntityUtils.lua") - -GeomCache = -{ - Properties = { - geomcacheFile = "EngineAssets/GeomCaches/defaultGeomCache.cax", - bPlaying = 0, - fStartTime = 0, - bLooping = 0, - objectStandIn = "", - materialStandInMaterial = "", - objectFirstFrameStandIn = "", - materialFirstFrameStandInMaterial = "", - objectLastFrameStandIn = "", - materialLastFrameStandInMaterial = "", - fStandInDistance = 0, - fStreamInDistance = 0, - Physics = { - bPhysicalize = 0, - } - }, - - Editor={ - Icon = "animobject.bmp", - IconOnTop = 1, - }, - - bPlaying = 0, - currentTime = 0, - precacheTime = 0, - bPrecachedOutputTriggered = false, -} - -function GeomCache:OnLoad(table) - self.currentTime = table.currentTime; -end - -function GeomCache:OnSave(table) - table.currentTime = self.currentTime; -end - -function GeomCache:OnSpawn() - self.currentTime = self.Properties.fStartTime; - self:SetFromProperties(); -end - -function GeomCache:OnReset() - self.currentTime = self.Properties.fStartTime; - self.bPrecachedOutputTriggered = true; - self:SetFromProperties(); -end - -function GeomCache:SetFromProperties() - local Properties = self.Properties; - - if (Properties.geomcacheFile == "") then - do return end; - end - - self:LoadGeomCache(0, Properties.geomcacheFile); - - self.bPlaying = Properties.bPlaying; - if (self.bPlaying == 0) then - self.currentTime = Properties.fStartTime; - end - - self:SetGeomCachePlaybackTime(self.currentTime); - self:SetGeomCacheParams(Properties.bLooping, Properties.objectStandIn, Properties.materialStandInMaterial, Properties.objectFirstFrameStandIn, - Properties.materialFirstFrameStandInMaterial, Properties.objectLastFrameStandIn, Properties.materialLastFrameStandInMaterial, - Properties.fStandInDistance, Properties.fStreamInDistance); - self:SetGeomCacheStreaming(false, 0); - - if (Properties.Physics.bPhysicalize == 1) then - local tempPhysParams = EntityCommon.TempPhysParams; - self:Physicalize(0, PE_ARTICULATED, tempPhysParams); - end - - self:Activate(1); -end - -function GeomCache:PhysicalizeThis() - local Physics = self.Properties.Physics; - EntityCommon.PhysicalizeRigid(self, 0, Physics, false); -end - -function GeomCache:OnUpdate(dt) - if (self.bPlaying == 1) then - self:SetGeomCachePlaybackTime(self.currentTime); - end - - if (self:IsGeomCacheStreaming() and not self.bPrecachedOutputTriggered) then - local precachedTime = self:GetGeomCachePrecachedTime(); - if (precachedTime >= self.precacheTime) then - self:ActivateOutput("Precached", true); - self.bPrecachedOutputTriggered = true; - end - end - - if (self.bPlaying == 1) then - self.currentTime = self.currentTime + dt; - end -end - -function GeomCache:OnPropertyChange() - self:SetFromProperties(); -end - -function GeomCache:Event_Start(sender, val) - self.bPlaying = 1; -end - -function GeomCache:Event_Stop(sender, value) - self.bPlaying = 0; -end - -function GeomCache:Event_SetTime(sender, value) - self.currentTime = value; -end - -function GeomCache:Event_StartStreaming(sender, value) - self.bPrecachedOutputTriggered = false; - self:SetGeomCacheStreaming(true, self.currentTime); -end - -function GeomCache:Event_StopStreaming(sender, value) - self:SetGeomCacheStreaming(false, 0); -end - -function GeomCache:Event_PrecacheTime(sender, value) - self.precacheTime = value; -end - -function GeomCache:Event_Hide(sender, value) - self:Hide(1); -end - -function GeomCache:Event_Unhide(sender, value) - self:Hide(0); -end - -function GeomCache:Event_StopDrawing(sender, value) - self:SetGeomCacheDrawing(false); -end - -function GeomCache:Event_StartDrawing(sender, value) - self:SetGeomCacheDrawing(true); -end - -GeomCache.FlowEvents = -{ - Inputs = - { - Start = { GeomCache.Event_Start, "any" }, - Stop = { GeomCache.Event_Stop, "any" }, - SetTime = { GeomCache.Event_SetTime, "float" }, - StartStreaming = { GeomCache.Event_StartStreaming, "any" }, - StopStreaming = { GeomCache.Event_StopStreaming, "any" }, - PrecacheTime = { GeomCache.Event_PrecacheTime, "float" }, - Hide = { GeomCache.Event_Hide, "any" }, - Unhide = { GeomCache.Event_Unhide, "any" }, - StopDrawing = { GeomCache.Event_StopDrawing, "any" }, - StartDrawing = { GeomCache.Event_StartDrawing, "any" }, - }, - Outputs = - { - Precached = "bool", - }, -} diff --git a/Code/Editor/CryEdit.cpp b/Code/Editor/CryEdit.cpp index 0ea22e8ce3..0b40390a18 100644 --- a/Code/Editor/CryEdit.cpp +++ b/Code/Editor/CryEdit.cpp @@ -1362,16 +1362,6 @@ void CCryEditApp::CompileCriticalAssets() const assetsInQueueNotifcation.BusDisconnect(); CCryEditApp::OutputStartupMessage(QString("Asset Processor is now ready.")); - // VERY early on, as soon as we can, request that the asset system make sure the following assets take priority over others, - // so that by the time we ask for them there is a greater likelihood that they're already good to go. - // these can be loaded later but are still important: - AzFramework::AssetSystemRequestBus::Broadcast(&AzFramework::AssetSystem::AssetSystemRequests::EscalateAssetBySearchTerm, "/texturemsg/"); - AzFramework::AssetSystemRequestBus::Broadcast(&AzFramework::AssetSystem::AssetSystemRequests::EscalateAssetBySearchTerm, "engineassets/materials"); - AzFramework::AssetSystemRequestBus::Broadcast(&AzFramework::AssetSystem::AssetSystemRequests::EscalateAssetBySearchTerm, "engineassets/geomcaches"); - AzFramework::AssetSystemRequestBus::Broadcast(&AzFramework::AssetSystem::AssetSystemRequests::EscalateAssetBySearchTerm, "engineassets/objects"); - - // some are specifically extra important and will cause issues if missing completely: - AzFramework::AssetSystemRequestBus::Broadcast(&AzFramework::AssetSystem::AssetSystemRequests::CompileAssetSync, "engineassets/objects/default.cgf"); } bool CCryEditApp::ConnectToAssetProcessor() const diff --git a/Code/Editor/Include/IFileUtil.h b/Code/Editor/Include/IFileUtil.h index 4d5f6e23c4..036a0bc5ee 100644 --- a/Code/Editor/Include/IFileUtil.h +++ b/Code/Editor/Include/IFileUtil.h @@ -60,7 +60,6 @@ struct IFileUtil EFILE_TYPE_GEOMETRY, EFILE_TYPE_TEXTURE, EFILE_TYPE_SOUND, - EFILE_TYPE_GEOMCACHE, EFILE_TYPE_LAST, }; diff --git a/Code/Editor/Objects/EntityObject.cpp b/Code/Editor/Objects/EntityObject.cpp index 6e2354998c..b2dfc04102 100644 --- a/Code/Editor/Objects/EntityObject.cpp +++ b/Code/Editor/Objects/EntityObject.cpp @@ -956,11 +956,7 @@ void CEntityObject::Serialize(CObjectArchive& ar) QString attachmentType; xmlNode->getAttr("AttachmentType", attachmentType); - if (attachmentType == "GeomCacheNode") - { - m_attachmentType = eAT_GeomCacheNode; - } - else if (attachmentType == "CharacterBone") + if (attachmentType == "CharacterBone") { m_attachmentType = eAT_CharacterBone; } @@ -987,11 +983,7 @@ void CEntityObject::Serialize(CObjectArchive& ar) { if (m_attachmentType != eAT_Pivot) { - if (m_attachmentType == eAT_GeomCacheNode) - { - xmlNode->setAttr("AttachmentType", "GeomCacheNode"); - } - else if (m_attachmentType == eAT_CharacterBone) + if (m_attachmentType == eAT_CharacterBone) { xmlNode->setAttr("AttachmentType", "CharacterBone"); } @@ -1091,11 +1083,7 @@ XmlNodeRef CEntityObject::Export([[maybe_unused]] const QString& levelPath, XmlN objNode->setAttr("ParentId", parentEntity->GetEntityId()); if (m_attachmentType != eAT_Pivot) { - if (m_attachmentType == eAT_GeomCacheNode) - { - objNode->setAttr("AttachmentType", "GeomCacheNode"); - } - else if (m_attachmentType == eAT_CharacterBone) + if (m_attachmentType == eAT_CharacterBone) { objNode->setAttr("AttachmentType", "CharacterBone"); } diff --git a/Code/Editor/Objects/EntityObject.h b/Code/Editor/Objects/EntityObject.h index dcc6ff7b22..a4f4752b75 100644 --- a/Code/Editor/Objects/EntityObject.h +++ b/Code/Editor/Objects/EntityObject.h @@ -131,7 +131,6 @@ public: enum EAttachmentType { eAT_Pivot, - eAT_GeomCacheNode, eAT_CharacterBone, }; diff --git a/Code/Editor/Objects/ObjectManager.cpp b/Code/Editor/Objects/ObjectManager.cpp index ee7e9a8e96..265d828481 100644 --- a/Code/Editor/Objects/ObjectManager.cpp +++ b/Code/Editor/Objects/ObjectManager.cpp @@ -608,7 +608,7 @@ bool CObjectManager::AddObject(CBaseObject* obj) if (CEntityObject* entityObj = qobject_cast(obj)) { CEntityObject::EAttachmentType attachType = entityObj->GetAttachType(); - if (attachType == CEntityObject::EAttachmentType::eAT_GeomCacheNode || attachType == CEntityObject::EAttachmentType::eAT_CharacterBone) + if (attachType == CEntityObject::EAttachmentType::eAT_CharacterBone) { m_animatedAttachedEntities.insert(entityObj); } diff --git a/Code/Editor/Util/FileUtil.cpp b/Code/Editor/Util/FileUtil.cpp index 36c1879407..9f96d45381 100644 --- a/Code/Editor/Util/FileUtil.cpp +++ b/Code/Editor/Util/FileUtil.cpp @@ -54,8 +54,8 @@ #include #endif -bool CFileUtil::s_singleFileDlgPref[IFileUtil::EFILE_TYPE_LAST] = { true, true, true, true, true }; -bool CFileUtil::s_multiFileDlgPref[IFileUtil::EFILE_TYPE_LAST] = { true, true, true, true, true }; +bool CFileUtil::s_singleFileDlgPref[IFileUtil::EFILE_TYPE_LAST] = { true, true, true, true }; +bool CFileUtil::s_multiFileDlgPref[IFileUtil::EFILE_TYPE_LAST] = { true, true, true, true }; CAutoRestorePrimaryCDRoot::~CAutoRestorePrimaryCDRoot() { diff --git a/Code/LauncherUnified/Launcher.cpp b/Code/LauncherUnified/Launcher.cpp index 0f832ff1a5..97859a604b 100644 --- a/Code/LauncherUnified/Launcher.cpp +++ b/Code/LauncherUnified/Launcher.cpp @@ -369,7 +369,6 @@ namespace O3DELauncher } } - void CompileCriticalAssets(); void CreateRemoteFileIO(); bool ConnectToAssetProcessor() @@ -397,29 +396,11 @@ namespace O3DELauncher { AZ_TracePrintf("Launcher", "Connected to Asset Processor\n"); CreateRemoteFileIO(); - CompileCriticalAssets(); } return connectedToAssetProcessor; } - //! Compiles the critical assets that are within the Engine directory of Open 3D Engine - //! This code should be in a centralized location, but doesn't belong in AzFramework - //! since it is specific to how Open 3D Engine projects has assets setup - void CompileCriticalAssets() - { - // VERY early on, as soon as we can, request that the asset system make sure the following assets take priority over others, - // so that by the time we ask for them there is a greater likelihood that they're already good to go. - // these can be loaded later but are still important: - AzFramework::AssetSystemRequestBus::Broadcast(&AzFramework::AssetSystem::AssetSystemRequests::EscalateAssetBySearchTerm, "/texturemsg/"); - AzFramework::AssetSystemRequestBus::Broadcast(&AzFramework::AssetSystem::AssetSystemRequests::EscalateAssetBySearchTerm, "engineassets/materials"); - AzFramework::AssetSystemRequestBus::Broadcast(&AzFramework::AssetSystem::AssetSystemRequests::EscalateAssetBySearchTerm, "engineassets/geomcaches"); - AzFramework::AssetSystemRequestBus::Broadcast(&AzFramework::AssetSystem::AssetSystemRequests::EscalateAssetBySearchTerm, "engineassets/objects"); - - // some are specifically extra important and will cause issues if missing completely: - AzFramework::AssetSystemRequestBus::Broadcast(&AzFramework::AssetSystem::AssetSystemRequests::CompileAssetSync, "engineassets/objects/default.cgf"); - } - //! Remote FileIO to use as a Virtual File System //! Communication of FileIOBase operations occur through an AssetProcessor connection void CreateRemoteFileIO() diff --git a/Code/Tools/AssetProcessor/AssetBuilderSDK/AssetBuilderSDK/AssetBuilderSDK.cpp b/Code/Tools/AssetProcessor/AssetBuilderSDK/AssetBuilderSDK/AssetBuilderSDK.cpp index 62b063c83b..a02eef8b75 100644 --- a/Code/Tools/AssetProcessor/AssetBuilderSDK/AssetBuilderSDK/AssetBuilderSDK.cpp +++ b/Code/Tools/AssetProcessor/AssetBuilderSDK/AssetBuilderSDK/AssetBuilderSDK.cpp @@ -699,7 +699,6 @@ namespace AssetBuilderSDK // XML files may contain generic data (avoid this in new builders - use a custom extension!) static const char* xmlExtensions = ".xml"; - static const char* geomCacheExtensions = ".cax"; static const char* skeletonExtensions = ".chr"; static AZ::Data::AssetType unknownAssetType = AZ::Data::AssetType::CreateNull(); @@ -710,7 +709,6 @@ namespace AssetBuilderSDK static AZ::Data::AssetType textureMipsAssetType("{3918728C-D3CA-4D9E-813E-A5ED20C6821E}"); static AZ::Data::AssetType skinnedMeshLodsAssetType("{58E5824F-C27B-46FD-AD48-865BA41B7A51}"); static AZ::Data::AssetType staticMeshLodsAssetType("{9AAE4926-CB6A-4C60-9948-A1A22F51DB23}"); - static AZ::Data::AssetType geomCacheAssetType("{EBC96071-E960-41B6-B3E3-328F515AE5DA}"); static AZ::Data::AssetType skeletonAssetType("{60161B46-21F0-4396-A4F0-F2CCF0664CDE}"); static AZ::Data::AssetType entityIconAssetType("{3436C30E-E2C5-4C3B-A7B9-66C94A28701B}"); @@ -822,11 +820,6 @@ namespace AssetBuilderSDK return skinnedMeshAssetType; } - if (AzFramework::StringFunc::Find(geomCacheExtensions, extension.c_str()) != AZStd::string::npos) - { - return geomCacheAssetType; - } - if (AzFramework::StringFunc::Find(skeletonExtensions, extension.c_str()) != AZStd::string::npos) { return skeletonAssetType; diff --git a/Gems/GameStateSamples/Assets/UI/Canvases/DefaultMainMenuScreen.uicanvas b/Gems/GameStateSamples/Assets/UI/Canvases/DefaultMainMenuScreen.uicanvas index 2a0d6d476a..d87baa8aa2 100644 --- a/Gems/GameStateSamples/Assets/UI/Canvases/DefaultMainMenuScreen.uicanvas +++ b/Gems/GameStateSamples/Assets/UI/Canvases/DefaultMainMenuScreen.uicanvas @@ -753,7 +753,7 @@ - + @@ -983,7 +983,7 @@ - + diff --git a/Gems/LmbrCentral/Assets/seedList.seed b/Gems/LmbrCentral/Assets/seedList.seed deleted file mode 100644 index 54c12c9faa..0000000000 --- a/Gems/LmbrCentral/Assets/seedList.seed +++ /dev/null @@ -1,37 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Gems/LyShine/Assets/seedList.seed b/Gems/LyShine/Assets/seedList.seed index b19aa77191..6b53200c4a 100644 --- a/Gems/LyShine/Assets/seedList.seed +++ b/Gems/LyShine/Assets/seedList.seed @@ -2,8 +2,8 @@ - - + + diff --git a/Gems/LyShine/Code/Source/Sprite.cpp b/Gems/LyShine/Code/Source/Sprite.cpp index 5c7adae481..d9a0775cc1 100644 --- a/Gems/LyShine/Code/Source/Sprite.cpp +++ b/Gems/LyShine/Code/Source/Sprite.cpp @@ -855,7 +855,8 @@ bool CSprite::LoadImage(const AZStd::string& nameTex, AZ::Data::Instance().c_str()); return false; } diff --git a/Gems/LyShineExamples/Assets/UI/Canvases/LyShineExamples/Comp/Button/Styles.uicanvas b/Gems/LyShineExamples/Assets/UI/Canvases/LyShineExamples/Comp/Button/Styles.uicanvas index 386df81e5c..6a41034bd2 100644 --- a/Gems/LyShineExamples/Assets/UI/Canvases/LyShineExamples/Comp/Button/Styles.uicanvas +++ b/Gems/LyShineExamples/Assets/UI/Canvases/LyShineExamples/Comp/Button/Styles.uicanvas @@ -569,7 +569,7 @@ - + @@ -591,7 +591,7 @@ - + @@ -626,7 +626,7 @@ - + @@ -650,7 +650,7 @@ - + @@ -1161,7 +1161,7 @@ - + @@ -1209,7 +1209,7 @@ - + @@ -1227,7 +1227,7 @@ - + @@ -1368,7 +1368,7 @@ - + @@ -1438,7 +1438,7 @@ - + @@ -1498,7 +1498,7 @@ - + @@ -1516,7 +1516,7 @@ - + @@ -1657,7 +1657,7 @@ - + @@ -1714,7 +1714,7 @@ - + @@ -1771,7 +1771,7 @@ - + diff --git a/Gems/LyShineExamples/Assets/UI/Canvases/LyShineExamples/Comp/Image/ImageTypes.uicanvas b/Gems/LyShineExamples/Assets/UI/Canvases/LyShineExamples/Comp/Image/ImageTypes.uicanvas index a0fbcbc0ce..0fb5e390d3 100644 --- a/Gems/LyShineExamples/Assets/UI/Canvases/LyShineExamples/Comp/Image/ImageTypes.uicanvas +++ b/Gems/LyShineExamples/Assets/UI/Canvases/LyShineExamples/Comp/Image/ImageTypes.uicanvas @@ -370,7 +370,7 @@ - + @@ -475,7 +475,7 @@ - + @@ -616,7 +616,7 @@ - + @@ -757,7 +757,7 @@ - + @@ -898,7 +898,7 @@ - + @@ -1118,7 +1118,7 @@ - + diff --git a/Gems/LyShineExamples/Assets/UI/Canvases/LyShineExamples/Comp/Mask/MaskingInteractables.uicanvas b/Gems/LyShineExamples/Assets/UI/Canvases/LyShineExamples/Comp/Mask/MaskingInteractables.uicanvas index a99a40c6be..e627fafd54 100644 --- a/Gems/LyShineExamples/Assets/UI/Canvases/LyShineExamples/Comp/Mask/MaskingInteractables.uicanvas +++ b/Gems/LyShineExamples/Assets/UI/Canvases/LyShineExamples/Comp/Mask/MaskingInteractables.uicanvas @@ -215,7 +215,7 @@ - + @@ -240,7 +240,7 @@ - + @@ -265,7 +265,7 @@ - + @@ -301,7 +301,7 @@ - + @@ -378,7 +378,7 @@ - + @@ -455,7 +455,7 @@ - + @@ -645,7 +645,7 @@ - + @@ -716,7 +716,7 @@ - + @@ -975,7 +975,7 @@ - + @@ -1000,7 +1000,7 @@ - + @@ -1052,7 +1052,7 @@ - + @@ -1129,7 +1129,7 @@ - + @@ -1206,7 +1206,7 @@ - + @@ -1296,7 +1296,7 @@ - + @@ -1399,7 +1399,7 @@ - + @@ -1425,7 +1425,7 @@ - + @@ -1475,7 +1475,7 @@ - + @@ -1658,7 +1658,7 @@ - + diff --git a/Gems/LyShineExamples/Assets/UI/Canvases/LyShineExamples/Comp/Text/ImageMarkup.uicanvas b/Gems/LyShineExamples/Assets/UI/Canvases/LyShineExamples/Comp/Text/ImageMarkup.uicanvas index 3bcd4f3db3..efa2e79b50 100644 --- a/Gems/LyShineExamples/Assets/UI/Canvases/LyShineExamples/Comp/Text/ImageMarkup.uicanvas +++ b/Gems/LyShineExamples/Assets/UI/Canvases/LyShineExamples/Comp/Text/ImageMarkup.uicanvas @@ -475,7 +475,7 @@ - + @@ -854,7 +854,7 @@ - + diff --git a/Gems/LyShineExamples/Assets/UI/Canvases/LyShineExamples/Performance/DrawCallsControl.uicanvas b/Gems/LyShineExamples/Assets/UI/Canvases/LyShineExamples/Performance/DrawCallsControl.uicanvas index 9b89289dd4..4d3f08a1cd 100644 --- a/Gems/LyShineExamples/Assets/UI/Canvases/LyShineExamples/Performance/DrawCallsControl.uicanvas +++ b/Gems/LyShineExamples/Assets/UI/Canvases/LyShineExamples/Performance/DrawCallsControl.uicanvas @@ -1910,7 +1910,7 @@ - + diff --git a/Gems/LyShineExamples/Assets/UI/Slices/LyShineExamples/DragAndDrop/ChildDropTargets/ChildDropTargets_Draggable.slice b/Gems/LyShineExamples/Assets/UI/Slices/LyShineExamples/DragAndDrop/ChildDropTargets/ChildDropTargets_Draggable.slice index 4c857ecb60..9e5c72b9ee 100644 --- a/Gems/LyShineExamples/Assets/UI/Slices/LyShineExamples/DragAndDrop/ChildDropTargets/ChildDropTargets_Draggable.slice +++ b/Gems/LyShineExamples/Assets/UI/Slices/LyShineExamples/DragAndDrop/ChildDropTargets/ChildDropTargets_Draggable.slice @@ -64,7 +64,7 @@ - + @@ -102,7 +102,7 @@ - + @@ -422,7 +422,7 @@ - + diff --git a/Gems/LyShineExamples/Assets/UI/Slices/LyShineExamples/DragAndDrop/ChildDropTargets/ChildDropTargets_EndDropTarget.slice b/Gems/LyShineExamples/Assets/UI/Slices/LyShineExamples/DragAndDrop/ChildDropTargets/ChildDropTargets_EndDropTarget.slice index cb6f6749d4..6f00a98399 100644 --- a/Gems/LyShineExamples/Assets/UI/Slices/LyShineExamples/DragAndDrop/ChildDropTargets/ChildDropTargets_EndDropTarget.slice +++ b/Gems/LyShineExamples/Assets/UI/Slices/LyShineExamples/DragAndDrop/ChildDropTargets/ChildDropTargets_EndDropTarget.slice @@ -174,7 +174,7 @@ - + diff --git a/Gems/LyShineExamples/Assets/UI/Slices/LyShineExamples/DragAndDrop/DraggableElement.slice b/Gems/LyShineExamples/Assets/UI/Slices/LyShineExamples/DragAndDrop/DraggableElement.slice index 8781688a94..3249e61b53 100644 --- a/Gems/LyShineExamples/Assets/UI/Slices/LyShineExamples/DragAndDrop/DraggableElement.slice +++ b/Gems/LyShineExamples/Assets/UI/Slices/LyShineExamples/DragAndDrop/DraggableElement.slice @@ -61,7 +61,7 @@ - + @@ -99,7 +99,7 @@ - + diff --git a/Gems/LyShineExamples/Assets/UI/Slices/LyShineExamples/NextButton.slice b/Gems/LyShineExamples/Assets/UI/Slices/LyShineExamples/NextButton.slice index 85046d4d1b..661fa6ccf3 100644 --- a/Gems/LyShineExamples/Assets/UI/Slices/LyShineExamples/NextButton.slice +++ b/Gems/LyShineExamples/Assets/UI/Slices/LyShineExamples/NextButton.slice @@ -63,7 +63,7 @@ - + @@ -118,7 +118,7 @@ - + diff --git a/Gems/LyShineExamples/Assets/seedList.seed b/Gems/LyShineExamples/Assets/seedList.seed index 777269ee7a..d730765515 100644 --- a/Gems/LyShineExamples/Assets/seedList.seed +++ b/Gems/LyShineExamples/Assets/seedList.seed @@ -11,10 +11,10 @@ - + - + @@ -27,10 +27,10 @@ - + - + @@ -43,10 +43,10 @@ - + - + @@ -59,10 +59,10 @@ - + - + @@ -75,10 +75,10 @@ - + - + @@ -91,26 +91,26 @@ - + - + - + - + - + - + diff --git a/Gems/UiBasics/Assets/UI/Slices/Library/Button.slice b/Gems/UiBasics/Assets/UI/Slices/Library/Button.slice index 276d181ad6..020db8367a 100644 --- a/Gems/UiBasics/Assets/UI/Slices/Library/Button.slice +++ b/Gems/UiBasics/Assets/UI/Slices/Library/Button.slice @@ -112,7 +112,7 @@ - + @@ -158,7 +158,7 @@ - + diff --git a/Gems/UiBasics/Assets/UI/Slices/Library/Checkbox.slice b/Gems/UiBasics/Assets/UI/Slices/Library/Checkbox.slice index 9334903463..74e7bb1c2b 100644 --- a/Gems/UiBasics/Assets/UI/Slices/Library/Checkbox.slice +++ b/Gems/UiBasics/Assets/UI/Slices/Library/Checkbox.slice @@ -30,7 +30,7 @@ - + @@ -55,7 +55,7 @@ - + @@ -74,7 +74,7 @@ - + @@ -234,7 +234,7 @@ - + @@ -311,7 +311,7 @@ - + diff --git a/Gems/UiBasics/Assets/UI/Slices/Library/Dropdown.slice b/Gems/UiBasics/Assets/UI/Slices/Library/Dropdown.slice index e73c53e0d5..4185e80332 100644 --- a/Gems/UiBasics/Assets/UI/Slices/Library/Dropdown.slice +++ b/Gems/UiBasics/Assets/UI/Slices/Library/Dropdown.slice @@ -231,7 +231,7 @@ - + @@ -383,7 +383,7 @@ - + @@ -1218,7 +1218,7 @@ - + diff --git a/Gems/UiBasics/Assets/UI/Slices/Library/Textinput.slice b/Gems/UiBasics/Assets/UI/Slices/Library/Textinput.slice index cb9eaeb213..f57d307543 100644 --- a/Gems/UiBasics/Assets/UI/Slices/Library/Textinput.slice +++ b/Gems/UiBasics/Assets/UI/Slices/Library/Textinput.slice @@ -75,7 +75,7 @@ - + @@ -233,7 +233,7 @@ - + diff --git a/Gems/UiBasics/Assets/UI/Slices/Library/TooltipDisplay.slice b/Gems/UiBasics/Assets/UI/Slices/Library/TooltipDisplay.slice index e92f722837..5c9aa5cbf2 100644 --- a/Gems/UiBasics/Assets/UI/Slices/Library/TooltipDisplay.slice +++ b/Gems/UiBasics/Assets/UI/Slices/Library/TooltipDisplay.slice @@ -79,7 +79,7 @@ - + From 2812ec2024a7c884ad0110f84602ef54d98c9dd5 Mon Sep 17 00:00:00 2001 From: Tom Hulton-Harrop <82228511+hultonha@users.noreply.github.com> Date: Thu, 11 Nov 2021 16:33:08 +0000 Subject: [PATCH 71/71] Fix brute force mesh intersection function (#5447) * fix brute force mesh intersection function Signed-off-by: Tom Hulton-Harrop <82228511+hultonha@users.noreply.github.com> * add test for brute force ray intersection fix Signed-off-by: Tom Hulton-Harrop <82228511+hultonha@users.noreply.github.com> * refactor tests to remove as much duplication and provide API for future tests if required Signed-off-by: Tom Hulton-Harrop <82228511+hultonha@users.noreply.github.com> * small updates after review feedback Signed-off-by: Tom Hulton-Harrop <82228511+hultonha@users.noreply.github.com> * update following review feedback Signed-off-by: Tom Hulton-Harrop <82228511+hultonha@users.noreply.github.com> * fix for pointer offset Signed-off-by: Tom Hulton-Harrop <82228511+hultonha@users.noreply.github.com> --- Code/Framework/AzCore/AzCore/Math/Vector3.h | 2 +- Code/Framework/AzCore/AzCore/Math/Vector3.inl | 2 +- .../Model/ModelAssetBuilderComponent.cpp | 2 +- .../Source/RPI.Reflect/Model/ModelAsset.cpp | 56 +++--- Gems/Atom/RPI/Code/Tests/Model/ModelTests.cpp | 179 +++++++++++++++--- 5 files changed, 178 insertions(+), 63 deletions(-) diff --git a/Code/Framework/AzCore/AzCore/Math/Vector3.h b/Code/Framework/AzCore/AzCore/Math/Vector3.h index 821dc8292c..6b7c53266d 100644 --- a/Code/Framework/AzCore/AzCore/Math/Vector3.h +++ b/Code/Framework/AzCore/AzCore/Math/Vector3.h @@ -100,7 +100,7 @@ namespace AZ void Set(float x, float y, float z); //! Sets components from an array of 3 floats in xyz order. - void Set(float values[]); + void Set(const float values[]); //! Indexed access using operator(), just for convenience. float operator()(int32_t index) const; diff --git a/Code/Framework/AzCore/AzCore/Math/Vector3.inl b/Code/Framework/AzCore/AzCore/Math/Vector3.inl index 879ade38cf..6371c688b8 100644 --- a/Code/Framework/AzCore/AzCore/Math/Vector3.inl +++ b/Code/Framework/AzCore/AzCore/Math/Vector3.inl @@ -186,7 +186,7 @@ namespace AZ } - AZ_MATH_INLINE void Vector3::Set(float values[]) + AZ_MATH_INLINE void Vector3::Set(const float values[]) { m_value = Simd::Vec3::LoadImmediate(values[0], values[1], values[2]); } diff --git a/Gems/Atom/RPI/Code/Source/RPI.Builders/Model/ModelAssetBuilderComponent.cpp b/Gems/Atom/RPI/Code/Source/RPI.Builders/Model/ModelAssetBuilderComponent.cpp index 9fc99e3ea4..dbf0fea791 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Builders/Model/ModelAssetBuilderComponent.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Builders/Model/ModelAssetBuilderComponent.cpp @@ -2088,7 +2088,7 @@ namespace AZ AZ::Vector3 vpos; //note: it seems to be fastest to reuse a local Vector3 rather than constructing new ones each loop iteration for (uint32_t i = 0; i < elementCount; ++i) { - vpos.Set(const_cast(reinterpret_cast(&buffer[i]))); + vpos.Set(reinterpret_cast(&buffer[i])); aabb.AddPoint(vpos); } } diff --git a/Gems/Atom/RPI/Code/Source/RPI.Reflect/Model/ModelAsset.cpp b/Gems/Atom/RPI/Code/Source/RPI.Reflect/Model/ModelAsset.cpp index 9a432643d7..e362229d2d 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Reflect/Model/ModelAsset.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Reflect/Model/ModelAsset.cpp @@ -201,23 +201,11 @@ namespace AZ AZ::Vector3& normal) const { const BufferAssetView& indexBufferView = mesh.GetIndexBufferAssetView(); - const AZStd::array_view& streamBufferList = mesh.GetStreamBufferInfoList(); + const BufferAssetView* positionBufferView = mesh.GetSemanticBufferAssetView(m_positionName); - // find position semantic - const ModelLodAsset::Mesh::StreamBufferInfo* positionBuffer = nullptr; - - for (const ModelLodAsset::Mesh::StreamBufferInfo& bufferInfo : streamBufferList) + if (positionBufferView && positionBufferView->GetBufferAsset().Get()) { - if (bufferInfo.m_semantic.m_name == m_positionName) - { - positionBuffer = &bufferInfo; - break; - } - } - - if (positionBuffer && positionBuffer->m_bufferAssetView.GetBufferAsset().Get()) - { - BufferAsset* bufferAssetViewPtr = positionBuffer->m_bufferAssetView.GetBufferAsset().Get(); + BufferAsset* bufferAssetViewPtr = positionBufferView->GetBufferAsset().Get(); BufferAsset* indexAssetViewPtr = indexBufferView.GetBufferAsset().Get(); if (!bufferAssetViewPtr || !indexAssetViewPtr) @@ -225,7 +213,7 @@ namespace AZ return false; } - RHI::BufferViewDescriptor positionBufferViewDesc = bufferAssetViewPtr->GetBufferViewDescriptor(); + RHI::BufferViewDescriptor positionBufferViewDesc = positionBufferView->GetBufferViewDescriptor(); AZStd::array_view positionRawBuffer = bufferAssetViewPtr->GetBuffer(); const uint32_t positionElementSize = positionBufferViewDesc.m_elementSize; @@ -234,22 +222,28 @@ namespace AZ // Position is 3 floats if (positionElementSize != sizeof(float) * 3) { - AZ_Warning("ModelAsset", false, "unsupported mesh posiiton format, only full 3 floats per vertex are supported at the moment"); + AZ_Warning( + "ModelAsset", false, "unsupported mesh posiiton format, only full 3 floats per vertex are supported at the moment"); return false; } + RHI::BufferViewDescriptor indexBufferViewDesc = indexBufferView.GetBufferViewDescriptor(); AZStd::array_view indexRawBuffer = indexAssetViewPtr->GetBuffer(); - RHI::BufferViewDescriptor indexRawDesc = indexAssetViewPtr->GetBufferViewDescriptor(); - - bool anyHit = false; const AZ::Vector3 rayEnd = rayStart + rayDir; AZ::Vector3 a, b, c; AZ::Vector3 intersectionNormal; + bool anyHit = false; float shortestDistanceNormalized = AZStd::numeric_limits::max(); - const AZ::u32* indexPtr = reinterpret_cast(indexRawBuffer.data()); - for (uint32_t indexIter = 0; indexIter <= indexRawDesc.m_elementCount - 3; indexIter += 3, indexPtr += 3) + + const AZ::u32* indexPtr = reinterpret_cast( + indexRawBuffer.data() + (indexBufferViewDesc.m_elementOffset * indexBufferViewDesc.m_elementSize)); + const float* positionPtr = reinterpret_cast( + positionRawBuffer.data() + (positionBufferViewDesc.m_elementOffset * positionBufferViewDesc.m_elementSize)); + + constexpr int StepSize = 3; // number of values per vertex (x, y, z) + for (uint32_t indexIter = 0; indexIter < indexBufferViewDesc.m_elementCount; indexIter += StepSize, indexPtr += StepSize) { AZ::u32 index0 = indexPtr[0]; AZ::u32 index1 = indexPtr[1]; @@ -261,17 +255,17 @@ namespace AZ return false; } - const float* p = reinterpret_cast(&positionRawBuffer[index0 * positionElementSize]); - a.Set(const_cast(p)); // faster than AZ::Vector3 c-tor - - p = reinterpret_cast(&positionRawBuffer[index1 * positionElementSize]); - b.Set(const_cast(p)); - - p = reinterpret_cast(&positionRawBuffer[index2 * positionElementSize]); - c.Set(const_cast(p)); + // faster than AZ::Vector3 c-tor + const float* aRef = &positionPtr[index0 * StepSize]; + a.Set(aRef); + const float* bRef = &positionPtr[index1 * StepSize]; + b.Set(bRef); + const float* cRef = &positionPtr[index2 * StepSize]; + c.Set(cRef); float currentDistanceNormalized; - if (AZ::Intersect::IntersectSegmentTriangleCCW(rayStart, rayEnd, a, b, c, intersectionNormal, currentDistanceNormalized)) + if (AZ::Intersect::IntersectSegmentTriangleCCW( + rayStart, rayEnd, a, b, c, intersectionNormal, currentDistanceNormalized)) { anyHit = true; diff --git a/Gems/Atom/RPI/Code/Tests/Model/ModelTests.cpp b/Gems/Atom/RPI/Code/Tests/Model/ModelTests.cpp index 7b07e14de0..81d773d8c0 100644 --- a/Gems/Atom/RPI/Code/Tests/Model/ModelTests.cpp +++ b/Gems/Atom/RPI/Code/Tests/Model/ModelTests.cpp @@ -38,7 +38,7 @@ namespace UnitTest bufferData.resize(bufferSize); //The actual data doesn't matter - const uint8_t bufferDataSize = static_cast(bufferData.size()); + const uint8_t bufferDataSize = aznumeric_cast(bufferData.size()); for (uint8_t i = 0; i < bufferDataSize; ++i) { bufferData[i] = i; @@ -248,7 +248,8 @@ namespace UnitTest return asset; } - AZ::Data::Asset BuildTestModel(const uint32_t lodCount, const uint32_t sharedMeshCount, const uint32_t separateMeshCount, ExpectedModel& expectedModel) + AZ::Data::Asset BuildTestModel( + const uint32_t lodCount, const uint32_t sharedMeshCount, const uint32_t separateMeshCount, ExpectedModel& expectedModel) { using namespace AZ; @@ -989,6 +990,9 @@ namespace UnitTest uint32_t{ 0 }, 2, 1, 1, 2, 3, 4, 5, 6, 5, 7, 6, 0, 4, 2, 4, 6, 2, 1, 3, 5, 5, 3, 7, 0, 1, 4, 4, 1, 5, 2, 6, 3, 6, 7, 3, }; + static constexpr AZStd::array QuadPositions = { -1.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, -1.0f, -1.0f, 0.0f, 1.0f, -1.0f, 0.0f }; + static constexpr AZStd::array QuadIndices = { uint32_t{ 0 }, 2, 1, 1, 2, 3 }; + // This class creates a Model with one LOD, whose mesh contains 2 planes. Plane 1 is in the XY plane at Z=-0.5, and // plane 2 is in the XY plane at Z=0.5. The two planes each have 9 quads which have been triangulated. It only has // a position and index buffer. @@ -1031,42 +1035,80 @@ namespace UnitTest static constexpr inline auto minmaxElement = AZStd::minmax_element(begin(TwoSeparatedPlanesIndices), end(TwoSeparatedPlanesIndices)); static_assert(*minmaxElement.second == (TwoSeparatedPlanesPositions.size() / 3) - 1); - template class TD; class TestMesh { public: + TestMesh() = default; + TestMesh(const float* positions, size_t positionCount, const uint32_t* indices, size_t indicesCount) { AZ::RPI::ModelLodAssetCreator lodCreator; - lodCreator.Begin(AZ::Data::AssetId(AZ::Uuid::CreateRandom())); + Begin(lodCreator); + Add(lodCreator, positions, positionCount, /*positionOffset=*/0, indices, indicesCount, /*indexOffset=*/0); + End(lodCreator); + } + // initiate the asset lod creation process (note: End must be called after meshes have been added). + void Begin(AZ::RPI::ModelLodAssetCreator& lodCreator) + { + lodCreator.Begin(AZ::Data::AssetId(AZ::Uuid::CreateRandom())); + } + + // add a sub mesh and reuse existing position/index buffer (be very careful with the offsets used) + void Add( + AZ::RPI::ModelLodAssetCreator& lodCreator, + const float* positions, + size_t positionCount, + size_t positionOffset, + AZ::Data::Asset positionBuffer, + const uint32_t* indices, + size_t indexCount, + size_t indexOffset, + AZ::Data::Asset indexBuffer) + { lodCreator.BeginMesh(); - lodCreator.SetMeshAabb(AZ::Aabb::CreateFromMinMax({-1.0f, -1.0f, -0.5f}, {1.0f, 1.0f, 0.5f})); + lodCreator.SetMeshAabb(AZ::Aabb::CreateFromMinMax({ -1.0f, -1.0f, -0.5f }, { 1.0f, 1.0f, 0.5f })); lodCreator.SetMeshMaterialSlot(AZ::Sfmt::GetInstance().Rand32()); - { - AZ::Data::Asset indexBuffer = BuildTestBuffer(static_cast(indicesCount), sizeof(uint32_t)); - AZStd::copy(indices, indices + indicesCount, reinterpret_cast(const_cast(indexBuffer->GetBuffer().data()))); - lodCreator.SetMeshIndexBuffer({ - indexBuffer, - AZ::RHI::BufferViewDescriptor::CreateStructured(0, static_cast(indicesCount), sizeof(uint32_t)) - }); - } + AZStd::copy( + indices, indices + indexCount, + reinterpret_cast(const_cast(indexBuffer->GetBuffer().data())) + indexOffset); + lodCreator.SetMeshIndexBuffer( + { indexBuffer, + AZ::RHI::BufferViewDescriptor::CreateStructured( + aznumeric_cast(indexOffset), aznumeric_cast(indexCount), sizeof(uint32_t)) }); + AZStd::copy( + positions, positions + positionCount, + reinterpret_cast(const_cast(positionBuffer->GetBuffer().data())) + positionOffset); + lodCreator.AddMeshStreamBuffer( + AZ::RHI::ShaderSemantic(AZ::Name("POSITION")), AZ::Name(), + { positionBuffer, + AZ::RHI::BufferViewDescriptor::CreateStructured( + aznumeric_cast(positionOffset / 3), aznumeric_cast(positionCount / 3), sizeof(float) * 3) }); - { - AZ::Data::Asset positionBuffer = BuildTestBuffer(static_cast(positionCount / 3), sizeof(float) * 3); - AZStd::copy(positions, positions + positionCount, reinterpret_cast(const_cast(positionBuffer->GetBuffer().data()))); - lodCreator.AddMeshStreamBuffer( - AZ::RHI::ShaderSemantic(AZ::Name("POSITION")), - AZ::Name(), - { - positionBuffer, - AZ::RHI::BufferViewDescriptor::CreateStructured(0, static_cast(positionCount / 3), sizeof(float) * 3) - } - ); - } lodCreator.EndMesh(); + } + // overload of Add - here a new index/position buffer is created for the new data instead of potentially reusing an existing buffer + void Add( + AZ::RPI::ModelLodAssetCreator& lodCreator, + const float* positions, + size_t positionCount, + size_t positionOffset, + const uint32_t* indices, + size_t indexCount, + size_t indexOffset) + { + AZ::Data::Asset indexBuffer = BuildTestBuffer(aznumeric_cast(indexCount), sizeof(uint32_t)); + AZ::Data::Asset positionBuffer = + BuildTestBuffer(aznumeric_cast(positionCount / 3), sizeof(float) * 3); + + Add(lodCreator, positions, positionCount, positionOffset, positionBuffer, indices, indexCount, indexOffset, indexBuffer); + } + + // complete the asset lod creation process + void End(AZ::RPI::ModelLodAssetCreator& lodCreator) + { AZ::Data::Asset lodAsset; lodCreator.End(lodAsset); @@ -1199,7 +1241,7 @@ namespace UnitTest constexpr float rayLength = 100.0f; EXPECT_THAT( m_kdTree->RayIntersection( - AZ::Vector3::CreateZero(), AZ::Vector3::CreateAxisZ(-rayLength), t, normal), testing::Eq(true)); + AZ::Vector3::CreateZero(), AZ::Vector3::CreateAxisZ(-rayLength), t, normal), testing::IsTrue()); EXPECT_THAT(t, testing::FloatEq(0.005f)); } @@ -1210,7 +1252,7 @@ namespace UnitTest constexpr float rayLength = 10.0f; EXPECT_THAT( - m_kdTree->RayIntersection(AZ::Vector3::CreateAxisZ(0.75f), AZ::Vector3::CreateAxisZ(-rayLength), t, normal), testing::Eq(true)); + m_kdTree->RayIntersection(AZ::Vector3::CreateAxisZ(0.75f), AZ::Vector3::CreateAxisZ(-rayLength), t, normal), testing::IsTrue()); EXPECT_THAT(t, testing::FloatEq(0.025f)); } @@ -1288,7 +1330,7 @@ namespace UnitTest EXPECT_THAT( m_mesh->GetModel()->LocalRayIntersectionAgainstModel( AZ::Vector3::CreateAxisZ(5.0f), -AZ::Vector3::CreateAxisZ(10.0f), AllowBruteForce, t, normal), - testing::Eq(true)); + testing::IsTrue()); EXPECT_THAT(t, testing::FloatEq(0.4f)); } @@ -1302,8 +1344,87 @@ namespace UnitTest EXPECT_THAT( m_mesh->GetModel()->LocalRayIntersectionAgainstModel( AZ::Vector3::CreateAxisY(10.0f), -AZ::Vector3::CreateAxisY(9.0f), AllowBruteForce, t, normal), - testing::Eq(true)); + testing::IsTrue()); EXPECT_THAT(t, testing::FloatEq(1.0f)); EXPECT_THAT(normal, IsClose(AZ::Vector3::CreateAxisY())); } + + // test to verify that each secondary sub meshes are still intersected with correctly when using brute-force + // ray intersection + class BruteForceMultiModelIntersectsFixture : public ModelTests + { + public: + inline static const float QuadOffsetX = 15.0f; + + void SetUp() override + { + ModelTests::SetUp(); + m_mesh = AZStd::make_unique(); + + AZ::RPI::ModelLodAssetCreator lodCreator; + m_mesh->Begin(lodCreator); + + // take default quad positions and offset in X by set amount + AZStd::vector offsetQuadPositions; + offsetQuadPositions.resize(QuadPositions.size()); + AZStd::copy(QuadPositions.begin(), QuadPositions.end(), offsetQuadPositions.begin()); + for (size_t xVertIndex = 0; xVertIndex < offsetQuadPositions.size(); xVertIndex += 3) + { + offsetQuadPositions[xVertIndex] += QuadOffsetX; + } + + // create shared buffer to store cube and quad mesh in the same buffer + const size_t indicesCount = QuadIndices.size() + CubeIndices.size(); + const size_t positionCount = QuadPositions.size() + CubePositions.size(); + AZ::Data::Asset indexBuffer = BuildTestBuffer(aznumeric_cast(indicesCount), sizeof(uint32_t)); + AZ::Data::Asset positionBuffer = + BuildTestBuffer(aznumeric_cast(positionCount / 3), sizeof(float) * 3); + + // add the cube mesh + m_mesh->Add( + lodCreator, CubePositions.data(), CubePositions.size(), 0, positionBuffer, CubeIndices.data(), CubeIndices.size(), 0, + indexBuffer); + // add the quad mesh (offset by the cube position and index data into the same buffer) + m_mesh->Add( + lodCreator, offsetQuadPositions.data(), offsetQuadPositions.size(), /*offset=*/CubePositions.size(), positionBuffer, + QuadIndices.data(), QuadIndices.size(), /*offset=*/CubeIndices.size(), indexBuffer); + + m_mesh->End(lodCreator); + } + + void TearDown() override + { + m_mesh.reset(); + ModelTests::TearDown(); + } + + AZStd::unique_ptr m_mesh; + inline static constexpr bool AllowBruteForce = false; + }; + + TEST_F(BruteForceMultiModelIntersectsFixture, RayIntersectsWithFirstSubMesh) + { + float t = 0.0f; + AZ::Vector3 normal = AZ::Vector3::CreateOne(); // invalid starting normal + // fire a ray at the first sub mesh and ensure a successful hit is returned + EXPECT_THAT( + m_mesh->GetModel()->LocalRayIntersectionAgainstModel( + AZ::Vector3(0.0f, 0.0f, 5.0f), -AZ::Vector3::CreateAxisZ(10.0f), AllowBruteForce, t, normal), + testing::IsTrue()); + EXPECT_THAT(t, testing::FloatEq(0.4f)); + EXPECT_THAT(normal, IsClose(AZ::Vector3::CreateAxisZ())); + } + + TEST_F(BruteForceMultiModelIntersectsFixture, RayIntersectsWithSecondSubMesh) + { + float t = 0.0f; + AZ::Vector3 normal = AZ::Vector3::CreateOne(); // invalid starting normal + // fire a ray at the second sub mesh and ensure a successful hit is returned + EXPECT_THAT( + m_mesh->GetModel()->LocalRayIntersectionAgainstModel( + AZ::Vector3(QuadOffsetX, 0.0f, 5.0f), -AZ::Vector3::CreateAxisZ(10.0f), AllowBruteForce, t, normal), + testing::IsTrue()); + EXPECT_THAT(t, testing::FloatEq(0.5f)); + EXPECT_THAT(normal, IsClose(AZ::Vector3::CreateAxisZ())); + } } // namespace UnitTest